mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-29 17:02:28 +00:00
feat: prioritize video root pointer for view tracking
This commit is contained in:
1 parent
e9ec0b790e
commit
0addd59226
3 files changed
+144
-70
No files matched your search
@@ -71,6 +71,7 @@ import ProfileModalController from "./ui/profileModalController.js";
|
||||
import ZapController from "./ui/zapController.js";
|
||||
import { MediaLoader } from "./utils/mediaLoader.js";
|
||||
import { pointerArrayToKey } from "./utils/pointer.js";
|
||||
import { resolveVideoPointer } from "./utils/videoPointer.js";
|
||||
import { isValidMagnetUri } from "./utils/magnetValidators.js";
|
||||
import { dedupeToNewestByRoot } from "./utils/videoDeduper.js";
|
||||
import {
|
||||
@@ -1309,34 +1310,14 @@ class Application {
|
||||
}
|
||||
|
||||
const dTagValue = (this.extractDTagValue(video.tags) || "").trim();
|
||||
const normalizedPubkey =
|
||||
typeof video.pubkey === "string" ? video.pubkey.trim() : "";
|
||||
const kind =
|
||||
typeof video.kind === "number" && Number.isFinite(video.kind)
|
||||
? video.kind
|
||||
: VIDEO_EVENT_KIND;
|
||||
|
||||
if (dTagValue && normalizedPubkey) {
|
||||
const pointer = ["a", `${kind}:${normalizedPubkey}:${dTagValue}`];
|
||||
const key = pointerArrayToKey(pointer);
|
||||
if (key) {
|
||||
return { pointer, key };
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackId =
|
||||
typeof video.id === "string" && video.id.trim()
|
||||
? video.id.trim()
|
||||
: "";
|
||||
if (fallbackId) {
|
||||
const pointer = ["e", fallbackId];
|
||||
const key = pointerArrayToKey(pointer);
|
||||
if (key) {
|
||||
return { pointer, key };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return resolveVideoPointer({
|
||||
kind: video.kind,
|
||||
pubkey: video.pubkey,
|
||||
videoRootId: video.videoRootId,
|
||||
dTag: dTagValue,
|
||||
fallbackEventId: video.id,
|
||||
});
|
||||
}
|
||||
|
||||
formatViewCountLabel(total) {
|
||||
@@ -6257,50 +6238,16 @@ class Application {
|
||||
};
|
||||
|
||||
const dTagValue = (this.extractDTagValue(video.tags) || "").trim();
|
||||
const normalizedPubkey =
|
||||
typeof video.pubkey === "string" ? video.pubkey.trim() : "";
|
||||
const primaryPointer =
|
||||
dTagValue && normalizedPubkey
|
||||
? [
|
||||
"a",
|
||||
`${
|
||||
typeof video.kind === "number" && Number.isFinite(video.kind)
|
||||
? video.kind
|
||||
: 30078
|
||||
}:${normalizedPubkey}:${dTagValue}`,
|
||||
]
|
||||
: null;
|
||||
const fallbackId =
|
||||
typeof (video.id || eventId) === "string"
|
||||
? (video.id || eventId).trim()
|
||||
: "";
|
||||
const fallbackPointer = fallbackId ? ["e", fallbackId] : null;
|
||||
const pointerInfo = resolveVideoPointer({
|
||||
kind: video.kind,
|
||||
pubkey: video.pubkey,
|
||||
videoRootId: video.videoRootId,
|
||||
dTag: dTagValue,
|
||||
fallbackEventId: video.id || eventId,
|
||||
});
|
||||
|
||||
let resolvedPointer = null;
|
||||
let resolvedPointerKey = "";
|
||||
const pointerCandidates = [];
|
||||
if (primaryPointer) {
|
||||
pointerCandidates.push(primaryPointer);
|
||||
}
|
||||
if (fallbackPointer) {
|
||||
pointerCandidates.push(fallbackPointer);
|
||||
}
|
||||
|
||||
for (const candidate of pointerCandidates) {
|
||||
const key = pointerArrayToKey(candidate);
|
||||
if (key) {
|
||||
resolvedPointer = candidate;
|
||||
resolvedPointerKey = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.currentVideoPointer = resolvedPointer && resolvedPointerKey
|
||||
? resolvedPointer
|
||||
: null;
|
||||
this.currentVideoPointerKey = this.currentVideoPointer
|
||||
? resolvedPointerKey
|
||||
: null;
|
||||
this.currentVideoPointer = pointerInfo?.pointer || null;
|
||||
this.currentVideoPointerKey = pointerInfo?.key || null;
|
||||
|
||||
if (this.currentVideo) {
|
||||
this.currentVideo.pointer = this.currentVideoPointer;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// js/utils/videoPointer.js
|
||||
|
||||
import { pointerArrayToKey } from "./pointer.js";
|
||||
|
||||
const DEFAULT_VIDEO_KIND = 30078;
|
||||
|
||||
function normalizeString(value) {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
export function resolveVideoPointer({
|
||||
kind,
|
||||
pubkey,
|
||||
videoRootId,
|
||||
dTag,
|
||||
fallbackEventId,
|
||||
} = {}) {
|
||||
const normalizedPubkey = normalizeString(pubkey).toLowerCase();
|
||||
const normalizedKind =
|
||||
typeof kind === "number" && Number.isFinite(kind) ? kind : DEFAULT_VIDEO_KIND;
|
||||
const pointerCandidates = [];
|
||||
|
||||
const rootId = normalizeString(videoRootId);
|
||||
if (rootId && normalizedPubkey) {
|
||||
pointerCandidates.push(["a", `${normalizedKind}:${normalizedPubkey}:${rootId}`]);
|
||||
}
|
||||
|
||||
const normalizedDTag = normalizeString(dTag);
|
||||
if (normalizedDTag && normalizedPubkey) {
|
||||
pointerCandidates.push([
|
||||
"a",
|
||||
`${normalizedKind}:${normalizedPubkey}:${normalizedDTag}`,
|
||||
]);
|
||||
}
|
||||
|
||||
const fallbackId = normalizeString(fallbackEventId);
|
||||
if (fallbackId) {
|
||||
pointerCandidates.push(["e", fallbackId]);
|
||||
}
|
||||
|
||||
for (const pointer of pointerCandidates) {
|
||||
const key = pointerArrayToKey(pointer);
|
||||
if (key) {
|
||||
return { pointer, key };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default resolveVideoPointer;
|
||||
@@ -47,6 +47,14 @@ if (!globalThis.window.NostrTools) {
|
||||
globalThis.window.NostrTools = {};
|
||||
}
|
||||
|
||||
if (typeof globalThis.window.NostrTools.getEventHash !== "function") {
|
||||
globalThis.window.NostrTools.getEventHash = () => "test-event-hash";
|
||||
}
|
||||
|
||||
if (typeof globalThis.window.NostrTools.signEvent !== "function") {
|
||||
globalThis.window.NostrTools.signEvent = () => "test-event-sig";
|
||||
}
|
||||
|
||||
setNostrEventSchemaOverrides({});
|
||||
|
||||
const canonicalViewEvent = buildViewEvent({
|
||||
@@ -275,11 +283,79 @@ const {
|
||||
unsubscribeFromVideoViewCount,
|
||||
ingestLocalViewEvent,
|
||||
} = await import("../js/viewCounter.js");
|
||||
const { resolveVideoPointer } = await import("../js/utils/videoPointer.js");
|
||||
|
||||
initViewCounter({ nostrClient });
|
||||
|
||||
const flushPromises = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
function testPointerPrefersVideoRootId() {
|
||||
const info = resolveVideoPointer({
|
||||
pubkey: "ABCDEF1234",
|
||||
videoRootId: "ROOT-POINTER",
|
||||
dTag: "legacy-d-tag",
|
||||
fallbackEventId: "event-fallback",
|
||||
kind: 30078,
|
||||
});
|
||||
|
||||
assert.ok(info, "expected pointer info for root-backed video");
|
||||
assert.deepEqual(
|
||||
info.pointer,
|
||||
["a", "30078:abcdef1234:ROOT-POINTER"],
|
||||
"videos with a videoRootId should resolve to the root pointer"
|
||||
);
|
||||
assert.equal(
|
||||
info.key,
|
||||
"a:30078:abcdef1234:root-pointer",
|
||||
"root pointer key should be normalized for view counter lookups"
|
||||
);
|
||||
}
|
||||
|
||||
function testPointerFallsBackToDTag() {
|
||||
const info = resolveVideoPointer({
|
||||
pubkey: "ABCDEF1234",
|
||||
dTag: "legacy-pointer",
|
||||
fallbackEventId: "event-fallback",
|
||||
kind: 30078,
|
||||
});
|
||||
|
||||
assert.ok(info, "expected pointer info when only d-tag is present");
|
||||
assert.deepEqual(
|
||||
info.pointer,
|
||||
["a", "30078:abcdef1234:legacy-pointer"],
|
||||
"videos without a root should fall back to the d-tag pointer"
|
||||
);
|
||||
assert.equal(
|
||||
info.key,
|
||||
"a:30078:abcdef1234:legacy-pointer",
|
||||
"d-tag pointer key should match the normalized value"
|
||||
);
|
||||
}
|
||||
|
||||
function testPointerFallsBackToEventId() {
|
||||
const info = resolveVideoPointer({
|
||||
pubkey: "ABCDEF1234",
|
||||
fallbackEventId: "legacy-event-id",
|
||||
kind: 30078,
|
||||
});
|
||||
|
||||
assert.ok(info, "expected pointer info when only event id is present");
|
||||
assert.deepEqual(
|
||||
info.pointer,
|
||||
["e", "legacy-event-id"],
|
||||
"videos without root or d-tag should fall back to the event pointer"
|
||||
);
|
||||
assert.equal(
|
||||
info.key,
|
||||
"e:legacy-event-id",
|
||||
"event pointer key should normalize correctly"
|
||||
);
|
||||
}
|
||||
|
||||
testPointerPrefersVideoRootId();
|
||||
testPointerFallsBackToDTag();
|
||||
testPointerFallsBackToEventId();
|
||||
|
||||
async function testDedupesWithinWindow() {
|
||||
localStorage.clear();
|
||||
harness.reset();
|
||||
|
||||
Reference in new issue
Block a user