mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-05 20:32:27 +00:00
Show posted and edited times from root history
This commit is contained in:
1 parent
7d389bb33d
commit
c99f6834cd
3 files changed
+242
-12
No files matched your search
@@ -237,10 +237,14 @@
|
||||
|
||||
<!-- Video Timestamp -->
|
||||
<div
|
||||
class="flex items-center justify-between text-sm text-gray-400 mb-4"
|
||||
class="flex items-start justify-between text-sm text-gray-400 mb-4"
|
||||
>
|
||||
<div class="flex items-center gap-2 modal-meta">
|
||||
<span id="videoTimestamp">just now</span>
|
||||
<div class="flex flex-wrap items-center gap-2 modal-meta">
|
||||
<span id="videoTimestamp">Posted just now</span>
|
||||
<span
|
||||
id="videoEditedTimestamp"
|
||||
class="hidden"
|
||||
>Last edited just now</span>
|
||||
<span id="videoViewCount" class="modal-view-count">– views</span>
|
||||
</div>
|
||||
<div id="modalStatus" class="text-gray-300">
|
||||
|
||||
@@ -6226,6 +6226,11 @@ class Application {
|
||||
hasUrl: !!trimmedUrl,
|
||||
});
|
||||
|
||||
const knownPostedAt = this.getKnownVideoPostedAt(video);
|
||||
const normalizedEditedAt = Number.isFinite(video.created_at)
|
||||
? Math.floor(video.created_at)
|
||||
: null;
|
||||
|
||||
this.currentVideo = {
|
||||
...video,
|
||||
url: trimmedUrl,
|
||||
@@ -6235,8 +6240,15 @@ class Application {
|
||||
torrentSupported: magnetSupported,
|
||||
legacyInfoHash: video.legacyInfoHash || legacyInfoHash,
|
||||
lightningAddress: null,
|
||||
lastEditedAt: normalizedEditedAt,
|
||||
};
|
||||
|
||||
if (Number.isFinite(knownPostedAt)) {
|
||||
this.cacheVideoRootCreatedAt(this.currentVideo, knownPostedAt);
|
||||
} else if (this.currentVideo.rootCreatedAt) {
|
||||
delete this.currentVideo.rootCreatedAt;
|
||||
}
|
||||
|
||||
const dTagValue = (this.extractDTagValue(video.tags) || "").trim();
|
||||
const pointerInfo = resolveVideoPointer({
|
||||
kind: video.kind,
|
||||
@@ -6320,12 +6332,15 @@ class Application {
|
||||
|
||||
const creatorNpub = this.safeEncodeNpub(video.pubkey) || video.pubkey;
|
||||
if (this.videoModal) {
|
||||
const formattedTimestamp = this.formatTimeAgo(video.created_at);
|
||||
const timestampPayload = this.buildModalTimestampPayload({
|
||||
postedAt: this.currentVideo?.rootCreatedAt ?? null,
|
||||
editedAt: normalizedEditedAt,
|
||||
});
|
||||
const displayNpub = `${creatorNpub.slice(0, 8)}...${creatorNpub.slice(-4)}`;
|
||||
this.videoModal.updateMetadata({
|
||||
title: video.title || "Untitled",
|
||||
description: video.description || "No description available.",
|
||||
timestamp: formattedTimestamp,
|
||||
timestamps: timestampPayload,
|
||||
creator: {
|
||||
name: creatorProfile.name,
|
||||
avatarUrl: creatorProfile.picture,
|
||||
@@ -6334,6 +6349,8 @@ class Application {
|
||||
});
|
||||
}
|
||||
|
||||
this.ensureModalPostedTimestamp(this.currentVideo);
|
||||
|
||||
const playbackResult =
|
||||
playbackPromise && typeof playbackPromise.then === "function"
|
||||
? await playbackPromise
|
||||
@@ -6342,6 +6359,183 @@ class Application {
|
||||
return playbackResult;
|
||||
}
|
||||
|
||||
buildModalTimestampPayload({ postedAt = null, editedAt = null } = {}) {
|
||||
const normalizedPostedAt = Number.isFinite(postedAt)
|
||||
? Math.floor(postedAt)
|
||||
: null;
|
||||
const normalizedEditedAt = Number.isFinite(editedAt)
|
||||
? Math.floor(editedAt)
|
||||
: null;
|
||||
|
||||
const payload = {
|
||||
posted: "",
|
||||
edited: "",
|
||||
};
|
||||
|
||||
const effectivePostedAt =
|
||||
normalizedPostedAt !== null ? normalizedPostedAt : normalizedEditedAt;
|
||||
|
||||
if (effectivePostedAt !== null) {
|
||||
payload.posted = `Posted ${this.formatTimeAgo(effectivePostedAt)}`;
|
||||
}
|
||||
|
||||
const shouldShowEdited =
|
||||
normalizedEditedAt !== null &&
|
||||
(normalizedPostedAt === null || normalizedEditedAt - normalizedPostedAt >= 60);
|
||||
|
||||
if (shouldShowEdited) {
|
||||
payload.edited = `Last edited ${this.formatTimeAgo(normalizedEditedAt)}`;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
getKnownVideoPostedAt(video) {
|
||||
if (!video || typeof video !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const directValue = Number.isFinite(video.rootCreatedAt)
|
||||
? Math.floor(video.rootCreatedAt)
|
||||
: null;
|
||||
if (directValue !== null) {
|
||||
return directValue;
|
||||
}
|
||||
|
||||
if (video.id && this.videosMap instanceof Map) {
|
||||
const stored = this.videosMap.get(video.id);
|
||||
const storedValue = Number.isFinite(stored?.rootCreatedAt)
|
||||
? Math.floor(stored.rootCreatedAt)
|
||||
: null;
|
||||
if (storedValue !== null) {
|
||||
video.rootCreatedAt = storedValue;
|
||||
return storedValue;
|
||||
}
|
||||
}
|
||||
|
||||
const nip71Created = Number.isFinite(video?.nip71Source?.created_at)
|
||||
? Math.floor(video.nip71Source.created_at)
|
||||
: null;
|
||||
|
||||
if (nip71Created !== null) {
|
||||
return nip71Created;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
cacheVideoRootCreatedAt(video, timestamp) {
|
||||
if (!Number.isFinite(timestamp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalized = Math.floor(timestamp);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async resolveVideoPostedAt(video) {
|
||||
if (!video || typeof video !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cached = this.getKnownVideoPostedAt(video);
|
||||
if (cached !== null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (!nostrClient || typeof nostrClient.hydrateVideoHistory !== "function") {
|
||||
const fallback = Number.isFinite(video.created_at)
|
||||
? Math.floor(video.created_at)
|
||||
: null;
|
||||
if (fallback !== null) {
|
||||
this.cacheVideoRootCreatedAt(video, fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
try {
|
||||
const history = await nostrClient.hydrateVideoHistory(video);
|
||||
if (Array.isArray(history) && history.length) {
|
||||
let earliest = null;
|
||||
for (const entry of history) {
|
||||
if (!entry || entry.deleted) {
|
||||
continue;
|
||||
}
|
||||
const created = Number.isFinite(entry.created_at)
|
||||
? Math.floor(entry.created_at)
|
||||
: null;
|
||||
if (created === null) {
|
||||
continue;
|
||||
}
|
||||
if (earliest === null || created < earliest) {
|
||||
earliest = created;
|
||||
}
|
||||
}
|
||||
|
||||
if (earliest === null) {
|
||||
const lastEntry = history[history.length - 1];
|
||||
if (Number.isFinite(lastEntry?.created_at)) {
|
||||
earliest = Math.floor(lastEntry.created_at);
|
||||
}
|
||||
}
|
||||
|
||||
if (earliest !== null) {
|
||||
this.cacheVideoRootCreatedAt(video, earliest);
|
||||
return earliest;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (isDevMode) {
|
||||
console.warn(
|
||||
"[Application] Failed to hydrate video history for timestamps:",
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const fallback = Number.isFinite(video.created_at)
|
||||
? Math.floor(video.created_at)
|
||||
: null;
|
||||
if (fallback !== null) {
|
||||
this.cacheVideoRootCreatedAt(video, fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
async ensureModalPostedTimestamp(video) {
|
||||
if (!video || !this.videoModal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const postedAt = await this.resolveVideoPostedAt(video);
|
||||
if (!this.videoModal || this.currentVideo !== video) {
|
||||
return;
|
||||
}
|
||||
|
||||
const editedAt = Number.isFinite(video.lastEditedAt)
|
||||
? Math.floor(video.lastEditedAt)
|
||||
: Number.isFinite(video.created_at)
|
||||
? Math.floor(video.created_at)
|
||||
: null;
|
||||
|
||||
const payload = this.buildModalTimestampPayload({
|
||||
postedAt,
|
||||
editedAt,
|
||||
});
|
||||
|
||||
this.videoModal.updateMetadata({ timestamps: payload });
|
||||
}
|
||||
|
||||
async playVideoWithoutEvent({
|
||||
url = "",
|
||||
magnet = "",
|
||||
|
||||
@@ -35,6 +35,7 @@ export class VideoModal {
|
||||
this.videoTitle = null;
|
||||
this.videoDescription = null;
|
||||
this.videoTimestamp = null;
|
||||
this.videoEditedTimestamp = null;
|
||||
this.videoViewCountEl = null;
|
||||
this.creatorAvatar = null;
|
||||
this.creatorName = null;
|
||||
@@ -185,6 +186,8 @@ export class VideoModal {
|
||||
playerModal.querySelector("#videoDescription") || null;
|
||||
this.videoTimestamp =
|
||||
playerModal.querySelector("#videoTimestamp") || null;
|
||||
this.videoEditedTimestamp =
|
||||
playerModal.querySelector("#videoEditedTimestamp") || null;
|
||||
this.videoViewCountEl =
|
||||
playerModal.querySelector("#videoViewCount") || null;
|
||||
this.creatorAvatar =
|
||||
@@ -933,26 +936,55 @@ export class VideoModal {
|
||||
title,
|
||||
description,
|
||||
timestamp,
|
||||
timestamps,
|
||||
viewCount,
|
||||
creator,
|
||||
} = {}) {
|
||||
if (this.videoTitle) {
|
||||
if (this.videoTitle && title !== undefined) {
|
||||
this.videoTitle.textContent = title || "Untitled";
|
||||
}
|
||||
if (this.videoDescription) {
|
||||
if (this.videoDescription && description !== undefined) {
|
||||
this.videoDescription.textContent = description || "";
|
||||
}
|
||||
if (this.videoTimestamp) {
|
||||
this.videoTimestamp.textContent = timestamp || "";
|
||||
if (timestamps) {
|
||||
this.updateTimestamps(timestamps);
|
||||
} else if (timestamp !== undefined) {
|
||||
this.updateTimestamps({ posted: timestamp });
|
||||
}
|
||||
if (typeof viewCount === "string") {
|
||||
this.updateViewCountLabel(viewCount);
|
||||
if (this.videoViewCountEl && viewCount !== undefined) {
|
||||
if (typeof viewCount === "string") {
|
||||
this.updateViewCountLabel(viewCount);
|
||||
} else {
|
||||
this.updateViewCountLabel("");
|
||||
}
|
||||
}
|
||||
if (creator) {
|
||||
if (creator !== undefined) {
|
||||
this.updateCreator(creator);
|
||||
}
|
||||
}
|
||||
|
||||
updateTimestamps({ posted, edited } = {}) {
|
||||
if (this.videoTimestamp) {
|
||||
if (posted) {
|
||||
this.videoTimestamp.textContent = posted;
|
||||
this.videoTimestamp.classList.remove("hidden");
|
||||
} else {
|
||||
this.videoTimestamp.textContent = "";
|
||||
this.videoTimestamp.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.videoEditedTimestamp) {
|
||||
if (edited) {
|
||||
this.videoEditedTimestamp.textContent = edited;
|
||||
this.videoEditedTimestamp.classList.remove("hidden");
|
||||
} else {
|
||||
this.videoEditedTimestamp.textContent = "";
|
||||
this.videoEditedTimestamp.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateCreator({ name, avatarUrl, npub } = {}) {
|
||||
if (this.creatorName) {
|
||||
this.creatorName.textContent = name || "Unknown";
|
||||
|
||||
Reference in new issue
Block a user