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