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