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