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