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