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