mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Synchronize modal and card posted timestamps
This commit is contained in:
1 parent
0434401596
commit
f9e2b975d1
3 files changed
+201
-6
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.");
|
||||
Reference in new issue
Block a user