aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Fink <lukas.fink1@gmail.com>2022-02-11 22:35:34 +0100
committerGitHub <noreply@github.com>2022-02-11 13:35:34 -0800
commit1ce9a3cb49b209ccb999d4fb97851f60d51dabd3 (patch)
tree700859a559953123918f00674685aef771c5f9e2
parentd49f8db39fd94a9ec314c43ce31d85facb1b8886 (diff)
downloadhypervideo-pre-1ce9a3cb49b209ccb999d4fb97851f60d51dabd3.tar.lz
hypervideo-pre-1ce9a3cb49b209ccb999d4fb97851f60d51dabd3.tar.xz
hypervideo-pre-1ce9a3cb49b209ccb999d4fb97851f60d51dabd3.zip
Add regex operator and quoting to format filters (#2698)
Closes #2681 Authored by: lukasfink1
-rw-r--r--README.md9
-rw-r--r--yt_dlp/YoutubeDL.py12
2 files changed, 14 insertions, 7 deletions
diff --git a/README.md b/README.md
index b00cdfdcb..7446cc2c2 100644
--- a/README.md
+++ b/README.md
@@ -1399,7 +1399,7 @@ The following numeric meta fields can be used with comparisons `<`, `<=`, `>`, `
- `asr`: Audio sampling rate in Hertz
- `fps`: Frame rate
-Also filtering work for comparisons `=` (equals), `^=` (starts with), `$=` (ends with), `*=` (contains) and following string meta fields:
+Also filtering work for comparisons `=` (equals), `^=` (starts with), `$=` (ends with), `*=` (contains), `~=` (matches regex) and following string meta fields:
- `ext`: File extension
- `acodec`: Name of the audio codec in use
@@ -1409,7 +1409,7 @@ Also filtering work for comparisons `=` (equals), `^=` (starts with), `$=` (ends
- `format_id`: A short description of the format
- `language`: Language code
-Any string comparison may be prefixed with negation `!` in order to produce an opposite comparison, e.g. `!*=` (does not contain).
+Any string comparison may be prefixed with negation `!` in order to produce an opposite comparison, e.g. `!*=` (does not contain). The comparand of a string comparison needs to be quoted with either double or single quotes if it contains spaces or special characters other than `._-`.
Note that none of the aforementioned meta fields are guaranteed to be present since this solely depends on the metadata obtained by particular extractor, i.e. the metadata offered by the website. Any other field made available by the extractor can also be used for filtering.
@@ -1552,8 +1552,9 @@ $ yt-dlp -S "proto"
-# Download the best video with h264 codec, or the best video if there is no such video
-$ yt-dlp -f "(bv*[vcodec^=avc1]+ba) / (bv*+ba/b)"
+# Download the best video with either h264 or h265 codec,
+# or the best video if there is no such video
+$ yt-dlp -f "(bv*[vcodec~='^((he|a)vc|h26[45])']+ba) / (bv*+ba/b)"
# Download the best video with best codec no better than h264,
# or the best video with worst codec if there is no such video
diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py
index 74684dea3..9892ed328 100644
--- a/yt_dlp/YoutubeDL.py
+++ b/yt_dlp/YoutubeDL.py
@@ -1842,15 +1842,21 @@ class YoutubeDL(object):
'^=': lambda attr, value: attr.startswith(value),
'$=': lambda attr, value: attr.endswith(value),
'*=': lambda attr, value: value in attr,
+ '~=': lambda attr, value: value.search(attr) is not None
}
str_operator_rex = re.compile(r'''(?x)\s*
(?P<key>[a-zA-Z0-9._-]+)\s*
- (?P<negation>!\s*)?(?P<op>%s)(?P<none_inclusive>\s*\?)?\s*
- (?P<value>[a-zA-Z0-9._-]+)\s*
+ (?P<negation>!\s*)?(?P<op>%s)\s*(?P<none_inclusive>\?\s*)?
+ (?P<quote>["'])?
+ (?P<value>(?(quote)(?:(?!(?P=quote))[^\\]|\\.)+|[\w.-]+))
+ (?(quote)(?P=quote))\s*
''' % '|'.join(map(re.escape, STR_OPERATORS.keys())))
m = str_operator_rex.fullmatch(filter_spec)
if m:
- comparison_value = m.group('value')
+ if m.group('op') == '~=':
+ comparison_value = re.compile(m.group('value'))
+ else:
+ comparison_value = re.sub(r'''\\([\\"'])''', r'\1', m.group('value'))
str_op = STR_OPERATORS[m.group('op')]
if m.group('negation'):
op = lambda attr, value: not str_op(attr, value)