|
|
@ -3950,12 +3950,13 @@ class YoutubeTabBaseInfoExtractor(YoutubeBaseInfoExtractor):
|
|
|
|
break
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
@staticmethod
|
|
|
|
def _extract_selected_tab(tabs):
|
|
|
|
def _extract_selected_tab(tabs, fatal=True):
|
|
|
|
for tab in tabs:
|
|
|
|
for tab in tabs:
|
|
|
|
renderer = dict_get(tab, ('tabRenderer', 'expandableTabRenderer')) or {}
|
|
|
|
renderer = dict_get(tab, ('tabRenderer', 'expandableTabRenderer')) or {}
|
|
|
|
if renderer.get('selected') is True:
|
|
|
|
if renderer.get('selected') is True:
|
|
|
|
return renderer
|
|
|
|
return renderer
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
|
|
|
|
if fatal:
|
|
|
|
raise ExtractorError('Unable to find selected tab')
|
|
|
|
raise ExtractorError('Unable to find selected tab')
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@classmethod
|
|
|
@ -4229,7 +4230,7 @@ class YoutubeTabBaseInfoExtractor(YoutubeBaseInfoExtractor):
|
|
|
|
self.report_warning(error_to_compat_str(e))
|
|
|
|
self.report_warning(error_to_compat_str(e))
|
|
|
|
break
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
if dict_get(data, ('contents', 'currentVideoEndpoint')):
|
|
|
|
if dict_get(data, ('contents', 'currentVideoEndpoint', 'onResponseReceivedActions')):
|
|
|
|
break
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
last_error = 'Incomplete yt initial data received'
|
|
|
|
last_error = 'Incomplete yt initial data received'
|
|
|
@ -4248,7 +4249,7 @@ class YoutubeTabBaseInfoExtractor(YoutubeBaseInfoExtractor):
|
|
|
|
ytcfg = ytcfg or self.extract_ytcfg(item_id, webpage)
|
|
|
|
ytcfg = ytcfg or self.extract_ytcfg(item_id, webpage)
|
|
|
|
# Reject webpage data if redirected to home page without explicitly requesting
|
|
|
|
# Reject webpage data if redirected to home page without explicitly requesting
|
|
|
|
selected_tab = self._extract_selected_tab(traverse_obj(
|
|
|
|
selected_tab = self._extract_selected_tab(traverse_obj(
|
|
|
|
data, ('contents', 'twoColumnBrowseResultsRenderer', 'tabs'), expected_type=list, default=[])) or {}
|
|
|
|
data, ('contents', 'twoColumnBrowseResultsRenderer', 'tabs'), expected_type=list, default=[]), fatal=False) or {}
|
|
|
|
if (url != 'https://www.youtube.com/feed/recommended'
|
|
|
|
if (url != 'https://www.youtube.com/feed/recommended'
|
|
|
|
and selected_tab.get('tabIdentifier') == 'FEwhat_to_watch' # Home page
|
|
|
|
and selected_tab.get('tabIdentifier') == 'FEwhat_to_watch' # Home page
|
|
|
|
and 'no-youtube-channel-redirect' not in self.get_param('compat_opts', [])):
|
|
|
|
and 'no-youtube-channel-redirect' not in self.get_param('compat_opts', [])):
|
|
|
@ -4280,7 +4281,7 @@ class YoutubeTabBaseInfoExtractor(YoutubeBaseInfoExtractor):
|
|
|
|
return self._extract_response(
|
|
|
|
return self._extract_response(
|
|
|
|
item_id=item_id, query=params, ep=ep, headers=headers,
|
|
|
|
item_id=item_id, query=params, ep=ep, headers=headers,
|
|
|
|
ytcfg=ytcfg, fatal=fatal, default_client=default_client,
|
|
|
|
ytcfg=ytcfg, fatal=fatal, default_client=default_client,
|
|
|
|
check_get_keys=('contents', 'currentVideoEndpoint'))
|
|
|
|
check_get_keys=('contents', 'currentVideoEndpoint', 'onResponseReceivedActions'))
|
|
|
|
err_note = 'Failed to resolve url (does the playlist exist?)'
|
|
|
|
err_note = 'Failed to resolve url (does the playlist exist?)'
|
|
|
|
if fatal:
|
|
|
|
if fatal:
|
|
|
|
raise ExtractorError(err_note, expected=True)
|
|
|
|
raise ExtractorError(err_note, expected=True)
|
|
|
@ -4981,6 +4982,10 @@ class YoutubeTabIE(YoutubeTabBaseInfoExtractor):
|
|
|
|
'skip_download': True,
|
|
|
|
'skip_download': True,
|
|
|
|
'extractor_args': {'youtubetab': {'skip': ['webpage']}}
|
|
|
|
'extractor_args': {'youtubetab': {'skip': ['webpage']}}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
'note': 'non-standard redirect to regional channel',
|
|
|
|
|
|
|
|
'url': 'https://www.youtube.com/channel/UCwVVpHQ2Cs9iGJfpdFngePQ',
|
|
|
|
|
|
|
|
'only_matching': True
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@classmethod
|
|
|
@ -5053,6 +5058,16 @@ class YoutubeTabIE(YoutubeTabBaseInfoExtractor):
|
|
|
|
|
|
|
|
|
|
|
|
data, ytcfg = self._extract_data(url, item_id)
|
|
|
|
data, ytcfg = self._extract_data(url, item_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# YouTube may provide a non-standard redirect to the regional channel
|
|
|
|
|
|
|
|
# See: https://github.com/yt-dlp/yt-dlp/issues/2694
|
|
|
|
|
|
|
|
redirect_url = traverse_obj(
|
|
|
|
|
|
|
|
data, ('onResponseReceivedActions', ..., 'navigateAction', 'endpoint', 'commandMetadata', 'webCommandMetadata', 'url'), get_all=False)
|
|
|
|
|
|
|
|
if redirect_url and 'no-youtube-channel-redirect' not in compat_opts:
|
|
|
|
|
|
|
|
redirect_url = ''.join((
|
|
|
|
|
|
|
|
urljoin('https://www.youtube.com', redirect_url), mobj['tab'], mobj['post']))
|
|
|
|
|
|
|
|
self.to_screen(f'This playlist is likely not available in your region. Following redirect to regional playlist {redirect_url}')
|
|
|
|
|
|
|
|
return self.url_result(redirect_url, ie=YoutubeTabIE.ie_key())
|
|
|
|
|
|
|
|
|
|
|
|
tabs = traverse_obj(data, ('contents', 'twoColumnBrowseResultsRenderer', 'tabs'), expected_type=list)
|
|
|
|
tabs = traverse_obj(data, ('contents', 'twoColumnBrowseResultsRenderer', 'tabs'), expected_type=list)
|
|
|
|
if tabs:
|
|
|
|
if tabs:
|
|
|
|
selected_tab = self._extract_selected_tab(tabs)
|
|
|
|
selected_tab = self._extract_selected_tab(tabs)
|
|
|
|