mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-28 16:32:28 +00:00
201 lines
4.6 KiB
JavaScript
201 lines
4.6 KiB
JavaScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import Application from "../../js/app.js";
|
|
|
|
const computeSimilarContent = Application.prototype.computeSimilarContentCandidates;
|
|
|
|
function createAppStub({ videos = [] } = {}) {
|
|
const videosMap = new Map();
|
|
for (const video of videos) {
|
|
if (video && typeof video.id === "string") {
|
|
videosMap.set(video.id, video);
|
|
}
|
|
}
|
|
|
|
return {
|
|
videoListView: { currentVideos: videos },
|
|
videosMap,
|
|
getKnownVideoPostedAt(video) {
|
|
if (Number.isFinite(video?.rootCreatedAt)) {
|
|
return Math.floor(video.rootCreatedAt);
|
|
}
|
|
if (Number.isFinite(video?.created_at)) {
|
|
return Math.floor(video.created_at);
|
|
}
|
|
return null;
|
|
},
|
|
buildShareUrlFromEventId(id) {
|
|
return id ? `https://bitvid.invalid/${id}` : "";
|
|
},
|
|
formatTimeAgo(timestamp) {
|
|
return Number.isFinite(timestamp) ? `${timestamp}s` : "";
|
|
},
|
|
deriveVideoPointerInfo(video) {
|
|
if (video?.pointerInfo) {
|
|
return video.pointerInfo;
|
|
}
|
|
if (typeof video?.pointerKey === "string" && video.pointerKey.trim()) {
|
|
return { key: video.pointerKey.trim() };
|
|
}
|
|
return null;
|
|
},
|
|
isAuthorBlocked() {
|
|
return false;
|
|
},
|
|
};
|
|
}
|
|
|
|
function createVideo({
|
|
id,
|
|
pubkey = "author",
|
|
displayTags,
|
|
tags,
|
|
rootCreatedAt,
|
|
created_at,
|
|
pointerKey,
|
|
pointerInfo,
|
|
shareUrl,
|
|
isPrivate = false,
|
|
isNsfw = false,
|
|
} = {}) {
|
|
const video = {
|
|
id,
|
|
pubkey,
|
|
isPrivate,
|
|
isNsfw,
|
|
};
|
|
|
|
if (Array.isArray(displayTags)) {
|
|
video.displayTags = displayTags.slice();
|
|
}
|
|
if (Array.isArray(tags)) {
|
|
video.tags = tags.slice();
|
|
}
|
|
if (Number.isFinite(rootCreatedAt)) {
|
|
video.rootCreatedAt = Math.floor(rootCreatedAt);
|
|
}
|
|
if (Number.isFinite(created_at)) {
|
|
video.created_at = Math.floor(created_at);
|
|
}
|
|
if (typeof pointerKey === "string") {
|
|
video.pointerKey = pointerKey;
|
|
}
|
|
if (pointerInfo) {
|
|
video.pointerInfo = pointerInfo;
|
|
}
|
|
if (typeof shareUrl === "string") {
|
|
video.shareUrl = shareUrl;
|
|
}
|
|
|
|
return video;
|
|
}
|
|
|
|
test("orders similar videos by shared tags then timestamp", () => {
|
|
const activeVideo = createVideo({
|
|
id: "root-video",
|
|
displayTags: ["Art", "Music", "News"],
|
|
});
|
|
|
|
const candidateA = createVideo({
|
|
id: "video-a",
|
|
displayTags: ["art", "music"],
|
|
rootCreatedAt: 100,
|
|
});
|
|
const candidateB = createVideo({
|
|
id: "video-b",
|
|
displayTags: ["art"],
|
|
rootCreatedAt: 200,
|
|
});
|
|
const candidateC = createVideo({
|
|
id: "video-c",
|
|
displayTags: ["art", "music"],
|
|
rootCreatedAt: 50,
|
|
});
|
|
|
|
const app = createAppStub({
|
|
videos: [candidateA, candidateB, candidateC],
|
|
});
|
|
|
|
const matches = computeSimilarContent.call(app, { activeVideo, maxItems: 5 });
|
|
assert.equal(matches.length, 3);
|
|
assert.deepEqual(
|
|
matches.map((entry) => entry.video.id),
|
|
["video-a", "video-c", "video-b"],
|
|
);
|
|
assert.deepEqual(
|
|
matches.map((entry) => entry.sharedTagCount),
|
|
[2, 2, 1],
|
|
);
|
|
});
|
|
|
|
test("returns no matches when the active video lacks tags", () => {
|
|
const activeVideo = createVideo({
|
|
id: "root-video",
|
|
});
|
|
|
|
const candidate = createVideo({
|
|
id: "video-a",
|
|
displayTags: ["art"],
|
|
});
|
|
|
|
const app = createAppStub({ videos: [candidate] });
|
|
const matches = computeSimilarContent.call(app, { activeVideo, maxItems: 5 });
|
|
assert.deepEqual(matches, []);
|
|
});
|
|
|
|
test("skips candidates without tag metadata", () => {
|
|
const activeVideo = createVideo({
|
|
id: "root-video",
|
|
displayTags: ["art"],
|
|
});
|
|
|
|
const candidateWithTags = createVideo({
|
|
id: "video-a",
|
|
displayTags: ["art"],
|
|
});
|
|
const candidateWithoutTags = createVideo({
|
|
id: "video-b",
|
|
});
|
|
|
|
const app = createAppStub({
|
|
videos: [candidateWithTags, candidateWithoutTags],
|
|
});
|
|
|
|
const matches = computeSimilarContent.call(app, { activeVideo, maxItems: 5 });
|
|
assert.equal(matches.length, 1);
|
|
assert.equal(matches[0].video.id, "video-a");
|
|
});
|
|
|
|
test("filters NSFW and private videos when NSFW content is disabled", () => {
|
|
const activeVideo = createVideo({
|
|
id: "root-video",
|
|
displayTags: ["art"],
|
|
});
|
|
|
|
const publicVideo = createVideo({
|
|
id: "video-public",
|
|
displayTags: ["art"],
|
|
});
|
|
const nsfwVideo = createVideo({
|
|
id: "video-nsfw",
|
|
displayTags: ["art"],
|
|
isNsfw: true,
|
|
});
|
|
const privateVideo = createVideo({
|
|
id: "video-private",
|
|
displayTags: ["art"],
|
|
isPrivate: true,
|
|
});
|
|
|
|
const app = createAppStub({
|
|
videos: [publicVideo, nsfwVideo, privateVideo],
|
|
});
|
|
|
|
const matches = computeSimilarContent.call(app, { activeVideo, maxItems: 5 });
|
|
assert.deepEqual(
|
|
matches.map((entry) => entry.video.id),
|
|
["video-public"],
|
|
);
|
|
});
|