195
244
def to_stdout(self, message, skip_eol=False):
196
245
"""Print message to stdout if not in quiet mode."""
197
if not self._params.get('quiet', False):
198
print u'%s%s' % (message, [u'\n', u''][skip_eol]),
246
if not self.params.get('quiet', False):
247
print (u'%s%s' % (message, [u'\n', u''][skip_eol])).encode(preferredencoding()),
199
248
sys.stdout.flush()
201
250
def to_stderr(self, message):
202
251
"""Print message to stderr."""
203
print >>sys.stderr, message
252
print >>sys.stderr, message.encode(preferredencoding())
205
254
def fixed_template(self):
206
255
"""Checks if the output template is fixed."""
207
return (re.search(ur'(?u)%\(.+?\)s', self._params['outtmpl']) is None)
256
return (re.search(ur'(?u)%\(.+?\)s', self.params['outtmpl']) is None)
209
258
def trouble(self, message=None):
210
259
"""Determine action to take when a download problem appears.
212
261
Depending on if the downloader has been configured to ignore
213
262
download errors or not, this method may throw an exception or
214
not when errors are found, after printing the message. If it
215
doesn't raise, it returns an error code suitable to be returned
216
later as a program exit code to indicate error.
263
not when errors are found, after printing the message.
218
265
if message is not None:
219
266
self.to_stderr(message)
220
if not self._params.get('ignoreerrors', False):
267
if not self.params.get('ignoreerrors', False):
221
268
raise DownloadError(message)
269
self._download_retcode = 1
224
271
def slow_down(self, start_time, byte_counter):
225
272
"""Sleep if the download speed is over the rate limit."""
226
rate_limit = self._params.get('ratelimit', None)
273
rate_limit = self.params.get('ratelimit', None)
227
274
if rate_limit is None or byte_counter == 0:
229
276
now = time.time()
243
290
self.to_stdout(u'\r[download] %s of %s at %s ETA %s' %
244
291
(percent_str, data_len_str, speed_str, eta_str), skip_eol=True)
293
def report_resuming_byte(self, resume_len):
294
"""Report attemtp to resume at given byte."""
295
self.to_stdout(u'[download] Resuming download at byte %s' % resume_len)
297
def report_file_already_downloaded(self, file_name):
298
"""Report file has already been fully downloaded."""
299
self.to_stdout(u'[download] %s has already been downloaded' % file_name)
301
def report_unable_to_resume(self):
302
"""Report it was impossible to resume download."""
303
self.to_stdout(u'[download] Unable to resume')
246
305
def report_finish(self):
247
306
"""Report download finished."""
248
307
self.to_stdout(u'')
309
def process_info(self, info_dict):
310
"""Process a single dictionary returned by an InfoExtractor."""
311
# Do nothing else if in simulate mode
312
if self.params.get('simulate', False):
314
info_dict['url'] = self.verify_url(info_dict['url'])
315
except (OSError, IOError, urllib2.URLError, httplib.HTTPException, socket.error), err:
316
raise UnavailableFormatError
319
if self.params.get('forcetitle', False):
320
print info_dict['title'].encode(preferredencoding())
321
if self.params.get('forceurl', False):
322
print info_dict['url'].encode(preferredencoding())
327
template_dict = dict(info_dict)
328
template_dict['epoch'] = unicode(long(time.time()))
329
filename = self.params['outtmpl'] % template_dict
330
except (ValueError, KeyError), err:
331
self.trouble('ERROR: invalid output template or system charset: %s' % str(err))
332
if self.params['nooverwrites'] and os.path.exists(filename):
333
self.to_stderr(u'WARNING: file exists: %s; skipping' % filename)
337
self.pmkdir(filename)
338
except (OSError, IOError), err:
339
self.trouble('ERROR: unable to create directories: %s' % str(err))
343
success = self._do_download(filename, info_dict['url'])
344
except (OSError, IOError), err:
345
raise UnavailableFormatError
346
except (urllib2.URLError, httplib.HTTPException, socket.error), err:
347
self.trouble('ERROR: unable to download video data: %s' % str(err))
349
except (ContentTooShortError, ), err:
350
self.trouble('ERROR: content too short (expected %s bytes and served %s)' % (err.expected, err.downloaded))
355
self.post_process(filename, info_dict)
356
except (PostProcessingError), err:
357
self.trouble('ERROR: postprocessing: %s' % str(err))
250
360
def download(self, url_list):
251
361
"""Download a given list of URLs."""
253
362
if len(url_list) > 1 and self.fixed_template():
254
raise SameFileError(self._params['outtmpl'])
363
raise SameFileError(self.params['outtmpl'])
256
365
for url in url_list:
257
366
suitable_found = False
258
367
for ie in self._ies:
368
# Go to next InfoExtractor if not suitable
259
369
if not ie.suitable(url):
261
371
# Suitable InfoExtractor found
262
372
suitable_found = True
263
all_results = ie.extract(url)
264
results = [x for x in all_results if x is not None]
265
if len(results) != len(all_results):
266
retcode = self.trouble()
268
if len(results) > 1 and self.fixed_template():
269
raise SameFileError(self._params['outtmpl'])
271
for result in results:
273
if self._params.get('forcetitle', False):
274
print result['title']
275
if self._params.get('forceurl', False):
278
# Do nothing else if in simulate mode
279
if self._params.get('simulate', False):
283
filename = self._params['outtmpl'] % result
284
self.report_destination(filename)
285
except (ValueError, KeyError), err:
286
retcode = self.trouble('ERROR: invalid output template or system charset: %s' % str(err))
289
self.pmkdir(filename)
290
except (OSError, IOError), err:
291
retcode = self.trouble('ERROR: unable to create directories: %s' % str(err))
294
outstream = open(filename, 'wb')
295
except (OSError, IOError), err:
296
retcode = self.trouble('ERROR: unable to open for writing: %s' % str(err))
299
self._do_download(outstream, result['url'])
301
except (OSError, IOError), err:
302
retcode = self.trouble('ERROR: unable to write video data: %s' % str(err))
304
except (urllib2.URLError, httplib.HTTPException, socket.error), err:
305
retcode = self.trouble('ERROR: unable to download video data: %s' % str(err))
308
self.post_process(filename, result)
309
except (PostProcessingError), err:
310
retcode = self.trouble('ERROR: postprocessing: %s' % str(err))
373
# Extract information from URL and process it
376
# Suitable InfoExtractor had been found; go to next URL
314
379
if not suitable_found:
315
retcode = self.trouble('ERROR: no suitable InfoExtractor: %s' % url)
380
self.trouble('ERROR: no suitable InfoExtractor: %s' % url)
382
return self._download_retcode
319
384
def get_real_urls(self, url_list):
320
385
"""Download a given list of URLs."""
437
504
_LOGIN_URL = 'http://www.youtube.com/signup?next=/&gl=US&hl=en'
438
505
_AGE_URL = 'http://www.youtube.com/verify_age?next_url=/&gl=US&hl=en'
439
506
_NETRC_MACHINE = 'youtube'
507
_available_formats = ['22', '35', '18', '5', '17', '13', None] # listed in order of priority for -b flag
508
_video_extensions = {
442
516
def suitable(url):
443
517
return (re.match(YoutubeIE._VALID_URL, url) is not None)
445
def report_lang(self):
446
"""Report attempt to set language."""
447
self.to_stdout(u'[youtube] Setting language')
520
def htmlentity_transform(matchobj):
521
"""Transforms an HTML entity to a Unicode character."""
522
entity = matchobj.group(1)
524
# Known non-numeric HTML entity
525
if entity in htmlentitydefs.name2codepoint:
526
return unichr(htmlentitydefs.name2codepoint[entity])
529
mobj = re.match(ur'(?u)#(x?\d+)', entity)
531
numstr = mobj.group(1)
532
if numstr.startswith(u'x'):
534
numstr = u'0%s' % numstr
537
return unichr(long(numstr, base))
539
# Unknown entity in name, return its literal representation
540
return (u'&%s;' % entity)
543
def report_lang(self):
544
"""Report attempt to set language."""
545
self._downloader.to_stdout(u'[youtube] Setting language')
449
547
def report_login(self):
450
548
"""Report attempt to log in."""
451
self.to_stdout(u'[youtube] Logging in')
549
self._downloader.to_stdout(u'[youtube] Logging in')
453
551
def report_age_confirmation(self):
454
552
"""Report attempt to confirm age."""
455
self.to_stdout(u'[youtube] Confirming age')
457
def report_webpage_download(self, video_id):
458
"""Report attempt to download webpage."""
459
self.to_stdout(u'[youtube] %s: Downloading video webpage' % video_id)
553
self._downloader.to_stdout(u'[youtube] Confirming age')
555
def report_video_info_webpage_download(self, video_id):
556
"""Report attempt to download video info webpage."""
557
self._downloader.to_stdout(u'[youtube] %s: Downloading video info webpage' % video_id)
461
559
def report_information_extraction(self, video_id):
462
560
"""Report attempt to extract video information."""
463
self.to_stdout(u'[youtube] %s: Extracting video information' % video_id)
561
self._downloader.to_stdout(u'[youtube] %s: Extracting video information' % video_id)
563
def report_unavailable_format(self, video_id, format):
564
"""Report extracted video URL."""
565
self._downloader.to_stdout(u'[youtube] %s: Format %s not available' % (video_id, format))
465
567
def report_video_url(self, video_id, video_real_url):
466
568
"""Report extracted video URL."""
467
self.to_stdout(u'[youtube] %s: URL: %s' % (video_id, video_real_url))
569
self._downloader.to_stdout(u'[youtube] %s: URL: %s' % (video_id, video_real_url))
469
571
def _real_initialize(self):
571
686
print "...HD video OK!"
574
mobj = re.search(r', "t": "([^"]+)"', video_webpage)
689
mobj = re.search(r'(?m)&token=([^&]+)(?:&|$)', video_info_webpage)
576
self.to_stderr(u'ERROR: unable to extract "t" parameter')
578
video_real_url = 'http://uk.youtube.com/get_video?video_id=%s&t=%s' % (video_id, mobj.group(1))
691
# Attempt to see if YouTube has issued an error message
692
mobj = re.search(r'(?m)&reason=([^&]+)(?:&|$)', video_info_webpage)
694
self.to_stderr(u'ERROR: unable to extract "t" parameter')
695
print video_info_webpage
698
reason = unquote_plus(mobj.group(1))
699
self.to_stderr(u'ERROR: YouTube said: %s' % reason.decode('utf-8'))
701
token = unquote(mobj.group(1))
702
video_real_url = 'http://www.youtube.com/get_video?video_id=%s&t=%s&eurl=&el=detailpage&ps=default&gl=US&hl=en' % (video_id, token)
579
703
if format_param is not None:
580
704
video_real_url = '%s&fmt=%s' % (video_real_url, format_param)
583
mobj = re.search(r"var watchUsername = '([^']+)';", video_webpage)
707
mobj = re.search(r'(?m)&author=([^&]+)(?:&|$)', video_info_webpage)
585
self.to_stderr(u'ERROR: unable to extract uploader nickname')
587
video_uploader = mobj.group(1)
709
self._downloader.trouble(u'ERROR: unable to extract uploader nickname')
711
video_uploader = unquote(mobj.group(1))
590
mobj = re.search(r'(?im)<title>YouTube - ([^<]*)</title>', video_webpage)
714
mobj = re.search(r'(?m)&title=([^&]+)(?:&|$)', video_info_webpage)
592
self.to_stderr(u'ERROR: unable to extract video title')
594
video_title = mobj.group(1).decode('utf-8')
595
video_title = re.sub(ur'(?u)&(.+?);', lambda x: unichr(htmlentitydefs.name2codepoint[x.group(1)]), video_title)
716
self._downloader.trouble(u'ERROR: unable to extract video title')
718
video_title = unquote(mobj.group(1))
719
video_title = video_title.decode('utf-8')
720
video_title = re.sub(ur'(?u)&(.+?);', self.htmlentity_transform, video_title)
596
721
video_title = video_title.replace(os.sep, u'%')
598
723
# simplified title
599
724
simple_title = re.sub(ur'(?u)([^%s]+)' % simple_title_chars, ur'_', video_title)
600
725
simple_title = simple_title.strip(ur'_')
602
727
# Return information
604
729
'id': video_id.decode('utf-8'),
698
825
self.report_download_webpage(video_id)
699
826
webpage = urllib2.urlopen(request).read()
700
827
except (urllib2.URLError, httplib.HTTPException, socket.error), err:
701
self.to_stderr(u'ERROR: unable retrieve video webpage: %s' % str(err))
828
self._downloader.trouble(u'ERROR: unable retrieve video webpage: %s' % str(err))
704
831
# Extract URL, uploader and title from webpage
705
832
self.report_extraction(video_id)
706
mobj = re.search(r'(?m)"mediaURL":"(http.*?\.flv)"', webpage)
708
self.to_stderr(u'ERROR: unable to extract media URL')
710
mediaURL = mobj.group(1).replace('\\', '')
712
mobj = re.search(r'(?m)"gdaKey":"(.*?)"', webpage)
714
self.to_stderr(u'ERROR: unable to extract gdaKey')
716
gdaKey = mobj.group(1)
718
video_url = '%s?__gda__=%s' % (mediaURL, gdaKey)
833
mobj = re.search(r'(?m)&mediaURL=([^&]+)', webpage)
835
self._downloader.trouble(u'ERROR: unable to extract media URL')
837
mediaURL = urllib.unquote(mobj.group(1))
839
#mobj = re.search(r'(?m)&gdaKey=(.*?)&', webpage)
841
# self._downloader.trouble(u'ERROR: unable to extract gdaKey')
843
#gdaKey = mobj.group(1)
845
#video_url = '%s?__gda__=%s' % (mediaURL, gdaKey)
720
849
mobj = re.search(r'(?im)<title>(.*) - Video</title>', webpage)
722
self.to_stderr(u'ERROR: unable to extract title')
851
self._downloader.trouble(u'ERROR: unable to extract title')
724
853
video_title = mobj.group(1).decode('utf-8')
726
mobj = re.search(r'(?m)<li id="ChnlUsr">.*?Submitter:<br />(.*?)</li>', webpage)
728
self.to_stderr(u'ERROR: unable to extract uploader nickname')
730
video_uploader = re.sub(r'<.*?>', '', mobj.group(1))
734
'id': video_id.decode('utf-8'),
735
'url': video_url.decode('utf-8'),
736
'uploader': video_uploader.decode('utf-8'),
737
'title': video_title,
738
'stitle': simple_title,
739
'ext': video_extension.decode('utf-8'),
855
mobj = re.search(r'(?ms)<li id="ChnlUsr">.*?Submitter:.*?<a .*?>(.*?)<', webpage)
857
self._downloader.trouble(u'ERROR: unable to extract uploader nickname')
859
video_uploader = mobj.group(1)
862
# Process video information
863
self._downloader.process_info({
864
'id': video_id.decode('utf-8'),
865
'url': video_url.decode('utf-8'),
866
'uploader': video_uploader.decode('utf-8'),
867
'title': video_title,
868
'stitle': simple_title,
869
'ext': video_extension.decode('utf-8'),
871
except UnavailableFormatError:
872
self._downloader.trouble(u'ERROR: format not available for video')
875
class YoutubeSearchIE(InfoExtractor):
876
"""Information Extractor for YouTube search queries."""
877
_VALID_QUERY = r'ytsearch(\d+|all)?:[\s\S]+'
878
_TEMPLATE_URL = 'http://www.youtube.com/results?search_query=%s&page=%s&gl=US&hl=en'
879
_VIDEO_INDICATOR = r'href="/watch\?v=.+?"'
880
_MORE_PAGES_INDICATOR = r'(?m)>\s*Next\s*</a>'
882
_max_youtube_results = 1000
884
def __init__(self, youtube_ie, downloader=None):
885
InfoExtractor.__init__(self, downloader)
886
self._youtube_ie = youtube_ie
890
return (re.match(YoutubeSearchIE._VALID_QUERY, url) is not None)
892
def report_download_page(self, query, pagenum):
893
"""Report attempt to download playlist page with given number."""
894
self._downloader.to_stdout(u'[youtube] query "%s": Downloading page %s' % (query, pagenum))
896
def _real_initialize(self):
897
self._youtube_ie.initialize()
899
def _real_extract(self, query):
900
mobj = re.match(self._VALID_QUERY, query)
902
self._downloader.trouble(u'ERROR: invalid search query "%s"' % query)
905
prefix, query = query.split(':')
908
self._download_n_results(query, 1)
910
elif prefix == 'all':
911
self._download_n_results(query, self._max_youtube_results)
917
self._downloader.trouble(u'ERROR: invalid download number %s for query "%s"' % (n, query))
919
elif n > self._max_youtube_results:
920
self._downloader.to_stderr(u'WARNING: ytsearch returns max %i results (you requested %i)' % (self._max_youtube_results, n))
921
n = self._max_youtube_results
922
self._download_n_results(query, n)
924
except ValueError: # parsing prefix as integer fails
925
self._download_n_results(query, 1)
928
def _download_n_results(self, query, n):
929
"""Downloads a specified number of results for a query"""
936
self.report_download_page(query, pagenum)
937
result_url = self._TEMPLATE_URL % (urllib.quote_plus(query), pagenum)
938
request = urllib2.Request(result_url, None, std_headers)
940
page = urllib2.urlopen(request).read()
941
except (urllib2.URLError, httplib.HTTPException, socket.error), err:
942
self._downloader.trouble(u'ERROR: unable to download webpage: %s' % str(err))
945
# Extract video identifiers
946
for mobj in re.finditer(self._VIDEO_INDICATOR, page):
947
video_id = page[mobj.span()[0]:mobj.span()[1]].split('=')[2][:-1]
948
if video_id not in already_seen:
949
video_ids.append(video_id)
950
already_seen.add(video_id)
951
if len(video_ids) == n:
952
# Specified n videos reached
954
self._youtube_ie.extract('http://www.youtube.com/watch?v=%s' % id)
957
if re.search(self._MORE_PAGES_INDICATOR, page) is None:
959
self._youtube_ie.extract('http://www.youtube.com/watch?v=%s' % id)
962
pagenum = pagenum + 1
742
965
class YoutubePlaylistIE(InfoExtractor):
743
966
"""Information Extractor for YouTube playlists."""
745
_VALID_URL = r'(?:http://)?(?:\w+\.)?youtube.com/view_play_list\?p=(.+)'
968
_VALID_URL = r'(?:http://)?(?:\w+\.)?youtube.com/(?:view_play_list|my_playlists)\?.*?p=([^&]+).*'
746
969
_TEMPLATE_URL = 'http://www.youtube.com/view_play_list?p=%s&page=%s&gl=US&hl=en'
747
970
_VIDEO_INDICATOR = r'/watch\?v=(.+?)&'
748
_MORE_PAGES_INDICATOR = r'/view_play_list?p=%s&page=%s'
971
_MORE_PAGES_INDICATOR = r'/view_play_list?p=%s&page=%s'
749
972
_youtube_ie = None
751
974
def __init__(self, youtube_ie, downloader=None):
870
1092
# Parse command line
871
1093
parser = optparse.OptionParser(
872
1094
usage='Usage: %prog [options] url...',
873
version='2009.01.31',
1095
version='2009.09.13',
874
1096
conflict_handler='resolve',
876
1098
parser.add_option('-h', '--help',
877
1099
action='help', help='print this help text and exit')
878
1100
parser.add_option('-v', '--version',
879
1101
action='version', help='print program version and exit')
880
parser.add_option('-u', '--username',
1102
parser.add_option('-i', '--ignore-errors',
1103
action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
1104
parser.add_option('-r', '--rate-limit',
1105
dest='ratelimit', metavar='L', help='download rate limit (e.g. 50k or 44.6m)')
1107
authentication = optparse.OptionGroup(parser, 'Authentication Options')
1108
authentication.add_option('-u', '--username',
881
1109
dest='username', metavar='UN', help='account username')
882
parser.add_option('-p', '--password',
1110
authentication.add_option('-p', '--password',
883
1111
dest='password', metavar='PW', help='account password')
884
parser.add_option('-o', '--output',
885
dest='outtmpl', metavar='TPL', help='output filename template')
886
parser.add_option('-q', '--quiet',
1112
authentication.add_option('-n', '--netrc',
1113
action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
1114
parser.add_option_group(authentication)
1116
video_format = optparse.OptionGroup(parser, 'Video Format Options')
1117
video_format.add_option('-f', '--format',
1118
action='store', dest='format', metavar='FMT', help='video format code')
1119
video_format.add_option('-b', '--best-quality',
1120
action='store_const', dest='format', help='download the best quality video possible', const='0')
1121
video_format.add_option('-m', '--mobile-version',
1122
action='store_const', dest='format', help='alias for -f 17', const='17')
1123
video_format.add_option('-d', '--high-def',
1124
action='store_const', dest='format', help='alias for -f 22', const='22')
1125
parser.add_option_group(video_format)
1127
verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
1128
verbosity.add_option('-q', '--quiet',
887
1129
action='store_true', dest='quiet', help='activates quiet mode', default=False)
888
parser.add_option('-s', '--simulate',
1130
verbosity.add_option('-s', '--simulate',
889
1131
action='store_true', dest='simulate', help='do not download video', default=False)
890
parser.add_option('-t', '--title',
1132
verbosity.add_option('-g', '--get-url',
1133
action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
1134
verbosity.add_option('-e', '--get-title',
1135
action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
1136
parser.add_option_group(verbosity)
1138
filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
1139
filesystem.add_option('-t', '--title',
891
1140
action='store_true', dest='usetitle', help='use title in file name', default=False)
892
parser.add_option('-l', '--literal',
1141
filesystem.add_option('-l', '--literal',
893
1142
action='store_true', dest='useliteral', help='use literal title in file name', default=False)
894
parser.add_option('-n', '--netrc',
895
action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
896
parser.add_option('-g', '--get-url',
897
action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
898
parser.add_option('-e', '--get-title',
899
action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
900
parser.add_option('-f', '--format',
901
dest='format', metavar='FMT', help='video format code')
902
parser.add_option('-b', '--best-quality',
903
action='store_const', dest='format', help='alias for -f 18', const='18')
904
parser.add_option('-m', '--mobile-version',
905
action='store_const', dest='format', help='alias for -f 17', const='17')
906
parser.add_option('-i', '--ignore-errors',
907
action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
908
parser.add_option('-r', '--rate-limit',
909
dest='ratelimit', metavar='L', help='download rate limit (e.g. 50k or 44.6m)')
910
parser.add_option('-a', '--batch-file',
911
dest='batchfile', metavar='F', help='file containing URLs to download')
1143
filesystem.add_option('-o', '--output',
1144
dest='outtmpl', metavar='TPL', help='output filename template')
1145
filesystem.add_option('-a', '--batch-file',
1146
dest='batchfile', metavar='F', help='file containing URLs to download')
1147
filesystem.add_option('-w', '--no-overwrites',
1148
action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
1149
filesystem.add_option('-c', '--continue',
1150
action='store_true', dest='continue_dl', help='resume partially downloaded files', default=False)
1151
parser.add_option_group(filesystem)
912
1153
(opts, args) = parser.parse_args()
914
# Batch file verification
1155
# Batch file verification
916
1157
if opts.batchfile is not None:
918
batchurls = [line.strip() for line in open(opts.batchfile, 'r')]
920
sys.exit(u'ERROR: batch file could not be read')
1159
batchurls = open(opts.batchfile, 'r').readlines()
1160
batchurls = [x.strip() for x in batchurls]
1161
batchurls = [x for x in batchurls if len(x) > 0]
1163
sys.exit(u'ERROR: batch file could not be read')
921
1164
all_urls = batchurls + args
923
# Conflicting, missing and erroneous options
1166
# Conflicting, missing and erroneous options
924
1167
if len(all_urls) < 1:
925
sys.exit(u'ERROR: you must provide at least one URL')
1168
parser.error(u'you must provide at least one URL')
926
1169
if opts.usenetrc and (opts.username is not None or opts.password is not None):
927
sys.exit(u'ERROR: using .netrc conflicts with giving username/password')
1170
parser.error(u'using .netrc conflicts with giving username/password')
928
1171
if opts.password is not None and opts.username is None:
929
sys.exit(u'ERROR: account username missing')
1172
parser.error(u'account username missing')
930
1173
if opts.outtmpl is not None and (opts.useliteral or opts.usetitle):
931
sys.exit(u'ERROR: using output template conflicts with using title or literal title')
1174
parser.error(u'using output template conflicts with using title or literal title')
932
1175
if opts.usetitle and opts.useliteral:
933
sys.exit(u'ERROR: using title conflicts with using literal title')
1176
parser.error(u'using title conflicts with using literal title')
934
1177
if opts.username is not None and opts.password is None:
935
1178
opts.password = getpass.getpass(u'Type account password and press return:')
936
1179
if opts.ratelimit is not None:
937
1180
numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
938
1181
if numeric_limit is None:
939
sys.exit(u'ERROR: invalid rate limit specified')
1182
parser.error(u'invalid rate limit specified')
940
1183
opts.ratelimit = numeric_limit
942
1185
# Information extractors
943
1186
youtube_ie = YoutubeIE()
944
1187
metacafe_ie = MetacafeIE(youtube_ie)
945
1188
youtube_pl_ie = YoutubePlaylistIE(youtube_ie)
1189
youtube_search_ie = YoutubeSearchIE(youtube_ie)
947
1191
# File downloader
948
charset = locale.getdefaultlocale()[1]
951
1192
fd = FileDownloader({
952
1193
'usenetrc': opts.usenetrc,
953
1194
'username': opts.username,