diff --git a/js/feedEngine/watchHistoryFeed.js b/js/feedEngine/watchHistoryFeed.js index 098b1ea8..dc788062 100644 --- a/js/feedEngine/watchHistoryFeed.js +++ b/js/feedEngine/watchHistoryFeed.js @@ -195,8 +195,19 @@ function createWatchHistorySource({ service = watchHistoryService } = {}) { } results.sort((a, b) => { - if (a.watchedAt !== b.watchedAt) { - return b.watchedAt - a.watchedAt; + const watchedA = a?.watchedAt || 0; + const watchedB = b?.watchedAt || 0; + if (watchedA !== watchedB) { + return watchedB - watchedA; + } + const createdA = Number.isFinite(a?.video?.created_at) + ? a.video.created_at + : 0; + const createdB = Number.isFinite(b?.video?.created_at) + ? b.video.created_at + : 0; + if (createdA !== createdB) { + return createdB - createdA; } return a.pointerKey.localeCompare(b.pointerKey); }); @@ -488,8 +499,19 @@ function createWatchHistorySorter() { } const copy = [...items]; copy.sort((a, b) => { - if (a?.watchedAt !== b?.watchedAt) { - return (b?.watchedAt || 0) - (a?.watchedAt || 0); + const watchedA = a?.watchedAt || 0; + const watchedB = b?.watchedAt || 0; + if (watchedA !== watchedB) { + return watchedB - watchedA; + } + const createdA = Number.isFinite(a?.video?.created_at) + ? a.video.created_at + : 0; + const createdB = Number.isFinite(b?.video?.created_at) + ? b.video.created_at + : 0; + if (createdA !== createdB) { + return createdB - createdA; } const aKey = typeof a?.pointerKey === "string" ? a.pointerKey : ""; const bKey = typeof b?.pointerKey === "string" ? b.pointerKey : ""; diff --git a/js/historyView.js b/js/historyView.js index dfec3d96..5a832a14 100644 --- a/js/historyView.js +++ b/js/historyView.js @@ -240,6 +240,15 @@ function normalizeHistoryItems(rawItems) { if (a.watchedAt !== b.watchedAt) { return b.watchedAt - a.watchedAt; } + const createdA = Number.isFinite(a?.video?.created_at) + ? a.video.created_at + : 0; + const createdB = Number.isFinite(b?.video?.created_at) + ? b.video.created_at + : 0; + if (createdA !== createdB) { + return createdB - createdA; + } return a.pointerKey.localeCompare(b.pointerKey); }); return normalized; diff --git a/js/nostr/watchHistory.js b/js/nostr/watchHistory.js index b1ac8a68..4d06982b 100644 --- a/js/nostr/watchHistory.js +++ b/js/nostr/watchHistory.js @@ -526,7 +526,11 @@ async function computeWatchHistoryFingerprintForItems(itemsOrBuckets) { if (Array.isArray(itemsOrBuckets)) { flatItems = itemsOrBuckets; } else if (itemsOrBuckets && typeof itemsOrBuckets === "object") { - flatItems = Object.values(itemsOrBuckets).flat(); + flatItems = Object.keys(itemsOrBuckets) + .sort() + .reverse() + .map((k) => itemsOrBuckets[k]) + .flat(); } // Sort for deterministic fingerprint @@ -1617,7 +1621,11 @@ class WatchHistoryManager { // Existing items - try to get records, fallback to items let existingItems = []; if (cachedEntry.records && typeof cachedEntry.records === "object") { - existingItems = Object.values(cachedEntry.records).flat(); + existingItems = Object.keys(cachedEntry.records) + .sort() + .reverse() + .map((k) => cachedEntry.records[k]) + .flat(); } else if (Array.isArray(cachedEntry.items)) { existingItems = cachedEntry.items; } @@ -1959,7 +1967,11 @@ class WatchHistoryManager { mergedItems, WATCH_HISTORY_MAX_ITEMS, ); - const flatItems = Object.values(records).flat(); + const flatItems = Object.keys(records) + .sort() + .reverse() + .map((k) => records[k]) + .flat(); const fingerprint = await this.getFingerprint( resolvedActor, @@ -2038,7 +2050,11 @@ class WatchHistoryManager { merged.items || [], batchLimit, ); - const flatItems = Object.values(records).flat(); + const flatItems = Object.keys(records) + .sort() + .reverse() + .map((k) => records[k]) + .flat(); const fingerprint = await this.getFingerprint( resolvedActor,