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