Files
bitvid/tests/channel-profile-videos.test.mjs
thePR0M3TH3ANandClaude Opus 4.8 7236496a16 nip71: show creators' NIP-71 videos on their channel-profile wall (17b)
The channel-profile grid fetched only kind-30078, so a creator's NIP-71
videos (incl. their Nostube cross-posts) appeared in the main feed via
ingest but were absent from their profile wall.

New js/channelProfileVideos.js:
- buildChannelVideoFilters(pubkey): native (kind 30078, #t=video) + NIP-71
  (kinds 21/22/34235/34236) filters for the author.
- convertChannelEvent(entry): routes NIP-71 kinds through
  buildVideoFromNip71Event (which rejects bitvid's own outbound mirrors so
  they don't duplicate the canonical note); kind-30078 uses the standard
  converter.

channelProfile.js now uses these (net fewer lines, stays under size cap).
Existing buildRenderableChannelVideos dedupe-by-root + canAccess handle
precedence and whitelist/blacklist gating, so foreign videos inherit the
same gating as native ones.

Closes pre-launch TODO 17b. Tests + mutation-verified (NIP-71 routing,
mirror skip, dual-filter build). 1253/1254 unit (known UploadModal flake).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 19:20:48 -04:00

82 lines
2.4 KiB
JavaScript

// Channel-profile wall must source BOTH native kind-30078 videos and the
// creator's NIP-71 videos (cross-posted via other apps), while skipping bitvid's
// own outbound mirrors so they don't duplicate the canonical note.
import assert from "node:assert/strict";
import test from "node:test";
import {
buildChannelVideoFilters,
convertChannelEvent,
} from "../js/channelProfileVideos.js";
const PK = "a".repeat(64);
test("builds a native (30078) filter AND a NIP-71 filter for the author", () => {
const filters = buildChannelVideoFilters(PK);
assert.equal(filters.length, 2);
const native = filters.find((f) => f.kinds.includes(30078));
assert.deepEqual(native.authors, [PK]);
assert.deepEqual(native["#t"], ["video"]);
const nip71 = filters.find((f) => !f.kinds.includes(30078));
assert.deepEqual(nip71.kinds.slice().sort((a, b) => a - b), [21, 22, 34235, 34236]);
assert.deepEqual(nip71.authors, [PK]);
});
test("converts a foreign NIP-71 event into a renderable video", () => {
const v = convertChannelEvent({
id: "evt",
pubkey: PK,
kind: 34235,
created_at: 1000,
content: "desc",
tags: [
["d", "root"],
["title", "Nostube clip"],
["imeta", "url https://example.com/v.mp4", "m video/mp4"],
],
});
assert.equal(v.invalid, false);
assert.equal(v.title, "Nostube clip");
assert.equal(v.source, "nip71-ingest");
});
test("skips bitvid's own mirror (returns invalid so the caller drops it)", () => {
const v = convertChannelEvent({
id: "mirror",
pubkey: PK,
kind: 34235,
created_at: 1000,
content: "",
tags: [
["d", "root"],
["client", "bitvid"],
["title", "Our mirror"],
["imeta", "url https://example.com/v.mp4", "m video/mp4"],
],
});
assert.equal(v.invalid, true);
assert.equal(v.reason, "bitvid-mirror");
});
test("routes kind-30078 events through the standard converter", () => {
const v = convertChannelEvent({
id: "native",
pubkey: PK,
kind: 30078,
created_at: 2000,
content: JSON.stringify({
version: 3,
title: "Native bitvid video",
videoRootId: "vr",
url: "https://example.com/native.mp4",
}),
tags: [["d", "vr"], ["t", "video"]],
});
assert.equal(v.invalid, false);
assert.equal(v.title, "Native bitvid video");
// Not stamped as ingested — it's a native note.
assert.notEqual(v.source, "nip71-ingest");
});