added --get-id option to print video IDs
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from __future__ import with_statement
5 from __future__ import absolute_import
6
7 __authors__  = (
8     'Ricardo Garcia Gonzalez',
9     'Danny Colligan',
10     'Benjamin Johnson',
11     'Vasyl\' Vavrychuk',
12     'Witold Baryluk',
13     'Paweł Paprota',
14     'Gergely Imreh',
15     'Rogério Brito',
16     'Philipp Hagemeister',
17     'Sören Schulze',
18     'Kevin Ngo',
19     'Ori Avtalion',
20     'shizeeg',
21     'Filippo Valsorda',
22     'Christian Albrecht',
23     'Dave Vasilevsky',
24     'Jaime Marquínez Ferrándiz',
25     'Jeff Crouse',
26     'Osama Khalid',
27     'Michael Walter',
28     'M. Yasoob Ullah Khalid',
29     'Julien Fraichard',
30     'Johny Mo Swag',
31     )
32
33 __license__ = 'Public Domain'
34
35 import codecs
36 import getpass
37 import optparse
38 import os
39 import re
40 import shlex
41 import socket
42 import subprocess
43 import sys
44 import warnings
45 import platform
46
47 from .utils import *
48 from .update import update_self
49 from .version import __version__
50 from .FileDownloader import *
51 from .InfoExtractors import gen_extractors
52 from .PostProcessor import *
53
54 def parseOpts(overrideArguments=None):
55     def _readOptions(filename_bytes):
56         try:
57             optionf = open(filename_bytes)
58         except IOError:
59             return [] # silently skip if file is not present
60         try:
61             res = []
62             for l in optionf:
63                 res += shlex.split(l, comments=True)
64         finally:
65             optionf.close()
66         return res
67
68     def _format_option_string(option):
69         ''' ('-o', '--option') -> -o, --format METAVAR'''
70
71         opts = []
72
73         if option._short_opts:
74             opts.append(option._short_opts[0])
75         if option._long_opts:
76             opts.append(option._long_opts[0])
77         if len(opts) > 1:
78             opts.insert(1, ', ')
79
80         if option.takes_value(): opts.append(' %s' % option.metavar)
81
82         return "".join(opts)
83
84     def _find_term_columns():
85         columns = os.environ.get('COLUMNS', None)
86         if columns:
87             return int(columns)
88
89         try:
90             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
91             out,err = sp.communicate()
92             return int(out.split()[1])
93         except:
94             pass
95         return None
96
97     max_width = 80
98     max_help_position = 80
99
100     # No need to wrap help messages if we're on a wide console
101     columns = _find_term_columns()
102     if columns: max_width = columns
103
104     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
105     fmt.format_option_strings = _format_option_string
106
107     kw = {
108         'version'   : __version__,
109         'formatter' : fmt,
110         'usage' : '%prog [options] url [url...]',
111         'conflict_handler' : 'resolve',
112     }
113
114     parser = optparse.OptionParser(**kw)
115
116     # option groups
117     general        = optparse.OptionGroup(parser, 'General Options')
118     selection      = optparse.OptionGroup(parser, 'Video Selection')
119     authentication = optparse.OptionGroup(parser, 'Authentication Options')
120     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
121     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
122     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
123     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
124
125     general.add_option('-h', '--help',
126             action='help', help='print this help text and exit')
127     general.add_option('-v', '--version',
128             action='version', help='print program version and exit')
129     general.add_option('-U', '--update',
130             action='store_true', dest='update_self', help='update this program to latest version')
131     general.add_option('-i', '--ignore-errors',
132             action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
133     general.add_option('-r', '--rate-limit',
134             dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
135     general.add_option('-R', '--retries',
136             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
137     general.add_option('--buffer-size',
138             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
139     general.add_option('--no-resize-buffer',
140             action='store_true', dest='noresizebuffer',
141             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
142     general.add_option('--dump-user-agent',
143             action='store_true', dest='dump_user_agent',
144             help='display the current browser identification', default=False)
145     general.add_option('--user-agent',
146             dest='user_agent', help='specify a custom user agent', metavar='UA')
147     general.add_option('--referer',
148             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
149             metavar='REF', default=None)
150     general.add_option('--list-extractors',
151             action='store_true', dest='list_extractors',
152             help='List all supported extractors and the URLs they would handle', default=False)
153     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
154     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
155     general.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
156
157     selection.add_option('--playlist-start',
158             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
159     selection.add_option('--playlist-end',
160             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
161     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
162     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
163     selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
164     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)
165     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)
166     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
167     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
168     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
169
170
171     authentication.add_option('-u', '--username',
172             dest='username', metavar='USERNAME', help='account username')
173     authentication.add_option('-p', '--password',
174             dest='password', metavar='PASSWORD', help='account password')
175     authentication.add_option('-n', '--netrc',
176             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
177
178
179     video_format.add_option('-f', '--format',
180             action='store', dest='format', metavar='FORMAT',
181             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
182     video_format.add_option('--all-formats',
183             action='store_const', dest='format', help='download all available video formats', const='all')
184     video_format.add_option('--prefer-free-formats',
185             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
186     video_format.add_option('--max-quality',
187             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
188     video_format.add_option('-F', '--list-formats',
189             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
190     video_format.add_option('--write-sub', '--write-srt',
191             action='store_true', dest='writesubtitles',
192             help='write subtitle file (currently youtube only)', default=False)
193     video_format.add_option('--only-sub',
194             action='store_true', dest='onlysubtitles',
195             help='downloads only the subtitles (no video)', default=False)
196     video_format.add_option('--all-subs',
197             action='store_true', dest='allsubtitles',
198             help='downloads all the available subtitles of the video (currently youtube only)', default=False)
199     video_format.add_option('--list-subs',
200             action='store_true', dest='listsubtitles',
201             help='lists all available subtitles for the video (currently youtube only)', default=False)
202     video_format.add_option('--sub-format',
203             action='store', dest='subtitlesformat', metavar='LANG',
204             help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
205     video_format.add_option('--sub-lang', '--srt-lang',
206             action='store', dest='subtitleslang', metavar='LANG',
207             help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
208
209     verbosity.add_option('-q', '--quiet',
210             action='store_true', dest='quiet', help='activates quiet mode', default=False)
211     verbosity.add_option('-s', '--simulate',
212             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
213     verbosity.add_option('--skip-download',
214             action='store_true', dest='skip_download', help='do not download the video', default=False)
215     verbosity.add_option('-g', '--get-url',
216             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
217     verbosity.add_option('-e', '--get-title',
218             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
219     verbosity.add_option('--get-id',
220             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
221     verbosity.add_option('--get-thumbnail',
222             action='store_true', dest='getthumbnail',
223             help='simulate, quiet but print thumbnail URL', default=False)
224     verbosity.add_option('--get-description',
225             action='store_true', dest='getdescription',
226             help='simulate, quiet but print video description', default=False)
227     verbosity.add_option('--get-filename',
228             action='store_true', dest='getfilename',
229             help='simulate, quiet but print output filename', default=False)
230     verbosity.add_option('--get-format',
231             action='store_true', dest='getformat',
232             help='simulate, quiet but print output format', default=False)
233     verbosity.add_option('--newline',
234             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
235     verbosity.add_option('--no-progress',
236             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
237     verbosity.add_option('--console-title',
238             action='store_true', dest='consoletitle',
239             help='display progress in console titlebar', default=False)
240     verbosity.add_option('-v', '--verbose',
241             action='store_true', dest='verbose', help='print various debugging information', default=False)
242     verbosity.add_option('--dump-intermediate-pages',
243             action='store_true', dest='dump_intermediate_pages', default=False,
244             help='print downloaded pages to debug problems(very verbose)')
245
246     filesystem.add_option('-t', '--title',
247             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
248     filesystem.add_option('--id',
249             action='store_true', dest='useid', help='use only video ID in file name', default=False)
250     filesystem.add_option('-l', '--literal',
251             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
252     filesystem.add_option('-A', '--auto-number',
253             action='store_true', dest='autonumber',
254             help='number downloaded files starting from 00000', default=False)
255     filesystem.add_option('-o', '--output',
256             dest='outtmpl', metavar='TEMPLATE',
257             help=('output filename template. Use %(title)s to get the title, '
258                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
259                   '%(autonumber)s to get an automatically incremented number, '
260                   '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
261                   '%(extractor)s for the provider (youtube, metacafe, etc), '
262                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
263                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
264                   'Use - to output to stdout. Can also be used to download to a different directory, '
265                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
266     filesystem.add_option('--autonumber-size',
267             dest='autonumber_size', metavar='NUMBER',
268             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
269     filesystem.add_option('--restrict-filenames',
270             action='store_true', dest='restrictfilenames',
271             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
272     filesystem.add_option('-a', '--batch-file',
273             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
274     filesystem.add_option('-w', '--no-overwrites',
275             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
276     filesystem.add_option('-c', '--continue',
277             action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
278     filesystem.add_option('--no-continue',
279             action='store_false', dest='continue_dl',
280             help='do not resume partially downloaded files (restart from beginning)')
281     filesystem.add_option('--cookies',
282             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
283     filesystem.add_option('--no-part',
284             action='store_true', dest='nopart', help='do not use .part files', default=False)
285     filesystem.add_option('--no-mtime',
286             action='store_false', dest='updatetime',
287             help='do not use the Last-modified header to set the file modification time', default=True)
288     filesystem.add_option('--write-description',
289             action='store_true', dest='writedescription',
290             help='write video description to a .description file', default=False)
291     filesystem.add_option('--write-info-json',
292             action='store_true', dest='writeinfojson',
293             help='write video metadata to a .info.json file', default=False)
294     filesystem.add_option('--write-thumbnail',
295             action='store_true', dest='writethumbnail',
296             help='write thumbnail image to disk', default=False)
297
298
299     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
300             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
301     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
302             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
303     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
304             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)')
305     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
306             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
307     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
308             help='keeps the video file on disk after the post-processing; the video is erased by default')
309     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
310             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
311
312
313     parser.add_option_group(general)
314     parser.add_option_group(selection)
315     parser.add_option_group(filesystem)
316     parser.add_option_group(verbosity)
317     parser.add_option_group(video_format)
318     parser.add_option_group(authentication)
319     parser.add_option_group(postproc)
320
321     if overrideArguments is not None:
322         opts, args = parser.parse_args(overrideArguments)
323         if opts.verbose:
324             print(u'[debug] Override config: ' + repr(overrideArguments))
325     else:
326         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
327         if xdg_config_home:
328             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
329         else:
330             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
331         systemConf = _readOptions('/etc/youtube-dl.conf')
332         userConf = _readOptions(userConfFile)
333         commandLineConf = sys.argv[1:] 
334         argv = systemConf + userConf + commandLineConf
335         opts, args = parser.parse_args(argv)
336         if opts.verbose:
337             print(u'[debug] System config: ' + repr(systemConf))
338             print(u'[debug] User config: ' + repr(userConf))
339             print(u'[debug] Command-line args: ' + repr(commandLineConf))
340
341     return parser, opts, args
342
343 def _real_main(argv=None):
344     # Compatibility fixes for Windows
345     if sys.platform == 'win32':
346         # https://github.com/rg3/youtube-dl/issues/820
347         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
348
349     parser, opts, args = parseOpts(argv)
350
351     # Open appropriate CookieJar
352     if opts.cookiefile is None:
353         jar = compat_cookiejar.CookieJar()
354     else:
355         try:
356             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
357             if os.access(opts.cookiefile, os.R_OK):
358                 jar.load()
359         except (IOError, OSError) as err:
360             if opts.verbose:
361                 traceback.print_exc()
362             sys.stderr.write(u'ERROR: unable to open cookie file\n')
363             sys.exit(101)
364     # Set user agent
365     if opts.user_agent is not None:
366         std_headers['User-Agent'] = opts.user_agent
367     
368     # Set referer
369     if opts.referer is not None:
370         std_headers['Referer'] = opts.referer
371
372     # Dump user agent
373     if opts.dump_user_agent:
374         print(std_headers['User-Agent'])
375         sys.exit(0)
376
377     # Batch file verification
378     batchurls = []
379     if opts.batchfile is not None:
380         try:
381             if opts.batchfile == '-':
382                 batchfd = sys.stdin
383             else:
384                 batchfd = open(opts.batchfile, 'r')
385             batchurls = batchfd.readlines()
386             batchurls = [x.strip() for x in batchurls]
387             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
388         except IOError:
389             sys.exit(u'ERROR: batch file could not be read')
390     all_urls = batchurls + args
391     all_urls = [url.strip() for url in all_urls]
392
393     # General configuration
394     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
395     if opts.proxy:
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         parser.error(u'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         'onlysubtitles': opts.onlysubtitles,
536         'allsubtitles': opts.allsubtitles,
537         'listsubtitles': opts.listsubtitles,
538         'subtitlesformat': opts.subtitlesformat,
539         'subtitleslang': opts.subtitleslang,
540         'matchtitle': decodeOption(opts.matchtitle),
541         'rejecttitle': decodeOption(opts.rejecttitle),
542         'max_downloads': opts.max_downloads,
543         'prefer_free_formats': opts.prefer_free_formats,
544         'verbose': opts.verbose,
545         'dump_intermediate_pages': opts.dump_intermediate_pages,
546         'test': opts.test,
547         'keepvideo': opts.keepvideo,
548         'min_filesize': opts.min_filesize,
549         'max_filesize': opts.max_filesize,
550         'daterange': date,
551         })
552
553     if opts.verbose:
554         fd.to_screen(u'[debug] youtube-dl version ' + __version__)
555         try:
556             sp = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
557                                   cwd=os.path.dirname(os.path.abspath(__file__)))
558             out, err = sp.communicate()
559             out = out.decode().strip()
560             if re.match('[0-9a-f]+', out):
561                 fd.to_screen(u'[debug] Git HEAD: ' + out)
562         except:
563             pass
564         fd.to_screen(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()))
565         fd.to_screen(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
566
567     for extractor in extractors:
568         fd.add_info_extractor(extractor)
569
570     # PostProcessors
571     if opts.extractaudio:
572         fd.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
573     if opts.recodevideo:
574         fd.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
575
576     # Update version
577     if opts.update_self:
578         update_self(fd.to_screen, opts.verbose, sys.argv[0])
579
580     # Maybe do nothing
581     if len(all_urls) < 1:
582         if not opts.update_self:
583             parser.error(u'you must provide at least one URL')
584         else:
585             sys.exit()
586
587     try:
588         retcode = fd.download(all_urls)
589     except MaxDownloadsReached:
590         fd.to_screen(u'--max-download limit reached, aborting.')
591         retcode = 101
592
593     # Dump cookie jar if requested
594     if opts.cookiefile is not None:
595         try:
596             jar.save()
597         except (IOError, OSError) as err:
598             sys.exit(u'ERROR: unable to save cookie jar')
599
600     sys.exit(retcode)
601
602 def main(argv=None):
603     try:
604         _real_main(argv)
605     except DownloadError:
606         sys.exit(1)
607     except SameFileError:
608         sys.exit(u'ERROR: fixed output name but more than one file to download')
609     except KeyboardInterrupt:
610         sys.exit(u'\nERROR: Interrupted by user')