youtube quality: map profile -> yt-dlp format selection

pure format_selection(profile) -> {format, format_sort, merge_output_format}.
caps to the resolution ceiling (falls back to uncapped so above-cap-only videos
still grab), ranks codec/res/fps/sdr as soft prefs (never excludes a stream).
the one piece the youtube downloader needs regardless of how the engine is wired.
exact yt-dlp tokens tunable on live yt-dlp; tests pin the shape.
This commit is contained in:
BoulderBadgeDad 2026-06-25 19:11:35 -07:00
parent 31d284ab0d
commit 568e297d36
2 changed files with 75 additions and 1 deletions

View file

@ -54,6 +54,44 @@ def normalize(raw: Any) -> dict:
return d
# Resolution → pixel-height ceiling for yt-dlp's ``height<=`` filter. "best" = no cap.
_RES_HEIGHT = {"best": None, "4320p": 4320, "2160p": 2160, "1440p": 1440,
"1080p": 1080, "720p": 720, "480p": 480, "360p": 360}
def format_selection(profile: Any) -> dict:
"""Map a profile to the yt-dlp options the (download) engine passes through:
``{format, format_sort, merge_output_format}``. Pure no DB, no network.
* ``format`` takes the best video+audio capped to the resolution ceiling, falling
back to an uncapped best so a video that only exists above the cap still grabs.
* ``format_sort`` is an ordered soft-preference list (codec resolution fps
SDR) yt-dlp picks the top match, so these never *exclude* a stream, they rank it.
* ``merge_output_format`` is the container yt-dlp muxes into.
NB: the exact yt-dlp tokens are tunable against the live yt-dlp version when the
downloader is wired; the shape (one capped format expr + a ranked sort list) is the
contract the tests pin.
"""
p = normalize(profile)
height = _RES_HEIGHT.get(p["max_resolution"])
if height:
fmt = "bv*[height<=%d]+ba/b[height<=%d]/bv*+ba/b" % (height, height)
else:
fmt = "bv*+ba/b"
sort: list[str] = []
if p["video_codec"] != "any":
sort.append("vcodec:%s" % p["video_codec"]) # soft codec preference
sort.append("res:%d" % height if height else "res") # prefer the ceiling, else highest
if p["prefer_60fps"]:
sort.append("fps") # prefer higher frame rate
if not p["allow_hdr"]:
sort.append("hdr:SDR") # rank SDR above HDR (don't exclude)
return {"format": fmt, "format_sort": sort, "merge_output_format": p["container"]}
def load(db) -> dict:
"""Read + normalize the stored profile, or the default if none/garbage."""
raw = db.get_setting("youtube_quality_profile")
@ -74,5 +112,5 @@ def save(db, raw: Any) -> dict:
__all__ = [
"RESOLUTIONS", "CODECS", "CONTAINERS",
"default_profile", "normalize", "load", "save",
"default_profile", "normalize", "format_selection", "load", "save",
]

View file

@ -11,6 +11,7 @@ from core.video.youtube_quality import (
CONTAINERS,
RESOLUTIONS,
default_profile,
format_selection,
load,
normalize,
save,
@ -79,3 +80,38 @@ def test_load_recovers_from_corrupt_json():
db = _FakeDB()
db.set_setting("youtube_quality_profile", "{nope")
assert load(db) == default_profile()
# ── yt-dlp format mapping (what the downloader passes through) ────────────────
def test_format_selection_default_caps_to_1080_sdr_60fps_mp4():
sel = format_selection(default_profile())
assert sel["format"] == "bv*[height<=1080]+ba/b[height<=1080]/bv*+ba/b"
assert sel["merge_output_format"] == "mp4"
# default: any-codec (no vcodec pref), prefer the cap res, 60fps, SDR
assert sel["format_sort"] == ["res:1080", "fps", "hdr:SDR"]
def test_format_selection_best_has_no_height_cap():
sel = format_selection({"max_resolution": "best", "video_codec": "any",
"prefer_60fps": False, "allow_hdr": True})
assert sel["format"] == "bv*+ba/b"
assert sel["format_sort"] == ["res"] # no codec/fps/sdr prefs → just highest res
def test_format_selection_codec_pref_leads_the_sort():
sel = format_selection({"max_resolution": "2160p", "video_codec": "av1",
"container": "mkv", "prefer_60fps": True, "allow_hdr": False})
assert sel["format"].startswith("bv*[height<=2160]")
assert sel["format_sort"] == ["vcodec:av1", "res:2160", "fps", "hdr:SDR"]
assert sel["merge_output_format"] == "mkv"
def test_format_selection_allow_hdr_drops_the_sdr_rank():
sel = format_selection({"max_resolution": "1080p", "video_codec": "any",
"prefer_60fps": True, "allow_hdr": True})
assert "hdr:SDR" not in sel["format_sort"]
def test_format_selection_normalizes_garbage_input():
# a junk profile still yields a valid default selection (never raises)
assert format_selection("nope")["format"] == "bv*[height<=1080]+ba/b[height<=1080]/bv*+ba/b"