|
|
|
@ -77,25 +77,25 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
|
|
|
|
|
|
|
|
|
|
# Log in
|
|
|
|
|
login_form_strs = {
|
|
|
|
|
'continue': 'https://www.youtube.com/signin?action_handle_signin=true&feature=sign_in_button&hl=en_US&nomobiletemp=1',
|
|
|
|
|
'Email': username,
|
|
|
|
|
'GALX': galx,
|
|
|
|
|
'Passwd': password,
|
|
|
|
|
|
|
|
|
|
'PersistentCookie': 'yes',
|
|
|
|
|
'_utf8': '霱',
|
|
|
|
|
'bgresponse': 'js_disabled',
|
|
|
|
|
'checkConnection': '',
|
|
|
|
|
'checkedDomains': 'youtube',
|
|
|
|
|
'dnConn': '',
|
|
|
|
|
'pstMsg': '0',
|
|
|
|
|
'rmShown': '1',
|
|
|
|
|
'secTok': '',
|
|
|
|
|
'signIn': 'Sign in',
|
|
|
|
|
'timeStmp': '',
|
|
|
|
|
'service': 'youtube',
|
|
|
|
|
'uilel': '3',
|
|
|
|
|
'hl': 'en_US',
|
|
|
|
|
'continue': 'https://www.youtube.com/signin?action_handle_signin=true&feature=sign_in_button&hl=en_US&nomobiletemp=1',
|
|
|
|
|
'Email': username,
|
|
|
|
|
'GALX': galx,
|
|
|
|
|
'Passwd': password,
|
|
|
|
|
|
|
|
|
|
'PersistentCookie': 'yes',
|
|
|
|
|
'_utf8': '霱',
|
|
|
|
|
'bgresponse': 'js_disabled',
|
|
|
|
|
'checkConnection': '',
|
|
|
|
|
'checkedDomains': 'youtube',
|
|
|
|
|
'dnConn': '',
|
|
|
|
|
'pstMsg': '0',
|
|
|
|
|
'rmShown': '1',
|
|
|
|
|
'secTok': '',
|
|
|
|
|
'signIn': 'Sign in',
|
|
|
|
|
'timeStmp': '',
|
|
|
|
|
'service': 'youtube',
|
|
|
|
|
'uilel': '3',
|
|
|
|
|
'hl': 'en_US',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Convert to UTF-8 *before* urlencode because Python 2.x's urlencode
|
|
|
|
@ -181,8 +181,10 @@ class YoutubeBaseInfoExtractor(InfoExtractor):
|
|
|
|
|
'next_url': '/',
|
|
|
|
|
'action_confirm': 'Confirm',
|
|
|
|
|
}
|
|
|
|
|
req = compat_urllib_request.Request(self._AGE_URL,
|
|
|
|
|
compat_urllib_parse.urlencode(age_form).encode('ascii'))
|
|
|
|
|
req = compat_urllib_request.Request(
|
|
|
|
|
self._AGE_URL,
|
|
|
|
|
compat_urllib_parse.urlencode(age_form).encode('ascii')
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
self._download_webpage(
|
|
|
|
|
req, None,
|
|
|
|
@ -492,7 +494,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
|
|
|
|
|
def gen_sig_code(idxs):
|
|
|
|
|
def _genslice(start, end, step):
|
|
|
|
|
starts = '' if start == 0 else str(start)
|
|
|
|
|
ends = (':%d' % (end+step)) if end + step >= 0 else ':'
|
|
|
|
|
ends = (':%d' % (end + step)) if end + step >= 0 else ':'
|
|
|
|
|
steps = '' if step == 1 else (':%d' % step)
|
|
|
|
|
return 's[%s%s%s]' % (starts, ends, steps)
|
|
|
|
|
|
|
|
|
@ -530,7 +532,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
|
|
|
|
|
def _parse_sig_js(self, jscode):
|
|
|
|
|
funcname = self._search_regex(
|
|
|
|
|
r'\.sig\|\|([a-zA-Z0-9]+)\(', jscode,
|
|
|
|
|
'Initial JS player signature function name')
|
|
|
|
|
'Initial JS player signature function name')
|
|
|
|
|
|
|
|
|
|
jsi = JSInterpreter(jscode)
|
|
|
|
|
initial_function = jsi.extract_function(funcname)
|
|
|
|
@ -656,7 +658,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
|
|
|
|
|
def _get_urls(_manifest):
|
|
|
|
|
lines = _manifest.split('\n')
|
|
|
|
|
urls = filter(lambda l: l and not l.startswith('#'),
|
|
|
|
|
lines)
|
|
|
|
|
lines)
|
|
|
|
|
return urls
|
|
|
|
|
manifest = self._download_webpage(manifest_url, video_id, 'Downloading formats manifest')
|
|
|
|
|
formats_urls = _get_urls(manifest)
|
|
|
|
@ -723,10 +725,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
|
|
|
|
|
age_gate = False
|
|
|
|
|
for el_type in ['&el=embedded', '&el=detailpage', '&el=vevo', '']:
|
|
|
|
|
video_info_url = (proto + '://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en'
|
|
|
|
|
% (video_id, el_type))
|
|
|
|
|
% (video_id, el_type))
|
|
|
|
|
video_info_webpage = self._download_webpage(video_info_url, video_id,
|
|
|
|
|
note=False,
|
|
|
|
|
errnote='unable to download video info webpage')
|
|
|
|
|
note=False,
|
|
|
|
|
errnote='unable to download video info webpage')
|
|
|
|
|
video_info = compat_parse_qs(video_info_webpage)
|
|
|
|
|
if 'token' in video_info:
|
|
|
|
|
break
|
|
|
|
@ -1017,23 +1019,23 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
|
|
|
|
|
self._sort_formats(formats)
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
'id': video_id,
|
|
|
|
|
'uploader': video_uploader,
|
|
|
|
|
'uploader_id': video_uploader_id,
|
|
|
|
|
'upload_date': upload_date,
|
|
|
|
|
'title': video_title,
|
|
|
|
|
'thumbnail': video_thumbnail,
|
|
|
|
|
'description': video_description,
|
|
|
|
|
'categories': video_categories,
|
|
|
|
|
'subtitles': video_subtitles,
|
|
|
|
|
'duration': video_duration,
|
|
|
|
|
'age_limit': 18 if age_gate else 0,
|
|
|
|
|
'annotations': video_annotations,
|
|
|
|
|
'id': video_id,
|
|
|
|
|
'uploader': video_uploader,
|
|
|
|
|
'uploader_id': video_uploader_id,
|
|
|
|
|
'upload_date': upload_date,
|
|
|
|
|
'title': video_title,
|
|
|
|
|
'thumbnail': video_thumbnail,
|
|
|
|
|
'description': video_description,
|
|
|
|
|
'categories': video_categories,
|
|
|
|
|
'subtitles': video_subtitles,
|
|
|
|
|
'duration': video_duration,
|
|
|
|
|
'age_limit': 18 if age_gate else 0,
|
|
|
|
|
'annotations': video_annotations,
|
|
|
|
|
'webpage_url': proto + '://www.youtube.com/watch?v=%s' % video_id,
|
|
|
|
|
'view_count': view_count,
|
|
|
|
|
'view_count': view_count,
|
|
|
|
|
'like_count': like_count,
|
|
|
|
|
'dislike_count': dislike_count,
|
|
|
|
|
'formats': formats,
|
|
|
|
|
'formats': formats,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1167,7 +1169,7 @@ class YoutubePlaylistIE(YoutubeBaseInfoExtractor):
|
|
|
|
|
return self._extract_mix(playlist_id)
|
|
|
|
|
if playlist_id.startswith('TL'):
|
|
|
|
|
raise ExtractorError('For downloading YouTube.com top lists, use '
|
|
|
|
|
'the "yttoplist" keyword, for example "youtube-dl \'yttoplist:music:Top Tracks\'"', expected=True)
|
|
|
|
|
'the "yttoplist" keyword, for example "youtube-dl \'yttoplist:music:Top Tracks\'"', expected=True)
|
|
|
|
|
|
|
|
|
|
url = self._TEMPLATE_URL % playlist_id
|
|
|
|
|
page = self._download_webpage(url, playlist_id)
|
|
|
|
@ -1546,8 +1548,8 @@ class YoutubeFeedsInfoExtractor(YoutubeBaseInfoExtractor):
|
|
|
|
|
paging = 0
|
|
|
|
|
for i in itertools.count(1):
|
|
|
|
|
info = self._download_json(self._FEED_TEMPLATE % paging,
|
|
|
|
|
'%s feed' % self._FEED_NAME,
|
|
|
|
|
'Downloading page %s' % i)
|
|
|
|
|
'%s feed' % self._FEED_NAME,
|
|
|
|
|
'Downloading page %s' % i)
|
|
|
|
|
feed_html = info.get('feed_html') or info.get('content_html')
|
|
|
|
|
load_more_widget_html = info.get('load_more_widget_html') or feed_html
|
|
|
|
|
m_ids = re.finditer(r'"/watch\?v=(.*?)["&]', feed_html)
|
|
|
|
|