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