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