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