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