Fix watch history pointer classification

This commit is contained in:
thePR0M3TH3AN committed 2025-09-30 19:52:25 -04:00
1 parent e127c6f58e
commit 5e81bc9aef
2 files changed
+108 -6

No files matched your search

+33 -6
View File
@@ -2579,19 +2579,46 @@ class NostrClient {
? Math.max(1, normalizedBatchSize)
: 1;
const classifyWatchHistoryPointer = (pointer) => {
const classifyWatchHistoryPointer = (pointer, ownerPubkey) => {
if (!pointer || pointer.type !== "a") {
return "none";
}
const [kindStr, pubkey, identifier] = pointer.value.split(":");
const value =
typeof pointer.value === "string" ? pointer.value.trim() : "";
if (!value) {
return "none";
}
const parts = value.split(":");
if (parts.length < 3) {
return "none";
}
const [kindStr, pubkeyRaw, ...identifierParts] = parts;
const kind = Number.parseInt(kindStr, 10);
if (!Number.isFinite(kind) || kind !== WATCH_HISTORY_KIND) {
return "none";
}
if (identifier === WATCH_HISTORY_LIST_IDENTIFIER) {
const identifier = identifierParts.join(":");
const normalizedIdentifier =
typeof identifier === "string" ? identifier.trim() : "";
if (!normalizedIdentifier) {
return "none";
}
const normalizedIdentifierLower = normalizedIdentifier.toLowerCase();
if (normalizedIdentifierLower === WATCH_HISTORY_LIST_IDENTIFIER) {
return "head";
}
if (typeof identifier === "string" && identifier) {
if (!normalizedIdentifierLower.startsWith("watch-history:")) {
return "none";
}
const normalizedOwner =
typeof ownerPubkey === "string" && ownerPubkey.trim()
? ownerPubkey.trim().toLowerCase()
: "";
const normalizedPubkey =
typeof pubkeyRaw === "string" && pubkeyRaw.trim()
? pubkeyRaw.trim().toLowerCase()
: "";
if (!normalizedOwner || !normalizedPubkey || normalizedOwner === normalizedPubkey) {
return "chunk";
}
return "none";
@@ -2628,7 +2655,7 @@ class NostrClient {
if (!pointer) {
continue;
}
const pointerType = classifyWatchHistoryPointer(pointer);
const pointerType = classifyWatchHistoryPointer(pointer, actor);
if (pointerType === "head") {
addPointerToMap(pointer, headPointerMap);
continue;
@@ -2776,7 +2803,7 @@ class NostrClient {
if (!key) {
continue;
}
const pointerType = classifyWatchHistoryPointer(pointer);
const pointerType = classifyWatchHistoryPointer(pointer, actor);
const event = pointerMatches.get(key);
if (pointerType === "chunk" || pointerType === "head") {
if (event) {
+75
View File
@@ -398,6 +398,81 @@ try {
localStorage.clear();
const VIDEO_POINTER_AUTHOR = `${ACTOR}-video-author`;
const VIDEO_POINTER_IDENTIFIER = "pointer-video-identifier";
const videoPointer = {
type: "a",
value: `${WATCH_HISTORY_KIND}:${VIDEO_POINTER_AUTHOR}:${VIDEO_POINTER_IDENTIFIER}`,
relay: null,
};
const pointerClient = createDecryptClient(ACTOR);
const pointerEntry = pointerClient.createWatchHistoryEntry(
null,
[videoPointer],
Date.now()
);
pointerClient.watchHistoryCache.set(ACTOR, pointerEntry);
pointerClient.fetchWatchHistory = async () => {};
const observedResolveFilters = [];
const videoEvent = {
id: "video-pointer-event",
kind: WATCH_HISTORY_KIND,
pubkey: VIDEO_POINTER_AUTHOR,
created_at: 1_700_555_000,
tags: [["d", VIDEO_POINTER_IDENTIFIER]],
content: JSON.stringify({
version: 3,
title: "Pointer Video",
url: "https://cdn.example.com/video.mp4",
}),
};
pointerClient.pool = {
list: async (_relays, filters) => {
observedResolveFilters.push(filters);
return [videoEvent];
},
};
const resolvedFromPointer = await pointerClient.resolveWatchHistory(1);
assert.equal(
resolvedFromPointer.length,
1,
"resolveWatchHistory should return results for 'a' style video pointers"
);
assert.equal(
resolvedFromPointer[0].id,
videoEvent.id,
"resolved video should match the pointer event id"
);
assert.equal(
resolvedFromPointer[0].title,
"Pointer Video",
"resolved video should parse title from the event payload"
);
const pointerKey = `a:${videoPointer.value.trim().toLowerCase()}`;
const cachedEntry = pointerClient.watchHistoryCache.get(ACTOR);
assert(cachedEntry.resolved.has(pointerKey), "resolved cache should retain the video");
assert.equal(
cachedEntry.resolved.get(pointerKey)?.id,
videoEvent.id,
"resolved cache should store the converted video result"
);
assert(
observedResolveFilters.some((filters) =>
filters.some((filter) =>
Array.isArray(filter?.["#d"]) &&
filter["#d"].includes(VIDEO_POINTER_IDENTIFIER)
)
),
"resolveWatchHistory should request the video identifier instead of treating it as a chunk"
);
const originalDateNow = Date.now;
try {
const baseTime = 1_700_000_000_000;