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