Add --get-duration (Fixes #859)
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 __authors__  = (
5     'Ricardo Garcia Gonzalez',
6     'Danny Colligan',
7     'Benjamin Johnson',
8     'Vasyl\' Vavrychuk',
9     'Witold Baryluk',
10     'Paweł Paprota',
11     'Gergely Imreh',
12     'Rogério Brito',
13     'Philipp Hagemeister',
14     'Sören Schulze',
15     'Kevin Ngo',
16     'Ori Avtalion',
17     'shizeeg',
18     'Filippo Valsorda',
19     'Christian Albrecht',
20     'Dave Vasilevsky',
21     'Jaime Marquínez Ferrándiz',
22     'Jeff Crouse',
23     'Osama Khalid',
24     'Michael Walter',
25     'M. Yasoob Ullah Khalid',
26     'Julien Fraichard',
27     'Johny Mo Swag',
28     'Axel Noack',
29     'Albert Kim',
30     'Pierre Rudloff',
31     'Huarong Huo',
32     'Ismael Mejía',
33     'Steffan \'Ruirize\' James',
34     'Andras Elso',
35     'Jelle van der Waa',
36     'Marcin Cieślak',
37     'Anton Larionov',
38     'Takuya Tsuchida',
39     'Sergey M.',
40 )
41
42 __license__ = 'Public Domain'
43
44 import codecs
45 import getpass
46 import optparse
47 import os
48 import random
49 import re
50 import shlex
51 import sys
52
53
54 from .utils import (
55     compat_print,
56     DateRange,
57     decodeOption,
58     determine_ext,
59     get_term_width,
60     DownloadError,
61     get_cachedir,
62     MaxDownloadsReached,
63     preferredencoding,
64     SameFileError,
65     std_headers,
66     write_string,
67 )
68 from .update import update_self
69 from .FileDownloader import (
70     FileDownloader,
71 )
72 from .extractor import gen_extractors
73 from .version import __version__
74 from .YoutubeDL import YoutubeDL
75 from .PostProcessor import (
76     FFmpegMetadataPP,
77     FFmpegVideoConvertor,
78     FFmpegExtractAudioPP,
79     FFmpegEmbedSubtitlePP,
80 )
81
82
83 def parseOpts(overrideArguments=None):
84     def _readOptions(filename_bytes, default=[]):
85         try:
86             optionf = open(filename_bytes)
87         except IOError:
88             return default  # silently skip if file is not present
89         try:
90             res = []
91             for l in optionf:
92                 res += shlex.split(l, comments=True)
93         finally:
94             optionf.close()
95         return res
96
97     def _format_option_string(option):
98         ''' ('-o', '--option') -> -o, --format METAVAR'''
99
100         opts = []
101
102         if option._short_opts:
103             opts.append(option._short_opts[0])
104         if option._long_opts:
105             opts.append(option._long_opts[0])
106         if len(opts) > 1:
107             opts.insert(1, ', ')
108
109         if option.takes_value(): opts.append(' %s' % option.metavar)
110
111         return "".join(opts)
112
113     def _comma_separated_values_options_callback(option, opt_str, value, parser):
114         setattr(parser.values, option.dest, value.split(','))
115
116     def _hide_login_info(opts):
117         opts = list(opts)
118         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
119             try:
120                 i = opts.index(private_opt)
121                 opts[i+1] = '<PRIVATE>'
122             except ValueError:
123                 pass
124         return opts
125
126     max_width = 80
127     max_help_position = 80
128
129     # No need to wrap help messages if we're on a wide console
130     columns = get_term_width()
131     if columns: max_width = columns
132
133     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
134     fmt.format_option_strings = _format_option_string
135
136     kw = {
137         'version'   : __version__,
138         'formatter' : fmt,
139         'usage' : '%prog [options] url [url...]',
140         'conflict_handler' : 'resolve',
141     }
142
143     parser = optparse.OptionParser(**kw)
144
145     # option groups
146     general        = optparse.OptionGroup(parser, 'General Options')
147     selection      = optparse.OptionGroup(parser, 'Video Selection')
148     authentication = optparse.OptionGroup(parser, 'Authentication Options')
149     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
150     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
151     downloader     = optparse.OptionGroup(parser, 'Download Options')
152     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
153     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
154     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
155
156     general.add_option('-h', '--help',
157             action='help', help='print this help text and exit')
158     general.add_option('-v', '--version',
159             action='version', help='print program version and exit')
160     general.add_option('-U', '--update',
161             action='store_true', dest='update_self', help='update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)')
162     general.add_option('-i', '--ignore-errors',
163             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
164     general.add_option('--abort-on-error',
165             action='store_false', dest='ignoreerrors',
166             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
167     general.add_option('--dump-user-agent',
168             action='store_true', dest='dump_user_agent',
169             help='display the current browser identification', default=False)
170     general.add_option('--user-agent',
171             dest='user_agent', help='specify a custom user agent', metavar='UA')
172     general.add_option('--referer',
173             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
174             metavar='REF', default=None)
175     general.add_option('--list-extractors',
176             action='store_true', dest='list_extractors',
177             help='List all supported extractors and the URLs they would handle', default=False)
178     general.add_option('--extractor-descriptions',
179             action='store_true', dest='list_extractor_descriptions',
180             help='Output descriptions of all supported extractors', default=False)
181     general.add_option(
182         '--proxy', dest='proxy', default=None, metavar='URL',
183         help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
184     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
185     general.add_option(
186         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
187         help='Location in the filesystem where youtube-dl can store downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl .')
188     general.add_option(
189         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
190         help='Disable filesystem caching')
191     general.add_option(
192         '--socket-timeout', dest='socket_timeout',
193         type=float, default=None, help=optparse.SUPPRESS_HELP)
194     general.add_option(
195         '--bidi-workaround', dest='bidi_workaround', action='store_true',
196         help=u'Work around terminals that lack bidirectional text support. Requires fribidi executable in PATH')
197
198
199     selection.add_option('--playlist-start',
200             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
201     selection.add_option('--playlist-end',
202             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
203     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
204     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
205     selection.add_option('--max-downloads', metavar='NUMBER',
206                          dest='max_downloads', type=int, default=None,
207                          help='Abort after downloading NUMBER files')
208     selection.add_option('--min-filesize', metavar='SIZE', dest='min_filesize', help="Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)", default=None)
209     selection.add_option('--max-filesize', metavar='SIZE', dest='max_filesize', help="Do not download any videos larger than SIZE (e.g. 50k or 44.6m)", default=None)
210     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
211     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
212     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
213     selection.add_option(
214         '--min-views', metavar='COUNT', dest='min_views',
215         default=None, type=int,
216         help="Do not download any videos with less than COUNT views",)
217     selection.add_option(
218         '--max-views', metavar='COUNT', dest='max_views',
219         default=None, type=int,
220         help="Do not download any videos with more than COUNT views",)
221     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
222     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
223                          help='download only videos suitable for the given age',
224                          default=None, type=int)
225     selection.add_option('--download-archive', metavar='FILE',
226                          dest='download_archive',
227                          help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
228
229
230     authentication.add_option('-u', '--username',
231             dest='username', metavar='USERNAME', help='account username')
232     authentication.add_option('-p', '--password',
233             dest='password', metavar='PASSWORD', help='account password')
234     authentication.add_option('-n', '--netrc',
235             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
236     authentication.add_option('--video-password',
237             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
238
239
240     video_format.add_option('-f', '--format',
241             action='store', dest='format', metavar='FORMAT', default='best',
242             help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
243     video_format.add_option('--all-formats',
244             action='store_const', dest='format', help='download all available video formats', const='all')
245     video_format.add_option('--prefer-free-formats',
246             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
247     video_format.add_option('--max-quality',
248             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
249     video_format.add_option('-F', '--list-formats',
250             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
251
252     subtitles.add_option('--write-sub', '--write-srt',
253             action='store_true', dest='writesubtitles',
254             help='write subtitle file', default=False)
255     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
256             action='store_true', dest='writeautomaticsub',
257             help='write automatic subtitle file (youtube only)', default=False)
258     subtitles.add_option('--all-subs',
259             action='store_true', dest='allsubtitles',
260             help='downloads all the available subtitles of the video', default=False)
261     subtitles.add_option('--list-subs',
262             action='store_true', dest='listsubtitles',
263             help='lists all available subtitles for the video', default=False)
264     subtitles.add_option('--sub-format',
265             action='store', dest='subtitlesformat', metavar='FORMAT',
266             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
267     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
268             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
269             default=[], callback=_comma_separated_values_options_callback,
270             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
271
272     downloader.add_option('-r', '--rate-limit',
273             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
274     downloader.add_option('-R', '--retries',
275             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
276     downloader.add_option('--buffer-size',
277             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
278     downloader.add_option('--no-resize-buffer',
279             action='store_true', dest='noresizebuffer',
280             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
281     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
282
283     verbosity.add_option('-q', '--quiet',
284             action='store_true', dest='quiet', help='activates quiet mode', default=False)
285     verbosity.add_option('-s', '--simulate',
286             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
287     verbosity.add_option('--skip-download',
288             action='store_true', dest='skip_download', help='do not download the video', default=False)
289     verbosity.add_option('-g', '--get-url',
290             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
291     verbosity.add_option('-e', '--get-title',
292             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
293     verbosity.add_option('--get-id',
294             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
295     verbosity.add_option('--get-thumbnail',
296             action='store_true', dest='getthumbnail',
297             help='simulate, quiet but print thumbnail URL', default=False)
298     verbosity.add_option('--get-description',
299             action='store_true', dest='getdescription',
300             help='simulate, quiet but print video description', default=False)
301     verbosity.add_option('--get-duration',
302             action='store_true', dest='getduration',
303             help='simulate, quiet but print video length', default=False)
304     verbosity.add_option('--get-filename',
305             action='store_true', dest='getfilename',
306             help='simulate, quiet but print output filename', default=False)
307     verbosity.add_option('--get-format',
308             action='store_true', dest='getformat',
309             help='simulate, quiet but print output format', default=False)
310     verbosity.add_option('-j', '--dump-json',
311             action='store_true', dest='dumpjson',
312             help='simulate, quiet but print JSON information', default=False)
313     verbosity.add_option('--newline',
314             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
315     verbosity.add_option('--no-progress',
316             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
317     verbosity.add_option('--console-title',
318             action='store_true', dest='consoletitle',
319             help='display progress in console titlebar', default=False)
320     verbosity.add_option('-v', '--verbose',
321             action='store_true', dest='verbose', help='print various debugging information', default=False)
322     verbosity.add_option('--dump-intermediate-pages',
323             action='store_true', dest='dump_intermediate_pages', default=False,
324             help='print downloaded pages to debug problems(very verbose)')
325     verbosity.add_option('--write-pages',
326             action='store_true', dest='write_pages', default=False,
327             help='Write downloaded intermediary pages to files in the current directory to debug problems')
328     verbosity.add_option('--youtube-print-sig-code',
329             action='store_true', dest='youtube_print_sig_code', default=False,
330             help=optparse.SUPPRESS_HELP)
331
332
333     filesystem.add_option('-t', '--title',
334             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
335     filesystem.add_option('--id',
336             action='store_true', dest='useid', help='use only video ID in file name', default=False)
337     filesystem.add_option('-l', '--literal',
338             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
339     filesystem.add_option('-A', '--auto-number',
340             action='store_true', dest='autonumber',
341             help='number downloaded files starting from 00000', default=False)
342     filesystem.add_option('-o', '--output',
343             dest='outtmpl', metavar='TEMPLATE',
344             help=('output filename template. Use %(title)s to get the title, '
345                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
346                   '%(autonumber)s to get an automatically incremented number, '
347                   '%(ext)s for the filename extension, '
348                   '%(format)s for the format description (like "22 - 1280x720" or "HD"),'
349                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"),'
350                   '%(upload_date)s for the upload date (YYYYMMDD), '
351                   '%(extractor)s for the provider (youtube, metacafe, etc), '
352                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
353                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
354                   'Use - to output to stdout. Can also be used to download to a different directory, '
355                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
356     filesystem.add_option('--autonumber-size',
357             dest='autonumber_size', metavar='NUMBER',
358             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
359     filesystem.add_option('--restrict-filenames',
360             action='store_true', dest='restrictfilenames',
361             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
362     filesystem.add_option('-a', '--batch-file',
363             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
364     filesystem.add_option('--load-info',
365             dest='load_info_filename', metavar='FILE',
366             help='json file containing the video information (created with the "--write-json" option')
367     filesystem.add_option('-w', '--no-overwrites',
368             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
369     filesystem.add_option('-c', '--continue',
370             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
371     filesystem.add_option('--no-continue',
372             action='store_false', dest='continue_dl',
373             help='do not resume partially downloaded files (restart from beginning)')
374     filesystem.add_option('--cookies',
375             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
376     filesystem.add_option('--no-part',
377             action='store_true', dest='nopart', help='do not use .part files', default=False)
378     filesystem.add_option('--no-mtime',
379             action='store_false', dest='updatetime',
380             help='do not use the Last-modified header to set the file modification time', default=True)
381     filesystem.add_option('--write-description',
382             action='store_true', dest='writedescription',
383             help='write video description to a .description file', default=False)
384     filesystem.add_option('--write-info-json',
385             action='store_true', dest='writeinfojson',
386             help='write video metadata to a .info.json file', default=False)
387     filesystem.add_option('--write-annotations',
388             action='store_true', dest='writeannotations',
389             help='write video annotations to a .annotation file', default=False)
390     filesystem.add_option('--write-thumbnail',
391             action='store_true', dest='writethumbnail',
392             help='write thumbnail image to disk', default=False)
393
394
395     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
396             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
397     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
398             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
399     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
400             help='ffmpeg/avconv audio quality specification, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default 5)')
401     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
402             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
403     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
404             help='keeps the video file on disk after the post-processing; the video is erased by default')
405     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
406             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
407     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
408             help='embed subtitles in the video (only for mp4 videos)')
409     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
410             help='add metadata to the files')
411
412
413     parser.add_option_group(general)
414     parser.add_option_group(selection)
415     parser.add_option_group(downloader)
416     parser.add_option_group(filesystem)
417     parser.add_option_group(verbosity)
418     parser.add_option_group(video_format)
419     parser.add_option_group(subtitles)
420     parser.add_option_group(authentication)
421     parser.add_option_group(postproc)
422
423     if overrideArguments is not None:
424         opts, args = parser.parse_args(overrideArguments)
425         if opts.verbose:
426             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
427     else:
428         systemConf = _readOptions('/etc/youtube-dl.conf')
429
430         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
431         if xdg_config_home:
432             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
433             if not os.path.isfile(userConfFile):
434                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
435         else:
436             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
437             if not os.path.isfile(userConfFile):
438                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
439         userConf = _readOptions(userConfFile, None)
440
441         if userConf is None:
442             appdata_dir = os.environ.get('appdata')
443             if appdata_dir:
444                 userConf = _readOptions(
445                     os.path.join(appdata_dir, 'youtube-dl', 'config'),
446                     default=None)
447                 if userConf is None:
448                     userConf = _readOptions(
449                         os.path.join(appdata_dir, 'youtube-dl', 'config.txt'),
450                         default=None)
451
452         if userConf is None:
453             userConf = _readOptions(
454                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf'),
455                 default=None)
456         if userConf is None:
457             userConf = _readOptions(
458                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf.txt'),
459                 default=None)
460
461         if userConf is None:
462             userConf = []
463
464         commandLineConf = sys.argv[1:]
465         argv = systemConf + userConf + commandLineConf
466         opts, args = parser.parse_args(argv)
467         if opts.verbose:
468             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
469             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
470             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
471
472     return parser, opts, args
473
474 def _real_main(argv=None):
475     # Compatibility fixes for Windows
476     if sys.platform == 'win32':
477         # https://github.com/rg3/youtube-dl/issues/820
478         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
479
480     parser, opts, args = parseOpts(argv)
481
482     # Set user agent
483     if opts.user_agent is not None:
484         std_headers['User-Agent'] = opts.user_agent
485
486     # Set referer
487     if opts.referer is not None:
488         std_headers['Referer'] = opts.referer
489
490     # Dump user agent
491     if opts.dump_user_agent:
492         compat_print(std_headers['User-Agent'])
493         sys.exit(0)
494
495     # Batch file verification
496     batchurls = []
497     if opts.batchfile is not None:
498         try:
499             if opts.batchfile == '-':
500                 batchfd = sys.stdin
501             else:
502                 batchfd = open(opts.batchfile, 'r')
503             batchurls = batchfd.readlines()
504             batchurls = [x.strip() for x in batchurls]
505             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
506             if opts.verbose:
507                 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
508         except IOError:
509             sys.exit(u'ERROR: batch file could not be read')
510     all_urls = batchurls + args
511     all_urls = [url.strip() for url in all_urls]
512
513     extractors = gen_extractors()
514
515     if opts.list_extractors:
516         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
517             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
518             matchedUrls = [url for url in all_urls if ie.suitable(url)]
519             all_urls = [url for url in all_urls if url not in matchedUrls]
520             for mu in matchedUrls:
521                 compat_print(u'  ' + mu)
522         sys.exit(0)
523     if opts.list_extractor_descriptions:
524         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
525             if not ie._WORKING:
526                 continue
527             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
528             if desc is False:
529                 continue
530             if hasattr(ie, 'SEARCH_KEY'):
531                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
532                 _COUNTS = (u'', u'5', u'10', u'all')
533                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
534             compat_print(desc)
535         sys.exit(0)
536
537
538     # Conflicting, missing and erroneous options
539     if opts.usenetrc and (opts.username is not None or opts.password is not None):
540         parser.error(u'using .netrc conflicts with giving username/password')
541     if opts.password is not None and opts.username is None:
542         parser.error(u' account username missing\n')
543     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
544         parser.error(u'using output template conflicts with using title, video ID or auto number')
545     if opts.usetitle and opts.useid:
546         parser.error(u'using title conflicts with using video ID')
547     if opts.username is not None and opts.password is None:
548         opts.password = getpass.getpass(u'Type account password and press return:')
549     if opts.ratelimit is not None:
550         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
551         if numeric_limit is None:
552             parser.error(u'invalid rate limit specified')
553         opts.ratelimit = numeric_limit
554     if opts.min_filesize is not None:
555         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
556         if numeric_limit is None:
557             parser.error(u'invalid min_filesize specified')
558         opts.min_filesize = numeric_limit
559     if opts.max_filesize is not None:
560         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
561         if numeric_limit is None:
562             parser.error(u'invalid max_filesize specified')
563         opts.max_filesize = numeric_limit
564     if opts.retries is not None:
565         try:
566             opts.retries = int(opts.retries)
567         except (TypeError, ValueError):
568             parser.error(u'invalid retry count specified')
569     if opts.buffersize is not None:
570         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
571         if numeric_buffersize is None:
572             parser.error(u'invalid buffer size specified')
573         opts.buffersize = numeric_buffersize
574     try:
575         opts.playliststart = int(opts.playliststart)
576         if opts.playliststart <= 0:
577             raise ValueError(u'Playlist start must be positive')
578     except (TypeError, ValueError):
579         parser.error(u'invalid playlist start number specified')
580     try:
581         opts.playlistend = int(opts.playlistend)
582         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
583             raise ValueError(u'Playlist end must be greater than playlist start')
584     except (TypeError, ValueError):
585         parser.error(u'invalid playlist end number specified')
586     if opts.extractaudio:
587         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
588             parser.error(u'invalid audio format specified')
589     if opts.audioquality:
590         opts.audioquality = opts.audioquality.strip('k').strip('K')
591         if not opts.audioquality.isdigit():
592             parser.error(u'invalid audio quality specified')
593     if opts.recodevideo is not None:
594         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
595             parser.error(u'invalid video recode format specified')
596     if opts.date is not None:
597         date = DateRange.day(opts.date)
598     else:
599         date = DateRange(opts.dateafter, opts.datebefore)
600
601     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
602     # this was the old behaviour if only --all-sub was given.
603     if opts.allsubtitles and (opts.writeautomaticsub == False):
604         opts.writesubtitles = True
605
606     if sys.version_info < (3,):
607         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
608         if opts.outtmpl is not None:
609             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
610     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
611             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
612             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
613             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
614             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
615             or (opts.useid and u'%(id)s.%(ext)s')
616             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
617             or u'%(title)s-%(id)s.%(ext)s')
618     if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
619         parser.error(u'Cannot download a video and extract audio into the same'
620                      u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
621                      u' template'.format(outtmpl))
622
623     any_printing = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson
624
625     ydl_opts = {
626         'usenetrc': opts.usenetrc,
627         'username': opts.username,
628         'password': opts.password,
629         'videopassword': opts.videopassword,
630         'quiet': (opts.quiet or any_printing),
631         'forceurl': opts.geturl,
632         'forcetitle': opts.gettitle,
633         'forceid': opts.getid,
634         'forcethumbnail': opts.getthumbnail,
635         'forcedescription': opts.getdescription,
636         'forceduration': opts.getduration,
637         'forcefilename': opts.getfilename,
638         'forceformat': opts.getformat,
639         'forcejson': opts.dumpjson,
640         'simulate': opts.simulate,
641         'skip_download': (opts.skip_download or opts.simulate or any_printing),
642         'format': opts.format,
643         'format_limit': opts.format_limit,
644         'listformats': opts.listformats,
645         'outtmpl': outtmpl,
646         'autonumber_size': opts.autonumber_size,
647         'restrictfilenames': opts.restrictfilenames,
648         'ignoreerrors': opts.ignoreerrors,
649         'ratelimit': opts.ratelimit,
650         'nooverwrites': opts.nooverwrites,
651         'retries': opts.retries,
652         'buffersize': opts.buffersize,
653         'noresizebuffer': opts.noresizebuffer,
654         'continuedl': opts.continue_dl,
655         'noprogress': opts.noprogress,
656         'progress_with_newline': opts.progress_with_newline,
657         'playliststart': opts.playliststart,
658         'playlistend': opts.playlistend,
659         'noplaylist': opts.noplaylist,
660         'logtostderr': opts.outtmpl == '-',
661         'consoletitle': opts.consoletitle,
662         'nopart': opts.nopart,
663         'updatetime': opts.updatetime,
664         'writedescription': opts.writedescription,
665         'writeannotations': opts.writeannotations,
666         'writeinfojson': opts.writeinfojson,
667         'writethumbnail': opts.writethumbnail,
668         'writesubtitles': opts.writesubtitles,
669         'writeautomaticsub': opts.writeautomaticsub,
670         'allsubtitles': opts.allsubtitles,
671         'listsubtitles': opts.listsubtitles,
672         'subtitlesformat': opts.subtitlesformat,
673         'subtitleslangs': opts.subtitleslangs,
674         'matchtitle': decodeOption(opts.matchtitle),
675         'rejecttitle': decodeOption(opts.rejecttitle),
676         'max_downloads': opts.max_downloads,
677         'prefer_free_formats': opts.prefer_free_formats,
678         'verbose': opts.verbose,
679         'dump_intermediate_pages': opts.dump_intermediate_pages,
680         'write_pages': opts.write_pages,
681         'test': opts.test,
682         'keepvideo': opts.keepvideo,
683         'min_filesize': opts.min_filesize,
684         'max_filesize': opts.max_filesize,
685         'min_views': opts.min_views,
686         'max_views': opts.max_views,
687         'daterange': date,
688         'cachedir': opts.cachedir,
689         'youtube_print_sig_code': opts.youtube_print_sig_code,
690         'age_limit': opts.age_limit,
691         'download_archive': opts.download_archive,
692         'cookiefile': opts.cookiefile,
693         'nocheckcertificate': opts.no_check_certificate,
694         'proxy': opts.proxy,
695         'socket_timeout': opts.socket_timeout,
696         'bidi_workaround': opts.bidi_workaround,
697     }
698
699     with YoutubeDL(ydl_opts) as ydl:
700         ydl.print_debug_header()
701         ydl.add_default_info_extractors()
702
703         # PostProcessors
704         # Add the metadata pp first, the other pps will copy it
705         if opts.addmetadata:
706             ydl.add_post_processor(FFmpegMetadataPP())
707         if opts.extractaudio:
708             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
709         if opts.recodevideo:
710             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
711         if opts.embedsubtitles:
712             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
713
714         # Update version
715         if opts.update_self:
716             update_self(ydl.to_screen, opts.verbose)
717
718         # Maybe do nothing
719         if (len(all_urls) < 1) and (opts.load_info_filename is None):
720             if not opts.update_self:
721                 parser.error(u'you must provide at least one URL')
722             else:
723                 sys.exit()
724
725         try:
726             if opts.load_info_filename is not None:
727                 retcode = ydl.download_with_info_file(opts.load_info_filename)
728             else:
729                 retcode = ydl.download(all_urls)
730         except MaxDownloadsReached:
731             ydl.to_screen(u'--max-download limit reached, aborting.')
732             retcode = 101
733
734     sys.exit(retcode)
735
736
737 def main(argv=None):
738     try:
739         _real_main(argv)
740     except DownloadError:
741         sys.exit(1)
742     except SameFileError:
743         sys.exit(u'ERROR: fixed output name but more than one file to download')
744     except KeyboardInterrupt:
745         sys.exit(u'\nERROR: Interrupted by user')