mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Clarify legacy handling comment
This commit is contained in:
1 parent
fea5835a62
commit
d271bd335c
6 files changed
+222
-39
No files matched your search
+46
-12
@@ -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
@@ -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
@@ -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
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: "",
|
||||
|
||||
Reference in new issue
Block a user