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