Synchronize modal and card posted timestamps

This commit is contained in:
thePR0M3TH3AN committed 2025-10-08 21:35:26 -04:00
1 parent 0434401596
commit f9e2b975d1
3 files changed
+201 -6

No files matched your search

+21 -6
View File
@@ -74,6 +74,11 @@ 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 {
getVideoRootIdentifier,
applyRootTimestampToVideosMap,
syncActiveVideoRootTimestamp,
} from "./utils/videoTimestamps.js";
import {
getPubkey as getStoredPubkey,
setPubkey as setStoredPubkey,
@@ -6432,17 +6437,27 @@ class Application {
}
const normalized = Math.floor(timestamp);
const rootId = getVideoRootIdentifier(video);
if (video && typeof video === "object") {
video.rootCreatedAt = normalized;
}
if (video?.id && this.videosMap instanceof Map) {
const existing = this.videosMap.get(video.id);
if (existing && typeof existing === "object") {
existing.rootCreatedAt = normalized;
}
}
applyRootTimestampToVideosMap({
videosMap: this.videosMap,
video,
rootId,
timestamp: normalized,
});
syncActiveVideoRootTimestamp({
activeVideo: this.currentVideo,
rootId,
timestamp: normalized,
buildModalTimestampPayload: (payload) =>
this.buildModalTimestampPayload(payload),
videoModal: this.videoModal,
});
if (nostrClient && typeof nostrClient.applyRootCreatedAt === "function") {
try {
+102
View File
@@ -0,0 +1,102 @@
export function getVideoRootIdentifier(video) {
if (!video || typeof video !== "object") {
return "";
}
if (typeof video.videoRootId === "string" && video.videoRootId) {
return video.videoRootId;
}
if (typeof video.id === "string" && video.id) {
return video.id;
}
return "";
}
export function applyRootTimestampToVideosMap({
videosMap,
video,
rootId = "",
timestamp,
}) {
if (!(videosMap instanceof Map)) {
return;
}
if (video?.id) {
const existing = videosMap.get(video.id);
if (existing && typeof existing === "object") {
existing.rootCreatedAt = timestamp;
}
}
if (!rootId) {
return;
}
for (const stored of videosMap.values()) {
if (!stored || typeof stored !== "object") {
continue;
}
if (stored === video) {
continue;
}
const storedRootId = getVideoRootIdentifier(stored);
if (storedRootId && storedRootId === rootId) {
stored.rootCreatedAt = timestamp;
}
}
}
export function syncActiveVideoRootTimestamp({
activeVideo,
rootId = "",
timestamp = null,
buildModalTimestampPayload,
videoModal,
}) {
if (!Number.isFinite(timestamp)) {
return false;
}
const normalized = Math.floor(timestamp);
if (!activeVideo || typeof activeVideo !== "object") {
return false;
}
const activeRootId = getVideoRootIdentifier(activeVideo);
if (!activeRootId) {
return false;
}
if (rootId && activeRootId !== rootId) {
return false;
}
if (activeVideo.rootCreatedAt === normalized) {
return false;
}
activeVideo.rootCreatedAt = normalized;
const editedAt = Number.isFinite(activeVideo.lastEditedAt)
? Math.floor(activeVideo.lastEditedAt)
: Number.isFinite(activeVideo.created_at)
? Math.floor(activeVideo.created_at)
: null;
if (
typeof buildModalTimestampPayload === "function" &&
videoModal &&
typeof videoModal.updateMetadata === "function"
) {
const payload = buildModalTimestampPayload({
postedAt: normalized,
editedAt,
});
videoModal.updateMetadata({ timestamps: payload });
}
return true;
}
+78
View File
@@ -284,6 +284,11 @@ const {
ingestLocalViewEvent,
} = await import("../js/viewCounter.js");
const { resolveVideoPointer } = await import("../js/utils/videoPointer.js");
const {
getVideoRootIdentifier,
applyRootTimestampToVideosMap,
syncActiveVideoRootTimestamp,
} = await import("../js/utils/videoTimestamps.js");
initViewCounter({ nostrClient });
@@ -863,6 +868,78 @@ async function testHydrateHistoryPrefersRootEvent() {
}
}
async function testModalPostedTimestampStaysInSync() {
const videosMap = new Map();
const currentVideo = {
id: "latest-edit",
videoRootId: "root-event-note",
created_at: 260,
lastEditedAt: 260,
};
const storedVideo = { id: "latest-edit", videoRootId: "root-event-note" };
videosMap.set(storedVideo.id, storedVideo);
const incomingVideo = { ...currentVideo };
const rootId = getVideoRootIdentifier(incomingVideo);
const timestamp = 100;
applyRootTimestampToVideosMap({
videosMap,
video: incomingVideo,
rootId,
timestamp,
});
assert.equal(
storedVideo.rootCreatedAt,
timestamp,
"videosMap entries that share the root should receive the cached timestamp",
);
const modalUpdates = [];
const videoModal = {
updateMetadata: ({ timestamps }) => {
if (timestamps) {
modalUpdates.push({ ...timestamps });
}
},
};
const buildModalTimestampPayload = ({ postedAt, editedAt }) => ({
posted: postedAt !== null ? `Posted time-${postedAt}` : "",
edited: editedAt !== null ? `Last edited time-${editedAt}` : "",
});
const updated = syncActiveVideoRootTimestamp({
activeVideo: currentVideo,
rootId,
timestamp,
buildModalTimestampPayload,
videoModal,
});
assert.ok(updated, "syncActiveVideoRootTimestamp should record the new root time");
assert.equal(
currentVideo.rootCreatedAt,
timestamp,
"current video should stay aligned with the cached root timestamp",
);
const lastModalUpdate = modalUpdates.at(-1);
assert.ok(lastModalUpdate, "video modal should receive a timestamp update");
assert.equal(
lastModalUpdate.posted,
"Posted time-100",
"modal posted label should reflect the root timestamp",
);
assert.equal(
lastModalUpdate.edited,
"Last edited time-260",
"modal edited label should continue to show the latest edit time",
);
}
await testHydrationRefreshesAfterCacheTtl();
await testDedupesWithinWindow();
await testHydrationSkipsStaleEventsAndRollsOff();
@@ -871,5 +948,6 @@ await testUnsubscribeStopsCallbacks();
await testRelayCountAggregationUsesBestEstimate();
await testRecordVideoViewEmitsJsonPayload();
await testHydrateHistoryPrefersRootEvent();
await testModalPostedTimestampStaysInSync();
console.log("View counter tests completed successfully.");