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