Clarify legacy handling comment

This commit is contained in:
thePR0M3TH3AN committed 2025-09-23 13:52:33 -04:00
1 parent fea5835a62
commit d271bd335c
6 files changed
+222 -39

No files matched your search

+46 -12
View File
@@ -5,7 +5,10 @@ import { app } from "./app.js";
import { subscriptions } from "./subscriptions.js"; // <-- NEW import
import { initialBlacklist, initialWhitelist } from "./lists.js";
import { isWhitelistEnabled } from "./config.js";
import { parseVideoEventPayload } from "./videoEventUtils.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
} from "./videoEventUtils.js";
/**
* Initialize the channel profile view.
@@ -473,26 +476,57 @@ function dedupeToNewestByRoot(videos) {
* Convert raw event => "video" object.
*/
function localConvertEventToVideo(event) {
const { parsedContent, parseError, title, url, magnet, version } =
parseVideoEventPayload(event);
const {
parsedContent,
parseError,
title,
url,
magnet,
infoHash,
version,
} = parseVideoEventPayload(event);
if (!title) {
const reason = parseError ? "missing title (json parse error)" : "missing title";
return { id: event.id, invalid: true, reason };
const trimmedUrl = typeof url === "string" ? url.trim() : "";
const trimmedMagnet = typeof magnet === "string" ? magnet.trim() : "";
const trimmedInfoHash = typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet = trimmedMagnet || trimmedInfoHash;
const numericVersion = Number.isFinite(version) ? version : 0;
const hasPlayableSource = Boolean(trimmedUrl) || Boolean(playbackMagnet);
if (!hasPlayableSource) {
return { id: event.id, invalid: true, reason: "missing playable source" };
}
if (!url && !magnet) {
return { id: event.id, invalid: true, reason: "missing playable source" };
const derivedTitle = deriveTitleFromEvent({
parsedContent,
tags: event.tags,
primaryTitle: title,
});
let resolvedTitle = derivedTitle;
if (!resolvedTitle && numericVersion < 2 && playbackMagnet) {
resolvedTitle = trimmedInfoHash
? `Legacy Video ${trimmedInfoHash.slice(0, 8)}`
: "Legacy BitTorrent Video";
}
if (!resolvedTitle) {
const reason = parseError
? "missing title (json parse error)"
: "missing title";
return { id: event.id, invalid: true, reason };
}
return {
id: event.id,
videoRootId: parsedContent.videoRootId || event.id,
version,
version: numericVersion,
isPrivate: parsedContent.isPrivate ?? false,
title,
url,
magnet,
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
infoHash: trimmedInfoHash,
thumbnail: parsedContent.thumbnail ?? "",
description: parsedContent.description ?? "",
mode: parsedContent.mode ?? "live",
+10 -1
View File
@@ -205,7 +205,16 @@ export function normalizeAndAugmentMagnet(
}
}
const finalMagnet = parsed.toString();
let finalMagnet = parsed.toString();
const decodedFinalMagnet = finalMagnet.replace(
ENCODED_BTih_PATTERN,
(_, hash) => `xt=${BTIH_PREFIX}${hash}`
);
if (decodedFinalMagnet !== finalMagnet) {
finalMagnet = decodedFinalMagnet;
didMutate = true;
}
return {
magnet: finalMagnet,
didChange: didMutate || finalMagnet !== initial,
+33 -11
View File
@@ -2,7 +2,10 @@
import { isDevMode } from "./config.js";
import { accessControl } from "./accessControl.js";
import { parseVideoEventPayload } from "./videoEventUtils.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
} from "./videoEventUtils.js";
/**
* The usual relays
@@ -88,7 +91,7 @@ function inferMimeTypeFromUrl(url) {
/**
* Convert a raw Nostr event => your "video" object.
* CHANGED: skip if version <2
* Accepts legacy (<2) payloads when they expose a usable magnet/info hash.
*/
function convertEventToVideo(event) {
const {
@@ -101,16 +104,15 @@ function convertEventToVideo(event) {
version,
} = parseVideoEventPayload(event);
if (!title) {
const reason = parseError ? "missing title (json parse error)" : "missing title";
return { id: event.id, invalid: true, reason };
}
const trimmedUrl = typeof url === "string" ? url.trim() : "";
const trimmedMagnet = typeof magnet === "string" ? magnet.trim() : "";
const trimmedInfoHash = typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet = trimmedMagnet || trimmedInfoHash;
if (!url && !playbackMagnet) {
const numericVersion = Number.isFinite(version) ? version : 0;
const hasPlayableSource = Boolean(trimmedUrl) || Boolean(playbackMagnet);
if (!hasPlayableSource) {
return {
id: event.id,
invalid: true,
@@ -118,13 +120,33 @@ function convertEventToVideo(event) {
};
}
const derivedTitle = deriveTitleFromEvent({
parsedContent,
tags: event.tags,
primaryTitle: title,
});
let resolvedTitle = derivedTitle;
if (!resolvedTitle && numericVersion < 2 && playbackMagnet) {
resolvedTitle = trimmedInfoHash
? `Legacy Video ${trimmedInfoHash.slice(0, 8)}`
: "Legacy BitTorrent Video";
}
if (!resolvedTitle) {
const reason = parseError
? "missing title (json parse error)"
: "missing title";
return { id: event.id, invalid: true, reason };
}
return {
id: event.id,
videoRootId: parsedContent.videoRootId || event.id,
version,
version: numericVersion,
isPrivate: parsedContent.isPrivate ?? false,
title,
url,
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
infoHash: trimmedInfoHash,
+49 -15
View File
@@ -1,6 +1,9 @@
// js/subscriptions.js
import { nostrClient } from "./nostr.js";
import { parseVideoEventPayload } from "./videoEventUtils.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
} from "./videoEventUtils.js";
/**
* Manages the user's subscription list (kind=30002) *privately*,
@@ -501,18 +504,24 @@ class SubscriptionsManager {
}
convertEventToVideo(evt) {
const { parsedContent, parseError, title, url, magnet, version } =
parseVideoEventPayload(evt);
const {
parsedContent,
parseError,
title,
url,
magnet,
infoHash,
version,
} = parseVideoEventPayload(evt);
if (!title) {
return {
id: evt.id,
invalid: true,
reason: parseError ? "missing title (json parse error)" : "missing title",
};
}
const trimmedUrl = typeof url === "string" ? url.trim() : "";
const trimmedMagnet = typeof magnet === "string" ? magnet.trim() : "";
const trimmedInfoHash = typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet = trimmedMagnet || trimmedInfoHash;
const numericVersion = Number.isFinite(version) ? version : 0;
if (!url && !magnet) {
const hasPlayableSource = Boolean(trimmedUrl) || Boolean(playbackMagnet);
if (!hasPlayableSource) {
return {
id: evt.id,
invalid: true,
@@ -520,17 +529,42 @@ class SubscriptionsManager {
};
}
const derivedTitle = deriveTitleFromEvent({
parsedContent,
tags: evt.tags,
primaryTitle: title,
});
let resolvedTitle = derivedTitle;
if (!resolvedTitle && numericVersion < 2 && playbackMagnet) {
resolvedTitle = trimmedInfoHash
? `Legacy Video ${trimmedInfoHash.slice(0, 8)}`
: "Legacy BitTorrent Video";
}
if (!resolvedTitle) {
return {
id: evt.id,
invalid: true,
reason: parseError
? "missing title (json parse error)"
: "missing title",
};
}
return {
id: evt.id,
pubkey: evt.pubkey,
created_at: evt.created_at,
videoRootId: parsedContent.videoRootId || evt.id,
version,
version: numericVersion,
deleted: parsedContent.deleted === true,
isPrivate: parsedContent.isPrivate ?? false,
title,
url,
magnet,
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
infoHash: trimmedInfoHash,
thumbnail: parsedContent.thumbnail ?? "",
description: parsedContent.description ?? "",
mode: parsedContent.mode ?? "live",
+67
View File
@@ -7,6 +7,73 @@
const MAGNET_URI_PATTERN = /^magnet:\?/i;
const HEX_INFO_HASH_PATTERN = /\b[0-9a-f]{40}\b/gi;
function safeTrim(value) {
return typeof value === "string" ? value.trim() : "";
}
function pickFirstString(values = []) {
if (!Array.isArray(values)) {
return "";
}
for (const value of values) {
const trimmed = safeTrim(value);
if (trimmed) {
return trimmed;
}
}
return "";
}
export function deriveTitleFromEvent({
parsedContent = {},
tags = [],
primaryTitle = "",
} = {}) {
const initial = safeTrim(primaryTitle);
if (initial) {
return initial;
}
const directCandidates = pickFirstString([
parsedContent?.title,
parsedContent?.name,
parsedContent?.filename,
parsedContent?.fileName,
parsedContent?.subject,
parsedContent?.caption,
]);
if (directCandidates) {
return directCandidates;
}
const metaTitle = safeTrim(parsedContent?.meta?.title);
if (metaTitle) {
return metaTitle;
}
if (Array.isArray(tags)) {
for (const tag of tags) {
if (!Array.isArray(tag) || tag.length < 2) {
continue;
}
const key = safeTrim(tag[0]).toLowerCase();
if (!key) {
continue;
}
if (["title", "subject", "caption", "name"].includes(key)) {
const candidate = safeTrim(tag[1]);
if (candidate) {
return candidate;
}
}
}
}
return "";
}
function extractInfoHashesFromString(value, pushInfoHash) {
if (typeof value !== "string") {
return;
+17
View File
@@ -64,6 +64,23 @@ const LEGACY_INFO_HASH = "0123456789abcdef0123456789abcdef01234567";
assert.equal(video.rawMagnet, "");
})();
(function testLegacyEventWithoutTitleStillLoads() {
const event = {
id: "evt-no-title",
pubkey: "pk2",
created_at: 2,
tags: [],
content: JSON.stringify({
version: 1,
magnet: `magnet:?xt=urn:btih:${LEGACY_INFO_HASH}`,
}),
};
const video = convertEventToVideo(event);
assert.equal(video.invalid, false, "Legacy events without title should fallback");
assert.ok(video.title && video.title.length > 0, "Fallback title should be provided");
})();
(function testPlaybackConfigNormalizesInfoHash() {
const result = deriveTorrentPlaybackConfig({
magnet: "",