]> jfr.im git - yt-dlp.git/blame - youtube_dl/__init__.py
Merge remote-tracking branch 'jaimeMF/opus-fix'
[yt-dlp.git] / youtube_dl / __init__.py
CommitLineData
235b3ba4
PH
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
3906e6ce 4__authors__ = (
59ae15a5
PH
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',
88f6c78b 20 'Dave Vasilevsky',
2069acc6 21 'Jaime Marquínez Ferrándiz',
fffec3b9 22 'Jeff Crouse',
6aabe820 23 'Osama Khalid',
e8600d69 24 'Michael Walter',
95464f14 25 'M. Yasoob Ullah Khalid',
0ae456f0 26 'Julien Fraichard',
be74864a 27 'Johny Mo Swag',
df725153 28 'Axel Noack',
ba7a1de0 29 'Albert Kim',
4a55479f 30 'Pierre Rudloff',
085bea45 31 'Huarong Huo',
ac4f319b 32 'Ismael Mejía',
2dad310e 33 'Steffan \'Ruirize\' James',
ba7a1de0 34)
235b3ba4
PH
35
36__license__ = 'Public Domain'
235b3ba4 37
0d94f247 38import codecs
a27b9e8b 39import collections
c9ed14e6 40import getpass
c9ed14e6 41import optparse
235b3ba4 42import os
0f818663 43import random
235b3ba4 44import re
c9ed14e6 45import shlex
235b3ba4 46import socket
235b3ba4
PH
47import subprocess
48import sys
235b3ba4 49import warnings
4e38899e 50import platform
235b3ba4 51
c496ca96 52
9e8056d5 53from .utils import *
d5ed35b6 54from .update import update_self
f427df17 55from .version import __version__
9e8056d5 56from .FileDownloader import *
0824c28c 57from .extractor import gen_extractors
8222d8de 58from .YoutubeDL import YoutubeDL
9e8056d5 59from .PostProcessor import *
235b3ba4 60
75b5c590 61def parseOpts(overrideArguments=None):
59ae15a5
PH
62 def _readOptions(filename_bytes):
63 try:
64 optionf = open(filename_bytes)
65 except IOError:
66 return [] # silently skip if file is not present
67 try:
68 res = []
69 for l in optionf:
70 res += shlex.split(l, comments=True)
71 finally:
72 optionf.close()
73 return res
74
75 def _format_option_string(option):
76 ''' ('-o', '--option') -> -o, --format METAVAR'''
77
78 opts = []
79
80 if option._short_opts:
81 opts.append(option._short_opts[0])
82 if option._long_opts:
83 opts.append(option._long_opts[0])
84 if len(opts) > 1:
85 opts.insert(1, ', ')
86
87 if option.takes_value(): opts.append(' %s' % option.metavar)
88
89 return "".join(opts)
90
d6e203b3
IM
91 def _comma_separated_values_options_callback(option, opt_str, value, parser):
92 setattr(parser.values, option.dest, value.split(','))
93
59ae15a5
PH
94 def _find_term_columns():
95 columns = os.environ.get('COLUMNS', None)
96 if columns:
97 return int(columns)
98
99 try:
100 sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
101 out,err = sp.communicate()
102 return int(out.split()[1])
103 except:
104 pass
105 return None
106
920ef077
JMF
107 def _hide_login_info(opts):
108 opts = list(opts)
109 for private_opt in ['-p', '--password', '-u', '--username']:
110 try:
111 i = opts.index(private_opt)
112 opts[i+1] = '<PRIVATE>'
113 except ValueError:
114 pass
115 return opts
116
59ae15a5
PH
117 max_width = 80
118 max_help_position = 80
119
120 # No need to wrap help messages if we're on a wide console
121 columns = _find_term_columns()
122 if columns: max_width = columns
123
124 fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
125 fmt.format_option_strings = _format_option_string
126
127 kw = {
128 'version' : __version__,
129 'formatter' : fmt,
130 'usage' : '%prog [options] url [url...]',
131 'conflict_handler' : 'resolve',
132 }
133
134 parser = optparse.OptionParser(**kw)
135
136 # option groups
137 general = optparse.OptionGroup(parser, 'General Options')
138 selection = optparse.OptionGroup(parser, 'Video Selection')
139 authentication = optparse.OptionGroup(parser, 'Authentication Options')
140 video_format = optparse.OptionGroup(parser, 'Video Format Options')
505c28aa 141 subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
0beb3add 142 downloader = optparse.OptionGroup(parser, 'Download Options')
59ae15a5
PH
143 postproc = optparse.OptionGroup(parser, 'Post-processing Options')
144 filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
145 verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
146
147 general.add_option('-h', '--help',
148 action='help', help='print this help text and exit')
149 general.add_option('-v', '--version',
150 action='version', help='print program version and exit')
151 general.add_option('-U', '--update',
f631c331 152 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)')
59ae15a5 153 general.add_option('-i', '--ignore-errors',
830dd194 154 action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
59ae15a5
PH
155 general.add_option('--dump-user-agent',
156 action='store_true', dest='dump_user_agent',
157 help='display the current browser identification', default=False)
158 general.add_option('--user-agent',
159 dest='user_agent', help='specify a custom user agent', metavar='UA')
28535652 160 general.add_option('--referer',
3820df01
JMF
161 dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
162 metavar='REF', default=None)
59ae15a5
PH
163 general.add_option('--list-extractors',
164 action='store_true', dest='list_extractors',
165 help='List all supported extractors and the URLs they would handle', default=False)
62067cb9 166 general.add_option('--extractor-descriptions',
0f818663
PH
167 action='store_true', dest='list_extractor_descriptions',
168 help='Output descriptions of all supported extractors', default=False)
dbc50fdf 169 general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
ea6d901e 170 general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
7f747732 171 general.add_option(
c38b1e77 172 '--cache-dir', dest='cachedir', default=get_cachedir(),
be8fe32c 173 help='Location in the filesystem where youtube-dl can store downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl .')
7f747732
PH
174 general.add_option(
175 '--no-cache-dir', action='store_const', const=None, dest='cachedir',
176 help='Disable filesystem caching')
0beb3add 177
59ae15a5
PH
178
179 selection.add_option('--playlist-start',
180 dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
181 selection.add_option('--playlist-end',
182 dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
183 selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
184 selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
185 selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
dbf2ba3d
PH
186 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)
187 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)
bd558525
JMF
188 selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
189 selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
190 selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
47192f92 191 selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
8dbe9899
PH
192 selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
193 help='download only videos suitable for the given age',
194 default=None, type=int)
c1c9a79c
PH
195 selection.add_option('--download-archive', metavar='FILE',
196 dest='download_archive',
197 help='Download only videos not present in the archive file. Record all downloaded videos in it.')
9e982f9e
JC
198
199
59ae15a5
PH
200 authentication.add_option('-u', '--username',
201 dest='username', metavar='USERNAME', help='account username')
202 authentication.add_option('-p', '--password',
203 dest='password', metavar='PASSWORD', help='account password')
204 authentication.add_option('-n', '--netrc',
205 action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
c6c19746
JMF
206 authentication.add_option('--video-password',
207 dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
59ae15a5
PH
208
209
210 video_format.add_option('-f', '--format',
f4b659f7 211 action='store', dest='format', metavar='FORMAT',
bdc6b3fc 212 help='video format code, specifiy the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
59ae15a5
PH
213 video_format.add_option('--all-formats',
214 action='store_const', dest='format', help='download all available video formats', const='all')
215 video_format.add_option('--prefer-free-formats',
216 action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
217 video_format.add_option('--max-quality',
218 action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
219 video_format.add_option('-F', '--list-formats',
220 action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
505c28aa
IM
221
222 subtitles.add_option('--write-sub', '--write-srt',
59ae15a5 223 action='store_true', dest='writesubtitles',
953e32b2 224 help='write subtitle file', default=False)
505c28aa 225 subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
b004821f 226 action='store_true', dest='writeautomaticsub',
953e32b2 227 help='write automatic subtitle file (youtube only)', default=False)
505c28aa 228 subtitles.add_option('--all-subs',
ae608b80 229 action='store_true', dest='allsubtitles',
953e32b2 230 help='downloads all the available subtitles of the video', default=False)
505c28aa 231 subtitles.add_option('--list-subs',
2a4093ea 232 action='store_true', dest='listsubtitles',
953e32b2 233 help='lists all available subtitles for the video', default=False)
505c28aa 234 subtitles.add_option('--sub-format',
c3ab8f86 235 action='store', dest='subtitlesformat', metavar='FORMAT',
953e32b2 236 help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
d6e203b3
IM
237 subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
238 action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
239 default=[], callback=_comma_separated_values_options_callback,
240 help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
59ae15a5 241
0beb3add
PH
242 downloader.add_option('-r', '--rate-limit',
243 dest='ratelimit', metavar='LIMIT', help='maximum download rate (e.g. 50k or 44.6m)')
244 downloader.add_option('-R', '--retries',
245 dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
246 downloader.add_option('--buffer-size',
247 dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16k) (default is %default)', default="1024")
248 downloader.add_option('--no-resize-buffer',
249 action='store_true', dest='noresizebuffer',
250 help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
251 downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
252
59ae15a5
PH
253 verbosity.add_option('-q', '--quiet',
254 action='store_true', dest='quiet', help='activates quiet mode', default=False)
255 verbosity.add_option('-s', '--simulate',
256 action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
257 verbosity.add_option('--skip-download',
258 action='store_true', dest='skip_download', help='do not download the video', default=False)
259 verbosity.add_option('-g', '--get-url',
260 action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
261 verbosity.add_option('-e', '--get-title',
262 action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
1a2adf3f 263 verbosity.add_option('--get-id',
264 action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
59ae15a5
PH
265 verbosity.add_option('--get-thumbnail',
266 action='store_true', dest='getthumbnail',
267 help='simulate, quiet but print thumbnail URL', default=False)
268 verbosity.add_option('--get-description',
269 action='store_true', dest='getdescription',
270 help='simulate, quiet but print video description', default=False)
271 verbosity.add_option('--get-filename',
272 action='store_true', dest='getfilename',
273 help='simulate, quiet but print output filename', default=False)
274 verbosity.add_option('--get-format',
275 action='store_true', dest='getformat',
276 help='simulate, quiet but print output format', default=False)
7311fef8 277 verbosity.add_option('--newline',
5717d91a 278 action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
59ae15a5
PH
279 verbosity.add_option('--no-progress',
280 action='store_true', dest='noprogress', help='do not print progress bar', default=False)
281 verbosity.add_option('--console-title',
282 action='store_true', dest='consoletitle',
283 help='display progress in console titlebar', default=False)
284 verbosity.add_option('-v', '--verbose',
285 action='store_true', dest='verbose', help='print various debugging information', default=False)
855703e5
PH
286 verbosity.add_option('--dump-intermediate-pages',
287 action='store_true', dest='dump_intermediate_pages', default=False,
288 help='print downloaded pages to debug problems(very verbose)')
edf3e38e
PH
289 verbosity.add_option('--youtube-print-sig-code',
290 action='store_true', dest='youtube_print_sig_code', default=False,
291 help=optparse.SUPPRESS_HELP)
292
59ae15a5 293
59ae15a5 294 filesystem.add_option('-t', '--title',
08b2ac74 295 action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
59ae15a5 296 filesystem.add_option('--id',
08b2ac74 297 action='store_true', dest='useid', help='use only video ID in file name', default=False)
59ae15a5
PH
298 filesystem.add_option('-l', '--literal',
299 action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
300 filesystem.add_option('-A', '--auto-number',
301 action='store_true', dest='autonumber',
302 help='number downloaded files starting from 00000', default=False)
303 filesystem.add_option('-o', '--output',
74e3452b
JMF
304 dest='outtmpl', metavar='TEMPLATE',
305 help=('output filename template. Use %(title)s to get the title, '
306 '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
307 '%(autonumber)s to get an automatically incremented number, '
308 '%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
309 '%(extractor)s for the provider (youtube, metacafe, etc), '
310 '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
311 '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
312 'Use - to output to stdout. Can also be used to download to a different directory, '
313 'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
213c31ae
SK
314 filesystem.add_option('--autonumber-size',
315 dest='autonumber_size', metavar='NUMBER',
316 help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
59ae15a5
PH
317 filesystem.add_option('--restrict-filenames',
318 action='store_true', dest='restrictfilenames',
319 help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
320 filesystem.add_option('-a', '--batch-file',
321 dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
322 filesystem.add_option('-w', '--no-overwrites',
323 action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
324 filesystem.add_option('-c', '--continue',
325 action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
326 filesystem.add_option('--no-continue',
327 action='store_false', dest='continue_dl',
328 help='do not resume partially downloaded files (restart from beginning)')
329 filesystem.add_option('--cookies',
330 dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
331 filesystem.add_option('--no-part',
332 action='store_true', dest='nopart', help='do not use .part files', default=False)
333 filesystem.add_option('--no-mtime',
334 action='store_false', dest='updatetime',
335 help='do not use the Last-modified header to set the file modification time', default=True)
336 filesystem.add_option('--write-description',
337 action='store_true', dest='writedescription',
338 help='write video description to a .description file', default=False)
339 filesystem.add_option('--write-info-json',
340 action='store_true', dest='writeinfojson',
341 help='write video metadata to a .info.json file', default=False)
11d9224e
PH
342 filesystem.add_option('--write-thumbnail',
343 action='store_true', dest='writethumbnail',
344 help='write thumbnail image to disk', default=False)
59ae15a5
PH
345
346
347 postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
348 help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
349 postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
510e6f6d 350 help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
59ae15a5
PH
351 postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
352 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)')
7851b379
PH
353 postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
354 help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
59ae15a5
PH
355 postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
356 help='keeps the video file on disk after the post-processing; the video is erased by default')
f0648fc1
BPG
357 postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
358 help='do not overwrite post-processed files; the post-processed files are overwritten by default')
d4051a8e
JMF
359 postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
360 help='embed subtitles in the video (only for mp4 videos)')
bc4f2917
JMF
361 postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
362 help='add metadata to the files')
59ae15a5
PH
363
364
365 parser.add_option_group(general)
366 parser.add_option_group(selection)
0beb3add 367 parser.add_option_group(downloader)
59ae15a5
PH
368 parser.add_option_group(filesystem)
369 parser.add_option_group(verbosity)
370 parser.add_option_group(video_format)
505c28aa 371 parser.add_option_group(subtitles)
59ae15a5
PH
372 parser.add_option_group(authentication)
373 parser.add_option_group(postproc)
374
75b5c590
PH
375 if overrideArguments is not None:
376 opts, args = parser.parse_args(overrideArguments)
377 if opts.verbose:
7459e3a2 378 write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
59ae15a5 379 else:
75b5c590
PH
380 xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
381 if xdg_config_home:
fa556755
MO
382 userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
383 if not os.path.isfile(userConfFile):
384 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
75b5c590 385 else:
fa556755
MO
386 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
387 if not os.path.isfile(userConfFile):
388 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
75b5c590
PH
389 systemConf = _readOptions('/etc/youtube-dl.conf')
390 userConf = _readOptions(userConfFile)
1865ed31 391 commandLineConf = sys.argv[1:]
75b5c590
PH
392 argv = systemConf + userConf + commandLineConf
393 opts, args = parser.parse_args(argv)
c76cb6d5 394 if opts.verbose:
7459e3a2
PH
395 write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
396 write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
397 write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
8c42c506 398
59ae15a5 399 return parser, opts, args
235b3ba4 400
b8ad4f02 401def _real_main(argv=None):
0d94f247
PH
402 # Compatibility fixes for Windows
403 if sys.platform == 'win32':
404 # https://github.com/rg3/youtube-dl/issues/820
405 codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
406
b8ad4f02 407 parser, opts, args = parseOpts(argv)
59ae15a5
PH
408
409 # Open appropriate CookieJar
410 if opts.cookiefile is None:
411 jar = compat_cookiejar.CookieJar()
412 else:
413 try:
414 jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
229cac75 415 if os.access(opts.cookiefile, os.R_OK):
59ae15a5
PH
416 jar.load()
417 except (IOError, OSError) as err:
229cac75
PH
418 if opts.verbose:
419 traceback.print_exc()
7459e3a2 420 write_string(u'ERROR: unable to open cookie file\n')
229cac75 421 sys.exit(101)
59ae15a5
PH
422 # Set user agent
423 if opts.user_agent is not None:
424 std_headers['User-Agent'] = opts.user_agent
1865ed31 425
28535652
BH
426 # Set referer
427 if opts.referer is not None:
428 std_headers['Referer'] = opts.referer
59ae15a5
PH
429
430 # Dump user agent
431 if opts.dump_user_agent:
93eb15c5 432 compat_print(std_headers['User-Agent'])
59ae15a5
PH
433 sys.exit(0)
434
435 # Batch file verification
436 batchurls = []
437 if opts.batchfile is not None:
438 try:
439 if opts.batchfile == '-':
440 batchfd = sys.stdin
441 else:
442 batchfd = open(opts.batchfile, 'r')
443 batchurls = batchfd.readlines()
444 batchurls = [x.strip() for x in batchurls]
445 batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
05afc96b 446 if opts.verbose:
7459e3a2 447 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
59ae15a5
PH
448 except IOError:
449 sys.exit(u'ERROR: batch file could not be read')
450 all_urls = batchurls + args
451 all_urls = [url.strip() for url in all_urls]
452
2ae3edb1 453 opener = _setup_opener(jar=jar, opts=opts)
59ae15a5
PH
454
455 extractors = gen_extractors()
456
457 if opts.list_extractors:
7dba9cd0 458 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
93eb15c5 459 compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
1a2c3c0f
FV
460 matchedUrls = [url for url in all_urls if ie.suitable(url)]
461 all_urls = [url for url in all_urls if url not in matchedUrls]
59ae15a5 462 for mu in matchedUrls:
93eb15c5 463 compat_print(u' ' + mu)
59ae15a5 464 sys.exit(0)
0f818663
PH
465 if opts.list_extractor_descriptions:
466 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
467 if not ie._WORKING:
468 continue
469 desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
15870e90
PH
470 if desc is False:
471 continue
0f818663
PH
472 if hasattr(ie, 'SEARCH_KEY'):
473 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
474 _COUNTS = (u'', u'5', u'10', u'all')
475 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
476 compat_print(desc)
477 sys.exit(0)
478
59ae15a5
PH
479
480 # Conflicting, missing and erroneous options
481 if opts.usenetrc and (opts.username is not None or opts.password is not None):
482 parser.error(u'using .netrc conflicts with giving username/password')
483 if opts.password is not None and opts.username is None:
c6c19746 484 parser.error(u' account username missing\n')
59ae15a5
PH
485 if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
486 parser.error(u'using output template conflicts with using title, video ID or auto number')
487 if opts.usetitle and opts.useid:
488 parser.error(u'using title conflicts with using video ID')
489 if opts.username is not None and opts.password is None:
490 opts.password = getpass.getpass(u'Type account password and press return:')
491 if opts.ratelimit is not None:
492 numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
493 if numeric_limit is None:
494 parser.error(u'invalid rate limit specified')
495 opts.ratelimit = numeric_limit
9e982f9e
JC
496 if opts.min_filesize is not None:
497 numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
498 if numeric_limit is None:
499 parser.error(u'invalid min_filesize specified')
500 opts.min_filesize = numeric_limit
501 if opts.max_filesize is not None:
502 numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
503 if numeric_limit is None:
504 parser.error(u'invalid max_filesize specified')
505 opts.max_filesize = numeric_limit
59ae15a5
PH
506 if opts.retries is not None:
507 try:
508 opts.retries = int(opts.retries)
509 except (TypeError, ValueError) as err:
510 parser.error(u'invalid retry count specified')
511 if opts.buffersize is not None:
512 numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
513 if numeric_buffersize is None:
514 parser.error(u'invalid buffer size specified')
515 opts.buffersize = numeric_buffersize
516 try:
517 opts.playliststart = int(opts.playliststart)
518 if opts.playliststart <= 0:
519 raise ValueError(u'Playlist start must be positive')
520 except (TypeError, ValueError) as err:
521 parser.error(u'invalid playlist start number specified')
522 try:
523 opts.playlistend = int(opts.playlistend)
524 if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
525 raise ValueError(u'Playlist end must be greater than playlist start')
526 except (TypeError, ValueError) as err:
527 parser.error(u'invalid playlist end number specified')
528 if opts.extractaudio:
510e6f6d 529 if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
59ae15a5
PH
530 parser.error(u'invalid audio format specified')
531 if opts.audioquality:
532 opts.audioquality = opts.audioquality.strip('k').strip('K')
533 if not opts.audioquality.isdigit():
534 parser.error(u'invalid audio quality specified')
7851b379
PH
535 if opts.recodevideo is not None:
536 if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
537 parser.error(u'invalid video recode format specified')
bd558525
JMF
538 if opts.date is not None:
539 date = DateRange.day(opts.date)
540 else:
541 date = DateRange(opts.dateafter, opts.datebefore)
59ae15a5 542
0b7f3118
JMF
543 # --all-sub automatically sets --write-sub if --write-auto-sub is not given
544 # this was the old behaviour if only --all-sub was given.
545 if opts.allsubtitles and (opts.writeautomaticsub == False):
546 opts.writesubtitles = True
547
5cb9c312
PH
548 if sys.version_info < (3,):
549 # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
0be41ec2
PH
550 if opts.outtmpl is not None:
551 opts.outtmpl = opts.outtmpl.decode(preferredencoding())
5cb9c312
PH
552 outtmpl =((opts.outtmpl is not None and opts.outtmpl)
553 or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
554 or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
555 or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
556 or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
557 or (opts.useid and u'%(id)s.%(ext)s')
558 or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
08b2ac74 559 or u'%(title)s-%(id)s.%(ext)s')
b61067fa
PH
560 if '%(ext)s' not in outtmpl and opts.extractaudio:
561 parser.error(u'Cannot download a video and extract audio into the same'
562 u' file! Use "%%(ext)s" instead of %r' %
563 determine_ext(outtmpl, u''))
29c7a63d 564
8222d8de
JMF
565 # YoutubeDL
566 ydl = YoutubeDL({
59ae15a5
PH
567 'usenetrc': opts.usenetrc,
568 'username': opts.username,
569 'password': opts.password,
c6c19746 570 'videopassword': opts.videopassword,
1a2adf3f 571 'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
59ae15a5
PH
572 'forceurl': opts.geturl,
573 'forcetitle': opts.gettitle,
1a2adf3f 574 'forceid': opts.getid,
59ae15a5
PH
575 'forcethumbnail': opts.getthumbnail,
576 'forcedescription': opts.getdescription,
577 'forcefilename': opts.getfilename,
578 'forceformat': opts.getformat,
579 'simulate': opts.simulate,
1a2adf3f 580 '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),
59ae15a5
PH
581 'format': opts.format,
582 'format_limit': opts.format_limit,
583 'listformats': opts.listformats,
5cb9c312 584 'outtmpl': outtmpl,
213c31ae 585 'autonumber_size': opts.autonumber_size,
59ae15a5
PH
586 'restrictfilenames': opts.restrictfilenames,
587 'ignoreerrors': opts.ignoreerrors,
588 'ratelimit': opts.ratelimit,
589 'nooverwrites': opts.nooverwrites,
590 'retries': opts.retries,
591 'buffersize': opts.buffersize,
592 'noresizebuffer': opts.noresizebuffer,
593 'continuedl': opts.continue_dl,
594 'noprogress': opts.noprogress,
5717d91a 595 'progress_with_newline': opts.progress_with_newline,
59ae15a5
PH
596 'playliststart': opts.playliststart,
597 'playlistend': opts.playlistend,
47192f92 598 'noplaylist': opts.noplaylist,
59ae15a5
PH
599 'logtostderr': opts.outtmpl == '-',
600 'consoletitle': opts.consoletitle,
601 'nopart': opts.nopart,
602 'updatetime': opts.updatetime,
603 'writedescription': opts.writedescription,
604 'writeinfojson': opts.writeinfojson,
11d9224e 605 'writethumbnail': opts.writethumbnail,
59ae15a5 606 'writesubtitles': opts.writesubtitles,
b004821f 607 'writeautomaticsub': opts.writeautomaticsub,
ae608b80 608 'allsubtitles': opts.allsubtitles,
2a4093ea 609 'listsubtitles': opts.listsubtitles,
9e62bc44 610 'subtitlesformat': opts.subtitlesformat,
d6e203b3 611 'subtitleslangs': opts.subtitleslangs,
8271226a
PH
612 'matchtitle': decodeOption(opts.matchtitle),
613 'rejecttitle': decodeOption(opts.rejecttitle),
59ae15a5
PH
614 'max_downloads': opts.max_downloads,
615 'prefer_free_formats': opts.prefer_free_formats,
616 'verbose': opts.verbose,
855703e5 617 'dump_intermediate_pages': opts.dump_intermediate_pages,
8d5d3a5d 618 'test': opts.test,
7851b379 619 'keepvideo': opts.keepvideo,
9e982f9e 620 'min_filesize': opts.min_filesize,
bd558525 621 'max_filesize': opts.max_filesize,
11d9224e 622 'daterange': date,
7f747732 623 'cachedir': opts.cachedir,
f8061589 624 'youtube_print_sig_code': opts.youtube_print_sig_code,
8dbe9899 625 'age_limit': opts.age_limit,
c1c9a79c 626 'download_archive': opts.download_archive,
59ae15a5
PH
627 })
628
629 if opts.verbose:
7459e3a2 630 write_string(u'[debug] youtube-dl version ' + __version__ + u'\n')
4e38899e 631 try:
deacef65
PH
632 sp = subprocess.Popen(
633 ['git', 'rev-parse', '--short', 'HEAD'],
634 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
635 cwd=os.path.dirname(os.path.abspath(__file__)))
4e38899e
FV
636 out, err = sp.communicate()
637 out = out.decode().strip()
638 if re.match('[0-9a-f]+', out):
7459e3a2 639 write_string(u'[debug] Git HEAD: ' + out + u'\n')
4e38899e 640 except:
de29c414
PH
641 try:
642 sys.exc_clear()
643 except:
644 pass
7459e3a2 645 write_string(u'[debug] Python version %s - %s' %(platform.python_version(), platform_name()) + u'\n')
2ae3edb1
JMF
646
647 proxy_map = {}
648 for handler in opener.handlers:
649 if hasattr(handler, 'proxies'):
650 proxy_map.update(handler.proxies)
651 write_string(u'[debug] Proxy map: ' + compat_str(proxy_map) + u'\n')
59ae15a5 652
023fa8c4 653 ydl.add_default_info_extractors()
59ae15a5
PH
654
655 # PostProcessors
bc4f2917
JMF
656 # Add the metadata pp first, the other pps will copy it
657 if opts.addmetadata:
658 ydl.add_post_processor(FFmpegMetadataPP())
59ae15a5 659 if opts.extractaudio:
8222d8de 660 ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
7851b379 661 if opts.recodevideo:
8222d8de 662 ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
d4051a8e
JMF
663 if opts.embedsubtitles:
664 ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
59ae15a5 665
67353612
PH
666 # Update version
667 if opts.update_self:
46353f67 668 update_self(ydl.to_screen, opts.verbose)
67353612 669
59ae15a5
PH
670 # Maybe do nothing
671 if len(all_urls) < 1:
672 if not opts.update_self:
673 parser.error(u'you must provide at least one URL')
674 else:
675 sys.exit()
676
677 try:
8222d8de 678 retcode = ydl.download(all_urls)
59ae15a5 679 except MaxDownloadsReached:
8222d8de 680 ydl.to_screen(u'--max-download limit reached, aborting.')
59ae15a5
PH
681 retcode = 101
682
683 # Dump cookie jar if requested
684 if opts.cookiefile is not None:
685 try:
686 jar.save()
687 except (IOError, OSError) as err:
688 sys.exit(u'ERROR: unable to save cookie jar')
689
690 sys.exit(retcode)
235b3ba4 691
a27b9e8b
PH
692
693def _setup_opener(jar=None, opts=None, timeout=300):
694 if opts is None:
695 FakeOptions = collections.namedtuple(
696 'FakeOptions', ['proxy', 'no_check_certificate'])
697 opts = FakeOptions(proxy=None, no_check_certificate=False)
698
699 cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
700 if opts.proxy is not None:
701 if opts.proxy == '':
702 proxies = {}
703 else:
704 proxies = {'http': opts.proxy, 'https': opts.proxy}
705 else:
706 proxies = compat_urllib_request.getproxies()
707 # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
708 if 'http' in proxies and 'https' not in proxies:
709 proxies['https'] = proxies['http']
710 proxy_handler = compat_urllib_request.ProxyHandler(proxies)
711 https_handler = make_HTTPS_handler(opts)
712 opener = compat_urllib_request.build_opener(
713 https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
714 # Delete the default user-agent header, which would otherwise apply in
715 # cases where our custom HTTP handler doesn't come into play
716 # (See https://github.com/rg3/youtube-dl/issues/1309 for details)
717 opener.addheaders = []
718 compat_urllib_request.install_opener(opener)
719 socket.setdefaulttimeout(timeout)
720 return opener
721
722
b8ad4f02 723def main(argv=None):
59ae15a5 724 try:
b8ad4f02 725 _real_main(argv)
59ae15a5
PH
726 except DownloadError:
727 sys.exit(1)
728 except SameFileError:
729 sys.exit(u'ERROR: fixed output name but more than one file to download')
730 except KeyboardInterrupt:
731 sys.exit(u'\nERROR: Interrupted by user')