diff --git a/yt_dlp/extractor/youtube.py b/yt_dlp/extractor/youtube.py index 9eaa5c08d5..d30faf94ce 100644 --- a/yt_dlp/extractor/youtube.py +++ b/yt_dlp/extractor/youtube.py @@ -2998,19 +2998,29 @@ def _real_extract(self, url): return self.url_result(video_id, ie=YoutubeIE.ie_key(), video_id=video_id) self.to_screen('Downloading playlist %s - add --no-playlist to just download video %s' % (playlist_id, video_id)) - webpage = self._download_webpage(url, item_id) - identity_token = self._extract_identity_token(webpage, item_id) - data = self._extract_yt_initial_data(item_id, webpage) - err_msg = None - for alert_type, alert_message in self._extract_alerts(data): - if alert_type.lower() == 'error': - if err_msg: - self._downloader.report_warning('YouTube said: %s - %s' % ('ERROR', err_msg)) - err_msg = alert_message - else: - self._downloader.report_warning('YouTube said: %s - %s' % (alert_type, alert_message)) - if err_msg: - raise ExtractorError('YouTube said: %s' % err_msg, expected=True) + count = 0 + retries = 3 + while count < retries: + # Sometimes youtube returns a webpage with incomplete ytInitialData + webpage = self._download_webpage(url, item_id) + identity_token = self._extract_identity_token(webpage, item_id) + data = self._extract_yt_initial_data(item_id, webpage) + err_msg = None + for alert_type, alert_message in self._extract_alerts(data): + if alert_type.lower() == 'error': + if err_msg: + self._downloader.report_warning('YouTube said: %s - %s' % ('ERROR', err_msg)) + err_msg = alert_message + else: + self._downloader.report_warning('YouTube said: %s - %s' % (alert_type, alert_message)) + if err_msg: + raise ExtractorError('YouTube said: %s' % err_msg, expected=True) + if data.get('contents') or data.get('currentVideoEndpoint'): + break + count += 1 + self.to_screen( + 'Incomplete yt initial data recieved. Retrying (attempt %d of %d)...' % (count, retries)) + tabs = try_get( data, lambda x: x['contents']['twoColumnBrowseResultsRenderer']['tabs'], list) if tabs: