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