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