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