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