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