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