it go faster now

time to sleep...
This commit is contained in:
Keep Creating Online
2025-01-28 00:06:28 -05:00
parent c7d3579266
commit deab75d124
3 changed files with 594 additions and 688 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,9 @@ class NostrClient {
this.pool = null; this.pool = null;
this.pubkey = null; this.pubkey = null;
this.relays = RELAY_URLS; this.relays = RELAY_URLS;
// We keep a Map of subscribed videos for quick lookups by event.id
this.subscribedVideos = new Map();
} }
/** /**
@@ -207,7 +210,7 @@ class NostrClient {
const event = { const event = {
kind: 30078, kind: 30078,
pubkey, pubkey,
created_at: Math.floor(Date.now() / 1000), created_at: Math.floor(Date.now() / 100),
tags: [ tags: [
["t", "video"], ["t", "video"],
["d", uniqueD], ["d", uniqueD],
@@ -254,7 +257,6 @@ class NostrClient {
* Edits an existing video event by reusing the same "d" tag. * Edits an existing video event by reusing the same "d" tag.
* Allows toggling isPrivate on/off and re-encrypting or decrypting the magnet. * Allows toggling isPrivate on/off and re-encrypting or decrypting the magnet.
*/ */
// Minimal fix: ensures we only ever encrypt once per edit operation
async editVideo(originalEvent, updatedVideoData, pubkey) { async editVideo(originalEvent, updatedVideoData, pubkey) {
if (!pubkey) { if (!pubkey) {
throw new Error("User is not logged in."); throw new Error("User is not logged in.");
@@ -382,7 +384,7 @@ class NostrClient {
/** /**
* Soft-delete or hide an existing video by marking content as "deleted: true" * Soft-delete or hide an existing video by marking content as "deleted: true"
* and republishing with same (kind=30078, pubkey, d) address. * and republishing with the same (kind=30078, pubkey, d) address.
*/ */
async deleteVideo(originalEvent, pubkey) { async deleteVideo(originalEvent, pubkey) {
if (!pubkey) { if (!pubkey) {
@@ -407,6 +409,7 @@ class NostrClient {
const oldContent = JSON.parse(originalEvent.content || "{}"); const oldContent = JSON.parse(originalEvent.content || "{}");
const oldVersion = oldContent.version ?? 1; const oldVersion = oldContent.version ?? 1;
// Mark it "deleted" and clear out magnet, thumbnail, etc.
const contentObject = { const contentObject = {
version: oldVersion, version: oldVersion,
deleted: true, deleted: true,
@@ -418,6 +421,7 @@ class NostrClient {
isPrivate: oldContent.isPrivate || false, isPrivate: oldContent.isPrivate || false,
}; };
// Reuse the same d-tag for an addressable edit
const event = { const event = {
kind: 30078, kind: 30078,
pubkey, pubkey,
@@ -451,10 +455,7 @@ class NostrClient {
} }
} catch (err) { } catch (err) {
if (isDevMode) { if (isDevMode) {
console.error( console.error(`Failed to publish deleted event to ${url}:`, err);
`Failed to publish deleted event to ${url}:`,
err.message
);
} }
} }
}) })
@@ -463,117 +464,141 @@ class NostrClient {
return signedEvent; return signedEvent;
} catch (error) { } catch (error) {
if (isDevMode) { if (isDevMode) {
console.error("Failed to sign deleted event:", error.message); console.error("Failed to sign deleted event:", error);
} }
throw new Error("Failed to sign deleted event."); throw new Error("Failed to sign deleted event.");
} }
} }
/** /**
* Fetches videos from all configured relays. * Subscribes to video events from all configured relays, storing them in a Map.
*
* @param {Function} onVideo - Callback fired for each new/updated video
*/
subscribeVideos(onVideo) {
const filter = {
kinds: [30078],
"#t": ["video"],
limit: 500, // Adjust as needed
since: 0,
};
if (isDevMode) {
console.log("[subscribeVideos] Subscribing with filter:", filter);
}
// Create subscription across all relays
const sub = this.pool.sub(this.relays, [filter]);
sub.on("event", (event) => {
try {
const content = JSON.parse(event.content);
// If marked deleted
if (content.deleted === true) {
// Remove it from our Map if we had it
if (this.subscribedVideos.has(event.id)) {
this.subscribedVideos.delete(event.id);
// Optionally notify the callback so UI can remove it
// onVideo(null, { deletedId: event.id });
}
return;
}
// Construct a video object
const video = {
id: event.id,
version: content.version ?? 1,
isPrivate: content.isPrivate ?? false,
title: content.title || "",
magnet: content.magnet || "",
thumbnail: content.thumbnail || "",
description: content.description || "",
mode: content.mode || "live",
pubkey: event.pubkey,
created_at: event.created_at,
tags: event.tags,
};
// Check if we already have it in our Map
if (!this.subscribedVideos.has(event.id)) {
// It's new, so store it
this.subscribedVideos.set(event.id, video);
// Then notify the callback that a new video arrived
onVideo(video);
} else {
// Optional: if you want to detect edits, compare the new vs. old and update
// this.subscribedVideos.set(event.id, video);
// onVideo(video) to re-render, etc.
}
} catch (err) {
if (isDevMode) {
console.error("[subscribeVideos] Error parsing event:", err);
}
}
});
sub.on("eose", () => {
if (isDevMode) {
console.log("[subscribeVideos] Reached EOSE for all relays");
}
// Optionally: onVideo(null, { eose: true }) to signal initial load done
});
return sub; // so you can unsub later if needed
}
/**
* A one-time, bulk fetch of videos from all configured relays.
* (Limit has been reduced to 300 for better performance.)
*/ */
async fetchVideos() { async fetchVideos() {
const filter = { const filter = {
kinds: [30078], kinds: [30078],
"#t": ["video"], "#t": ["video"],
limit: 1000, limit: 300, // Reduced from 1000 for quicker fetches
since: 0, since: 0,
}; };
const videoEvents = new Map(); const videoEvents = new Map();
if (isDevMode) {
console.log("[fetchVideos] Starting fetch from all relays...");
console.log("[fetchVideos] Filter:", filter);
}
try { try {
// Query each relay in parallel
await Promise.all( await Promise.all(
this.relays.map(async (url) => { this.relays.map(async (url) => {
if (isDevMode) console.log(`[fetchVideos] Querying relay: ${url}`); const events = await this.pool.list([url], [filter]);
for (const evt of events) {
try { try {
const events = await this.pool.list([url], [filter]); const content = JSON.parse(evt.content);
if (content.deleted) {
if (isDevMode) { videoEvents.delete(evt.id);
console.log(`Events from ${url}:`, events.length); } else {
if (events.length > 0) { videoEvents.set(evt.id, {
events.forEach((evt, idx) => { id: evt.id,
console.log( pubkey: evt.pubkey,
`[fetchVideos] [${url}] Event[${idx}] ID: ${evt.id} | pubkey: ${evt.pubkey} | created_at: ${evt.created_at}` created_at: evt.created_at,
); title: content.title || "",
magnet: content.magnet || "",
thumbnail: content.thumbnail || "",
description: content.description || "",
mode: content.mode || "live",
isPrivate: content.isPrivate || false,
tags: evt.tags,
}); });
} }
} } catch (e) {
console.error("Error parsing event content:", e);
events.forEach((event) => {
try {
const content = JSON.parse(event.content);
// If deleted == true, it overrides older notes
if (content.deleted === true) {
videoEvents.delete(event.id);
return;
}
// If we haven't seen this event.id before, store it
if (!videoEvents.has(event.id)) {
videoEvents.set(event.id, {
id: event.id,
version: content.version ?? 1,
isPrivate: content.isPrivate ?? false,
title: content.title || "",
magnet: content.magnet || "",
thumbnail: content.thumbnail || "",
description: content.description || "",
mode: content.mode || "live",
pubkey: event.pubkey,
created_at: event.created_at,
tags: event.tags,
});
}
} catch (parseError) {
if (isDevMode) {
console.error(
"[fetchVideos] Event parsing error:",
parseError
);
}
}
});
} catch (relayError) {
if (isDevMode) {
console.error(
`[fetchVideos] Error fetching from ${url}:`,
relayError
);
} }
} }
}) })
); );
const videos = Array.from(videoEvents.values()).sort( // Turn the Map into a sorted array
const allVideos = Array.from(videoEvents.values()).sort(
(a, b) => b.created_at - a.created_at (a, b) => b.created_at - a.created_at
); );
return allVideos;
// Apply access control filtering } catch (err) {
const filteredVideos = accessControl.filterVideos(videos); console.error("fetchVideos error:", err);
if (isDevMode) {
console.log("[fetchVideos] All relays have responded.");
console.log(
`[fetchVideos] Total unique video events: ${videoEvents.size}`
);
console.log(
`[fetchVideos] Videos after filtering: ${filteredVideos.length}`
);
}
return filteredVideos;
} catch (error) {
if (isDevMode) {
console.error("FETCH VIDEOS ERROR:", error);
}
return []; return [];
} }
} }