mirror of https://github.com/yt-dlp/yt-dlp.git
Add `--print playlist:` to print fields per playlist
This commit is contained in:
parent
af3cbd8782
commit
ca30f449a1
10
README.md
10
README.md
|
@ -662,10 +662,12 @@ You can also fork the project on github and run your fork's [build workflow](.gi
|
||||||
formats are found (default)
|
formats are found (default)
|
||||||
--skip-download Do not download the video but write all
|
--skip-download Do not download the video but write all
|
||||||
related files (Alias: --no-download)
|
related files (Alias: --no-download)
|
||||||
-O, --print TEMPLATE Quiet, but print the given fields for each
|
-O, --print [WHEN:]TEMPLATE Field name or output template to print to
|
||||||
video. Simulate unless --no-simulate is
|
screen per video. Prefix the template with
|
||||||
used. Either a field name or same syntax as
|
"playlist:" to print it once per playlist
|
||||||
the output template can be used
|
instead. Implies --quiet and --simulate
|
||||||
|
(unless --no-simulate is used). This option
|
||||||
|
can be used multiple times
|
||||||
-j, --dump-json Quiet, but print JSON information for each
|
-j, --dump-json Quiet, but print JSON information for each
|
||||||
video. Simulate unless --no-simulate is
|
video. Simulate unless --no-simulate is
|
||||||
used. See "OUTPUT TEMPLATE" for a
|
used. See "OUTPUT TEMPLATE" for a
|
||||||
|
|
|
@ -199,7 +199,9 @@ class YoutubeDL(object):
|
||||||
verbose: Print additional info to stdout.
|
verbose: Print additional info to stdout.
|
||||||
quiet: Do not print messages to stdout.
|
quiet: Do not print messages to stdout.
|
||||||
no_warnings: Do not print out anything for warnings.
|
no_warnings: Do not print out anything for warnings.
|
||||||
forceprint: A list of templates to force print
|
forceprint: A dict with keys video/playlist mapped to
|
||||||
|
a list of templates to force print to stdout
|
||||||
|
For compatibility, a single list is also accepted
|
||||||
forceurl: Force printing final URL. (Deprecated)
|
forceurl: Force printing final URL. (Deprecated)
|
||||||
forcetitle: Force printing title. (Deprecated)
|
forcetitle: Force printing title. (Deprecated)
|
||||||
forceid: Force printing ID. (Deprecated)
|
forceid: Force printing ID. (Deprecated)
|
||||||
|
@ -585,6 +587,11 @@ class YoutubeDL(object):
|
||||||
else:
|
else:
|
||||||
self.params['nooverwrites'] = not self.params['overwrites']
|
self.params['nooverwrites'] = not self.params['overwrites']
|
||||||
|
|
||||||
|
# Compatibility with older syntax
|
||||||
|
params.setdefault('forceprint', {})
|
||||||
|
if not isinstance(params['forceprint'], dict):
|
||||||
|
params['forceprint'] = {'video': params['forceprint']}
|
||||||
|
|
||||||
if params.get('bidi_workaround', False):
|
if params.get('bidi_workaround', False):
|
||||||
try:
|
try:
|
||||||
import pty
|
import pty
|
||||||
|
@ -1755,6 +1762,9 @@ class YoutubeDL(object):
|
||||||
'updated playlist', ie_result,
|
'updated playlist', ie_result,
|
||||||
self.prepare_filename(ie_copy, 'pl_infojson'), overwrite=True) is None:
|
self.prepare_filename(ie_copy, 'pl_infojson'), overwrite=True) is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
for tmpl in self.params['forceprint'].get('playlist', []):
|
||||||
|
self._forceprint(tmpl, ie_result)
|
||||||
self.to_screen('[download] Finished downloading playlist: %s' % playlist)
|
self.to_screen('[download] Finished downloading playlist: %s' % playlist)
|
||||||
return ie_result
|
return ie_result
|
||||||
|
|
||||||
|
@ -2626,6 +2636,14 @@ class YoutubeDL(object):
|
||||||
subs[lang] = f
|
subs[lang] = f
|
||||||
return subs
|
return subs
|
||||||
|
|
||||||
|
def _forceprint(self, tmpl, info_dict):
|
||||||
|
mobj = re.match(r'\w+(=?)$', tmpl)
|
||||||
|
if mobj and mobj.group(1):
|
||||||
|
tmpl = f'{tmpl[:-1]} = %({tmpl[:-1]})s'
|
||||||
|
elif mobj:
|
||||||
|
tmpl = '%({})s'.format(tmpl)
|
||||||
|
self.to_stdout(self.evaluate_outtmpl(tmpl, info_dict))
|
||||||
|
|
||||||
def __forced_printings(self, info_dict, filename, incomplete):
|
def __forced_printings(self, info_dict, filename, incomplete):
|
||||||
def print_mandatory(field, actual_field=None):
|
def print_mandatory(field, actual_field=None):
|
||||||
if actual_field is None:
|
if actual_field is None:
|
||||||
|
@ -2648,15 +2666,10 @@ class YoutubeDL(object):
|
||||||
elif 'url' in info_dict:
|
elif 'url' in info_dict:
|
||||||
info_dict['urls'] = info_dict['url'] + info_dict.get('play_path', '')
|
info_dict['urls'] = info_dict['url'] + info_dict.get('play_path', '')
|
||||||
|
|
||||||
if self.params.get('forceprint') or self.params.get('forcejson'):
|
if self.params['forceprint'].get('video') or self.params.get('forcejson'):
|
||||||
self.post_extract(info_dict)
|
self.post_extract(info_dict)
|
||||||
for tmpl in self.params.get('forceprint', []):
|
for tmpl in self.params['forceprint'].get('video', []):
|
||||||
mobj = re.match(r'\w+(=?)$', tmpl)
|
self._forceprint(tmpl, info_dict)
|
||||||
if mobj and mobj.group(1):
|
|
||||||
tmpl = f'{tmpl[:-1]} = %({tmpl[:-1]})s'
|
|
||||||
elif mobj:
|
|
||||||
tmpl = '%({})s'.format(tmpl)
|
|
||||||
self.to_stdout(self.evaluate_outtmpl(tmpl, info_dict))
|
|
||||||
|
|
||||||
print_mandatory('title')
|
print_mandatory('title')
|
||||||
print_mandatory('id')
|
print_mandatory('id')
|
||||||
|
|
|
@ -351,9 +351,9 @@ def _real_main(argv=None):
|
||||||
|
|
||||||
for k, tmpl in opts.outtmpl.items():
|
for k, tmpl in opts.outtmpl.items():
|
||||||
validate_outtmpl(tmpl, f'{k} output template')
|
validate_outtmpl(tmpl, f'{k} output template')
|
||||||
opts.forceprint = opts.forceprint or []
|
for type_, tmpl_list in opts.forceprint.items():
|
||||||
for tmpl in opts.forceprint or []:
|
for tmpl in tmpl_list:
|
||||||
validate_outtmpl(tmpl, 'print template')
|
validate_outtmpl(tmpl, f'{type_} print template')
|
||||||
validate_outtmpl(opts.sponsorblock_chapter_title, 'SponsorBlock chapter title')
|
validate_outtmpl(opts.sponsorblock_chapter_title, 'SponsorBlock chapter title')
|
||||||
for k, tmpl in opts.progress_template.items():
|
for k, tmpl in opts.progress_template.items():
|
||||||
k = f'{k[:-6]} console title' if '-title' in k else f'{k} progress'
|
k = f'{k[:-6]} console title' if '-title' in k else f'{k} progress'
|
||||||
|
@ -395,7 +395,10 @@ def _real_main(argv=None):
|
||||||
opts.parse_metadata.append('title:%s' % opts.metafromtitle)
|
opts.parse_metadata.append('title:%s' % opts.metafromtitle)
|
||||||
opts.parse_metadata = list(itertools.chain(*map(metadataparser_actions, opts.parse_metadata)))
|
opts.parse_metadata = list(itertools.chain(*map(metadataparser_actions, opts.parse_metadata)))
|
||||||
|
|
||||||
any_getting = opts.forceprint 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_getting = (any(opts.forceprint.values()) or opts.dumpjson or opts.dump_single_json
|
||||||
|
or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail
|
||||||
|
or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -152,9 +152,9 @@ def parseOpts(overrideArguments=None):
|
||||||
def _dict_from_options_callback(
|
def _dict_from_options_callback(
|
||||||
option, opt_str, value, parser,
|
option, opt_str, value, parser,
|
||||||
allowed_keys=r'[\w-]+', delimiter=':', default_key=None, process=None, multiple_keys=True,
|
allowed_keys=r'[\w-]+', delimiter=':', default_key=None, process=None, multiple_keys=True,
|
||||||
process_key=str.lower):
|
process_key=str.lower, append=False):
|
||||||
|
|
||||||
out_dict = getattr(parser.values, option.dest)
|
out_dict = dict(getattr(parser.values, option.dest))
|
||||||
if multiple_keys:
|
if multiple_keys:
|
||||||
allowed_keys = r'(%s)(,(%s))*' % (allowed_keys, allowed_keys)
|
allowed_keys = r'(%s)(,(%s))*' % (allowed_keys, allowed_keys)
|
||||||
mobj = re.match(r'(?i)(?P<keys>%s)%s(?P<val>.*)$' % (allowed_keys, delimiter), value)
|
mobj = re.match(r'(?i)(?P<keys>%s)%s(?P<val>.*)$' % (allowed_keys, delimiter), value)
|
||||||
|
@ -171,7 +171,8 @@ def parseOpts(overrideArguments=None):
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise optparse.OptionValueError(f'wrong {opt_str} formatting; {err}')
|
raise optparse.OptionValueError(f'wrong {opt_str} formatting; {err}')
|
||||||
for key in keys:
|
for key in keys:
|
||||||
out_dict[key] = val
|
out_dict[key] = out_dict.get(key, []) + [val] if append else val
|
||||||
|
setattr(parser.values, option.dest, out_dict)
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -882,10 +883,17 @@ def parseOpts(overrideArguments=None):
|
||||||
help='Do not download the video but write all related files (Alias: --no-download)')
|
help='Do not download the video but write all related files (Alias: --no-download)')
|
||||||
verbosity.add_option(
|
verbosity.add_option(
|
||||||
'-O', '--print',
|
'-O', '--print',
|
||||||
metavar='TEMPLATE', action='append', dest='forceprint',
|
metavar='[WHEN:]TEMPLATE', dest='forceprint', default={}, type='str',
|
||||||
help=(
|
action='callback', callback=_dict_from_options_callback,
|
||||||
'Quiet, but print the given fields for each video. Simulate unless --no-simulate is used. '
|
callback_kwargs={
|
||||||
'Either a field name or same syntax as the output template can be used'))
|
'allowed_keys': 'video|playlist',
|
||||||
|
'default_key': 'video',
|
||||||
|
'multiple_keys': False,
|
||||||
|
'append': True,
|
||||||
|
}, help=(
|
||||||
|
'Field name or output template to print to screen per video. '
|
||||||
|
'Prefix the template with "playlist:" to print it once per playlist instead. '
|
||||||
|
'Implies --quiet and --simulate (unless --no-simulate is used). This option can be used multiple times'))
|
||||||
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 New Issue