Merge pull request #1301 from rzhxeo/xhamster
[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     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
327             help='embed subtitles in the video (only for mp4 videos)')
328
329
330     parser.add_option_group(general)
331     parser.add_option_group(selection)
332     parser.add_option_group(downloader)
333     parser.add_option_group(filesystem)
334     parser.add_option_group(verbosity)
335     parser.add_option_group(video_format)
336     parser.add_option_group(subtitles)
337     parser.add_option_group(authentication)
338     parser.add_option_group(postproc)
339
340     if overrideArguments is not None:
341         opts, args = parser.parse_args(overrideArguments)
342         if opts.verbose:
343             sys.stderr.write(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
344     else:
345         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
346         if xdg_config_home:
347             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
348         else:
349             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
350         systemConf = _readOptions('/etc/youtube-dl.conf')
351         userConf = _readOptions(userConfFile)
352         commandLineConf = sys.argv[1:]
353         argv = systemConf + userConf + commandLineConf
354         opts, args = parser.parse_args(argv)
355         if opts.verbose:
356             sys.stderr.write(u'[debug] System config: ' + repr(systemConf) + '\n')
357             sys.stderr.write(u'[debug] User config: ' + repr(userConf) + '\n')
358             sys.stderr.write(u'[debug] Command-line args: ' + repr(commandLineConf) + '\n')
359
360     return parser, opts, args
361
362 def _real_main(argv=None):
363     # Compatibility fixes for Windows
364     if sys.platform == 'win32':
365         # https://github.com/rg3/youtube-dl/issues/820
366         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
367
368     parser, opts, args = parseOpts(argv)
369
370     # Open appropriate CookieJar
371     if opts.cookiefile is None:
372         jar = compat_cookiejar.CookieJar()
373     else:
374         try:
375             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
376             if os.access(opts.cookiefile, os.R_OK):
377                 jar.load()
378         except (IOError, OSError) as err:
379             if opts.verbose:
380                 traceback.print_exc()
381             sys.stderr.write(u'ERROR: unable to open cookie file\n')
382             sys.exit(101)
383     # Set user agent
384     if opts.user_agent is not None:
385         std_headers['User-Agent'] = opts.user_agent
386
387     # Set referer
388     if opts.referer is not None:
389         std_headers['Referer'] = opts.referer
390
391     # Dump user agent
392     if opts.dump_user_agent:
393         compat_print(std_headers['User-Agent'])
394         sys.exit(0)
395
396     # Batch file verification
397     batchurls = []
398     if opts.batchfile is not None:
399         try:
400             if opts.batchfile == '-':
401                 batchfd = sys.stdin
402             else:
403                 batchfd = open(opts.batchfile, 'r')
404             batchurls = batchfd.readlines()
405             batchurls = [x.strip() for x in batchurls]
406             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
407             if opts.verbose:
408                 sys.stderr.write(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
409         except IOError:
410             sys.exit(u'ERROR: batch file could not be read')
411     all_urls = batchurls + args
412     all_urls = [url.strip() for url in all_urls]
413
414     # General configuration
415     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
416     if opts.proxy is not None:
417         if opts.proxy == '':
418             proxies = {}
419         else:
420             proxies = {'http': opts.proxy, 'https': opts.proxy}
421     else:
422         proxies = compat_urllib_request.getproxies()
423         # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
424         if 'http' in proxies and 'https' not in proxies:
425             proxies['https'] = proxies['http']
426     proxy_handler = compat_urllib_request.ProxyHandler(proxies)
427     https_handler = make_HTTPS_handler(opts)
428     opener = compat_urllib_request.build_opener(https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
429     compat_urllib_request.install_opener(opener)
430     socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
431
432     extractors = gen_extractors()
433
434     if opts.list_extractors:
435         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
436             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
437             matchedUrls = [url for url in all_urls if ie.suitable(url)]
438             all_urls = [url for url in all_urls if url not in matchedUrls]
439             for mu in matchedUrls:
440                 compat_print(u'  ' + mu)
441         sys.exit(0)
442     if opts.list_extractor_descriptions:
443         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
444             if not ie._WORKING:
445                 continue
446             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
447             if hasattr(ie, 'SEARCH_KEY'):
448                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
449                 _COUNTS = (u'', u'5', u'10', u'all')
450                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
451             compat_print(desc)
452         sys.exit(0)
453
454
455     # Conflicting, missing and erroneous options
456     if opts.usenetrc and (opts.username is not None or opts.password is not None):
457         parser.error(u'using .netrc conflicts with giving username/password')
458     if opts.password is not None and opts.username is None:
459         parser.error(u' account username missing\n')
460     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
461         parser.error(u'using output template conflicts with using title, video ID or auto number')
462     if opts.usetitle and opts.useid:
463         parser.error(u'using title conflicts with using video ID')
464     if opts.username is not None and opts.password is None:
465         opts.password = getpass.getpass(u'Type account password and press return:')
466     if opts.ratelimit is not None:
467         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
468         if numeric_limit is None:
469             parser.error(u'invalid rate limit specified')
470         opts.ratelimit = numeric_limit
471     if opts.min_filesize is not None:
472         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
473         if numeric_limit is None:
474             parser.error(u'invalid min_filesize specified')
475         opts.min_filesize = numeric_limit
476     if opts.max_filesize is not None:
477         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
478         if numeric_limit is None:
479             parser.error(u'invalid max_filesize specified')
480         opts.max_filesize = numeric_limit
481     if opts.retries is not None:
482         try:
483             opts.retries = int(opts.retries)
484         except (TypeError, ValueError) as err:
485             parser.error(u'invalid retry count specified')
486     if opts.buffersize is not None:
487         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
488         if numeric_buffersize is None:
489             parser.error(u'invalid buffer size specified')
490         opts.buffersize = numeric_buffersize
491     try:
492         opts.playliststart = int(opts.playliststart)
493         if opts.playliststart <= 0:
494             raise ValueError(u'Playlist start must be positive')
495     except (TypeError, ValueError) as err:
496         parser.error(u'invalid playlist start number specified')
497     try:
498         opts.playlistend = int(opts.playlistend)
499         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
500             raise ValueError(u'Playlist end must be greater than playlist start')
501     except (TypeError, ValueError) as err:
502         parser.error(u'invalid playlist end number specified')
503     if opts.extractaudio:
504         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
505             parser.error(u'invalid audio format specified')
506     if opts.audioquality:
507         opts.audioquality = opts.audioquality.strip('k').strip('K')
508         if not opts.audioquality.isdigit():
509             parser.error(u'invalid audio quality specified')
510     if opts.recodevideo is not None:
511         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
512             parser.error(u'invalid video recode format specified')
513     if opts.date is not None:
514         date = DateRange.day(opts.date)
515     else:
516         date = DateRange(opts.dateafter, opts.datebefore)
517
518     if sys.version_info < (3,):
519         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
520         if opts.outtmpl is not None:
521             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
522     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
523             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
524             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
525             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
526             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
527             or (opts.useid and u'%(id)s.%(ext)s')
528             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
529             or u'%(title)s-%(id)s.%(ext)s')
530
531     # YoutubeDL
532     ydl = YoutubeDL({
533         'usenetrc': opts.usenetrc,
534         'username': opts.username,
535         'password': opts.password,
536         'videopassword': opts.videopassword,
537         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
538         'forceurl': opts.geturl,
539         'forcetitle': opts.gettitle,
540         'forceid': opts.getid,
541         'forcethumbnail': opts.getthumbnail,
542         'forcedescription': opts.getdescription,
543         'forcefilename': opts.getfilename,
544         'forceformat': opts.getformat,
545         'simulate': opts.simulate,
546         '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),
547         'format': opts.format,
548         'format_limit': opts.format_limit,
549         'listformats': opts.listformats,
550         'outtmpl': outtmpl,
551         'autonumber_size': opts.autonumber_size,
552         'restrictfilenames': opts.restrictfilenames,
553         'ignoreerrors': opts.ignoreerrors,
554         'ratelimit': opts.ratelimit,
555         'nooverwrites': opts.nooverwrites,
556         'retries': opts.retries,
557         'buffersize': opts.buffersize,
558         'noresizebuffer': opts.noresizebuffer,
559         'continuedl': opts.continue_dl,
560         'noprogress': opts.noprogress,
561         'progress_with_newline': opts.progress_with_newline,
562         'playliststart': opts.playliststart,
563         'playlistend': opts.playlistend,
564         'logtostderr': opts.outtmpl == '-',
565         'consoletitle': opts.consoletitle,
566         'nopart': opts.nopart,
567         'updatetime': opts.updatetime,
568         'writedescription': opts.writedescription,
569         'writeinfojson': opts.writeinfojson,
570         'writethumbnail': opts.writethumbnail,
571         'writesubtitles': opts.writesubtitles,
572         'writeautomaticsub': opts.writeautomaticsub,
573         'allsubtitles': opts.allsubtitles,
574         'listsubtitles': opts.listsubtitles,
575         'subtitlesformat': opts.subtitlesformat,
576         'subtitleslang': opts.subtitleslang,
577         'matchtitle': decodeOption(opts.matchtitle),
578         'rejecttitle': decodeOption(opts.rejecttitle),
579         'max_downloads': opts.max_downloads,
580         'prefer_free_formats': opts.prefer_free_formats,
581         'verbose': opts.verbose,
582         'dump_intermediate_pages': opts.dump_intermediate_pages,
583         'test': opts.test,
584         'keepvideo': opts.keepvideo,
585         'min_filesize': opts.min_filesize,
586         'max_filesize': opts.max_filesize,
587         'daterange': date,
588         })
589
590     if opts.verbose:
591         sys.stderr.write(u'[debug] youtube-dl version ' + __version__ + u'\n')
592         try:
593             sp = subprocess.Popen(
594                 ['git', 'rev-parse', '--short', 'HEAD'],
595                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
596                 cwd=os.path.dirname(os.path.abspath(__file__)))
597             out, err = sp.communicate()
598             out = out.decode().strip()
599             if re.match('[0-9a-f]+', out):
600                 sys.stderr.write(u'[debug] Git HEAD: ' + out + u'\n')
601         except:
602             try:
603                 sys.exc_clear()
604             except:
605                 pass
606         sys.stderr.write(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()) + u'\n')
607         sys.stderr.write(u'[debug] Proxy map: ' + str(proxy_handler.proxies) + u'\n')
608
609     ydl.add_default_info_extractors()
610
611     # PostProcessors
612     if opts.extractaudio:
613         ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
614     if opts.recodevideo:
615         ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
616     if opts.embedsubtitles:
617         ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
618
619     # Update version
620     if opts.update_self:
621         update_self(ydl.to_screen, opts.verbose, sys.argv[0])
622
623     # Maybe do nothing
624     if len(all_urls) < 1:
625         if not opts.update_self:
626             parser.error(u'you must provide at least one URL')
627         else:
628             sys.exit()
629
630     try:
631         retcode = ydl.download(all_urls)
632     except MaxDownloadsReached:
633         ydl.to_screen(u'--max-download limit reached, aborting.')
634         retcode = 101
635
636     # Dump cookie jar if requested
637     if opts.cookiefile is not None:
638         try:
639             jar.save()
640         except (IOError, OSError) as err:
641             sys.exit(u'ERROR: unable to save cookie jar')
642
643     sys.exit(retcode)
644
645 def main(argv=None):
646     try:
647         _real_main(argv)
648     except DownloadError:
649         sys.exit(1)
650     except SameFileError:
651         sys.exit(u'ERROR: fixed output name but more than one file to download')
652     except KeyboardInterrupt:
653         sys.exit(u'\nERROR: Interrupted by user')