fix(feed): harden audio detection — audio/mp4 (.f4a/.m4b) podcasts

Follow-up to the audio-only feed guard. Real case: a Nodesignal-Talk podcast
published with `imeta m audio/mp4` + a `.f4a` URL. It was already filtered via
its imeta hint (audio/mp4 → hasAudio), but unlike the .ogg/.mp3 ones it actually
PLAYS in a <video> element (AAC-in-MP4 = audio + poster), which is why it looked
like it "worked." It's still a podcast, so it stays out of the video grid.

Closes the fallback gap for audio/mp4 notes that lack an imeta audio hint: added
.f4a/.m4b/.mka to AUDIO_ONLY_URL_PATTERN (AAC-in-MP4 audio / audiobooks /
Matroska audio). .mp4/.m4v remain video and are explicitly asserted not to match.

Tests: video-schema-and-conversion (+2, 13/13). Lint + build clean. TODO #60.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-07-09 09:50:52 -04:00
1 parent efdf497c59
commit 0c09f2854c
2 files changed
+41 -4

No files matched your search

@@ -226,6 +226,40 @@ test("isAudioOnlyVideoObject flags a cached .ogg only when imeta says audio", ()
);
});
test("audio/mp4 podcast (imeta) is filtered even though it would play", () => {
// Real case: Nodesignal-Talk E19 — m audio/mp4 + .f4a URL. AAC-in-MP4 plays in
// a <video> (audio + poster), but it's still a podcast → out of the video grid.
const podcast = {
id: "66c13a72",
content: JSON.stringify({
version: 3,
title: "Nodesignal-Talk E19",
url: "https://relay.example/talk.f4a",
videoRootId: "root-nodesignal",
}),
tags: [
["imeta", "url https://relay.example/talk.f4a", "m audio/mp4", "duration 3309"],
],
};
assert.equal(convertEventToVideo(podcast).invalid, true);
});
test("audio-only .f4a/.m4b URL with no imeta is filtered (fallback)", () => {
assert.equal(
isAudioOnlyVideoObject({ url: "https://x/a.f4a", magnet: "", tags: [] }),
true
);
assert.equal(
isAudioOnlyVideoObject({ url: "https://x/book.m4b", magnet: "", tags: [] }),
true
);
// .mp4/.m4v remain video and must NOT be filtered by the extension fallback.
assert.equal(
isAudioOnlyVideoObject({ url: "https://x/clip.mp4", magnet: "", tags: [] }),
false
);
});
test("isAudioOnlyVideoObject keeps a normal cached video object", () => {
assert.equal(
isAudioOnlyVideoObject({