mirror of
https://github.com/ytdl-org/youtube-dl.git
synced 2024-11-22 02:01:50 +00:00
[core] Implement a simple version of yt-dlp's --print
option
This commit is contained in:
parent
6508688e88
commit
a631e79b33
4 changed files with 61 additions and 10 deletions
|
@ -310,6 +310,9 @@ Alternatively, refer to the [developer instructions](#developer-instructions) fo
|
||||||
--get-filename Simulate, quiet but print output
|
--get-filename Simulate, quiet but print output
|
||||||
filename
|
filename
|
||||||
--get-format Simulate, quiet but print output format
|
--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
|
-j, --dump-json Simulate, quiet but print JSON
|
||||||
information. See the "OUTPUT TEMPLATE"
|
information. See the "OUTPUT TEMPLATE"
|
||||||
for a description of available keys.
|
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
|
- `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
|
- `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).
|
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.
|
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.
|
||||||
|
|
|
@ -1744,25 +1744,49 @@ class YoutubeDL(object):
|
||||||
return subs
|
return subs
|
||||||
|
|
||||||
def __forced_printings(self, info_dict, filename, incomplete):
|
def __forced_printings(self, info_dict, filename, incomplete):
|
||||||
|
FIELD_ALIASES = {}
|
||||||
|
|
||||||
def print_mandatory(field):
|
def print_mandatory(field):
|
||||||
|
actual_field = FIELD_ALIASES.get(field, field)
|
||||||
if (self.params.get('force%s' % field, False)
|
if (self.params.get('force%s' % field, False)
|
||||||
and (not incomplete or info_dict.get(field) is not None)):
|
and (not incomplete or info_dict.get(actual_field) is not None)):
|
||||||
self.to_stdout(info_dict[field])
|
self.to_stdout(info_dict[actual_field])
|
||||||
|
|
||||||
def print_optional(field):
|
def print_optional(field):
|
||||||
if (self.params.get('force%s' % field, False)
|
if (self.params.get('force%s' % field, False)
|
||||||
and info_dict.get(field) is not None):
|
and info_dict.get(field) is not None):
|
||||||
self.to_stdout(info_dict[field])
|
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('title')
|
||||||
print_mandatory('id')
|
print_mandatory('id')
|
||||||
if self.params.get('forceurl', False) and not incomplete:
|
print_mandatory('url')
|
||||||
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_optional('thumbnail')
|
print_optional('thumbnail')
|
||||||
print_optional('description')
|
print_optional('description')
|
||||||
if self.params.get('forcefilename', False) and filename is not None:
|
if self.params.get('forcefilename', False) and filename is not None:
|
||||||
|
@ -1770,6 +1794,7 @@ class YoutubeDL(object):
|
||||||
if self.params.get('forceduration', False) and info_dict.get('duration') is not None:
|
if self.params.get('forceduration', False) and info_dict.get('duration') is not None:
|
||||||
self.to_stdout(formatSeconds(info_dict['duration']))
|
self.to_stdout(formatSeconds(info_dict['duration']))
|
||||||
print_mandatory('format')
|
print_mandatory('format')
|
||||||
|
|
||||||
if self.params.get('forcejson', False):
|
if self.params.get('forcejson', False):
|
||||||
self.to_stdout(json.dumps(info_dict))
|
self.to_stdout(json.dumps(info_dict))
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ def _real_main(argv=None):
|
||||||
' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
|
' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
|
||||||
' template'.format(outtmpl))
|
' 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
|
any_printing = opts.print_json
|
||||||
download_archive_fn = expand_path(opts.download_archive) if opts.download_archive is not None else opts.download_archive
|
download_archive_fn = expand_path(opts.download_archive) if opts.download_archive is not None else opts.download_archive
|
||||||
|
|
||||||
|
@ -333,6 +333,7 @@ def _real_main(argv=None):
|
||||||
'forceduration': opts.getduration,
|
'forceduration': opts.getduration,
|
||||||
'forcefilename': opts.getfilename,
|
'forcefilename': opts.getfilename,
|
||||||
'forceformat': opts.getformat,
|
'forceformat': opts.getformat,
|
||||||
|
'forceprint': opts.print_,
|
||||||
'forcejson': opts.dumpjson or opts.print_json,
|
'forcejson': opts.dumpjson or opts.print_json,
|
||||||
'dump_single_json': opts.dump_single_json,
|
'dump_single_json': opts.dump_single_json,
|
||||||
'simulate': opts.simulate or any_getting,
|
'simulate': opts.simulate or any_getting,
|
||||||
|
|
|
@ -12,6 +12,7 @@ from .compat import (
|
||||||
compat_getenv,
|
compat_getenv,
|
||||||
compat_kwargs,
|
compat_kwargs,
|
||||||
compat_shlex_split,
|
compat_shlex_split,
|
||||||
|
compat_str,
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
preferredencoding,
|
preferredencoding,
|
||||||
|
@ -111,6 +112,14 @@ def parseOpts(overrideArguments=None):
|
||||||
def _comma_separated_values_options_callback(option, opt_str, value, parser):
|
def _comma_separated_values_options_callback(option, opt_str, value, parser):
|
||||||
setattr(parser.values, option.dest, value.split(','))
|
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
|
# No need to wrap help messages if we're on a wide console
|
||||||
columns = compat_get_terminal_size().columns
|
columns = compat_get_terminal_size().columns
|
||||||
max_width = columns if columns else 80
|
max_width = columns if columns else 80
|
||||||
|
@ -590,6 +599,13 @@ def parseOpts(overrideArguments=None):
|
||||||
'--skip-download',
|
'--skip-download',
|
||||||
action='store_true', dest='skip_download', default=False,
|
action='store_true', dest='skip_download', default=False,
|
||||||
help='Do not download the video')
|
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(
|
verbosity.add_option(
|
||||||
'-g', '--get-url',
|
'-g', '--get-url',
|
||||||
action='store_true', dest='geturl', default=False,
|
action='store_true', dest='geturl', default=False,
|
||||||
|
|
Loading…
Reference in a new issue