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