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