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