mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-13 02:14:20 +01:00
--match-filter -
to interactively ask for each video
This commit is contained in:
parent
59f943cd50
commit
492272fed6
5 changed files with 28 additions and 7 deletions
|
@ -451,7 +451,9 @@ ## Video Selection:
|
||||||
those that have a like count more than 100
|
those that have a like count more than 100
|
||||||
(or the like field is not available) and
|
(or the like field is not available) and
|
||||||
also has a description that contains the
|
also has a description that contains the
|
||||||
phrase "cats & dogs" (ignoring case)
|
phrase "cats & dogs" (ignoring case). Use
|
||||||
|
"--match-filter -" to interactively ask
|
||||||
|
whether to download each video
|
||||||
--no-match-filter Do not use generic video filter (default)
|
--no-match-filter Do not use generic video filter (default)
|
||||||
--no-playlist Download only the video, if the URL refers
|
--no-playlist Download only the video, if the URL refers
|
||||||
to a video and a playlist
|
to a video and a playlist
|
||||||
|
|
|
@ -413,6 +413,8 @@ class YoutubeDL:
|
||||||
every video.
|
every video.
|
||||||
If it returns a message, the video is ignored.
|
If it returns a message, the video is ignored.
|
||||||
If it returns None, the video is downloaded.
|
If it returns None, the video is downloaded.
|
||||||
|
If it returns utils.NO_DEFAULT, the user is interactively
|
||||||
|
asked whether to download the video.
|
||||||
match_filter_func in utils.py is one example for this.
|
match_filter_func in utils.py is one example for this.
|
||||||
no_color: Do not emit color codes in output.
|
no_color: Do not emit color codes in output.
|
||||||
geo_bypass: Bypass geographic restriction via faking X-Forwarded-For
|
geo_bypass: Bypass geographic restriction via faking X-Forwarded-For
|
||||||
|
@ -878,6 +880,7 @@ def trouble(self, message=None, tb=None, is_error=True):
|
||||||
Styles = Namespace(
|
Styles = Namespace(
|
||||||
HEADERS='yellow',
|
HEADERS='yellow',
|
||||||
EMPHASIS='light blue',
|
EMPHASIS='light blue',
|
||||||
|
FILENAME='green',
|
||||||
ID='green',
|
ID='green',
|
||||||
DELIM='blue',
|
DELIM='blue',
|
||||||
ERROR='red',
|
ERROR='red',
|
||||||
|
@ -1303,7 +1306,17 @@ def check_filter():
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# For backward compatibility
|
# For backward compatibility
|
||||||
ret = None if incomplete else match_filter(info_dict)
|
ret = None if incomplete else match_filter(info_dict)
|
||||||
if ret is not None:
|
if ret is NO_DEFAULT:
|
||||||
|
while True:
|
||||||
|
filename = self._format_screen(self.prepare_filename(info_dict), self.Styles.FILENAME)
|
||||||
|
reply = input(self._format_screen(
|
||||||
|
f'Download "{filename}"? (Y/n): ', self.Styles.EMPHASIS)).lower().strip()
|
||||||
|
if reply in {'y', ''}:
|
||||||
|
return None
|
||||||
|
elif reply == 'n':
|
||||||
|
return f'Skipping {video_title}'
|
||||||
|
return True
|
||||||
|
elif ret is not None:
|
||||||
return ret
|
return ret
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ def format_text(text, f):
|
||||||
raise SyntaxError(f'Invalid format {" ".join(tokens)!r} in {f!r}')
|
raise SyntaxError(f'Invalid format {" ".join(tokens)!r} in {f!r}')
|
||||||
|
|
||||||
if fg_color or bg_color:
|
if fg_color or bg_color:
|
||||||
|
text = text.replace(CONTROL_SEQUENCES['RESET'], f'{fg_color}{bg_color}')
|
||||||
return f'{fg_color}{bg_color}{text}{CONTROL_SEQUENCES["RESET"]}'
|
return f'{fg_color}{bg_color}{text}{CONTROL_SEQUENCES["RESET"]}'
|
||||||
else:
|
else:
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -471,7 +471,8 @@ def _dict_from_options_callback(
|
||||||
'!is_live --match-filter "like_count>?100 & description~=\'(?i)\\bcats \\& dogs\\b\'" '
|
'!is_live --match-filter "like_count>?100 & description~=\'(?i)\\bcats \\& dogs\\b\'" '
|
||||||
'matches only videos that are not live OR those that have a like count more than 100 '
|
'matches only videos that are not live OR those that have a like count more than 100 '
|
||||||
'(or the like field is not available) and also has a description '
|
'(or the like field is not available) and also has a description '
|
||||||
'that contains the phrase "cats & dogs" (ignoring case)'))
|
'that contains the phrase "cats & dogs" (ignoring case). '
|
||||||
|
'Use "--match-filter -" to interactively ask whether to download each video'))
|
||||||
selection.add_option(
|
selection.add_option(
|
||||||
'--no-match-filter',
|
'--no-match-filter',
|
||||||
metavar='FILTER', dest='match_filter', action='store_const', const=None,
|
metavar='FILTER', dest='match_filter', action='store_const', const=None,
|
||||||
|
|
|
@ -3407,11 +3407,15 @@ def match_str(filter_str, dct, incomplete=False):
|
||||||
def match_filter_func(filters):
|
def match_filter_func(filters):
|
||||||
if not filters:
|
if not filters:
|
||||||
return None
|
return None
|
||||||
filters = variadic(filters)
|
filters = set(variadic(filters))
|
||||||
|
|
||||||
def _match_func(info_dict, *args, **kwargs):
|
interactive = '-' in filters
|
||||||
if any(match_str(f, info_dict, *args, **kwargs) for f in filters):
|
if interactive:
|
||||||
return None
|
filters.remove('-')
|
||||||
|
|
||||||
|
def _match_func(info_dict, incomplete=False):
|
||||||
|
if not filters or any(match_str(f, info_dict, incomplete) for f in filters):
|
||||||
|
return NO_DEFAULT if interactive and not incomplete else None
|
||||||
else:
|
else:
|
||||||
video_title = info_dict.get('title') or info_dict.get('id') or 'video'
|
video_title = info_dict.get('title') or info_dict.get('id') or 'video'
|
||||||
filter_str = ') | ('.join(map(str.strip, filters))
|
filter_str = ') | ('.join(map(str.strip, filters))
|
||||||
|
|
Loading…
Reference in a new issue