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