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