]> Raphaël G. Git Repositories - youtubedl/blob - youtube_dl/__init__.py
Update changelog.
[youtubedl] / 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 downloader = optparse.OptionGroup(parser, 'Download Options')
123 postproc = optparse.OptionGroup(parser, 'Post-processing Options')
124 filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
125 verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
126
127 general.add_option('-h', '--help',
128 action='help', help='print this help text and exit')
129 general.add_option('-v', '--version',
130 action='version', help='print program version and exit')
131 general.add_option('-U', '--update',
132 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)')
133 general.add_option('-i', '--ignore-errors',
134 action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
135 general.add_option('--dump-user-agent',
136 action='store_true', dest='dump_user_agent',
137 help='display the current browser identification', default=False)
138 general.add_option('--user-agent',
139 dest='user_agent', help='specify a custom user agent', metavar='UA')
140 general.add_option('--referer',
141 dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
142 metavar='REF', default=None)
143 general.add_option('--list-extractors',
144 action='store_true', dest='list_extractors',
145 help='List all supported extractors and the URLs they would handle', default=False)
146 general.add_option('--extractor-descriptions',
147 action='store_true', dest='list_extractor_descriptions',
148 help='Output descriptions of all supported extractors', default=False)
149 general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
150 general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
151
152
153 selection.add_option('--playlist-start',
154 dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
155 selection.add_option('--playlist-end',
156 dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
157 selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
158 selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
159 selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
160 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)
161 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)
162 selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
163 selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
164 selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
165
166
167 authentication.add_option('-u', '--username',
168 dest='username', metavar='USERNAME', help='account username')
169 authentication.add_option('-p', '--password',
170 dest='password', metavar='PASSWORD', help='account password')
171 authentication.add_option('-n', '--netrc',
172 action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
173 authentication.add_option('--video-password',
174 dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
175
176
177 video_format.add_option('-f', '--format',
178 action='store', dest='format', metavar='FORMAT',
179 help='video format code, specifiy the order of preference using slashes: "-f 22/17/18"')
180 video_format.add_option('--all-formats',
181 action='store_const', dest='format', help='download all available video formats', const='all')
182 video_format.add_option('--prefer-free-formats',
183 action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
184 video_format.add_option('--max-quality',
185 action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
186 video_format.add_option('-F', '--list-formats',
187 action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
188 video_format.add_option('--write-sub', '--write-srt',
189 action='store_true', dest='writesubtitles',
190 help='write subtitle file (currently youtube only)', default=False)
191 video_format.add_option('--write-auto-sub', '--write-automatic-sub',
192 action='store_true', dest='writeautomaticsub',
193 help='write automatic subtitle file (currently youtube only)', default=False)
194 video_format.add_option('--only-sub',
195 action='store_true', dest='skip_download',
196 help='[deprecated] alias of --skip-download', default=False)
197 video_format.add_option('--all-subs',
198 action='store_true', dest='allsubtitles',
199 help='downloads all the available subtitles of the video (currently youtube only)', default=False)
200 video_format.add_option('--list-subs',
201 action='store_true', dest='listsubtitles',
202 help='lists all available subtitles for the video (currently youtube only)', default=False)
203 video_format.add_option('--sub-format',
204 action='store', dest='subtitlesformat', metavar='FORMAT',
205 help='subtitle format [srt/sbv/vtt] (default=srt) (currently youtube only)', default='srt')
206 video_format.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(authentication)
332 parser.add_option_group(postproc)
333
334 if overrideArguments is not None:
335 opts, args = parser.parse_args(overrideArguments)
336 if opts.verbose:
337 sys.stderr.write(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
338 else:
339 xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
340 if xdg_config_home:
341 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
342 else:
343 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
344 systemConf = _readOptions('/etc/youtube-dl.conf')
345 userConf = _readOptions(userConfFile)
346 commandLineConf = sys.argv[1:]
347 argv = systemConf + userConf + commandLineConf
348 opts, args = parser.parse_args(argv)
349 if opts.verbose:
350 sys.stderr.write(u'[debug] System config: ' + repr(systemConf) + '\n')
351 sys.stderr.write(u'[debug] User config: ' + repr(userConf) + '\n')
352 sys.stderr.write(u'[debug] Command-line args: ' + repr(commandLineConf) + '\n')
353
354 return parser, opts, args
355
356 def _real_main(argv=None):
357 # Compatibility fixes for Windows
358 if sys.platform == 'win32':
359 # https://github.com/rg3/youtube-dl/issues/820
360 codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
361
362 parser, opts, args = parseOpts(argv)
363
364 # Open appropriate CookieJar
365 if opts.cookiefile is None:
366 jar = compat_cookiejar.CookieJar()
367 else:
368 try:
369 jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
370 if os.access(opts.cookiefile, os.R_OK):
371 jar.load()
372 except (IOError, OSError) as err:
373 if opts.verbose:
374 traceback.print_exc()
375 sys.stderr.write(u'ERROR: unable to open cookie file\n')
376 sys.exit(101)
377 # Set user agent
378 if opts.user_agent is not None:
379 std_headers['User-Agent'] = opts.user_agent
380
381 # Set referer
382 if opts.referer is not None:
383 std_headers['Referer'] = opts.referer
384
385 # Dump user agent
386 if opts.dump_user_agent:
387 compat_print(std_headers['User-Agent'])
388 sys.exit(0)
389
390 # Batch file verification
391 batchurls = []
392 if opts.batchfile is not None:
393 try:
394 if opts.batchfile == '-':
395 batchfd = sys.stdin
396 else:
397 batchfd = open(opts.batchfile, 'r')
398 batchurls = batchfd.readlines()
399 batchurls = [x.strip() for x in batchurls]
400 batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
401 if opts.verbose:
402 sys.stderr.write(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
403 except IOError:
404 sys.exit(u'ERROR: batch file could not be read')
405 all_urls = batchurls + args
406 all_urls = [url.strip() for url in all_urls]
407
408 # General configuration
409 cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
410 if opts.proxy is not None:
411 if opts.proxy == '':
412 proxies = {}
413 else:
414 proxies = {'http': opts.proxy, 'https': opts.proxy}
415 else:
416 proxies = compat_urllib_request.getproxies()
417 # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
418 if 'http' in proxies and 'https' not in proxies:
419 proxies['https'] = proxies['http']
420 proxy_handler = compat_urllib_request.ProxyHandler(proxies)
421 https_handler = make_HTTPS_handler(opts)
422 opener = compat_urllib_request.build_opener(https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
423 compat_urllib_request.install_opener(opener)
424 socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
425
426 extractors = gen_extractors()
427
428 if opts.list_extractors:
429 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
430 compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
431 matchedUrls = [url for url in all_urls if ie.suitable(url)]
432 all_urls = [url for url in all_urls if url not in matchedUrls]
433 for mu in matchedUrls:
434 compat_print(u' ' + mu)
435 sys.exit(0)
436 if opts.list_extractor_descriptions:
437 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
438 if not ie._WORKING:
439 continue
440 desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
441 if hasattr(ie, 'SEARCH_KEY'):
442 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
443 _COUNTS = (u'', u'5', u'10', u'all')
444 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
445 compat_print(desc)
446 sys.exit(0)
447
448
449 # Conflicting, missing and erroneous options
450 if opts.usenetrc and (opts.username is not None or opts.password is not None):
451 parser.error(u'using .netrc conflicts with giving username/password')
452 if opts.password is not None and opts.username is None:
453 parser.error(u' account username missing\n')
454 if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
455 parser.error(u'using output template conflicts with using title, video ID or auto number')
456 if opts.usetitle and opts.useid:
457 parser.error(u'using title conflicts with using video ID')
458 if opts.username is not None and opts.password is None:
459 opts.password = getpass.getpass(u'Type account password and press return:')
460 if opts.ratelimit is not None:
461 numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
462 if numeric_limit is None:
463 parser.error(u'invalid rate limit specified')
464 opts.ratelimit = numeric_limit
465 if opts.min_filesize is not None:
466 numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
467 if numeric_limit is None:
468 parser.error(u'invalid min_filesize specified')
469 opts.min_filesize = numeric_limit
470 if opts.max_filesize is not None:
471 numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
472 if numeric_limit is None:
473 parser.error(u'invalid max_filesize specified')
474 opts.max_filesize = numeric_limit
475 if opts.retries is not None:
476 try:
477 opts.retries = int(opts.retries)
478 except (TypeError, ValueError) as err:
479 parser.error(u'invalid retry count specified')
480 if opts.buffersize is not None:
481 numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
482 if numeric_buffersize is None:
483 parser.error(u'invalid buffer size specified')
484 opts.buffersize = numeric_buffersize
485 try:
486 opts.playliststart = int(opts.playliststart)
487 if opts.playliststart <= 0:
488 raise ValueError(u'Playlist start must be positive')
489 except (TypeError, ValueError) as err:
490 parser.error(u'invalid playlist start number specified')
491 try:
492 opts.playlistend = int(opts.playlistend)
493 if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
494 raise ValueError(u'Playlist end must be greater than playlist start')
495 except (TypeError, ValueError) as err:
496 parser.error(u'invalid playlist end number specified')
497 if opts.extractaudio:
498 if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
499 parser.error(u'invalid audio format specified')
500 if opts.audioquality:
501 opts.audioquality = opts.audioquality.strip('k').strip('K')
502 if not opts.audioquality.isdigit():
503 parser.error(u'invalid audio quality specified')
504 if opts.recodevideo is not None:
505 if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
506 parser.error(u'invalid video recode format specified')
507 if opts.date is not None:
508 date = DateRange.day(opts.date)
509 else:
510 date = DateRange(opts.dateafter, opts.datebefore)
511
512 if sys.version_info < (3,):
513 # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
514 if opts.outtmpl is not None:
515 opts.outtmpl = opts.outtmpl.decode(preferredencoding())
516 outtmpl =((opts.outtmpl is not None and opts.outtmpl)
517 or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
518 or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
519 or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
520 or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
521 or (opts.useid and u'%(id)s.%(ext)s')
522 or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
523 or u'%(title)s-%(id)s.%(ext)s')
524
525 # YoutubeDL
526 ydl = YoutubeDL({
527 'usenetrc': opts.usenetrc,
528 'username': opts.username,
529 'password': opts.password,
530 'videopassword': opts.videopassword,
531 'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
532 'forceurl': opts.geturl,
533 'forcetitle': opts.gettitle,
534 'forceid': opts.getid,
535 'forcethumbnail': opts.getthumbnail,
536 'forcedescription': opts.getdescription,
537 'forcefilename': opts.getfilename,
538 'forceformat': opts.getformat,
539 'simulate': opts.simulate,
540 '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),
541 'format': opts.format,
542 'format_limit': opts.format_limit,
543 'listformats': opts.listformats,
544 'outtmpl': outtmpl,
545 'autonumber_size': opts.autonumber_size,
546 'restrictfilenames': opts.restrictfilenames,
547 'ignoreerrors': opts.ignoreerrors,
548 'ratelimit': opts.ratelimit,
549 'nooverwrites': opts.nooverwrites,
550 'retries': opts.retries,
551 'buffersize': opts.buffersize,
552 'noresizebuffer': opts.noresizebuffer,
553 'continuedl': opts.continue_dl,
554 'noprogress': opts.noprogress,
555 'progress_with_newline': opts.progress_with_newline,
556 'playliststart': opts.playliststart,
557 'playlistend': opts.playlistend,
558 'logtostderr': opts.outtmpl == '-',
559 'consoletitle': opts.consoletitle,
560 'nopart': opts.nopart,
561 'updatetime': opts.updatetime,
562 'writedescription': opts.writedescription,
563 'writeinfojson': opts.writeinfojson,
564 'writethumbnail': opts.writethumbnail,
565 'writesubtitles': opts.writesubtitles,
566 'writeautomaticsub': opts.writeautomaticsub,
567 'allsubtitles': opts.allsubtitles,
568 'listsubtitles': opts.listsubtitles,
569 'subtitlesformat': opts.subtitlesformat,
570 'subtitleslang': opts.subtitleslang,
571 'matchtitle': decodeOption(opts.matchtitle),
572 'rejecttitle': decodeOption(opts.rejecttitle),
573 'max_downloads': opts.max_downloads,
574 'prefer_free_formats': opts.prefer_free_formats,
575 'verbose': opts.verbose,
576 'dump_intermediate_pages': opts.dump_intermediate_pages,
577 'test': opts.test,
578 'keepvideo': opts.keepvideo,
579 'min_filesize': opts.min_filesize,
580 'max_filesize': opts.max_filesize,
581 'daterange': date,
582 })
583
584 if opts.verbose:
585 sys.stderr.write(u'[debug] youtube-dl version ' + __version__ + u'\n')
586 try:
587 sp = subprocess.Popen(
588 ['git', 'rev-parse', '--short', 'HEAD'],
589 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
590 cwd=os.path.dirname(os.path.abspath(__file__)))
591 out, err = sp.communicate()
592 out = out.decode().strip()
593 if re.match('[0-9a-f]+', out):
594 sys.stderr.write(u'[debug] Git HEAD: ' + out + u'\n')
595 except:
596 try:
597 sys.exc_clear()
598 except:
599 pass
600 sys.stderr.write(u'[debug] Python version %s - %s' %(platform.python_version(), platform.platform()) + u'\n')
601 sys.stderr.write(u'[debug] Proxy map: ' + str(proxy_handler.proxies) + u'\n')
602
603 ydl.add_default_info_extractors()
604
605 # PostProcessors
606 if opts.extractaudio:
607 ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
608 if opts.recodevideo:
609 ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
610
611 # Update version
612 if opts.update_self:
613 update_self(ydl.to_screen, opts.verbose, sys.argv[0])
614
615 # Maybe do nothing
616 if len(all_urls) < 1:
617 if not opts.update_self:
618 parser.error(u'you must provide at least one URL')
619 else:
620 sys.exit()
621
622 try:
623 retcode = ydl.download(all_urls)
624 except MaxDownloadsReached:
625 ydl.to_screen(u'--max-download limit reached, aborting.')
626 retcode = 101
627
628 # Dump cookie jar if requested
629 if opts.cookiefile is not None:
630 try:
631 jar.save()
632 except (IOError, OSError) as err:
633 sys.exit(u'ERROR: unable to save cookie jar')
634
635 sys.exit(retcode)
636
637 def main(argv=None):
638 try:
639 _real_main(argv)
640 except DownloadError:
641 sys.exit(1)
642 except SameFileError:
643 sys.exit(u'ERROR: fixed output name but more than one file to download')
644 except KeyboardInterrupt:
645 sys.exit(u'\nERROR: Interrupted by user')