Fix magnet dataset handling and legacy fallback

This commit is contained in:
thePR0M3TH3AN committed 2025-09-24 12:38:59 -04:00
1 parent 873d1065e4
commit 3593fdd0ef
5 files changed
+117 -45

No files matched your search

+27 -16
View File
@@ -720,12 +720,19 @@ class bitvidApp {
}
};
const encodedUrl = trigger.getAttribute("data-play-url") || "";
const encodedMagnet = trigger.getAttribute("data-play-magnet") || "";
const rawUrlValue =
(trigger.dataset && typeof trigger.dataset.playUrl === "string"
? trigger.dataset.playUrl
: null) ?? trigger.getAttribute("data-play-url") ?? "";
const rawMagnetValue =
(trigger.dataset && typeof trigger.dataset.playMagnet === "string"
? trigger.dataset.playMagnet
: null) ?? trigger.getAttribute("data-play-magnet") ?? "";
const url = decodeDataValue(encodedUrl);
const rawMagnet = decodeDataValue(encodedMagnet);
const magnet = safeDecodeMagnet(rawMagnet) || rawMagnet;
const url = decodeDataValue(rawUrlValue);
const decodedMagnetValue = decodeDataValue(rawMagnetValue);
const magnet =
safeDecodeMagnet(decodedMagnetValue) || decodedMagnetValue;
const eventId = trigger.getAttribute("data-video-id");
if (eventId) {
@@ -1365,11 +1372,6 @@ class bitvidApp {
const authorSet = new Set();
// 3) Build each card
const encodeDataValue = (value) =>
typeof value === "string" && value.length > 0
? encodeURIComponent(value)
: "";
videos.forEach((video, index) => {
if (!video.id || !video.title) {
console.error("Video missing ID/title:", video);
@@ -1452,8 +1454,8 @@ class bitvidApp {
const magnetCandidate = trimmedMagnet || legacyInfoHash;
const magnetSupported = isValidMagnetUri(magnetCandidate);
const magnetProvided = magnetCandidate.length > 0;
const encodedMagnet = encodeDataValue(magnetCandidate);
const encodedUrl = encodeDataValue(trimmedUrl);
const playbackUrl = trimmedUrl;
const playbackMagnet = magnetCandidate;
const showUnsupportedTorrentBadge =
!trimmedUrl && magnetProvided && !magnetSupported;
const torrentBadge = showUnsupportedTorrentBadge
@@ -1474,8 +1476,8 @@ class bitvidApp {
<a
href="${shareUrl}"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
data-torrent-supported="${magnetSupported ? "true" : "false"}"
class="block cursor-pointer relative group"
>
@@ -1492,8 +1494,8 @@ class bitvidApp {
<h3
class="text-lg font-bold text-white line-clamp-2 hover:text-blue-400 cursor-pointer mb-3"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
data-torrent-supported="${magnetSupported ? "true" : "false"}"
>
${this.escapeHTML(video.title)}
@@ -1537,6 +1539,15 @@ class bitvidApp {
} else if (magnetProvided && magnetSupported) {
cardEl.dataset.torrentSupported = "true";
}
const interactiveEls = cardEl.querySelectorAll("[data-video-id]");
interactiveEls.forEach((el) => {
if (!el.dataset) return;
el.dataset.playUrl = playbackUrl || "";
el.dataset.playMagnet = playbackMagnet || "";
if (magnetProvided) {
el.dataset.torrentSupported = magnetSupported ? "true" : "false";
}
});
}
fragment.appendChild(cardEl);
});
+21 -13
View File
@@ -8,6 +8,7 @@ import { isWhitelistEnabled } from "./config.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
findLegacyMagnetInEvent,
} from "./videoEventUtils.js";
/**
@@ -244,11 +245,6 @@ async function loadUserVideos(pubkey) {
const fragment = document.createDocumentFragment();
const allKnownEventsArray = Array.from(nostrClient.allEvents.values());
const encodeDataValue = (value) =>
typeof value === "string" && value.length > 0
? encodeURIComponent(value)
: "";
videos.forEach((video, index) => {
// Decrypt if user owns a private video
if (
@@ -349,15 +345,16 @@ async function loadUserVideos(pubkey) {
const legacyInfoHash =
typeof video.infoHash === "string" ? video.infoHash.trim() : "";
const magnetCandidate = trimmedMagnet || legacyInfoHash;
const encodedUrl = encodeDataValue(video.url);
const encodedMagnet = encodeDataValue(magnetCandidate);
const playbackUrl =
typeof video.url === "string" ? video.url : "";
const playbackMagnet = magnetCandidate || "";
cardEl.innerHTML = `
<div
class="cursor-pointer relative group"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
>
<div class="ratio-16-9">
<img
@@ -372,8 +369,8 @@ async function loadUserVideos(pubkey) {
<h3
class="text-lg font-bold text-white mb-2 line-clamp-2"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
>
${safeTitle}
</h3>
@@ -385,6 +382,13 @@ async function loadUserVideos(pubkey) {
</div>
`;
const interactiveEls = cardEl.querySelectorAll("[data-video-id]");
interactiveEls.forEach((el) => {
if (!el.dataset) return;
el.dataset.playUrl = playbackUrl || "";
el.dataset.playMagnet = playbackMagnet || "";
});
fragment.appendChild(cardEl);
});
@@ -488,8 +492,12 @@ function localConvertEventToVideo(event) {
const trimmedUrl = typeof url === "string" ? url.trim() : "";
const trimmedMagnet = typeof magnet === "string" ? magnet.trim() : "";
const legacyMagnet = findLegacyMagnetInEvent(event);
const trimmedLegacyMagnet =
typeof legacyMagnet === "string" ? legacyMagnet.trim() : "";
const trimmedInfoHash = typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet = trimmedMagnet || trimmedInfoHash;
const playbackMagnet =
trimmedMagnet || trimmedLegacyMagnet || trimmedInfoHash;
const parsedVersion =
typeof version === "number"
? version
@@ -533,7 +541,7 @@ function localConvertEventToVideo(event) {
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
rawMagnet: trimmedMagnet || trimmedLegacyMagnet,
infoHash: trimmedInfoHash,
thumbnail: parsedContent.thumbnail ?? "",
description: parsedContent.description ?? "",
+7 -2
View File
@@ -5,6 +5,7 @@ import { accessControl } from "./accessControl.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
findLegacyMagnetInEvent,
} from "./videoEventUtils.js";
/**
@@ -106,8 +107,12 @@ function convertEventToVideo(event) {
const trimmedUrl = typeof url === "string" ? url.trim() : "";
const trimmedMagnet = typeof magnet === "string" ? magnet.trim() : "";
const legacyMagnet = findLegacyMagnetInEvent(event);
const trimmedLegacyMagnet =
typeof legacyMagnet === "string" ? legacyMagnet.trim() : "";
const trimmedInfoHash = typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet = trimmedMagnet || trimmedInfoHash;
const playbackMagnet =
trimmedMagnet || trimmedLegacyMagnet || trimmedInfoHash;
const numericVersion = Number.isFinite(version) ? version : 0;
const hasPlayableSource = Boolean(trimmedUrl) || Boolean(playbackMagnet);
@@ -148,7 +153,7 @@ function convertEventToVideo(event) {
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
rawMagnet: trimmedMagnet || trimmedLegacyMagnet,
infoHash: trimmedInfoHash,
thumbnail: parsedContent.thumbnail ?? "",
description: parsedContent.description ?? "",
+25 -14
View File
@@ -3,6 +3,7 @@ import { nostrClient } from "./nostr.js";
import {
deriveTitleFromEvent,
parseVideoEventPayload,
findLegacyMagnetInEvent,
} from "./videoEventUtils.js";
/**
@@ -254,11 +255,6 @@ class SubscriptionsManager {
// Only declare localAuthorSet once
const localAuthorSet = new Set();
const encodeDataValue = (value) =>
typeof value === "string" && value.length > 0
? encodeURIComponent(value)
: "";
videos.forEach((video, index) => {
if (!video.id || !video.title) {
console.error("Missing ID or title:", video);
@@ -342,15 +338,17 @@ class SubscriptionsManager {
const safeTitle = window.app?.escapeHTML(video.title) || "Untitled";
const safeThumb = window.app?.escapeHTML(video.thumbnail) || "";
const encodedMagnet = encodeDataValue(video.magnet);
const encodedUrl = encodeDataValue(video.url);
const playbackUrl =
typeof video.url === "string" ? video.url : "";
const playbackMagnet =
typeof video.magnet === "string" ? video.magnet : "";
const cardHtml = `
<div class="video-card bg-gray-900 rounded-lg overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 ${highlightClass}">
<a
href="${shareUrl}"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
class="block cursor-pointer relative group"
>
<div class="ratio-16-9">
@@ -365,8 +363,8 @@ class SubscriptionsManager {
<h3
class="text-lg font-bold text-white line-clamp-2 hover:text-blue-400 cursor-pointer mb-3"
data-video-id="${video.id}"
data-play-url="${encodedUrl}"
data-play-magnet="${encodedMagnet}"
data-play-url=""
data-play-magnet=""
>
${safeTitle}
</h3>
@@ -401,6 +399,14 @@ class SubscriptionsManager {
const t = document.createElement("template");
t.innerHTML = cardHtml.trim();
const cardEl = t.content.firstElementChild;
if (cardEl) {
const interactiveEls = cardEl.querySelectorAll("[data-video-id]");
interactiveEls.forEach((el) => {
if (!el.dataset) return;
el.dataset.playUrl = playbackUrl || "";
el.dataset.playMagnet = playbackMagnet || "";
});
}
fragment.appendChild(cardEl);
});
@@ -516,8 +522,13 @@ class SubscriptionsManager {
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 legacyMagnet = findLegacyMagnetInEvent(evt);
const trimmedLegacyMagnet =
typeof legacyMagnet === "string" ? legacyMagnet.trim() : "";
const trimmedInfoHash =
typeof infoHash === "string" ? infoHash.trim() : "";
const playbackMagnet =
trimmedMagnet || trimmedLegacyMagnet || trimmedInfoHash;
const parsedVersion =
typeof version === "number"
? version
@@ -571,7 +582,7 @@ class SubscriptionsManager {
title: resolvedTitle,
url: trimmedUrl,
magnet: playbackMagnet,
rawMagnet: trimmedMagnet,
rawMagnet: trimmedMagnet || trimmedLegacyMagnet,
infoHash: trimmedInfoHash,
thumbnail: parsedContent.thumbnail ?? "",
description: parsedContent.description ?? "",
+37
View File
@@ -6,6 +6,7 @@
*/
const MAGNET_URI_PATTERN = /^magnet:\?/i;
const HEX_INFO_HASH_PATTERN = /\b[0-9a-f]{40}\b/gi;
const LEGACY_MAGNET_PATTERN = /magnet:\?xt=urn:btih:[0-9a-z]{40,}[^\s"'<>]*/i;
function safeTrim(value) {
return typeof value === "string" ? value.trim() : "";
@@ -251,3 +252,39 @@ export function parseVideoEventPayload(event = {}) {
version,
};
}
function magnetFromText(value) {
if (typeof value !== "string") {
return "";
}
const match = value.match(LEGACY_MAGNET_PATTERN);
return match ? match[0] : "";
}
export function findLegacyMagnetInEvent(event = {}) {
const fromContent = magnetFromText(event?.content);
if (fromContent) {
return fromContent.trim();
}
const tags = Array.isArray(event?.tags) ? event.tags : [];
for (const tag of tags) {
if (!Array.isArray(tag) || tag.length < 2) {
continue;
}
const key = typeof tag[0] === "string" ? tag[0].trim().toLowerCase() : "";
const value = typeof tag[1] === "string" ? tag[1].trim() : "";
if (!value) {
continue;
}
if (key === "magnet" && value) {
return value;
}
const fromTag = magnetFromText(value);
if (fromTag) {
return fromTag.trim();
}
}
return "";
}