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