Add new --encoding option (Fixes #2650)
[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     general.add_option(
267         '--encoding', dest='encoding', metavar='ENCODING',
268         help='Force the specified encoding (experimental)')
269
270     selection.add_option(
271         '--playlist-start',
272         dest='playliststart', metavar='NUMBER', default=1, type=int,
273         help='playlist video to start at (default is %default)')
274     selection.add_option(
275         '--playlist-end',
276         dest='playlistend', metavar='NUMBER', default=None, type=int,
277         help='playlist video to end at (default is last)')
278     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
279     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
280     selection.add_option('--max-downloads', metavar='NUMBER',
281                          dest='max_downloads', type=int, default=None,
282                          help='Abort after downloading NUMBER files')
283     selection.add_option('--min-filesize', metavar='SIZE', dest='min_filesize', help="Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)", default=None)
284     selection.add_option('--max-filesize', metavar='SIZE', dest='max_filesize', help="Do not download any videos larger than SIZE (e.g. 50k or 44.6m)", default=None)
285     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
286     selection.add_option(
287         '--datebefore', metavar='DATE', dest='datebefore', default=None,
288         help='download only videos uploaded on or before this date (i.e. inclusive)')
289     selection.add_option(
290         '--dateafter', metavar='DATE', dest='dateafter', default=None,
291         help='download only videos uploaded on or after this date (i.e. inclusive)')
292     selection.add_option(
293         '--min-views', metavar='COUNT', dest='min_views',
294         default=None, type=int,
295         help="Do not download any videos with less than COUNT views",)
296     selection.add_option(
297         '--max-views', metavar='COUNT', dest='max_views',
298         default=None, type=int,
299         help="Do not download any videos with more than COUNT views",)
300     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
301     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
302                          help='download only videos suitable for the given age',
303                          default=None, type=int)
304     selection.add_option('--download-archive', metavar='FILE',
305                          dest='download_archive',
306                          help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
307     selection.add_option(
308         '--include-ads', dest='include_ads',
309         action='store_true',
310         help='Download advertisements as well (experimental)')
311     selection.add_option(
312         '--youtube-include-dash-manifest', action='store_true',
313         dest='youtube_include_dash_manifest', default=False,
314         help='Try to download the DASH manifest on YouTube videos (experimental)')
315
316     authentication.add_option('-u', '--username',
317             dest='username', metavar='USERNAME', help='account username')
318     authentication.add_option('-p', '--password',
319             dest='password', metavar='PASSWORD', help='account password')
320     authentication.add_option('-n', '--netrc',
321             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
322     authentication.add_option('--video-password',
323             dest='videopassword', metavar='PASSWORD', help='video password (vimeo, smotri)')
324
325
326     video_format.add_option('-f', '--format',
327             action='store', dest='format', metavar='FORMAT', default=None,
328             help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported. You can also use the special names "best", "bestvideo", "bestaudio", "worst", "worstvideo" and "worstaudio". By default, youtube-dl will pick the best quality.')
329     video_format.add_option('--all-formats',
330             action='store_const', dest='format', help='download all available video formats', const='all')
331     video_format.add_option('--prefer-free-formats',
332             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
333     video_format.add_option('--max-quality',
334             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
335     video_format.add_option('-F', '--list-formats',
336             action='store_true', dest='listformats', help='list all available formats')
337
338     subtitles.add_option('--write-sub', '--write-srt',
339             action='store_true', dest='writesubtitles',
340             help='write subtitle file', default=False)
341     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
342             action='store_true', dest='writeautomaticsub',
343             help='write automatic subtitle file (youtube only)', default=False)
344     subtitles.add_option('--all-subs',
345             action='store_true', dest='allsubtitles',
346             help='downloads all the available subtitles of the video', default=False)
347     subtitles.add_option('--list-subs',
348             action='store_true', dest='listsubtitles',
349             help='lists all available subtitles for the video', default=False)
350     subtitles.add_option('--sub-format',
351             action='store', dest='subtitlesformat', metavar='FORMAT',
352             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
353     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
354             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
355             default=[], callback=_comma_separated_values_options_callback,
356             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
357
358     downloader.add_option('-r', '--rate-limit',
359             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
360     downloader.add_option('-R', '--retries',
361             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
362     downloader.add_option('--buffer-size',
363             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
364     downloader.add_option('--no-resize-buffer',
365             action='store_true', dest='noresizebuffer',
366             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
367     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
368
369     verbosity.add_option('-q', '--quiet',
370             action='store_true', dest='quiet', help='activates quiet mode', default=False)
371     verbosity.add_option(
372         '--no-warnings',
373         dest='no_warnings', action='store_true', default=False,
374         help='Ignore warnings')
375     verbosity.add_option('-s', '--simulate',
376             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
377     verbosity.add_option('--skip-download',
378             action='store_true', dest='skip_download', help='do not download the video', default=False)
379     verbosity.add_option('-g', '--get-url',
380             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
381     verbosity.add_option('-e', '--get-title',
382             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
383     verbosity.add_option('--get-id',
384             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
385     verbosity.add_option('--get-thumbnail',
386             action='store_true', dest='getthumbnail',
387             help='simulate, quiet but print thumbnail URL', default=False)
388     verbosity.add_option('--get-description',
389             action='store_true', dest='getdescription',
390             help='simulate, quiet but print video description', default=False)
391     verbosity.add_option('--get-duration',
392             action='store_true', dest='getduration',
393             help='simulate, quiet but print video length', default=False)
394     verbosity.add_option('--get-filename',
395             action='store_true', dest='getfilename',
396             help='simulate, quiet but print output filename', default=False)
397     verbosity.add_option('--get-format',
398             action='store_true', dest='getformat',
399             help='simulate, quiet but print output format', default=False)
400     verbosity.add_option('-j', '--dump-json',
401             action='store_true', dest='dumpjson',
402             help='simulate, quiet but print JSON information. See --output for a description of available keys.', default=False)
403     verbosity.add_option('--newline',
404             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
405     verbosity.add_option('--no-progress',
406             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
407     verbosity.add_option('--console-title',
408             action='store_true', dest='consoletitle',
409             help='display progress in console titlebar', default=False)
410     verbosity.add_option('-v', '--verbose',
411             action='store_true', dest='verbose', help='print various debugging information', default=False)
412     verbosity.add_option('--dump-intermediate-pages',
413             action='store_true', dest='dump_intermediate_pages', default=False,
414             help='print downloaded pages to debug problems (very verbose)')
415     verbosity.add_option('--write-pages',
416             action='store_true', dest='write_pages', default=False,
417             help='Write downloaded intermediary pages to files in the current directory to debug problems')
418     verbosity.add_option('--youtube-print-sig-code',
419             action='store_true', dest='youtube_print_sig_code', default=False,
420             help=optparse.SUPPRESS_HELP)
421     verbosity.add_option('--print-traffic',
422             dest='debug_printtraffic', action='store_true', default=False,
423             help='Display sent and read HTTP traffic')
424
425
426     filesystem.add_option('-t', '--title',
427             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
428     filesystem.add_option('--id',
429             action='store_true', dest='useid', help='use only video ID in file name', default=False)
430     filesystem.add_option('-l', '--literal',
431             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
432     filesystem.add_option('-A', '--auto-number',
433             action='store_true', dest='autonumber',
434             help='number downloaded files starting from 00000', default=False)
435     filesystem.add_option('-o', '--output',
436             dest='outtmpl', metavar='TEMPLATE',
437             help=('output filename template. Use %(title)s to get the title, '
438                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
439                   '%(autonumber)s to get an automatically incremented number, '
440                   '%(ext)s for the filename extension, '
441                   '%(format)s for the format description (like "22 - 1280x720" or "HD"), '
442                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"), '
443                   '%(upload_date)s for the upload date (YYYYMMDD), '
444                   '%(extractor)s for the provider (youtube, metacafe, etc), '
445                   '%(id)s for the video id, %(playlist)s for the playlist the video is in, '
446                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
447                   '%(height)s and %(width)s for the width and height of the video format. '
448                   '%(resolution)s for a textual description of the resolution of the video format. '
449                   'Use - to output to stdout. Can also be used to download to a different directory, '
450                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
451     filesystem.add_option('--autonumber-size',
452             dest='autonumber_size', metavar='NUMBER',
453             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
454     filesystem.add_option('--restrict-filenames',
455             action='store_true', dest='restrictfilenames',
456             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
457     filesystem.add_option('-a', '--batch-file',
458             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
459     filesystem.add_option('--load-info',
460             dest='load_info_filename', metavar='FILE',
461             help='json file containing the video information (created with the "--write-json" option)')
462     filesystem.add_option('-w', '--no-overwrites',
463             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
464     filesystem.add_option('-c', '--continue',
465             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
466     filesystem.add_option('--no-continue',
467             action='store_false', dest='continue_dl',
468             help='do not resume partially downloaded files (restart from beginning)')
469     filesystem.add_option('--cookies',
470             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
471     filesystem.add_option('--no-part',
472             action='store_true', dest='nopart', help='do not use .part files', default=False)
473     filesystem.add_option('--no-mtime',
474             action='store_false', dest='updatetime',
475             help='do not use the Last-modified header to set the file modification time', default=True)
476     filesystem.add_option('--write-description',
477             action='store_true', dest='writedescription',
478             help='write video description to a .description file', default=False)
479     filesystem.add_option('--write-info-json',
480             action='store_true', dest='writeinfojson',
481             help='write video metadata to a .info.json file', default=False)
482     filesystem.add_option('--write-annotations',
483             action='store_true', dest='writeannotations',
484             help='write video annotations to a .annotation file', default=False)
485     filesystem.add_option('--write-thumbnail',
486             action='store_true', dest='writethumbnail',
487             help='write thumbnail image to disk', default=False)
488
489
490     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
491             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
492     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
493             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
494     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
495             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)')
496     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
497             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
498     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
499             help='keeps the video file on disk after the post-processing; the video is erased by default')
500     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
501             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
502     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
503             help='embed subtitles in the video (only for mp4 videos)')
504     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
505             help='write metadata to the video file')
506     postproc.add_option('--xattrs', action='store_true', dest='xattrs', default=False,
507             help='write metadata to the video file\'s xattrs (using dublin core and xdg standards)')
508     postproc.add_option('--prefer-avconv', action='store_false', dest='prefer_ffmpeg',
509         help='Prefer avconv over ffmpeg for running the postprocessors (default)')
510     postproc.add_option('--prefer-ffmpeg', action='store_true', dest='prefer_ffmpeg',
511         help='Prefer ffmpeg over avconv for running the postprocessors')
512
513
514     parser.add_option_group(general)
515     parser.add_option_group(selection)
516     parser.add_option_group(downloader)
517     parser.add_option_group(filesystem)
518     parser.add_option_group(verbosity)
519     parser.add_option_group(video_format)
520     parser.add_option_group(subtitles)
521     parser.add_option_group(authentication)
522     parser.add_option_group(postproc)
523
524     if overrideArguments is not None:
525         opts, args = parser.parse_args(overrideArguments)
526         if opts.verbose:
527             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
528     else:
529         commandLineConf = sys.argv[1:]
530         if '--ignore-config' in commandLineConf:
531             systemConf = []
532             userConf = []
533         else:
534             systemConf = _readOptions('/etc/youtube-dl.conf')
535             if '--ignore-config' in systemConf:
536                 userConf = []
537             else:
538                 userConf = _readUserConf()
539         argv = systemConf + userConf + commandLineConf
540
541         opts, args = parser.parse_args(argv)
542         if opts.verbose:
543             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
544             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
545             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
546
547     return parser, opts, args
548
549
550 def _real_main(argv=None):
551     # Compatibility fixes for Windows
552     if sys.platform == 'win32':
553         # https://github.com/rg3/youtube-dl/issues/820
554         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
555
556     setproctitle(u'youtube-dl')
557
558     parser, opts, args = parseOpts(argv)
559
560     # Set user agent
561     if opts.user_agent is not None:
562         std_headers['User-Agent'] = opts.user_agent
563
564     # Set referer
565     if opts.referer is not None:
566         std_headers['Referer'] = opts.referer
567
568     # Custom HTTP headers
569     if opts.headers is not None:
570         for h in opts.headers:
571             if h.find(':', 1) < 0:
572                 parser.error(u'wrong header formatting, it should be key:value, not "%s"'%h)
573             key, value = h.split(':', 2)
574             if opts.verbose:
575                 write_string(u'[debug] Adding header from command line option %s:%s\n'%(key, value))
576             std_headers[key] = value
577
578     # Dump user agent
579     if opts.dump_user_agent:
580         compat_print(std_headers['User-Agent'])
581         sys.exit(0)
582
583     # Batch file verification
584     batch_urls = []
585     if opts.batchfile is not None:
586         try:
587             if opts.batchfile == '-':
588                 batchfd = sys.stdin
589             else:
590                 batchfd = io.open(opts.batchfile, 'r', encoding='utf-8', errors='ignore')
591             batch_urls = read_batch_urls(batchfd)
592             if opts.verbose:
593                 write_string(u'[debug] Batch file urls: ' + repr(batch_urls) + u'\n')
594         except IOError:
595             sys.exit(u'ERROR: batch file could not be read')
596     all_urls = batch_urls + args
597     all_urls = [url.strip() for url in all_urls]
598     _enc = preferredencoding()
599     all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
600
601     extractors = gen_extractors()
602
603     if opts.list_extractors:
604         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
605             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
606             matchedUrls = [url for url in all_urls if ie.suitable(url)]
607             for mu in matchedUrls:
608                 compat_print(u'  ' + mu)
609         sys.exit(0)
610     if opts.list_extractor_descriptions:
611         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
612             if not ie._WORKING:
613                 continue
614             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
615             if desc is False:
616                 continue
617             if hasattr(ie, 'SEARCH_KEY'):
618                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
619                 _COUNTS = (u'', u'5', u'10', u'all')
620                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
621             compat_print(desc)
622         sys.exit(0)
623
624
625     # Conflicting, missing and erroneous options
626     if opts.usenetrc and (opts.username is not None or opts.password is not None):
627         parser.error(u'using .netrc conflicts with giving username/password')
628     if opts.password is not None and opts.username is None:
629         parser.error(u'account username missing\n')
630     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
631         parser.error(u'using output template conflicts with using title, video ID or auto number')
632     if opts.usetitle and opts.useid:
633         parser.error(u'using title conflicts with using video ID')
634     if opts.username is not None and opts.password is None:
635         opts.password = compat_getpass(u'Type account password and press [Return]: ')
636     if opts.ratelimit is not None:
637         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
638         if numeric_limit is None:
639             parser.error(u'invalid rate limit specified')
640         opts.ratelimit = numeric_limit
641     if opts.min_filesize is not None:
642         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
643         if numeric_limit is None:
644             parser.error(u'invalid min_filesize specified')
645         opts.min_filesize = numeric_limit
646     if opts.max_filesize is not None:
647         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
648         if numeric_limit is None:
649             parser.error(u'invalid max_filesize specified')
650         opts.max_filesize = numeric_limit
651     if opts.retries is not None:
652         try:
653             opts.retries = int(opts.retries)
654         except (TypeError, ValueError):
655             parser.error(u'invalid retry count specified')
656     if opts.buffersize is not None:
657         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
658         if numeric_buffersize is None:
659             parser.error(u'invalid buffer size specified')
660         opts.buffersize = numeric_buffersize
661     if opts.playliststart <= 0:
662         raise ValueError(u'Playlist start must be positive')
663     if opts.playlistend not in (-1, None) and opts.playlistend < opts.playliststart:
664         raise ValueError(u'Playlist end must be greater than playlist start')
665     if opts.extractaudio:
666         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
667             parser.error(u'invalid audio format specified')
668     if opts.audioquality:
669         opts.audioquality = opts.audioquality.strip('k').strip('K')
670         if not opts.audioquality.isdigit():
671             parser.error(u'invalid audio quality specified')
672     if opts.recodevideo is not None:
673         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
674             parser.error(u'invalid video recode format specified')
675     if opts.date is not None:
676         date = DateRange.day(opts.date)
677     else:
678         date = DateRange(opts.dateafter, opts.datebefore)
679     if opts.default_search not in ('auto', None) and ':' not in opts.default_search:
680         parser.error(u'--default-search invalid; did you forget a colon (:) at the end?')
681
682     # Do not download videos when there are audio-only formats
683     if opts.extractaudio and not opts.keepvideo and opts.format is None:
684         opts.format = 'bestaudio/best'
685
686     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
687     # this was the old behaviour if only --all-sub was given.
688     if opts.allsubtitles and (opts.writeautomaticsub == False):
689         opts.writesubtitles = True
690
691     if sys.version_info < (3,):
692         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
693         if opts.outtmpl is not None:
694             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
695     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
696             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
697             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
698             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
699             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
700             or (opts.useid and u'%(id)s.%(ext)s')
701             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
702             or u'%(title)s-%(id)s.%(ext)s')
703     if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
704         parser.error(u'Cannot download a video and extract audio into the same'
705                      u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
706                      u' template'.format(outtmpl))
707
708     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
709     download_archive_fn = os.path.expanduser(opts.download_archive) if opts.download_archive is not None else opts.download_archive
710
711     ydl_opts = {
712         'usenetrc': opts.usenetrc,
713         'username': opts.username,
714         'password': opts.password,
715         'videopassword': opts.videopassword,
716         'quiet': (opts.quiet or any_printing),
717         'no_warnings': opts.no_warnings,
718         'forceurl': opts.geturl,
719         'forcetitle': opts.gettitle,
720         'forceid': opts.getid,
721         'forcethumbnail': opts.getthumbnail,
722         'forcedescription': opts.getdescription,
723         'forceduration': opts.getduration,
724         'forcefilename': opts.getfilename,
725         'forceformat': opts.getformat,
726         'forcejson': opts.dumpjson,
727         'simulate': opts.simulate,
728         'skip_download': (opts.skip_download or opts.simulate or any_printing),
729         'format': opts.format,
730         'format_limit': opts.format_limit,
731         'listformats': opts.listformats,
732         'outtmpl': outtmpl,
733         'autonumber_size': opts.autonumber_size,
734         'restrictfilenames': opts.restrictfilenames,
735         'ignoreerrors': opts.ignoreerrors,
736         'ratelimit': opts.ratelimit,
737         'nooverwrites': opts.nooverwrites,
738         'retries': opts.retries,
739         'buffersize': opts.buffersize,
740         'noresizebuffer': opts.noresizebuffer,
741         'continuedl': opts.continue_dl,
742         'noprogress': opts.noprogress,
743         'progress_with_newline': opts.progress_with_newline,
744         'playliststart': opts.playliststart,
745         'playlistend': opts.playlistend,
746         'noplaylist': opts.noplaylist,
747         'logtostderr': opts.outtmpl == '-',
748         'consoletitle': opts.consoletitle,
749         'nopart': opts.nopart,
750         'updatetime': opts.updatetime,
751         'writedescription': opts.writedescription,
752         'writeannotations': opts.writeannotations,
753         'writeinfojson': opts.writeinfojson,
754         'writethumbnail': opts.writethumbnail,
755         'writesubtitles': opts.writesubtitles,
756         'writeautomaticsub': opts.writeautomaticsub,
757         'allsubtitles': opts.allsubtitles,
758         'listsubtitles': opts.listsubtitles,
759         'subtitlesformat': opts.subtitlesformat,
760         'subtitleslangs': opts.subtitleslangs,
761         'matchtitle': decodeOption(opts.matchtitle),
762         'rejecttitle': decodeOption(opts.rejecttitle),
763         'max_downloads': opts.max_downloads,
764         'prefer_free_formats': opts.prefer_free_formats,
765         'verbose': opts.verbose,
766         'dump_intermediate_pages': opts.dump_intermediate_pages,
767         'write_pages': opts.write_pages,
768         'test': opts.test,
769         'keepvideo': opts.keepvideo,
770         'min_filesize': opts.min_filesize,
771         'max_filesize': opts.max_filesize,
772         'min_views': opts.min_views,
773         'max_views': opts.max_views,
774         'daterange': date,
775         'cachedir': opts.cachedir,
776         'youtube_print_sig_code': opts.youtube_print_sig_code,
777         'age_limit': opts.age_limit,
778         'download_archive': download_archive_fn,
779         'cookiefile': opts.cookiefile,
780         'nocheckcertificate': opts.no_check_certificate,
781         'prefer_insecure': opts.prefer_insecure,
782         'proxy': opts.proxy,
783         'socket_timeout': opts.socket_timeout,
784         'bidi_workaround': opts.bidi_workaround,
785         'debug_printtraffic': opts.debug_printtraffic,
786         'prefer_ffmpeg': opts.prefer_ffmpeg,
787         'include_ads': opts.include_ads,
788         'default_search': opts.default_search,
789         'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
790         'encoding': opts.encoding,
791     }
792
793     with YoutubeDL(ydl_opts) as ydl:
794         ydl.print_debug_header()
795         ydl.add_default_info_extractors()
796
797         # PostProcessors
798         # Add the metadata pp first, the other pps will copy it
799         if opts.addmetadata:
800             ydl.add_post_processor(FFmpegMetadataPP())
801         if opts.extractaudio:
802             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
803         if opts.recodevideo:
804             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
805         if opts.embedsubtitles:
806             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
807         if opts.xattrs:
808             ydl.add_post_processor(XAttrMetadataPP())
809
810         # Update version
811         if opts.update_self:
812             update_self(ydl.to_screen, opts.verbose)
813
814         # Maybe do nothing
815         if (len(all_urls) < 1) and (opts.load_info_filename is None):
816             if not opts.update_self:
817                 parser.error(u'you must provide at least one URL')
818             else:
819                 sys.exit()
820
821         try:
822             if opts.load_info_filename is not None:
823                 retcode = ydl.download_with_info_file(opts.load_info_filename)
824             else:
825                 retcode = ydl.download(all_urls)
826         except MaxDownloadsReached:
827             ydl.to_screen(u'--max-download limit reached, aborting.')
828             retcode = 101
829
830     sys.exit(retcode)
831
832
833 def main(argv=None):
834     try:
835         _real_main(argv)
836     except DownloadError:
837         sys.exit(1)
838     except SameFileError:
839         sys.exit(u'ERROR: fixed output name but more than one file to download')
840     except KeyboardInterrupt:
841         sys.exit(u'\nERROR: Interrupted by user')