Separated subtitle options in their own group
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 __authors__  = (
5     'Ricardo Garcia Gonzalez',
6     'Danny Colligan',
7     'Benjamin Johnson',
8     'Vasyl\' Vavrychuk',
9     'Witold Baryluk',
10     'Paweł Paprota',
11     'Gergely Imreh',
12     'Rogério Brito',
13     'Philipp Hagemeister',
14     'Sören Schulze',
15     'Kevin Ngo',
16     'Ori Avtalion',
17     'shizeeg',
18     'Filippo Valsorda',
19     'Christian Albrecht',
20     'Dave Vasilevsky',
21     'Jaime Marquínez Ferrándiz',
22     'Jeff Crouse',
23     'Osama Khalid',
24     'Michael Walter',
25     'M. Yasoob Ullah Khalid',
26     'Julien Fraichard',
27     'Johny Mo Swag',
28     'Axel Noack',
29     'Albert Kim',
30 )
31
32 __license__ = 'Public Domain'
33
34 import codecs
35 import getpass
36 import optparse
37 import os
38 import random
39 import re
40 import shlex
41 import socket
42 import subprocess
43 import sys
44 import warnings
45 import platform
46
47 from .utils import *
48 from .update import update_self
49 from .version import __version__
50 from .FileDownloader import *
51 from .extractor import gen_extractors
52 from .YoutubeDL import YoutubeDL
53 from .PostProcessor import *
54
55 def parseOpts(overrideArguments=None):
56     def _readOptions(filename_bytes):
57         try:
58             optionf = open(filename_bytes)
59         except IOError:
60             return [] # silently skip if file is not present
61         try:
62             res = []
63             for l in optionf:
64                 res += shlex.split(l, comments=True)
65         finally:
66             optionf.close()
67         return res
68
69     def _format_option_string(option):
70         ''' ('-o', '--option') -> -o, --format METAVAR'''
71
72         opts = []
73
74         if option._short_opts:
75             opts.append(option._short_opts[0])
76         if option._long_opts:
77             opts.append(option._long_opts[0])
78         if len(opts) > 1:
79             opts.insert(1, ', ')
80
81         if option.takes_value(): opts.append(' %s' % option.metavar)
82
83         return "".join(opts)
84
85     def _find_term_columns():
86         columns = os.environ.get('COLUMNS', None)
87         if columns:
88             return int(columns)
89
90         try:
91             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
92             out,err = sp.communicate()
93             return int(out.split()[1])
94         except:
95             pass
96         return None
97
98     max_width = 80
99     max_help_position = 80
100
101     # No need to wrap help messages if we're on a wide console
102     columns = _find_term_columns()
103     if columns: max_width = columns
104
105     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
106     fmt.format_option_strings = _format_option_string
107
108     kw = {
109         'version'   : __version__,
110         'formatter' : fmt,
111         'usage' : '%prog [options] url [url...]',
112         'conflict_handler' : 'resolve',
113     }
114
115     parser = optparse.OptionParser(**kw)
116
117     # option groups
118     general        = optparse.OptionGroup(parser, 'General Options')
119     selection      = optparse.OptionGroup(parser, 'Video Selection')
120     authentication = optparse.OptionGroup(parser, 'Authentication Options')
121     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
122     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
123     downloader     = optparse.OptionGroup(parser, 'Download Options')
124     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
125     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
126     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
127
128     general.add_option('-h', '--help',
129             action='help', help='print this help text and exit')
130     general.add_option('-v', '--version',
131             action='version', help='print program version and exit')
132     general.add_option('-U', '--update',
133             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)')
134     general.add_option('-i', '--ignore-errors',
135             action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
136     general.add_option('--dump-user-agent',
137             action='store_true', dest='dump_user_agent',
138             help='display the current browser identification', default=False)
139     general.add_option('--user-agent',
140             dest='user_agent', help='specify a custom user agent', metavar='UA')
141     general.add_option('--referer',
142             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
143             metavar='REF', default=None)
144     general.add_option('--list-extractors',
145             action='store_true', dest='list_extractors',
146             help='List all supported extractors and the URLs they would handle', default=False)
147     general.add_option('--extractor-descriptions',
148             action='store_true', dest='list_extractor_descriptions',
149             help='Output descriptions of all supported extractors', default=False)
150     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
151     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
152
153
154     selection.add_option('--playlist-start',
155             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
156     selection.add_option('--playlist-end',
157             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
158     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
159     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
160     selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
161     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)
162     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)
163     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
164     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
165     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
166
167
168     authentication.add_option('-u', '--username',
169             dest='username', metavar='USERNAME', help='account username')
170     authentication.add_option('-p', '--password',
171             dest='password', metavar='PASSWORD', help='account password')
172     authentication.add_option('-n', '--netrc',
173             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
174     authentication.add_option('--video-password',
175             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
176
177
178     video_format.add_option('-f', '--format',
179             action='store', dest='format', metavar='FORMAT',
180             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
181     video_format.add_option('--all-formats',
182             action='store_const', dest='format', help='download all available video formats', const='all')
183     video_format.add_option('--prefer-free-formats',
184             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
185     video_format.add_option('--max-quality',
186             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
187     video_format.add_option('-F', '--list-formats',
188             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
189
190     subtitles.add_option('--write-sub', '--write-srt',
191             action='store_true', dest='writesubtitles',
192             help='write subtitle file', default=False)
193     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
194             action='store_true', dest='writeautomaticsub',
195             help='write automatic subtitle file (youtube only)', default=False)
196     subtitles.add_option('--only-sub',
197             action='store_true', dest='skip_download',
198             help='[deprecated] alias of --skip-download', default=False)
199     subtitles.add_option('--all-subs',
200             action='store_true', dest='allsubtitles',
201             help='downloads all the available subtitles of the video', default=False)
202     subtitles.add_option('--list-subs',
203             action='store_true', dest='listsubtitles',
204             help='lists all available subtitles for the video', default=False)
205     subtitles.add_option('--sub-format',
206             action='store', dest='subtitlesformat', metavar='FORMAT',
207             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
208     subtitles.add_option('--sub-lang', '--srt-lang',
209             action='store', dest='subtitleslang', metavar='LANG',
210             help='language of the subtitles to download (optional) use IETF language tags like \'en\'')
211
212     downloader.add_option('-r', '--rate-limit',
213             dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
214     downloader.add_option('-R', '--retries',
215             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
216     downloader.add_option('--buffer-size',
217             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
218     downloader.add_option('--no-resize-buffer',
219             action='store_true', dest='noresizebuffer',
220             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
221     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
222
223     verbosity.add_option('-q', '--quiet',
224             action='store_true', dest='quiet', help='activates quiet mode', default=False)
225     verbosity.add_option('-s', '--simulate',
226             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
227     verbosity.add_option('--skip-download',
228             action='store_true', dest='skip_download', help='do not download the video', default=False)
229     verbosity.add_option('-g', '--get-url',
230             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
231     verbosity.add_option('-e', '--get-title',
232             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
233     verbosity.add_option('--get-id',
234             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
235     verbosity.add_option('--get-thumbnail',
236             action='store_true', dest='getthumbnail',
237             help='simulate, quiet but print thumbnail URL', default=False)
238     verbosity.add_option('--get-description',
239             action='store_true', dest='getdescription',
240             help='simulate, quiet but print video description', default=False)
241     verbosity.add_option('--get-filename',
242             action='store_true', dest='getfilename',
243             help='simulate, quiet but print output filename', default=False)
244     verbosity.add_option('--get-format',
245             action='store_true', dest='getformat',
246             help='simulate, quiet but print output format', default=False)
247     verbosity.add_option('--newline',
248             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
249     verbosity.add_option('--no-progress',
250             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
251     verbosity.add_option('--console-title',
252             action='store_true', dest='consoletitle',
253             help='display progress in console titlebar', default=False)
254     verbosity.add_option('-v', '--verbose',
255             action='store_true', dest='verbose', help='print various debugging information', default=False)
256     verbosity.add_option('--dump-intermediate-pages',
257             action='store_true', dest='dump_intermediate_pages', default=False,
258             help='print downloaded pages to debug problems(very verbose)')
259
260     filesystem.add_option('-t', '--title',
261             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
262     filesystem.add_option('--id',
263             action='store_true', dest='useid', help='use only video ID in file name', default=False)
264     filesystem.add_option('-l', '--literal',
265             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
266     filesystem.add_option('-A', '--auto-number',
267             action='store_true', dest='autonumber',
268             help='number downloaded files starting from 00000', default=False)
269     filesystem.add_option('-o', '--output',
270             dest='outtmpl', metavar='TEMPLATE',
271             help=('output filename template. Use %(title)s to get the title, '
272                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
273                   '%(autonumber)s to get an automatically incremented number, '
274                   '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
275                   '%(extractor)s for the provider (youtube, metacafe, etc), '
276                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
277                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
278                   'Use - to output to stdout. Can also be used to download to a different directory, '
279                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
280     filesystem.add_option('--autonumber-size',
281             dest='autonumber_size', metavar='NUMBER',
282             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
283     filesystem.add_option('--restrict-filenames',
284             action='store_true', dest='restrictfilenames',
285             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
286     filesystem.add_option('-a', '--batch-file',
287             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
288     filesystem.add_option('-w', '--no-overwrites',
289             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
290     filesystem.add_option('-c', '--continue',
291             action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
292     filesystem.add_option('--no-continue',
293             action='store_false', dest='continue_dl',
294             help='do not resume partially downloaded files (restart from beginning)')
295     filesystem.add_option('--cookies',
296             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
297     filesystem.add_option('--no-part',
298             action='store_true', dest='nopart', help='do not use .part files', default=False)
299     filesystem.add_option('--no-mtime',
300             action='store_false', dest='updatetime',
301             help='do not use the Last-modified header to set the file modification time', default=True)
302     filesystem.add_option('--write-description',
303             action='store_true', dest='writedescription',
304             help='write video description to a .description file', default=False)
305     filesystem.add_option('--write-info-json',
306             action='store_true', dest='writeinfojson',
307             help='write video metadata to a .info.json file', default=False)
308     filesystem.add_option('--write-thumbnail',
309             action='store_true', dest='writethumbnail',
310             help='write thumbnail image to disk', default=False)
311
312
313     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
314             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
315     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
316             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
317     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
318             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)')
319     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
320             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
321     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
322             help='keeps the video file on disk after the post-processing; the video is erased by default')
323     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
324             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
325
326
327     parser.add_option_group(general)
328     parser.add_option_group(selection)
329     parser.add_option_group(downloader)
330     parser.add_option_group(filesystem)
331     parser.add_option_group(verbosity)
332     parser.add_option_group(video_format)
333     parser.add_option_group(subtitles)
334     parser.add_option_group(authentication)
335     parser.add_option_group(postproc)
336
337     if overrideArguments is not None:
338         opts, args = parser.parse_args(overrideArguments)
339         if opts.verbose:
340             sys.stderr.write(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
341     else:
342         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
343         if xdg_config_home:
344             userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
345         else:
346             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
347         systemConf = _readOptions('/etc/youtube-dl.conf')
348         userConf = _readOptions(userConfFile)
349         commandLineConf = sys.argv[1:] 
350         argv = systemConf + userConf + commandLineConf
351         opts, args = parser.parse_args(argv)
352         if opts.verbose:
353             sys.stderr.write(u'[debug] System config: ' + repr(systemConf) + '\n')
354             sys.stderr.write(u'[debug] User config: ' + repr(userConf) + '\n')
355             sys.stderr.write(u'[debug] Command-line args: ' + repr(commandLineConf) + '\n')
356
357     return parser, opts, args
358
359 def _real_main(argv=None):
360     # Compatibility fixes for Windows
361     if sys.platform == 'win32':
362         # https://github.com/rg3/youtube-dl/issues/820
363         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
364
365     parser, opts, args = parseOpts(argv)
366
367     # Open appropriate CookieJar
368     if opts.cookiefile is None:
369         jar = compat_cookiejar.CookieJar()
370     else:
371         try:
372             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
373             if os.access(opts.cookiefile, os.R_OK):
374                 jar.load()
375         except (IOError, OSError) as err:
376             if opts.verbose:
377                 traceback.print_exc()
378             sys.stderr.write(u'ERROR: unable to open cookie file\n')
379             sys.exit(101)
380     # Set user agent
381     if opts.user_agent is not None:
382         std_headers['User-Agent'] = opts.user_agent
383     
384     # Set referer
385     if opts.referer is not None:
386         std_headers['Referer'] = opts.referer
387
388     # Dump user agent
389     if opts.dump_user_agent:
390         compat_print(std_headers['User-Agent'])
391         sys.exit(0)
392
393     # Batch file verification
394     batchurls = []
395     if opts.batchfile is not None:
396         try:
397             if opts.batchfile == '-':
398                 batchfd = sys.stdin
399             else:
400                 batchfd = open(opts.batchfile, 'r')
401             batchurls = batchfd.readlines()
402             batchurls = [x.strip() for x in batchurls]
403             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
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')