]> jfr.im git - yt-dlp.git/blame - youtube_dl/__init__.py
deprecate --title
[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',
a623df4c 34 'Andras Elso',
b5bdc269 35 'Jelle van der Waa',
d3793638 36 'Marcin Cieślak',
0a120f74 37 'Anton Larionov',
38b2db6a 38 'Takuya Tsuchida',
87968574 39 'Sergey M.',
b83be81d 40 'Michael Orlitzky',
e63fc1be 41 'Chris Gahan',
a7732b67 42 'Saimadhav Heblikar',
2a893862 43 'Mike Col',
6d784e87 44 'Oleg Prutz',
0cea52cc 45 'pulpe',
845d14d3 46 'Andreas Schmitz',
cbffec0c 47 'Michael Kaiser',
96d16370 48 'Niklas Laxström',
f38da667 49 'David Triendl',
a339d7ba 50 'Anthony Weems',
dc3727b6 51 'David Wagner',
2fcec131 52 'Juan C. Olivares',
855e2750 53 'Mattias Harrysson',
2cc0082d 54 'phaer',
610e47c8 55 'Sainyam Kapoor',
bbe99d26 56 'Nicolas Évrard',
ccdd34ed 57 'Jason Normore',
25dfe0eb 58 'Hoje Lee',
c2ef2923 59 'Adam Thalhammer',
d30d2815 60 'Georg Jähnig',
9cc977f1 61 'Ralf Haring',
ba4133c9 62 'Koki Takahashi',
3d55f280 63 'Ariset Llerena',
cdc22cb8 64 'Adam Malcontenti-Wilson',
1df0ae21 65 'Tobias Bell',
0d90e0f0 66 'Naglis Jonaitis',
3b09757b 67 'Charles Chen',
5e95cb27 68 'Hassaan Ali',
ba7a1de0 69)
235b3ba4
PH
70
71__license__ = 'Public Domain'
235b3ba4 72
0d94f247 73import codecs
8f563f32 74import io
c9ed14e6 75import optparse
235b3ba4 76import os
0f818663 77import random
c9ed14e6 78import shlex
235b3ba4 79import sys
235b3ba4 80
c496ca96 81
a4fd0415 82from .utils import (
e68301af 83 compat_getpass,
a4fd0415 84 compat_print,
a4fd0415 85 DateRange,
acd69589 86 DEFAULT_OUTTMPL,
a4fd0415 87 decodeOption,
1c088fa8 88 get_term_width,
a4fd0415
PH
89 DownloadError,
90 get_cachedir,
a4fd0415 91 MaxDownloadsReached,
a4fd0415 92 preferredencoding,
62e609ab 93 read_batch_urls,
a4fd0415 94 SameFileError,
e3946f98 95 setproctitle,
a4fd0415
PH
96 std_headers,
97 write_string,
a4fd0415 98)
d5ed35b6 99from .update import update_self
92a86f4c 100from .downloader import (
a4fd0415
PH
101 FileDownloader,
102)
0824c28c 103from .extractor import gen_extractors
dca08720 104from .version import __version__
8222d8de 105from .YoutubeDL import YoutubeDL
56327689 106from .postprocessor import (
0c14e2fb 107 AtomicParsleyPP,
149254d0 108 FFmpegAudioFixPP,
a4fd0415
PH
109 FFmpegMetadataPP,
110 FFmpegVideoConvertor,
111 FFmpegExtractAudioPP,
112 FFmpegEmbedSubtitlePP,
e63fc1be 113 XAttrMetadataPP,
a4fd0415
PH
114)
115
235b3ba4 116
75b5c590 117def parseOpts(overrideArguments=None):
fb27c229 118 def _readOptions(filename_bytes, default=[]):
59ae15a5
PH
119 try:
120 optionf = open(filename_bytes)
121 except IOError:
fb27c229 122 return default # silently skip if file is not present
59ae15a5 123 try:
a0eaa341
PH
124 res = []
125 for l in optionf:
126 res += shlex.split(l, comments=True)
59ae15a5
PH
127 finally:
128 optionf.close()
129 return res
130
588128d0
PH
131 def _readUserConf():
132 xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
133 if xdg_config_home:
134 userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
135 if not os.path.isfile(userConfFile):
136 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
137 else:
138 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
139 if not os.path.isfile(userConfFile):
140 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
141 userConf = _readOptions(userConfFile, None)
142
143 if userConf is None:
144 appdata_dir = os.environ.get('appdata')
145 if appdata_dir:
146 userConf = _readOptions(
147 os.path.join(appdata_dir, 'youtube-dl', 'config'),
148 default=None)
149 if userConf is None:
150 userConf = _readOptions(
151 os.path.join(appdata_dir, 'youtube-dl', 'config.txt'),
152 default=None)
153
154 if userConf is None:
155 userConf = _readOptions(
156 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf'),
157 default=None)
158 if userConf is None:
159 userConf = _readOptions(
160 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf.txt'),
161 default=None)
162
163 if userConf is None:
164 userConf = []
165
166 return userConf
167
59ae15a5
PH
168 def _format_option_string(option):
169 ''' ('-o', '--option') -> -o, --format METAVAR'''
170
171 opts = []
172
173 if option._short_opts:
174 opts.append(option._short_opts[0])
175 if option._long_opts:
176 opts.append(option._long_opts[0])
177 if len(opts) > 1:
178 opts.insert(1, ', ')
179
180 if option.takes_value(): opts.append(' %s' % option.metavar)
181
182 return "".join(opts)
183
d6e203b3
IM
184 def _comma_separated_values_options_callback(option, opt_str, value, parser):
185 setattr(parser.values, option.dest, value.split(','))
186
920ef077
JMF
187 def _hide_login_info(opts):
188 opts = list(opts)
3126050c 189 for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
920ef077
JMF
190 try:
191 i = opts.index(private_opt)
192 opts[i+1] = '<PRIVATE>'
193 except ValueError:
194 pass
195 return opts
196
59ae15a5
PH
197 max_width = 80
198 max_help_position = 80
199
200 # No need to wrap help messages if we're on a wide console
1c088fa8 201 columns = get_term_width()
59ae15a5
PH
202 if columns: max_width = columns
203
204 fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
205 fmt.format_option_strings = _format_option_string
206
207 kw = {
208 'version' : __version__,
209 'formatter' : fmt,
210 'usage' : '%prog [options] url [url...]',
211 'conflict_handler' : 'resolve',
212 }
213
214 parser = optparse.OptionParser(**kw)
215
216 # option groups
217 general = optparse.OptionGroup(parser, 'General Options')
218 selection = optparse.OptionGroup(parser, 'Video Selection')
219 authentication = optparse.OptionGroup(parser, 'Authentication Options')
220 video_format = optparse.OptionGroup(parser, 'Video Format Options')
505c28aa 221 subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
0beb3add 222 downloader = optparse.OptionGroup(parser, 'Download Options')
59ae15a5
PH
223 postproc = optparse.OptionGroup(parser, 'Post-processing Options')
224 filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
2fe3d240 225 workarounds = optparse.OptionGroup(parser, 'Workarounds')
59ae15a5
PH
226 verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
227
228 general.add_option('-h', '--help',
229 action='help', help='print this help text and exit')
230 general.add_option('-v', '--version',
231 action='version', help='print program version and exit')
232 general.add_option('-U', '--update',
f631c331 233 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 234 general.add_option('-i', '--ignore-errors',
98c4b8fa 235 action='store_true', dest='ignoreerrors', help='continue on download errors, for example to skip unavailable videos in a playlist', default=False)
41fd7c7e
PH
236 general.add_option('--abort-on-error',
237 action='store_false', dest='ignoreerrors',
238 help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
59ae15a5
PH
239 general.add_option('--dump-user-agent',
240 action='store_true', dest='dump_user_agent',
241 help='display the current browser identification', default=False)
59ae15a5
PH
242 general.add_option('--list-extractors',
243 action='store_true', dest='list_extractors',
244 help='List all supported extractors and the URLs they would handle', default=False)
62067cb9 245 general.add_option('--extractor-descriptions',
0f818663
PH
246 action='store_true', dest='list_extractor_descriptions',
247 help='Output descriptions of all supported extractors', default=False)
cf6758d2
PH
248 general.add_option(
249 '--proxy', dest='proxy', default=None, metavar='URL',
250 help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
6ad14cab
PH
251 general.add_option(
252 '--socket-timeout', dest='socket_timeout',
9656ee5d 253 type=float, default=None, help=u'Time to wait before giving up, in seconds')
0783b09b
PH
254 general.add_option(
255 '--bidi-workaround', dest='bidi_workaround', action='store_true',
5d681e96 256 help=u'Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH')
9c1fc022
PH
257 general.add_option(
258 '--default-search',
259 dest='default_search', metavar='PREFIX',
7571c02c 260 help='Use this prefix for unqualified URLs. For example "gvsearch2:" downloads two videos from google videos for youtube-dl "large apple". Use the value "auto" to let youtube-dl guess. The default value "error" just throws an error.')
588128d0
PH
261 general.add_option(
262 '--ignore-config',
263 action='store_true',
264 help='Do not read configuration files. When given in the global configuration file /etc/youtube-dl.conf: do not read the user configuration in ~/.config/youtube-dl.conf (%APPDATA%/youtube-dl/config.txt on Windows)')
265
a19fd00c
PH
266 selection.add_option(
267 '--playlist-start',
268 dest='playliststart', metavar='NUMBER', default=1, type=int,
269 help='playlist video to start at (default is %default)')
270 selection.add_option(
271 '--playlist-end',
272 dest='playlistend', metavar='NUMBER', default=None, type=int,
273 help='playlist video to end at (default is last)')
59ae15a5
PH
274 selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
275 selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
0c75c3fa
PH
276 selection.add_option('--max-downloads', metavar='NUMBER',
277 dest='max_downloads', type=int, default=None,
278 help='Abort after downloading NUMBER files')
dbf2ba3d
PH
279 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)
280 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 281 selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
bac268e2
PH
282 selection.add_option(
283 '--datebefore', metavar='DATE', dest='datebefore', default=None,
284 help='download only videos uploaded on or before this date (i.e. inclusive)')
285 selection.add_option(
286 '--dateafter', metavar='DATE', dest='dateafter', default=None,
287 help='download only videos uploaded on or after this date (i.e. inclusive)')
5fe18bdb
PH
288 selection.add_option(
289 '--min-views', metavar='COUNT', dest='min_views',
290 default=None, type=int,
291 help="Do not download any videos with less than COUNT views",)
292 selection.add_option(
293 '--max-views', metavar='COUNT', dest='max_views',
294 default=None, type=int,
295 help="Do not download any videos with more than COUNT views",)
47192f92 296 selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
8dbe9899
PH
297 selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
298 help='download only videos suitable for the given age',
299 default=None, type=int)
c1c9a79c
PH
300 selection.add_option('--download-archive', metavar='FILE',
301 dest='download_archive',
36a826a5 302 help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
7b0817e8
PH
303 selection.add_option(
304 '--include-ads', dest='include_ads',
305 action='store_true',
306 help='Download advertisements as well (experimental)')
8b1be5cd 307 selection.add_option(
4919603f
PH
308 '--youtube-include-dash-manifest', action='store_true',
309 dest='youtube_include_dash_manifest', default=False,
310 help='Try to download the DASH manifest on YouTube videos (experimental)')
9e982f9e 311
59ae15a5
PH
312 authentication.add_option('-u', '--username',
313 dest='username', metavar='USERNAME', help='account username')
314 authentication.add_option('-p', '--password',
315 dest='password', metavar='PASSWORD', help='account password')
316 authentication.add_option('-n', '--netrc',
317 action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
c6c19746 318 authentication.add_option('--video-password',
67d28bff 319 dest='videopassword', metavar='PASSWORD', help='video password (vimeo, smotri)')
59ae15a5
PH
320
321
322 video_format.add_option('-f', '--format',
de3ef3ed 323 action='store', dest='format', metavar='FORMAT', default=None,
bc6d5978 324 help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported. You can also use the special names "best", "bestvideo", "bestaudio", "worst", "worstvideo" and "worstaudio". By default, youtube-dl will pick the best quality.')
59ae15a5
PH
325 video_format.add_option('--all-formats',
326 action='store_const', dest='format', help='download all available video formats', const='all')
327 video_format.add_option('--prefer-free-formats',
328 action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
329 video_format.add_option('--max-quality',
330 action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
331 video_format.add_option('-F', '--list-formats',
4950f308 332 action='store_true', dest='listformats', help='list all available formats')
505c28aa
IM
333
334 subtitles.add_option('--write-sub', '--write-srt',
59ae15a5 335 action='store_true', dest='writesubtitles',
953e32b2 336 help='write subtitle file', default=False)
505c28aa 337 subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
b004821f 338 action='store_true', dest='writeautomaticsub',
953e32b2 339 help='write automatic subtitle file (youtube only)', default=False)
505c28aa 340 subtitles.add_option('--all-subs',
ae608b80 341 action='store_true', dest='allsubtitles',
953e32b2 342 help='downloads all the available subtitles of the video', default=False)
505c28aa 343 subtitles.add_option('--list-subs',
2a4093ea 344 action='store_true', dest='listsubtitles',
953e32b2 345 help='lists all available subtitles for the video', default=False)
505c28aa 346 subtitles.add_option('--sub-format',
c3ab8f86 347 action='store', dest='subtitlesformat', metavar='FORMAT',
953e32b2 348 help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
d6e203b3
IM
349 subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
350 action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
351 default=[], callback=_comma_separated_values_options_callback,
352 help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
59ae15a5 353
0beb3add 354 downloader.add_option('-r', '--rate-limit',
cd054fc4 355 dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
0beb3add
PH
356 downloader.add_option('-R', '--retries',
357 dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
358 downloader.add_option('--buffer-size',
cd054fc4 359 dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
0beb3add
PH
360 downloader.add_option('--no-resize-buffer',
361 action='store_true', dest='noresizebuffer',
362 help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
363 downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
364
2fe3d240
PH
365 workarounds.add_option(
366 '--encoding', dest='encoding', metavar='ENCODING',
367 help='Force the specified encoding (experimental)')
368 workarounds.add_option(
369 '--no-check-certificate', action='store_true',
370 dest='no_check_certificate', default=False,
371 help='Suppress HTTPS certificate validation.')
372 workarounds.add_option(
373 '--prefer-insecure', '--prefer-unsecure', action='store_true', dest='prefer_insecure',
374 help='Use an unencrypted connection to retrieve information about the video. (Currently supported only for YouTube)')
375 workarounds.add_option(
376 '--user-agent', metavar='UA',
377 dest='user_agent', help='specify a custom user agent')
378 workarounds.add_option(
379 '--referer', metavar='REF',
380 dest='referer', default=None,
381 help='specify a custom referer, use if the video access is restricted to one domain',
382 )
383 workarounds.add_option(
384 '--add-header', metavar='FIELD:VALUE',
385 dest='headers', action='append',
386 help='specify a custom HTTP header and its value, separated by a colon \':\'. You can use this option multiple times',
387 )
388
59ae15a5
PH
389 verbosity.add_option('-q', '--quiet',
390 action='store_true', dest='quiet', help='activates quiet mode', default=False)
ad8915b7
PH
391 verbosity.add_option(
392 '--no-warnings',
393 dest='no_warnings', action='store_true', default=False,
394 help='Ignore warnings')
59ae15a5
PH
395 verbosity.add_option('-s', '--simulate',
396 action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
397 verbosity.add_option('--skip-download',
398 action='store_true', dest='skip_download', help='do not download the video', default=False)
399 verbosity.add_option('-g', '--get-url',
400 action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
401 verbosity.add_option('-e', '--get-title',
402 action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
1a2adf3f 403 verbosity.add_option('--get-id',
404 action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
59ae15a5
PH
405 verbosity.add_option('--get-thumbnail',
406 action='store_true', dest='getthumbnail',
407 help='simulate, quiet but print thumbnail URL', default=False)
408 verbosity.add_option('--get-description',
409 action='store_true', dest='getdescription',
410 help='simulate, quiet but print video description', default=False)
525ef922
PH
411 verbosity.add_option('--get-duration',
412 action='store_true', dest='getduration',
413 help='simulate, quiet but print video length', default=False)
59ae15a5
PH
414 verbosity.add_option('--get-filename',
415 action='store_true', dest='getfilename',
416 help='simulate, quiet but print output filename', default=False)
417 verbosity.add_option('--get-format',
418 action='store_true', dest='getformat',
419 help='simulate, quiet but print output format', default=False)
9d153818
MF
420 verbosity.add_option('-j', '--dump-json',
421 action='store_true', dest='dumpjson',
330edf2d 422 help='simulate, quiet but print JSON information. See --output for a description of available keys.', default=False)
7311fef8 423 verbosity.add_option('--newline',
5717d91a 424 action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
59ae15a5
PH
425 verbosity.add_option('--no-progress',
426 action='store_true', dest='noprogress', help='do not print progress bar', default=False)
427 verbosity.add_option('--console-title',
428 action='store_true', dest='consoletitle',
429 help='display progress in console titlebar', default=False)
430 verbosity.add_option('-v', '--verbose',
431 action='store_true', dest='verbose', help='print various debugging information', default=False)
855703e5
PH
432 verbosity.add_option('--dump-intermediate-pages',
433 action='store_true', dest='dump_intermediate_pages', default=False,
67d28bff 434 help='print downloaded pages to debug problems (very verbose)')
d41e6efc
PH
435 verbosity.add_option('--write-pages',
436 action='store_true', dest='write_pages', default=False,
06dcbb71 437 help='Write downloaded intermediary pages to files in the current directory to debug problems')
edf3e38e
PH
438 verbosity.add_option('--youtube-print-sig-code',
439 action='store_true', dest='youtube_print_sig_code', default=False,
440 help=optparse.SUPPRESS_HELP)
a0ddb8a2
PH
441 verbosity.add_option('--print-traffic',
442 dest='debug_printtraffic', action='store_true', default=False,
4919603f
PH
443 help='Display sent and read HTTP traffic')
444
59ae15a5 445
a11165ec
PH
446 filesystem.add_option('-a', '--batch-file',
447 dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
59ae15a5 448 filesystem.add_option('--id',
08b2ac74 449 action='store_true', dest='useid', help='use only video ID in file name', default=False)
59ae15a5
PH
450 filesystem.add_option('-A', '--auto-number',
451 action='store_true', dest='autonumber',
452 help='number downloaded files starting from 00000', default=False)
453 filesystem.add_option('-o', '--output',
74e3452b
JMF
454 dest='outtmpl', metavar='TEMPLATE',
455 help=('output filename template. Use %(title)s to get the title, '
456 '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
457 '%(autonumber)s to get an automatically incremented number, '
fdefe96b 458 '%(ext)s for the filename extension, '
67d28bff 459 '%(format)s for the format description (like "22 - 1280x720" or "HD"), '
460 '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"), '
fdefe96b 461 '%(upload_date)s for the upload date (YYYYMMDD), '
74e3452b 462 '%(extractor)s for the provider (youtube, metacafe, etc), '
67d28bff 463 '%(id)s for the video id, %(playlist)s for the playlist the video is in, '
74e3452b 464 '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
17b75c0d
PH
465 '%(height)s and %(width)s for the width and height of the video format. '
466 '%(resolution)s for a textual description of the resolution of the video format. '
74e3452b
JMF
467 'Use - to output to stdout. Can also be used to download to a different directory, '
468 'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
213c31ae
SK
469 filesystem.add_option('--autonumber-size',
470 dest='autonumber_size', metavar='NUMBER',
2a9e9b21 471 help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
59ae15a5
PH
472 filesystem.add_option('--restrict-filenames',
473 action='store_true', dest='restrictfilenames',
474 help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
a11165ec 475 filesystem.add_option('-t', '--title',
4e99f488 476 action='store_true', dest='usetitle', help='[deprecated] use title in file name (default)', default=False)
a11165ec
PH
477 filesystem.add_option('-l', '--literal',
478 action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
59ae15a5
PH
479 filesystem.add_option('-w', '--no-overwrites',
480 action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
481 filesystem.add_option('-c', '--continue',
d4b7da84 482 action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
59ae15a5
PH
483 filesystem.add_option('--no-continue',
484 action='store_false', dest='continue_dl',
485 help='do not resume partially downloaded files (restart from beginning)')
59ae15a5
PH
486 filesystem.add_option('--no-part',
487 action='store_true', dest='nopart', help='do not use .part files', default=False)
488 filesystem.add_option('--no-mtime',
489 action='store_false', dest='updatetime',
490 help='do not use the Last-modified header to set the file modification time', default=True)
491 filesystem.add_option('--write-description',
492 action='store_true', dest='writedescription',
493 help='write video description to a .description file', default=False)
494 filesystem.add_option('--write-info-json',
495 action='store_true', dest='writeinfojson',
496 help='write video metadata to a .info.json file', default=False)
1fb07d10
JG
497 filesystem.add_option('--write-annotations',
498 action='store_true', dest='writeannotations',
499 help='write video annotations to a .annotation file', default=False)
11d9224e
PH
500 filesystem.add_option('--write-thumbnail',
501 action='store_true', dest='writethumbnail',
502 help='write thumbnail image to disk', default=False)
a11165ec
PH
503 filesystem.add_option('--load-info',
504 dest='load_info_filename', metavar='FILE',
505 help='json file containing the video information (created with the "--write-json" option)')
506 filesystem.add_option('--cookies',
507 dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
fbb2fc55
PH
508 filesystem.add_option(
509 '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
510 help='Location in the filesystem where youtube-dl can store some downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl . At the moment, only YouTube player files (for videos with obfuscated signatures) are cached, but that may change.')
511 filesystem.add_option(
512 '--no-cache-dir', action='store_const', const=None, dest='cachedir',
513 help='Disable filesystem caching')
59ae15a5
PH
514
515
516 postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
517 help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
518 postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
510e6f6d 519 help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
59ae15a5
PH
520 postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
521 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 522 postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
133af938 523 help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv)')
59ae15a5
PH
524 postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
525 help='keeps the video file on disk after the post-processing; the video is erased by default')
f0648fc1
BPG
526 postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
527 help='do not overwrite post-processed files; the post-processed files are overwritten by default')
d4051a8e
JMF
528 postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
529 help='embed subtitles in the video (only for mp4 videos)')
0c14e2fb 530 postproc.add_option('--embed-thumbnail', action='store_true', dest='embedthumbnail', default=False,
531 help='embed thumbnail in the audio as cover art')
bc4f2917 532 postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
e63fc1be 533 help='write metadata to the video file')
534 postproc.add_option('--xattrs', action='store_true', dest='xattrs', default=False,
535 help='write metadata to the video file\'s xattrs (using dublin core and xdg standards)')
76b1bd67
JMF
536 postproc.add_option('--prefer-avconv', action='store_false', dest='prefer_ffmpeg',
537 help='Prefer avconv over ffmpeg for running the postprocessors (default)')
538 postproc.add_option('--prefer-ffmpeg', action='store_true', dest='prefer_ffmpeg',
539 help='Prefer ffmpeg over avconv for running the postprocessors')
59ae15a5
PH
540
541
542 parser.add_option_group(general)
543 parser.add_option_group(selection)
0beb3add 544 parser.add_option_group(downloader)
59ae15a5
PH
545 parser.add_option_group(filesystem)
546 parser.add_option_group(verbosity)
2fe3d240 547 parser.add_option_group(workarounds)
59ae15a5 548 parser.add_option_group(video_format)
505c28aa 549 parser.add_option_group(subtitles)
59ae15a5
PH
550 parser.add_option_group(authentication)
551 parser.add_option_group(postproc)
552
75b5c590
PH
553 if overrideArguments is not None:
554 opts, args = parser.parse_args(overrideArguments)
555 if opts.verbose:
7459e3a2 556 write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
59ae15a5 557 else:
1865ed31 558 commandLineConf = sys.argv[1:]
588128d0
PH
559 if '--ignore-config' in commandLineConf:
560 systemConf = []
561 userConf = []
562 else:
563 systemConf = _readOptions('/etc/youtube-dl.conf')
564 if '--ignore-config' in systemConf:
565 userConf = []
566 else:
567 userConf = _readUserConf()
75b5c590 568 argv = systemConf + userConf + commandLineConf
588128d0 569
75b5c590 570 opts, args = parser.parse_args(argv)
c76cb6d5 571 if opts.verbose:
7459e3a2
PH
572 write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
573 write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
574 write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
8c42c506 575
59ae15a5 576 return parser, opts, args
235b3ba4 577
e3946f98 578
b8ad4f02 579def _real_main(argv=None):
0d94f247
PH
580 # Compatibility fixes for Windows
581 if sys.platform == 'win32':
582 # https://github.com/rg3/youtube-dl/issues/820
583 codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
584
e3946f98
PH
585 setproctitle(u'youtube-dl')
586
b8ad4f02 587 parser, opts, args = parseOpts(argv)
59ae15a5 588
59ae15a5
PH
589 # Set user agent
590 if opts.user_agent is not None:
591 std_headers['User-Agent'] = opts.user_agent
1865ed31 592
28535652
BH
593 # Set referer
594 if opts.referer is not None:
595 std_headers['Referer'] = opts.referer
59ae15a5 596
410afb20
AA
597 # Custom HTTP headers
598 if opts.headers is not None:
599 for h in opts.headers:
600 if h.find(':', 1) < 0:
601 parser.error(u'wrong header formatting, it should be key:value, not "%s"'%h)
602 key, value = h.split(':', 2)
603 if opts.verbose:
604 write_string(u'[debug] Adding header from command line option %s:%s\n'%(key, value))
605 std_headers[key] = value
606
59ae15a5
PH
607 # Dump user agent
608 if opts.dump_user_agent:
93eb15c5 609 compat_print(std_headers['User-Agent'])
59ae15a5
PH
610 sys.exit(0)
611
612 # Batch file verification
62e609ab 613 batch_urls = []
59ae15a5
PH
614 if opts.batchfile is not None:
615 try:
616 if opts.batchfile == '-':
617 batchfd = sys.stdin
618 else:
62e609ab
PH
619 batchfd = io.open(opts.batchfile, 'r', encoding='utf-8', errors='ignore')
620 batch_urls = read_batch_urls(batchfd)
05afc96b 621 if opts.verbose:
62e609ab 622 write_string(u'[debug] Batch file urls: ' + repr(batch_urls) + u'\n')
59ae15a5
PH
623 except IOError:
624 sys.exit(u'ERROR: batch file could not be read')
62e609ab 625 all_urls = batch_urls + args
59ae15a5 626 all_urls = [url.strip() for url in all_urls]
c774b3c6 627 _enc = preferredencoding()
41292a38 628 all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
59ae15a5 629
59ae15a5
PH
630 extractors = gen_extractors()
631
632 if opts.list_extractors:
7dba9cd0 633 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
93eb15c5 634 compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
1a2c3c0f 635 matchedUrls = [url for url in all_urls if ie.suitable(url)]
59ae15a5 636 for mu in matchedUrls:
93eb15c5 637 compat_print(u' ' + mu)
59ae15a5 638 sys.exit(0)
0f818663
PH
639 if opts.list_extractor_descriptions:
640 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
641 if not ie._WORKING:
642 continue
643 desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
15870e90
PH
644 if desc is False:
645 continue
0f818663 646 if hasattr(ie, 'SEARCH_KEY'):
53eb2176 647 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise', u'sleeping bunny')
0f818663
PH
648 _COUNTS = (u'', u'5', u'10', u'all')
649 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
650 compat_print(desc)
651 sys.exit(0)
652
59ae15a5
PH
653
654 # Conflicting, missing and erroneous options
655 if opts.usenetrc and (opts.username is not None or opts.password is not None):
656 parser.error(u'using .netrc conflicts with giving username/password')
657 if opts.password is not None and opts.username is None:
67d28bff 658 parser.error(u'account username missing\n')
59ae15a5
PH
659 if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
660 parser.error(u'using output template conflicts with using title, video ID or auto number')
661 if opts.usetitle and opts.useid:
662 parser.error(u'using title conflicts with using video ID')
663 if opts.username is not None and opts.password is None:
e68301af 664 opts.password = compat_getpass(u'Type account password and press [Return]: ')
59ae15a5
PH
665 if opts.ratelimit is not None:
666 numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
667 if numeric_limit is None:
668 parser.error(u'invalid rate limit specified')
669 opts.ratelimit = numeric_limit
9e982f9e
JC
670 if opts.min_filesize is not None:
671 numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
672 if numeric_limit is None:
673 parser.error(u'invalid min_filesize specified')
674 opts.min_filesize = numeric_limit
675 if opts.max_filesize is not None:
676 numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
677 if numeric_limit is None:
678 parser.error(u'invalid max_filesize specified')
679 opts.max_filesize = numeric_limit
59ae15a5
PH
680 if opts.retries is not None:
681 try:
682 opts.retries = int(opts.retries)
dca08720 683 except (TypeError, ValueError):
59ae15a5
PH
684 parser.error(u'invalid retry count specified')
685 if opts.buffersize is not None:
686 numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
687 if numeric_buffersize is None:
688 parser.error(u'invalid buffer size specified')
689 opts.buffersize = numeric_buffersize
a19fd00c
PH
690 if opts.playliststart <= 0:
691 raise ValueError(u'Playlist start must be positive')
692 if opts.playlistend not in (-1, None) and opts.playlistend < opts.playliststart:
693 raise ValueError(u'Playlist end must be greater than playlist start')
59ae15a5 694 if opts.extractaudio:
510e6f6d 695 if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
59ae15a5
PH
696 parser.error(u'invalid audio format specified')
697 if opts.audioquality:
698 opts.audioquality = opts.audioquality.strip('k').strip('K')
699 if not opts.audioquality.isdigit():
700 parser.error(u'invalid audio quality specified')
7851b379 701 if opts.recodevideo is not None:
b7d73595 702 if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv']:
7851b379 703 parser.error(u'invalid video recode format specified')
bd558525
JMF
704 if opts.date is not None:
705 date = DateRange.day(opts.date)
706 else:
707 date = DateRange(opts.dateafter, opts.datebefore)
9c1fc022 708 if opts.default_search not in ('auto', 'auto_warning', None) and ':' not in opts.default_search:
04b4d394 709 parser.error(u'--default-search invalid; did you forget a colon (:) at the end?')
59ae15a5 710
de3ef3ed
PH
711 # Do not download videos when there are audio-only formats
712 if opts.extractaudio and not opts.keepvideo and opts.format is None:
713 opts.format = 'bestaudio/best'
714
0b7f3118
JMF
715 # --all-sub automatically sets --write-sub if --write-auto-sub is not given
716 # this was the old behaviour if only --all-sub was given.
717 if opts.allsubtitles and (opts.writeautomaticsub == False):
718 opts.writesubtitles = True
719
5cb9c312
PH
720 if sys.version_info < (3,):
721 # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
0be41ec2
PH
722 if opts.outtmpl is not None:
723 opts.outtmpl = opts.outtmpl.decode(preferredencoding())
5cb9c312
PH
724 outtmpl =((opts.outtmpl is not None and opts.outtmpl)
725 or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
726 or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
727 or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
728 or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
729 or (opts.useid and u'%(id)s.%(ext)s')
730 or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
acd69589 731 or DEFAULT_OUTTMPL)
dca02c80 732 if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
b61067fa 733 parser.error(u'Cannot download a video and extract audio into the same'
dca02c80
JMF
734 u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
735 u' template'.format(outtmpl))
29c7a63d 736
525ef922 737 any_printing = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson
17093b83 738 download_archive_fn = os.path.expanduser(opts.download_archive) if opts.download_archive is not None else opts.download_archive
525ef922 739
bdde425c 740 ydl_opts = {
59ae15a5
PH
741 'usenetrc': opts.usenetrc,
742 'username': opts.username,
743 'password': opts.password,
c6c19746 744 'videopassword': opts.videopassword,
525ef922 745 'quiet': (opts.quiet or any_printing),
ad8915b7 746 'no_warnings': opts.no_warnings,
59ae15a5
PH
747 'forceurl': opts.geturl,
748 'forcetitle': opts.gettitle,
1a2adf3f 749 'forceid': opts.getid,
59ae15a5
PH
750 'forcethumbnail': opts.getthumbnail,
751 'forcedescription': opts.getdescription,
525ef922 752 'forceduration': opts.getduration,
59ae15a5
PH
753 'forcefilename': opts.getfilename,
754 'forceformat': opts.getformat,
9d153818 755 'forcejson': opts.dumpjson,
59ae15a5 756 'simulate': opts.simulate,
525ef922 757 'skip_download': (opts.skip_download or opts.simulate or any_printing),
59ae15a5
PH
758 'format': opts.format,
759 'format_limit': opts.format_limit,
760 'listformats': opts.listformats,
5cb9c312 761 'outtmpl': outtmpl,
213c31ae 762 'autonumber_size': opts.autonumber_size,
59ae15a5
PH
763 'restrictfilenames': opts.restrictfilenames,
764 'ignoreerrors': opts.ignoreerrors,
765 'ratelimit': opts.ratelimit,
766 'nooverwrites': opts.nooverwrites,
767 'retries': opts.retries,
768 'buffersize': opts.buffersize,
769 'noresizebuffer': opts.noresizebuffer,
770 'continuedl': opts.continue_dl,
771 'noprogress': opts.noprogress,
5717d91a 772 'progress_with_newline': opts.progress_with_newline,
59ae15a5
PH
773 'playliststart': opts.playliststart,
774 'playlistend': opts.playlistend,
47192f92 775 'noplaylist': opts.noplaylist,
59ae15a5
PH
776 'logtostderr': opts.outtmpl == '-',
777 'consoletitle': opts.consoletitle,
778 'nopart': opts.nopart,
779 'updatetime': opts.updatetime,
780 'writedescription': opts.writedescription,
1fb07d10 781 'writeannotations': opts.writeannotations,
59ae15a5 782 'writeinfojson': opts.writeinfojson,
11d9224e 783 'writethumbnail': opts.writethumbnail,
59ae15a5 784 'writesubtitles': opts.writesubtitles,
b004821f 785 'writeautomaticsub': opts.writeautomaticsub,
ae608b80 786 'allsubtitles': opts.allsubtitles,
2a4093ea 787 'listsubtitles': opts.listsubtitles,
9e62bc44 788 'subtitlesformat': opts.subtitlesformat,
d6e203b3 789 'subtitleslangs': opts.subtitleslangs,
8271226a
PH
790 'matchtitle': decodeOption(opts.matchtitle),
791 'rejecttitle': decodeOption(opts.rejecttitle),
59ae15a5
PH
792 'max_downloads': opts.max_downloads,
793 'prefer_free_formats': opts.prefer_free_formats,
794 'verbose': opts.verbose,
855703e5 795 'dump_intermediate_pages': opts.dump_intermediate_pages,
d41e6efc 796 'write_pages': opts.write_pages,
8d5d3a5d 797 'test': opts.test,
7851b379 798 'keepvideo': opts.keepvideo,
9e982f9e 799 'min_filesize': opts.min_filesize,
bd558525 800 'max_filesize': opts.max_filesize,
5fe18bdb
PH
801 'min_views': opts.min_views,
802 'max_views': opts.max_views,
11d9224e 803 'daterange': date,
7f747732 804 'cachedir': opts.cachedir,
f8061589 805 'youtube_print_sig_code': opts.youtube_print_sig_code,
8dbe9899 806 'age_limit': opts.age_limit,
17093b83 807 'download_archive': download_archive_fn,
dca08720
PH
808 'cookiefile': opts.cookiefile,
809 'nocheckcertificate': opts.no_check_certificate,
7e8c0af0 810 'prefer_insecure': opts.prefer_insecure,
c2e52508 811 'proxy': opts.proxy,
6ad14cab 812 'socket_timeout': opts.socket_timeout,
0783b09b 813 'bidi_workaround': opts.bidi_workaround,
a0ddb8a2 814 'debug_printtraffic': opts.debug_printtraffic,
76b1bd67 815 'prefer_ffmpeg': opts.prefer_ffmpeg,
7b0817e8 816 'include_ads': opts.include_ads,
04b4d394 817 'default_search': opts.default_search,
4919603f 818 'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
62fec3b2 819 'encoding': opts.encoding,
bdde425c 820 }
59ae15a5 821
bdde425c 822 with YoutubeDL(ydl_opts) as ydl:
dca08720 823 ydl.print_debug_header()
bdde425c
PH
824 ydl.add_default_info_extractors()
825
826 # PostProcessors
827 # Add the metadata pp first, the other pps will copy it
828 if opts.addmetadata:
829 ydl.add_post_processor(FFmpegMetadataPP())
830 if opts.extractaudio:
831 ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
832 if opts.recodevideo:
833 ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
834 if opts.embedsubtitles:
835 ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
e63fc1be 836 if opts.xattrs:
837 ydl.add_post_processor(XAttrMetadataPP())
0c14e2fb 838 if opts.embedthumbnail:
784763c5 839 if not opts.addmetadata:
840 ydl.add_post_processor(FFmpegAudioFixPP())
0c14e2fb 841 ydl.add_post_processor(AtomicParsleyPP())
bdde425c
PH
842
843 # Update version
844 if opts.update_self:
845 update_self(ydl.to_screen, opts.verbose)
846
847 # Maybe do nothing
1dcc4c0c 848 if (len(all_urls) < 1) and (opts.load_info_filename is None):
bdde425c
PH
849 if not opts.update_self:
850 parser.error(u'you must provide at least one URL')
851 else:
852 sys.exit()
59ae15a5 853
bdde425c 854 try:
1dcc4c0c
JMF
855 if opts.load_info_filename is not None:
856 retcode = ydl.download_with_info_file(opts.load_info_filename)
857 else:
858 retcode = ydl.download(all_urls)
bdde425c
PH
859 except MaxDownloadsReached:
860 ydl.to_screen(u'--max-download limit reached, aborting.')
861 retcode = 101
59ae15a5 862
59ae15a5 863 sys.exit(retcode)
235b3ba4 864
a27b9e8b 865
b8ad4f02 866def main(argv=None):
59ae15a5 867 try:
b8ad4f02 868 _real_main(argv)
59ae15a5
PH
869 except DownloadError:
870 sys.exit(1)
871 except SameFileError:
872 sys.exit(u'ERROR: fixed output name but more than one file to download')
873 except KeyboardInterrupt:
874 sys.exit(u'\nERROR: Interrupted by user')