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