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