Remove mentions of old InfoExtractors module
[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     )
29
30 __license__ = 'Public Domain'
31
32 import codecs
33 import getpass
34 import optparse
35 import os
36 import re
37 import shlex
38 import socket
39 import subprocess
40 import sys
41 import warnings
42 import platform
43
44 from .utils import *
45 from .update import update_self
46 from .version import __version__
47 from .FileDownloader import *
48 from .extractor import gen_extractors
49 from .PostProcessor import *
50
51 def parseOpts(overrideArguments=None):
52     def _readOptions(filename_bytes):
53         try:
54             optionf = open(filename_bytes)
55         except IOError:
56             return [] # silently skip if file is not present
57         try:
58             res = []
59             for l in optionf:
60                 res += shlex.split(l, comments=True)
61         finally:
62             optionf.close()
63         return res
64
65     def _format_option_string(option):
66         ''' ('-o', '--option') -> -o, --format METAVAR'''
67
68         opts = []
69
70         if option._short_opts:
71             opts.append(option._short_opts[0])
72         if option._long_opts:
73             opts.append(option._long_opts[0])
74         if len(opts) > 1:
75             opts.insert(1, ', ')
76
77         if option.takes_value(): opts.append(' %s' % option.metavar)
78
79         return "".join(opts)
80
81     def _find_term_columns():
82         columns = os.environ.get('COLUMNS', None)
83         if columns:
84             return int(columns)
85
86         try:
87             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
88             out,err = sp.communicate()
89             return int(out.split()[1])
90         except:
91             pass
92         return None
93
94     max_width = 80
95     max_help_position = 80
96
97     # No need to wrap help messages if we're on a wide console
98     columns = _find_term_columns()
99     if columns: max_width = columns
100
101     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
102     fmt.format_option_strings = _format_option_string
103
104     kw = {
105         'version'   : __version__,
106         'formatter' : fmt,
107         'usage' : '%prog [options] url [url...]',
108         'conflict_handler' : 'resolve',
109     }
110
111     parser = optparse.OptionParser(**kw)
112
113     # option groups
114     general        = optparse.OptionGroup(parser, 'General Options')
115     selection      = optparse.OptionGroup(parser, 'Video Selection')
116     authentication = optparse.OptionGroup(parser, 'Authentication Options')
117     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
118     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
119     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
120     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
121
122     general.add_option('-h', '--help',
123             action='help', help='print this help text and exit')
124     general.add_option('-v', '--version',
125             action='version', help='print program version and exit')
126     general.add_option('-U', '--update',
127             action='store_true', dest='update_self', help='update this program to latest version')
128     general.add_option('-i', '--ignore-errors',
129             action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
130     general.add_option('-r', '--rate-limit',
131             dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
132     general.add_option('-R', '--retries',
133             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
134     general.add_option('--buffer-size',
135             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
136     general.add_option('--no-resize-buffer',
137             action='store_true', dest='noresizebuffer',
138             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
139     general.add_option('--dump-user-agent',
140             action='store_true', dest='dump_user_agent',
141             help='display the current browser identification', default=False)
142     general.add_option('--user-agent',
143             dest='user_agent', help='specify a custom user agent', metavar='UA')
144     general.add_option('--referer',
145             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
146             metavar='REF', default=None)
147     general.add_option('--list-extractors',
148             action='store_true', dest='list_extractors',
149             help='List all supported extractors and the URLs they would handle', default=False)
150     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
151     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
152     general.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
153
154     selection.add_option('--playlist-start',
155             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
156     selection.add_option('--playlist-end',
157             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
158     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
159     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
160     selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
161     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)
162     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)
163     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
164     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
165     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
166
167
168     authentication.add_option('-u', '--username',
169             dest='username', metavar='USERNAME', help='account username')
170     authentication.add_option('-p', '--password',
171             dest='password', metavar='PASSWORD', help='account password')
172     authentication.add_option('-n', '--netrc',
173             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
174
175
176     video_format.add_option('-f', '--format',
177             action='store', dest='format', metavar='FORMAT',
178             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
179     video_format.add_option('--all-formats',
180             action='store_const', dest='format', help='download all available video formats', const='all')
181     video_format.add_option('--prefer-free-formats',
182             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
183     video_format.add_option('--max-quality',
184             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
185     video_format.add_option('-F', '--list-formats',
186             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
187     video_format.add_option('--write-sub', '--write-srt',
188             action='store_true', dest='writesubtitles',
189             help='write subtitle file (currently youtube only)', default=False)
190     video_format.add_option('--only-sub',
191             action='store_true', dest='skip_download',
192             help='[deprecated] alias of --skip-download', default=False)
193     video_format.add_option('--all-subs',
194             action='store_true', dest='allsubtitles',
195             help='downloads all the available subtitles of the video (currently youtube only)', default=False)
196     video_format.add_option('--list-subs',
197             action='store_true', dest='listsubtitles',
198             help='lists all available subtitles for the video (currently youtube only)', default=False)
199     video_format.add_option('--sub-format',
200             action='store', dest='subtitlesformat', metavar='FORMAT',
201             help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
202     video_format.add_option('--sub-lang', '--srt-lang',
203             action='store', dest='subtitleslang', metavar='LANG',
204             help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
205
206     verbosity.add_option('-q', '--quiet',
207             action='store_true', dest='quiet', help='activates quiet mode', default=False)
208     verbosity.add_option('-s', '--simulate',
209             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
210     verbosity.add_option('--skip-download',
211             action='store_true', dest='skip_download', help='do not download the video', default=False)
212     verbosity.add_option('-g', '--get-url',
213             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
214     verbosity.add_option('-e', '--get-title',
215             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
216     verbosity.add_option('--get-id',
217             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
218     verbosity.add_option('--get-thumbnail',
219             action='store_true', dest='getthumbnail',
220             help='simulate, quiet but print thumbnail URL', default=False)
221     verbosity.add_option('--get-description',
222             action='store_true', dest='getdescription',
223             help='simulate, quiet but print video description', default=False)
224     verbosity.add_option('--get-filename',
225             action='store_true', dest='getfilename',
226             help='simulate, quiet but print output filename', default=False)
227     verbosity.add_option('--get-format',
228             action='store_true', dest='getformat',
229             help='simulate, quiet but print output format', default=False)
230     verbosity.add_option('--newline',
231             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
232     verbosity.add_option('--no-progress',
233             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
234     verbosity.add_option('--console-title',
235             action='store_true', dest='consoletitle',
236             help='display progress in console titlebar', default=False)
237     verbosity.add_option('-v', '--verbose',
238             action='store_true', dest='verbose', help='print various debugging information', default=False)
239     verbosity.add_option('--dump-intermediate-pages',
240             action='store_true', dest='dump_intermediate_pages', default=False,
241             help='print downloaded pages to debug problems(very verbose)')
242
243     filesystem.add_option('-t', '--title',
244             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
245     filesystem.add_option('--id',
246             action='store_true', dest='useid', help='use only video ID in file name', default=False)
247     filesystem.add_option('-l', '--literal',
248             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
249     filesystem.add_option('-A', '--auto-number',
250             action='store_true', dest='autonumber',
251             help='number downloaded files starting from 00000', default=False)
252     filesystem.add_option('-o', '--output',
253             dest='outtmpl', metavar='TEMPLATE',
254             help=('output filename template. Use %(title)s to get the title, '
255                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
256                   '%(autonumber)s to get an automatically incremented number, '
257                   '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
258                   '%(extractor)s for the provider (youtube, metacafe, etc), '
259                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
260                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
261                   'Use - to output to stdout. Can also be used to download to a different directory, '
262                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
263     filesystem.add_option('--autonumber-size',
264             dest='autonumber_size', metavar='NUMBER',
265             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
266     filesystem.add_option('--restrict-filenames',
267             action='store_true', dest='restrictfilenames',
268             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
269     filesystem.add_option('-a', '--batch-file',
270             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
271     filesystem.add_option('-w', '--no-overwrites',
272             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
273     filesystem.add_option('-c', '--continue',
274             action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
275     filesystem.add_option('--no-continue',
276             action='store_false', dest='continue_dl',
277             help='do not resume partially downloaded files (restart from beginning)')
278     filesystem.add_option('--cookies',
279             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
280     filesystem.add_option('--no-part',
281             action='store_true', dest='nopart', help='do not use .part files', default=False)
282     filesystem.add_option('--no-mtime',
283             action='store_false', dest='updatetime',
284             help='do not use the Last-modified header to set the file modification time', default=True)
285     filesystem.add_option('--write-description',
286             action='store_true', dest='writedescription',
287             help='write video description to a .description file', default=False)
288     filesystem.add_option('--write-info-json',
289             action='store_true', dest='writeinfojson',
290             help='write video metadata to a .info.json file', default=False)
291     filesystem.add_option('--write-thumbnail',
292             action='store_true', dest='writethumbnail',
293             help='write thumbnail image to disk', default=False)
294
295
296     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
297             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
298     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
299             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
300     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
301             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)')
302     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
303             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
304     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
305             help='keeps the video file on disk after the post-processing; the video is erased by default')
306     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
307             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
308
309
310     parser.add_option_group(general)
311     parser.add_option_group(selection)
312     parser.add_option_group(filesystem)
313     parser.add_option_group(verbosity)
314     parser.add_option_group(video_format)
315     parser.add_option_group(authentication)
316     parser.add_option_group(postproc)
317
318     if overrideArguments is not None:
319         opts, args = parser.parse_args(overrideArguments)
320         if opts.verbose:
321             print(u'[debug] Override config: ' + repr(overrideArguments))
322     else:
323         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
324         if xdg_config_home:
325             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
326         else:
327             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
328         systemConf = _readOptions('/etc/youtube-dl.conf')
329         userConf = _readOptions(userConfFile)
330         commandLineConf = sys.argv[1:] 
331         argv = systemConf + userConf + commandLineConf
332         opts, args = parser.parse_args(argv)
333         if opts.verbose:
334             print(u'[debug] System config: ' + repr(systemConf))
335             print(u'[debug] User config: ' + repr(userConf))
336             print(u'[debug] Command-line args: ' + repr(commandLineConf))
337
338     return parser, opts, args
339
340 def _real_main(argv=None):
341     # Compatibility fixes for Windows
342     if sys.platform == 'win32':
343         # https://github.com/rg3/youtube-dl/issues/820
344         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
345
346     parser, opts, args = parseOpts(argv)
347
348     # Open appropriate CookieJar
349     if opts.cookiefile is None:
350         jar = compat_cookiejar.CookieJar()
351     else:
352         try:
353             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
354             if os.access(opts.cookiefile, os.R_OK):
355                 jar.load()
356         except (IOError, OSError) as err:
357             if opts.verbose:
358                 traceback.print_exc()
359             sys.stderr.write(u'ERROR: unable to open cookie file\n')
360             sys.exit(101)
361     # Set user agent
362     if opts.user_agent is not None:
363         std_headers['User-Agent'] = opts.user_agent
364     
365     # Set referer
366     if opts.referer is not None:
367         std_headers['Referer'] = opts.referer
368
369     # Dump user agent
370     if opts.dump_user_agent:
371         print(std_headers['User-Agent'])
372         sys.exit(0)
373
374     # Batch file verification
375     batchurls = []
376     if opts.batchfile is not None:
377         try:
378             if opts.batchfile == '-':
379                 batchfd = sys.stdin
380             else:
381                 batchfd = open(opts.batchfile, 'r')
382             batchurls = batchfd.readlines()
383             batchurls = [x.strip() for x in batchurls]
384             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
385         except IOError:
386             sys.exit(u'ERROR: batch file could not be read')
387     all_urls = batchurls + args
388     all_urls = [url.strip() for url in all_urls]
389
390     # General configuration
391     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
392     if opts.proxy is not None:
393         if opts.proxy == '':
394             proxies = {}
395         else:
396             proxies = {'http': opts.proxy, 'https': opts.proxy}
397     else:
398         proxies = compat_urllib_request.getproxies()
399         # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
400         if 'http' in proxies and 'https' not in proxies:
401             proxies['https'] = proxies['http']
402     proxy_handler = compat_urllib_request.ProxyHandler(proxies)
403     https_handler = make_HTTPS_handler(opts)
404     opener = compat_urllib_request.build_opener(https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
405     compat_urllib_request.install_opener(opener)
406     socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
407
408     extractors = gen_extractors()
409
410     if opts.list_extractors:
411         for ie in extractors:
412             print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
413             matchedUrls = [url for url in all_urls if ie.suitable(url)]
414             all_urls = [url for url in all_urls if url not in matchedUrls]
415             for mu in matchedUrls:
416                 print(u'  ' + mu)
417         sys.exit(0)
418
419     # Conflicting, missing and erroneous options
420     if opts.usenetrc and (opts.username is not None or opts.password is not None):
421         parser.error(u'using .netrc conflicts with giving username/password')
422     if opts.password is not None and opts.username is None:
423         print(u'WARNING: account username missing')
424     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
425         parser.error(u'using output template conflicts with using title, video ID or auto number')
426     if opts.usetitle and opts.useid:
427         parser.error(u'using title conflicts with using video ID')
428     if opts.username is not None and opts.password is None:
429         opts.password = getpass.getpass(u'Type account password and press return:')
430     if opts.ratelimit is not None:
431         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
432         if numeric_limit is None:
433             parser.error(u'invalid rate limit specified')
434         opts.ratelimit = numeric_limit
435     if opts.min_filesize is not None:
436         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
437         if numeric_limit is None:
438             parser.error(u'invalid min_filesize specified')
439         opts.min_filesize = numeric_limit
440     if opts.max_filesize is not None:
441         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
442         if numeric_limit is None:
443             parser.error(u'invalid max_filesize specified')
444         opts.max_filesize = numeric_limit
445     if opts.retries is not None:
446         try:
447             opts.retries = int(opts.retries)
448         except (TypeError, ValueError) as err:
449             parser.error(u'invalid retry count specified')
450     if opts.buffersize is not None:
451         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
452         if numeric_buffersize is None:
453             parser.error(u'invalid buffer size specified')
454         opts.buffersize = numeric_buffersize
455     try:
456         opts.playliststart = int(opts.playliststart)
457         if opts.playliststart <= 0:
458             raise ValueError(u'Playlist start must be positive')
459     except (TypeError, ValueError) as err:
460         parser.error(u'invalid playlist start number specified')
461     try:
462         opts.playlistend = int(opts.playlistend)
463         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
464             raise ValueError(u'Playlist end must be greater than playlist start')
465     except (TypeError, ValueError) as err:
466         parser.error(u'invalid playlist end number specified')
467     if opts.extractaudio:
468         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
469             parser.error(u'invalid audio format specified')
470     if opts.audioquality:
471         opts.audioquality = opts.audioquality.strip('k').strip('K')
472         if not opts.audioquality.isdigit():
473             parser.error(u'invalid audio quality specified')
474     if opts.recodevideo is not None:
475         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
476             parser.error(u'invalid video recode format specified')
477     if opts.date is not None:
478         date = DateRange.day(opts.date)
479     else:
480         date = DateRange(opts.dateafter, opts.datebefore)
481
482     if sys.version_info < (3,):
483         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
484         if opts.outtmpl is not None:
485             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
486     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
487             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
488             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
489             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
490             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
491             or (opts.useid and u'%(id)s.%(ext)s')
492             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
493             or u'%(title)s-%(id)s.%(ext)s')
494
495     # File downloader
496     fd = FileDownloader({
497         'usenetrc': opts.usenetrc,
498         'username': opts.username,
499         'password': opts.password,
500         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
501         'forceurl': opts.geturl,
502         'forcetitle': opts.gettitle,
503         'forceid': opts.getid,
504         'forcethumbnail': opts.getthumbnail,
505         'forcedescription': opts.getdescription,
506         'forcefilename': opts.getfilename,
507         'forceformat': opts.getformat,
508         'simulate': opts.simulate,
509         '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),
510         'format': opts.format,
511         'format_limit': opts.format_limit,
512         'listformats': opts.listformats,
513         'outtmpl': outtmpl,
514         'autonumber_size': opts.autonumber_size,
515         'restrictfilenames': opts.restrictfilenames,
516         'ignoreerrors': opts.ignoreerrors,
517         'ratelimit': opts.ratelimit,
518         'nooverwrites': opts.nooverwrites,
519         'retries': opts.retries,
520         'buffersize': opts.buffersize,
521         'noresizebuffer': opts.noresizebuffer,
522         'continuedl': opts.continue_dl,
523         'noprogress': opts.noprogress,
524         'progress_with_newline': opts.progress_with_newline,
525         'playliststart': opts.playliststart,
526         'playlistend': opts.playlistend,
527         'logtostderr': opts.outtmpl == '-',
528         'consoletitle': opts.consoletitle,
529         'nopart': opts.nopart,
530         'updatetime': opts.updatetime,
531         'writedescription': opts.writedescription,
532         'writeinfojson': opts.writeinfojson,
533         'writethumbnail': opts.writethumbnail,
534         'writesubtitles': opts.writesubtitles,
535         'allsubtitles': opts.allsubtitles,
536         'listsubtitles': opts.listsubtitles,
537         'subtitlesformat': opts.subtitlesformat,
538         'subtitleslang': opts.subtitleslang,
539         'matchtitle': decodeOption(opts.matchtitle),
540         'rejecttitle': decodeOption(opts.rejecttitle),
541         'max_downloads': opts.max_downloads,
542         'prefer_free_formats': opts.prefer_free_formats,
543         'verbose': opts.verbose,
544         'dump_intermediate_pages': opts.dump_intermediate_pages,
545         'test': opts.test,
546         'keepvideo': opts.keepvideo,
547         'min_filesize': opts.min_filesize,
548         'max_filesize': opts.max_filesize,
549         'daterange': date,
550         })
551
552     if opts.verbose:
553         fd.to_screen(u'[debug] youtube-dl version ' + __version__)
554         try:
555             sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
556                                   cwd=os.path.dirname(os.path.abspath(__file__)))
557             out, err = sp.communicate()
558             out = out.decode().strip()
559             if re.match('[0-9a-f]+', out):
560                 fd.to_screen(u'[debug] Git HEAD: ' + out)
561         except:
562             pass
563         fd.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
564         fd.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
565
566     for extractor in extractors:
567         fd.add_info_extractor(extractor)
568
569     # PostProcessors
570     if opts.extractaudio:
571         fd.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
572     if opts.recodevideo:
573         fd.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
574
575     # Update version
576     if opts.update_self:
577         update_self(fd.to_screen, opts.verbose, sys.argv[0])
578
579     # Maybe do nothing
580     if len(all_urls) < 1:
581         if not opts.update_self:
582             parser.error(u'you must provide at least one URL')
583         else:
584             sys.exit()
585
586     try:
587         retcode = fd.download(all_urls)
588     except MaxDownloadsReached:
589         fd.to_screen(u'--max-download limit reached, aborting.')
590         retcode = 101
591
592     # Dump cookie jar if requested
593     if opts.cookiefile is not None:
594         try:
595             jar.save()
596         except (IOError, OSError) as err:
597             sys.exit(u'ERROR: unable to save cookie jar')
598
599     sys.exit(retcode)
600
601 def main(argv=None):
602     try:
603         _real_main(argv)
604     except DownloadError:
605         sys.exit(1)
606     except SameFileError:
607         sys.exit(u'ERROR: fixed output name but more than one file to download')
608     except KeyboardInterrupt:
609         sys.exit(u'\nERROR: Interrupted by user')