[Youtube] Fix private feeds/playlists on multi-channel accounts (#143)
Authored by: colethedj
This commit is contained in:
parent
f3eaa8dd1c
commit
d069eca7a3
1 changed files with 22 additions and 6 deletions
|
@ -301,7 +301,6 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
|
||||||
auth = self._generate_sapisidhash_header()
|
auth = self._generate_sapisidhash_header()
|
||||||
if auth is not None:
|
if auth is not None:
|
||||||
headers.update({'Authorization': auth, 'X-Origin': 'https://www.youtube.com'})
|
headers.update({'Authorization': auth, 'X-Origin': 'https://www.youtube.com'})
|
||||||
|
|
||||||
return self._download_json(
|
return self._download_json(
|
||||||
'https://www.youtube.com/youtubei/v1/%s' % ep,
|
'https://www.youtube.com/youtubei/v1/%s' % ep,
|
||||||
video_id=video_id, fatal=fatal, note=note, errnote=errnote,
|
video_id=video_id, fatal=fatal, note=note, errnote=errnote,
|
||||||
|
@ -2704,7 +2703,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
ctp = continuation_ep.get('clickTrackingParams')
|
ctp = continuation_ep.get('clickTrackingParams')
|
||||||
return YoutubeTabIE._build_continuation_query(continuation, ctp)
|
return YoutubeTabIE._build_continuation_query(continuation, ctp)
|
||||||
|
|
||||||
def _entries(self, tab, identity_token, item_id):
|
def _entries(self, tab, item_id, identity_token, account_syncid):
|
||||||
|
|
||||||
def extract_entries(parent_renderer): # this needs to called again for continuation to work with feeds
|
def extract_entries(parent_renderer): # this needs to called again for continuation to work with feeds
|
||||||
contents = try_get(parent_renderer, lambda x: x['contents'], list) or []
|
contents = try_get(parent_renderer, lambda x: x['contents'], list) or []
|
||||||
|
@ -2764,6 +2763,10 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
if identity_token:
|
if identity_token:
|
||||||
headers['x-youtube-identity-token'] = identity_token
|
headers['x-youtube-identity-token'] = identity_token
|
||||||
|
|
||||||
|
if account_syncid:
|
||||||
|
headers['X-Goog-PageId'] = account_syncid
|
||||||
|
headers['X-Goog-AuthUser'] = 0
|
||||||
|
|
||||||
for page_num in itertools.count(1):
|
for page_num in itertools.count(1):
|
||||||
if not continuation:
|
if not continuation:
|
||||||
break
|
break
|
||||||
|
@ -2883,7 +2886,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
try_get(owner, lambda x: x['navigationEndpoint']['browseEndpoint']['canonicalBaseUrl'], compat_str))
|
try_get(owner, lambda x: x['navigationEndpoint']['browseEndpoint']['canonicalBaseUrl'], compat_str))
|
||||||
return {k: v for k, v in uploader.items() if v is not None}
|
return {k: v for k, v in uploader.items() if v is not None}
|
||||||
|
|
||||||
def _extract_from_tabs(self, item_id, webpage, data, tabs, identity_token):
|
def _extract_from_tabs(self, item_id, webpage, data, tabs):
|
||||||
playlist_id = title = description = channel_url = channel_name = channel_id = None
|
playlist_id = title = description = channel_url = channel_name = channel_id = None
|
||||||
thumbnails_list = tags = []
|
thumbnails_list = tags = []
|
||||||
|
|
||||||
|
@ -2947,7 +2950,10 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
'channel_id': metadata['uploader_id'],
|
'channel_id': metadata['uploader_id'],
|
||||||
'channel_url': metadata['uploader_url']})
|
'channel_url': metadata['uploader_url']})
|
||||||
return self.playlist_result(
|
return self.playlist_result(
|
||||||
self._entries(selected_tab, identity_token, playlist_id),
|
self._entries(
|
||||||
|
selected_tab, playlist_id,
|
||||||
|
self._extract_identity_token(webpage, item_id),
|
||||||
|
self._extract_account_syncid(data)),
|
||||||
**metadata)
|
**metadata)
|
||||||
|
|
||||||
def _extract_mix_playlist(self, playlist, playlist_id):
|
def _extract_mix_playlist(self, playlist, playlist_id):
|
||||||
|
@ -3026,6 +3032,17 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
r'\bID_TOKEN["\']\s*:\s*["\'](.+?)["\']', webpage,
|
r'\bID_TOKEN["\']\s*:\s*["\'](.+?)["\']', webpage,
|
||||||
'identity token', default=None)
|
'identity token', default=None)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_account_syncid(data):
|
||||||
|
"""Extract syncId required to download private playlists of secondary channels"""
|
||||||
|
sync_ids = (
|
||||||
|
try_get(data, lambda x: x['responseContext']['mainAppWebResponseContext']['datasyncId'], compat_str)
|
||||||
|
or '').split("||")
|
||||||
|
if len(sync_ids) >= 2 and sync_ids[1]:
|
||||||
|
# datasyncid is of the form "channel_syncid||user_syncid" for secondary channel
|
||||||
|
# and just "user_syncid||" for primary channel. We only want the channel_syncid
|
||||||
|
return sync_ids[0]
|
||||||
|
|
||||||
def _extract_webpage(self, url, item_id):
|
def _extract_webpage(self, url, item_id):
|
||||||
retries = self._downloader.params.get('extractor_retries', 3)
|
retries = self._downloader.params.get('extractor_retries', 3)
|
||||||
count = -1
|
count = -1
|
||||||
|
@ -3085,8 +3102,7 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
|
||||||
tabs = try_get(
|
tabs = try_get(
|
||||||
data, lambda x: x['contents']['twoColumnBrowseResultsRenderer']['tabs'], list)
|
data, lambda x: x['contents']['twoColumnBrowseResultsRenderer']['tabs'], list)
|
||||||
if tabs:
|
if tabs:
|
||||||
identity_token = self._extract_identity_token(webpage, item_id)
|
return self._extract_from_tabs(item_id, webpage, data, tabs)
|
||||||
return self._extract_from_tabs(item_id, webpage, data, tabs, identity_token)
|
|
||||||
|
|
||||||
playlist = try_get(
|
playlist = try_get(
|
||||||
data, lambda x: x['contents']['twoColumnWatchNextResults']['playlist']['playlist'], dict)
|
data, lambda x: x['contents']['twoColumnWatchNextResults']['playlist']['playlist'], dict)
|
||||||
|
|
Loading…
Reference in a new issue