This commit is contained in:
dirkf 2024-08-21 22:32:57 -04:00 committed by GitHub
commit f45d6c3063
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 10 deletions

View File

@ -310,6 +310,9 @@ Alternatively, refer to the [developer instructions](#developer-instructions) fo
--get-filename Simulate, quiet but print output
filename
--get-format Simulate, quiet but print output format
-O, --print TEMPLATE Simulate, quiet but print the given fields.
Either a field name or similar formatting
as the output template can be used
-j, --dump-json Simulate, quiet but print JSON
information. See the "OUTPUT TEMPLATE"
for a description of available keys.
@ -620,6 +623,12 @@ Available for the media that is a track or a part of a music album:
- `disc_number` (numeric): Number of the disc or other physical medium the track belongs to
- `release_year` (numeric): Year (YYYY) when the album was released
Available only when used in `--print`:
- `urls` (string): The URLs of all requested formats, one in each line
- `duration_string` (string): Length of the video (HH:mm:ss)
- `filename` (string): Name of the video file. Note that the actual filename may be different due to post-processing. Use `--exec echo` to get the name after all postprocessing is complete
Each aforementioned sequence when referenced in an output template will be replaced by the actual value corresponding to the sequence name. Note that some of the sequences are not guaranteed to be present since they depend on the metadata obtained by a particular extractor. Such sequences will be replaced with placeholder value provided with `--output-na-placeholder` (`NA` by default).
For example for `-o %(title)s-%(id)s.%(ext)s` and an mp4 video with title `youtube-dl test video` and id `BaW_jenozKcj`, this will result in a `youtube-dl test video-BaW_jenozKcj.mp4` file created in the current directory.

View File

@ -1912,25 +1912,49 @@ class YoutubeDL(object):
return subs
def __forced_printings(self, info_dict, filename, incomplete):
FIELD_ALIASES = {}
def print_mandatory(field):
actual_field = FIELD_ALIASES.get(field, field)
if (self.params.get('force%s' % field, False)
and (not incomplete or info_dict.get(field) is not None)):
self.to_stdout(info_dict[field])
and (not incomplete or info_dict.get(actual_field) is not None)):
self.to_stdout(info_dict[actual_field])
def print_optional(field):
if (self.params.get('force%s' % field, False)
and info_dict.get(field) is not None):
self.to_stdout(info_dict[field])
info_dict = info_dict.copy()
info_dict['duration_string'] = ( # %(duration>%H-%M-%S)s is wrong if duration > 24hrs
formatSeconds(info_dict['duration'])
if info_dict.get('duration', None) is not None
else None)
if info_dict.get('resolution') is None:
info_dict['resolution'] = self.format_resolution(info_dict, default=None)
if filename is not None:
info_dict['filename'] = filename
if info_dict.get('requested_formats') is not None:
# For RTMP URLs, also include the playpath
info_dict['urls'] = '\n'.join(f['url'] + f.get('play_path', '') for f in info_dict['requested_formats'])
elif 'url' in info_dict:
info_dict['urls'] = info_dict['url'] + info_dict.get('play_path', '')
if 'urls' in info_dict:
FIELD_ALIASES['url'] = 'urls'
for tmpl in self.params.get('forceprint', []):
if re.match(r'\w+$', tmpl):
tmpl = '%({0})s'.format(tmpl)
try:
out_txt = tmpl % info_dict
except KeyError:
self.report_warning('Skipping invalid print string "%s"' % (tmpl, ))
continue
self.to_stdout(out_txt)
print_mandatory('title')
print_mandatory('id')
if self.params.get('forceurl', False) and not incomplete:
if info_dict.get('requested_formats') is not None:
for f in info_dict['requested_formats']:
self.to_stdout(f['url'] + f.get('play_path', ''))
else:
# For RTMP URLs, also include the playpath
self.to_stdout(info_dict['url'] + info_dict.get('play_path', ''))
print_mandatory('url')
print_optional('thumbnail')
print_optional('description')
if self.params.get('forcefilename', False) and filename is not None:
@ -1938,6 +1962,7 @@ class YoutubeDL(object):
if self.params.get('forceduration', False) and info_dict.get('duration') is not None:
self.to_stdout(formatSeconds(info_dict['duration']))
print_mandatory('format')
if self.params.get('forcejson', False):
self.to_stdout(json.dumps(self.sanitize_info(info_dict)))

View File

@ -245,7 +245,7 @@ def _real_main(argv=None):
' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
' template'.format(outtmpl))
any_getting = 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 or opts.dump_single_json
any_getting = opts.print_ or 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 or opts.dump_single_json
any_printing = opts.print_json
download_archive_fn = expand_path(opts.download_archive) if opts.download_archive is not None else opts.download_archive
@ -335,6 +335,7 @@ def _real_main(argv=None):
'forceduration': opts.getduration,
'forcefilename': opts.getfilename,
'forceformat': opts.getformat,
'forceprint': opts.print_,
'forcejson': opts.dumpjson or opts.print_json,
'dump_single_json': opts.dump_single_json,
'simulate': opts.simulate or any_getting,

View File

@ -13,6 +13,7 @@ from .compat import (
compat_kwargs,
compat_open as open,
compat_shlex_split,
compat_str,
)
from .utils import (
preferredencoding,
@ -109,6 +110,14 @@ def parseOpts(overrideArguments=None):
def _comma_separated_values_options_callback(option, opt_str, value, parser):
setattr(parser.values, option.dest, value.split(','))
def _list_from_options_callback(option, opt_str, value, parser, append=True, delim=',', process=compat_str.strip):
# append can be True, False or -1 (prepend)
current = list(getattr(parser.values, option.dest)) if append else []
value = list(filter(None, [process(value)] if delim is None else map(process, value.split(delim))))
setattr(
parser.values, option.dest,
current + value if append is True else value + current)
# No need to wrap help messages if we're on a wide console
columns = compat_get_terminal_size().columns
max_width = columns if columns else 80
@ -594,6 +603,13 @@ def parseOpts(overrideArguments=None):
'--skip-download',
action='store_true', dest='skip_download', default=False,
help='Do not download the video')
verbosity.add_option(
'-O', '--print', metavar='TEMPLATE',
action='callback', dest='print_', type='str', default=[],
callback=_list_from_options_callback, callback_kwargs={'delim': None},
help=(
'Simulate, quiet but print the given fields. Either a field name '
'or similar formatting as the output template can be used'))
verbosity.add_option(
'-g', '--get-url',
action='store_true', dest='geturl', default=False,