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