]> jfr.im git - yt-dlp.git/blame_incremental - youtube_dl/__init__.py
deprecate --title
[yt-dlp.git] / youtube_dl / __init__.py
... / ...
CommitLineData
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4__authors__ = (
5 'Ricardo Garcia Gonzalez',
6 'Danny Colligan',
7 'Benjamin Johnson',
8 'Vasyl\' Vavrychuk',
9 'Witold Baryluk',
10 'Paweł Paprota',
11 'Gergely Imreh',
12 'Rogério Brito',
13 'Philipp Hagemeister',
14 'Sören Schulze',
15 'Kevin Ngo',
16 'Ori Avtalion',
17 'shizeeg',
18 'Filippo Valsorda',
19 'Christian Albrecht',
20 'Dave Vasilevsky',
21 'Jaime Marquínez Ferrándiz',
22 'Jeff Crouse',
23 'Osama Khalid',
24 'Michael Walter',
25 'M. Yasoob Ullah Khalid',
26 'Julien Fraichard',
27 'Johny Mo Swag',
28 'Axel Noack',
29 'Albert Kim',
30 'Pierre Rudloff',
31 'Huarong Huo',
32 'Ismael Mejía',
33 'Steffan \'Ruirize\' James',
34 'Andras Elso',
35 'Jelle van der Waa',
36 'Marcin Cieślak',
37 'Anton Larionov',
38 'Takuya Tsuchida',
39 'Sergey M.',
40 'Michael Orlitzky',
41 'Chris Gahan',
42 'Saimadhav Heblikar',
43 'Mike Col',
44 'Oleg Prutz',
45 'pulpe',
46 'Andreas Schmitz',
47 'Michael Kaiser',
48 'Niklas Laxström',
49 'David Triendl',
50 'Anthony Weems',
51 'David Wagner',
52 'Juan C. Olivares',
53 'Mattias Harrysson',
54 'phaer',
55 'Sainyam Kapoor',
56 'Nicolas Évrard',
57 'Jason Normore',
58 'Hoje Lee',
59 'Adam Thalhammer',
60 'Georg Jähnig',
61 'Ralf Haring',
62 'Koki Takahashi',
63 'Ariset Llerena',
64 'Adam Malcontenti-Wilson',
65 'Tobias Bell',
66 'Naglis Jonaitis',
67 'Charles Chen',
68 'Hassaan Ali',
69)
70
71__license__ = 'Public Domain'
72
73import codecs
74import io
75import optparse
76import os
77import random
78import shlex
79import sys
80
81
82from .utils import (
83 compat_getpass,
84 compat_print,
85 DateRange,
86 DEFAULT_OUTTMPL,
87 decodeOption,
88 get_term_width,
89 DownloadError,
90 get_cachedir,
91 MaxDownloadsReached,
92 preferredencoding,
93 read_batch_urls,
94 SameFileError,
95 setproctitle,
96 std_headers,
97 write_string,
98)
99from .update import update_self
100from .downloader import (
101 FileDownloader,
102)
103from .extractor import gen_extractors
104from .version import __version__
105from .YoutubeDL import YoutubeDL
106from .postprocessor import (
107 AtomicParsleyPP,
108 FFmpegAudioFixPP,
109 FFmpegMetadataPP,
110 FFmpegVideoConvertor,
111 FFmpegExtractAudioPP,
112 FFmpegEmbedSubtitlePP,
113 XAttrMetadataPP,
114)
115
116
117def parseOpts(overrideArguments=None):
118 def _readOptions(filename_bytes, default=[]):
119 try:
120 optionf = open(filename_bytes)
121 except IOError:
122 return default # silently skip if file is not present
123 try:
124 res = []
125 for l in optionf:
126 res += shlex.split(l, comments=True)
127 finally:
128 optionf.close()
129 return res
130
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
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
184 def _comma_separated_values_options_callback(option, opt_str, value, parser):
185 setattr(parser.values, option.dest, value.split(','))
186
187 def _hide_login_info(opts):
188 opts = list(opts)
189 for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
190 try:
191 i = opts.index(private_opt)
192 opts[i+1] = '<PRIVATE>'
193 except ValueError:
194 pass
195 return opts
196
197 max_width = 80
198 max_help_position = 80
199
200 # No need to wrap help messages if we're on a wide console
201 columns = get_term_width()
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')
221 subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
222 downloader = optparse.OptionGroup(parser, 'Download Options')
223 postproc = optparse.OptionGroup(parser, 'Post-processing Options')
224 filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
225 workarounds = optparse.OptionGroup(parser, 'Workarounds')
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',
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)')
234 general.add_option('-i', '--ignore-errors',
235 action='store_true', dest='ignoreerrors', help='continue on download errors, for example to skip unavailable videos in a playlist', default=False)
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')
239 general.add_option('--dump-user-agent',
240 action='store_true', dest='dump_user_agent',
241 help='display the current browser identification', default=False)
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)
245 general.add_option('--extractor-descriptions',
246 action='store_true', dest='list_extractor_descriptions',
247 help='Output descriptions of all supported extractors', default=False)
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')
251 general.add_option(
252 '--socket-timeout', dest='socket_timeout',
253 type=float, default=None, help=u'Time to wait before giving up, in seconds')
254 general.add_option(
255 '--bidi-workaround', dest='bidi_workaround', action='store_true',
256 help=u'Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH')
257 general.add_option(
258 '--default-search',
259 dest='default_search', metavar='PREFIX',
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.')
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
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)')
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)')
276 selection.add_option('--max-downloads', metavar='NUMBER',
277 dest='max_downloads', type=int, default=None,
278 help='Abort after downloading NUMBER files')
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)
281 selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
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)')
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",)
296 selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
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)
300 selection.add_option('--download-archive', metavar='FILE',
301 dest='download_archive',
302 help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
303 selection.add_option(
304 '--include-ads', dest='include_ads',
305 action='store_true',
306 help='Download advertisements as well (experimental)')
307 selection.add_option(
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)')
311
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)
318 authentication.add_option('--video-password',
319 dest='videopassword', metavar='PASSWORD', help='video password (vimeo, smotri)')
320
321
322 video_format.add_option('-f', '--format',
323 action='store', dest='format', metavar='FORMAT', default=None,
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.')
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',
332 action='store_true', dest='listformats', help='list all available formats')
333
334 subtitles.add_option('--write-sub', '--write-srt',
335 action='store_true', dest='writesubtitles',
336 help='write subtitle file', default=False)
337 subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
338 action='store_true', dest='writeautomaticsub',
339 help='write automatic subtitle file (youtube only)', default=False)
340 subtitles.add_option('--all-subs',
341 action='store_true', dest='allsubtitles',
342 help='downloads all the available subtitles of the video', default=False)
343 subtitles.add_option('--list-subs',
344 action='store_true', dest='listsubtitles',
345 help='lists all available subtitles for the video', default=False)
346 subtitles.add_option('--sub-format',
347 action='store', dest='subtitlesformat', metavar='FORMAT',
348 help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
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\'')
353
354 downloader.add_option('-r', '--rate-limit',
355 dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
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',
359 dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
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
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
389 verbosity.add_option('-q', '--quiet',
390 action='store_true', dest='quiet', help='activates quiet mode', default=False)
391 verbosity.add_option(
392 '--no-warnings',
393 dest='no_warnings', action='store_true', default=False,
394 help='Ignore warnings')
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)
403 verbosity.add_option('--get-id',
404 action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
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)
411 verbosity.add_option('--get-duration',
412 action='store_true', dest='getduration',
413 help='simulate, quiet but print video length', default=False)
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)
420 verbosity.add_option('-j', '--dump-json',
421 action='store_true', dest='dumpjson',
422 help='simulate, quiet but print JSON information. See --output for a description of available keys.', default=False)
423 verbosity.add_option('--newline',
424 action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
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)
432 verbosity.add_option('--dump-intermediate-pages',
433 action='store_true', dest='dump_intermediate_pages', default=False,
434 help='print downloaded pages to debug problems (very verbose)')
435 verbosity.add_option('--write-pages',
436 action='store_true', dest='write_pages', default=False,
437 help='Write downloaded intermediary pages to files in the current directory to debug problems')
438 verbosity.add_option('--youtube-print-sig-code',
439 action='store_true', dest='youtube_print_sig_code', default=False,
440 help=optparse.SUPPRESS_HELP)
441 verbosity.add_option('--print-traffic',
442 dest='debug_printtraffic', action='store_true', default=False,
443 help='Display sent and read HTTP traffic')
444
445
446 filesystem.add_option('-a', '--batch-file',
447 dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
448 filesystem.add_option('--id',
449 action='store_true', dest='useid', help='use only video ID in file name', default=False)
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',
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, '
458 '%(ext)s for the filename extension, '
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"), '
461 '%(upload_date)s for the upload date (YYYYMMDD), '
462 '%(extractor)s for the provider (youtube, metacafe, etc), '
463 '%(id)s for the video id, %(playlist)s for the playlist the video is in, '
464 '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
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. '
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\' .'))
469 filesystem.add_option('--autonumber-size',
470 dest='autonumber_size', metavar='NUMBER',
471 help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
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)
475 filesystem.add_option('-t', '--title',
476 action='store_true', dest='usetitle', help='[deprecated] use title in file name (default)', default=False)
477 filesystem.add_option('-l', '--literal',
478 action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
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',
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)
483 filesystem.add_option('--no-continue',
484 action='store_false', dest='continue_dl',
485 help='do not resume partially downloaded files (restart from beginning)')
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)
497 filesystem.add_option('--write-annotations',
498 action='store_true', dest='writeannotations',
499 help='write video annotations to a .annotation file', default=False)
500 filesystem.add_option('--write-thumbnail',
501 action='store_true', dest='writethumbnail',
502 help='write thumbnail image to disk', default=False)
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')
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')
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',
519 help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
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)')
522 postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
523 help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv)')
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')
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')
528 postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
529 help='embed subtitles in the video (only for mp4 videos)')
530 postproc.add_option('--embed-thumbnail', action='store_true', dest='embedthumbnail', default=False,
531 help='embed thumbnail in the audio as cover art')
532 postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
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)')
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')
540
541
542 parser.add_option_group(general)
543 parser.add_option_group(selection)
544 parser.add_option_group(downloader)
545 parser.add_option_group(filesystem)
546 parser.add_option_group(verbosity)
547 parser.add_option_group(workarounds)
548 parser.add_option_group(video_format)
549 parser.add_option_group(subtitles)
550 parser.add_option_group(authentication)
551 parser.add_option_group(postproc)
552
553 if overrideArguments is not None:
554 opts, args = parser.parse_args(overrideArguments)
555 if opts.verbose:
556 write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
557 else:
558 commandLineConf = sys.argv[1:]
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()
568 argv = systemConf + userConf + commandLineConf
569
570 opts, args = parser.parse_args(argv)
571 if opts.verbose:
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')
575
576 return parser, opts, args
577
578
579def _real_main(argv=None):
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
585 setproctitle(u'youtube-dl')
586
587 parser, opts, args = parseOpts(argv)
588
589 # Set user agent
590 if opts.user_agent is not None:
591 std_headers['User-Agent'] = opts.user_agent
592
593 # Set referer
594 if opts.referer is not None:
595 std_headers['Referer'] = opts.referer
596
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
607 # Dump user agent
608 if opts.dump_user_agent:
609 compat_print(std_headers['User-Agent'])
610 sys.exit(0)
611
612 # Batch file verification
613 batch_urls = []
614 if opts.batchfile is not None:
615 try:
616 if opts.batchfile == '-':
617 batchfd = sys.stdin
618 else:
619 batchfd = io.open(opts.batchfile, 'r', encoding='utf-8', errors='ignore')
620 batch_urls = read_batch_urls(batchfd)
621 if opts.verbose:
622 write_string(u'[debug] Batch file urls: ' + repr(batch_urls) + u'\n')
623 except IOError:
624 sys.exit(u'ERROR: batch file could not be read')
625 all_urls = batch_urls + args
626 all_urls = [url.strip() for url in all_urls]
627 _enc = preferredencoding()
628 all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
629
630 extractors = gen_extractors()
631
632 if opts.list_extractors:
633 for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
634 compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
635 matchedUrls = [url for url in all_urls if ie.suitable(url)]
636 for mu in matchedUrls:
637 compat_print(u' ' + mu)
638 sys.exit(0)
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)
644 if desc is False:
645 continue
646 if hasattr(ie, 'SEARCH_KEY'):
647 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise', u'sleeping bunny')
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
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:
658 parser.error(u'account username missing\n')
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:
664 opts.password = compat_getpass(u'Type account password and press [Return]: ')
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
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
680 if opts.retries is not None:
681 try:
682 opts.retries = int(opts.retries)
683 except (TypeError, ValueError):
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
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')
694 if opts.extractaudio:
695 if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
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')
701 if opts.recodevideo is not None:
702 if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv']:
703 parser.error(u'invalid video recode format specified')
704 if opts.date is not None:
705 date = DateRange.day(opts.date)
706 else:
707 date = DateRange(opts.dateafter, opts.datebefore)
708 if opts.default_search not in ('auto', 'auto_warning', None) and ':' not in opts.default_search:
709 parser.error(u'--default-search invalid; did you forget a colon (:) at the end?')
710
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
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
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)
722 if opts.outtmpl is not None:
723 opts.outtmpl = opts.outtmpl.decode(preferredencoding())
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')
731 or DEFAULT_OUTTMPL)
732 if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
733 parser.error(u'Cannot download a video and extract audio into the same'
734 u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
735 u' template'.format(outtmpl))
736
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
738 download_archive_fn = os.path.expanduser(opts.download_archive) if opts.download_archive is not None else opts.download_archive
739
740 ydl_opts = {
741 'usenetrc': opts.usenetrc,
742 'username': opts.username,
743 'password': opts.password,
744 'videopassword': opts.videopassword,
745 'quiet': (opts.quiet or any_printing),
746 'no_warnings': opts.no_warnings,
747 'forceurl': opts.geturl,
748 'forcetitle': opts.gettitle,
749 'forceid': opts.getid,
750 'forcethumbnail': opts.getthumbnail,
751 'forcedescription': opts.getdescription,
752 'forceduration': opts.getduration,
753 'forcefilename': opts.getfilename,
754 'forceformat': opts.getformat,
755 'forcejson': opts.dumpjson,
756 'simulate': opts.simulate,
757 'skip_download': (opts.skip_download or opts.simulate or any_printing),
758 'format': opts.format,
759 'format_limit': opts.format_limit,
760 'listformats': opts.listformats,
761 'outtmpl': outtmpl,
762 'autonumber_size': opts.autonumber_size,
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,
772 'progress_with_newline': opts.progress_with_newline,
773 'playliststart': opts.playliststart,
774 'playlistend': opts.playlistend,
775 'noplaylist': opts.noplaylist,
776 'logtostderr': opts.outtmpl == '-',
777 'consoletitle': opts.consoletitle,
778 'nopart': opts.nopart,
779 'updatetime': opts.updatetime,
780 'writedescription': opts.writedescription,
781 'writeannotations': opts.writeannotations,
782 'writeinfojson': opts.writeinfojson,
783 'writethumbnail': opts.writethumbnail,
784 'writesubtitles': opts.writesubtitles,
785 'writeautomaticsub': opts.writeautomaticsub,
786 'allsubtitles': opts.allsubtitles,
787 'listsubtitles': opts.listsubtitles,
788 'subtitlesformat': opts.subtitlesformat,
789 'subtitleslangs': opts.subtitleslangs,
790 'matchtitle': decodeOption(opts.matchtitle),
791 'rejecttitle': decodeOption(opts.rejecttitle),
792 'max_downloads': opts.max_downloads,
793 'prefer_free_formats': opts.prefer_free_formats,
794 'verbose': opts.verbose,
795 'dump_intermediate_pages': opts.dump_intermediate_pages,
796 'write_pages': opts.write_pages,
797 'test': opts.test,
798 'keepvideo': opts.keepvideo,
799 'min_filesize': opts.min_filesize,
800 'max_filesize': opts.max_filesize,
801 'min_views': opts.min_views,
802 'max_views': opts.max_views,
803 'daterange': date,
804 'cachedir': opts.cachedir,
805 'youtube_print_sig_code': opts.youtube_print_sig_code,
806 'age_limit': opts.age_limit,
807 'download_archive': download_archive_fn,
808 'cookiefile': opts.cookiefile,
809 'nocheckcertificate': opts.no_check_certificate,
810 'prefer_insecure': opts.prefer_insecure,
811 'proxy': opts.proxy,
812 'socket_timeout': opts.socket_timeout,
813 'bidi_workaround': opts.bidi_workaround,
814 'debug_printtraffic': opts.debug_printtraffic,
815 'prefer_ffmpeg': opts.prefer_ffmpeg,
816 'include_ads': opts.include_ads,
817 'default_search': opts.default_search,
818 'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
819 'encoding': opts.encoding,
820 }
821
822 with YoutubeDL(ydl_opts) as ydl:
823 ydl.print_debug_header()
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))
836 if opts.xattrs:
837 ydl.add_post_processor(XAttrMetadataPP())
838 if opts.embedthumbnail:
839 if not opts.addmetadata:
840 ydl.add_post_processor(FFmpegAudioFixPP())
841 ydl.add_post_processor(AtomicParsleyPP())
842
843 # Update version
844 if opts.update_self:
845 update_self(ydl.to_screen, opts.verbose)
846
847 # Maybe do nothing
848 if (len(all_urls) < 1) and (opts.load_info_filename is None):
849 if not opts.update_self:
850 parser.error(u'you must provide at least one URL')
851 else:
852 sys.exit()
853
854 try:
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)
859 except MaxDownloadsReached:
860 ydl.to_screen(u'--max-download limit reached, aborting.')
861 retcode = 101
862
863 sys.exit(retcode)
864
865
866def main(argv=None):
867 try:
868 _real_main(argv)
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')