fix(downloads): cap the media filename by BYTES, not characters
/code-review (S1, finding 1): sanitize truncated the title at 120 CHARACTERS, but a
path component's hard limit is 255 BYTES and rel_path packs channel + date + id + ext
into that same component — so a long accented/multi-byte title (Hungarian titles are
common here) could already overflow to ENAMETOOLONG, and the new _a{id} suffix shrank
the margin further. sanitize now truncates on a UTF-8 boundary by byte length, so the
title (≤120B) + channel (≤80B) + fixed parts stay comfortably under 255B. Two tests:
byte-cap on accented input, and every rel_path component ≤255B for a pathological
long-accented channel+title+asset_id.
This commit is contained in:
@@ -29,6 +29,14 @@ class TestSanitize:
|
||||
def test_length_is_capped(self):
|
||||
assert len(sanitize("x" * 500, limit=10)) <= 10
|
||||
|
||||
def test_cap_is_by_bytes_not_characters(self):
|
||||
# Accented (2-byte UTF-8) letters must not blow past the byte limit — the FS component cap
|
||||
# is 255 BYTES, so a char-only cap would overflow for multi-byte titles.
|
||||
out = sanitize("á" * 500, limit=10)
|
||||
assert len(out.encode("utf-8")) <= 10
|
||||
# And it never splits a character (would raise otherwise / leave a replacement char).
|
||||
out.encode("utf-8").decode("utf-8")
|
||||
|
||||
def test_empty_or_all_junk_falls_back_to_untitled(self):
|
||||
assert sanitize("") == "untitled"
|
||||
assert sanitize("🔥🔥") == "untitled"
|
||||
@@ -64,6 +72,19 @@ class TestRelPath:
|
||||
assert rel_path(self.meta, "mp4", layout="flat") == "Cool_Clip_[abc123].mp4"
|
||||
assert rel_path(self.meta, "mp4", layout="flat", asset_id=7) == "Cool_Clip_[abc123]_a7.mp4"
|
||||
|
||||
def test_every_component_stays_within_the_255_byte_fs_limit(self):
|
||||
# A long accented channel AND title, plus the asset-id suffix, must not overflow any path
|
||||
# component (the byte cap in sanitize is what guarantees this).
|
||||
meta = MediaMeta(
|
||||
video_id="abcdefghijk",
|
||||
title="Á" * 300,
|
||||
uploader="Ö" * 300,
|
||||
upload_date=date(2024, 5, 2),
|
||||
)
|
||||
out = rel_path(meta, "webm", asset_id=999999)
|
||||
for component in out.split("/"):
|
||||
assert len(component.encode("utf-8")) <= 255, component
|
||||
|
||||
|
||||
class TestDownloadFilename:
|
||||
def test_appends_the_container_extension(self):
|
||||
|
||||
Reference in New Issue
Block a user