mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #1189 from PR0M3TH3AN/fix-subscription-spinner-hang-134888602482071504
Fix infinite subscription loading spinner
This commit is contained in:
4 files changed
+56
-21
No files matched your search
@@ -66,6 +66,7 @@ export function createSubscriptionAuthorsSource({ service } = {}) {
|
||||
const resolvedService = resolveService(service, nostrService);
|
||||
|
||||
return async function subscriptionAuthorsSource(context = {}) {
|
||||
context?.log?.("[subscriptions-source] START");
|
||||
const runtimeAuthors = toArray(
|
||||
context?.runtime?.subscriptionAuthors || context?.runtime?.authors
|
||||
).map(normalizeAuthor);
|
||||
@@ -88,6 +89,8 @@ export function createSubscriptionAuthorsSource({ service } = {}) {
|
||||
[...runtimeAuthors, ...configAuthors, ...hookAuthors].filter(Boolean)
|
||||
);
|
||||
|
||||
context?.log?.(`[subscriptions-source] Resolved ${authors.size} authors.`);
|
||||
|
||||
if (!authors.size) {
|
||||
return [];
|
||||
}
|
||||
@@ -115,12 +118,16 @@ export function createSubscriptionAuthorsSource({ service } = {}) {
|
||||
let videos = [];
|
||||
try {
|
||||
if (hasTargetedLookup) {
|
||||
context?.log?.("[subscriptions-source] Calling getActiveVideosByAuthors...");
|
||||
videos = await Promise.resolve(
|
||||
resolvedService.getActiveVideosByAuthors(authorList, options)
|
||||
);
|
||||
context?.log?.(`[subscriptions-source] getActiveVideosByAuthors returned ${videos.length} videos.`);
|
||||
|
||||
if (!videos.length && typeof resolvedService.fetchVideosByAuthors === "function") {
|
||||
context?.log?.("[subscriptions-source] Cache empty. Calling fetchVideosByAuthors...");
|
||||
const fetched = await resolvedService.fetchVideosByAuthors(authorList, options);
|
||||
context?.log?.(`[subscriptions-source] fetchVideosByAuthors returned ${fetched ? fetched.length : 0} videos.`);
|
||||
if (Array.isArray(fetched) && fetched.length > 0) {
|
||||
videos = fetched;
|
||||
}
|
||||
|
||||
@@ -581,6 +581,7 @@ export function shimLegacySimplePoolMethods(pool) {
|
||||
: 7000;
|
||||
|
||||
timer = setTimeout(() => {
|
||||
devLogger.warn(`[toolkit] pool.list timed out after ${timeoutMs}ms.`);
|
||||
timer = null;
|
||||
try {
|
||||
subscription.unsub?.();
|
||||
|
||||
+40
-21
@@ -157,6 +157,17 @@ function extractSnapshotPreview(message) {
|
||||
return sanitizeSnapshotPreview(selected || "");
|
||||
}
|
||||
|
||||
function getActiveKey(video) {
|
||||
if (video.videoRootId) {
|
||||
return `ROOT:${video.videoRootId}`;
|
||||
}
|
||||
const dTag = video.tags?.find((t) => Array.isArray(t) && t[0] === "d");
|
||||
if (dTag && typeof dTag[1] === "string") {
|
||||
return `${video.pubkey}:${dTag[1]}`;
|
||||
}
|
||||
return `LEGACY:${video.id}`;
|
||||
}
|
||||
|
||||
function resolveDirectMessageRemotePubkey(message, actorPubkey = "") {
|
||||
const normalizedActor = normalizeHexPubkey(actorPubkey);
|
||||
|
||||
@@ -1165,10 +1176,11 @@ export class NostrService {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.log(`[nostrService] fetchVideosByAuthors START. Authors: ${authorList.length}`);
|
||||
|
||||
const requestedLimit = Number(options?.limit);
|
||||
const resolvedLimit = this.nostrClient.clampVideoRequestLimit(
|
||||
requestedLimit,
|
||||
DEFAULT_VIDEO_REQUEST_LIMIT
|
||||
requestedLimit
|
||||
);
|
||||
|
||||
const filter = {
|
||||
@@ -1183,31 +1195,38 @@ export class NostrService {
|
||||
const invalidNotes = [];
|
||||
|
||||
try {
|
||||
this.log(`[nostrService] Querying ${this.nostrClient.relays.length} relays...`);
|
||||
await Promise.all(
|
||||
this.nostrClient.relays.map(async (url) => {
|
||||
const events = await this.nostrClient.pool.list([url], [filter]);
|
||||
for (const evt of events) {
|
||||
if (evt && evt.id) {
|
||||
this.nostrClient.rawEvents.set(evt.id, evt);
|
||||
}
|
||||
const vid = convertEventToVideo(evt);
|
||||
if (vid.invalid) {
|
||||
invalidNotes.push({ id: vid.id, reason: vid.reason });
|
||||
} else {
|
||||
if (
|
||||
this.nostrClient &&
|
||||
typeof this.nostrClient.applyRootCreatedAt === "function"
|
||||
) {
|
||||
this.nostrClient.applyRootCreatedAt(vid);
|
||||
try {
|
||||
this.log(`[nostrService] Querying relay: ${url}`);
|
||||
const events = await this.nostrClient.pool.list([url], [filter]);
|
||||
this.log(`[nostrService] Relay ${url} returned ${events.length} events.`);
|
||||
for (const evt of events) {
|
||||
if (evt && evt.id) {
|
||||
this.nostrClient.rawEvents.set(evt.id, evt);
|
||||
}
|
||||
const activeKey = getActiveKey(vid);
|
||||
if (vid.deleted) {
|
||||
this.recordTombstone(activeKey, vid.created_at);
|
||||
const vid = convertEventToVideo(evt);
|
||||
if (vid.invalid) {
|
||||
invalidNotes.push({ id: vid.id, reason: vid.reason });
|
||||
} else {
|
||||
this.applyTombstoneGuard(vid);
|
||||
if (
|
||||
this.nostrClient &&
|
||||
typeof this.nostrClient.applyRootCreatedAt === "function"
|
||||
) {
|
||||
this.nostrClient.applyRootCreatedAt(vid);
|
||||
}
|
||||
const activeKey = getActiveKey(vid);
|
||||
if (vid.deleted) {
|
||||
this.nostrClient.recordTombstone(activeKey, vid.created_at);
|
||||
} else {
|
||||
this.nostrClient.applyTombstoneGuard(vid);
|
||||
}
|
||||
localAll.set(evt.id, vid);
|
||||
}
|
||||
localAll.set(evt.id, vid);
|
||||
}
|
||||
} catch (relayErr) {
|
||||
this.log(`[nostrService] Relay ${url} failed:`, relayErr);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -398,17 +398,20 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
async ensureLoaded(actorHex) {
|
||||
devLogger.log("[SubscriptionsManager] ensureLoaded start", actorHex);
|
||||
const normalizedActor = normalizeHexPubkey(actorHex) || actorHex;
|
||||
if (!normalizedActor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.loaded && this.currentUserPubkey === normalizedActor) {
|
||||
devLogger.log("[SubscriptionsManager] ensureLoaded already loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.loadingPromise) {
|
||||
try {
|
||||
devLogger.log("[SubscriptionsManager] ensureLoaded awaiting existing promise");
|
||||
await this.loadingPromise;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
@@ -431,6 +434,7 @@ class SubscriptionsManager {
|
||||
)
|
||||
),
|
||||
]);
|
||||
devLogger.log("[SubscriptionsManager] ensureLoaded success");
|
||||
} catch (error) {
|
||||
userLogger.warn("[SubscriptionsManager] ensureLoaded timed out or failed:", error);
|
||||
} finally {
|
||||
@@ -870,7 +874,9 @@ class SubscriptionsManager {
|
||||
|
||||
if (typeof nostrService?.awaitInitialLoad === "function") {
|
||||
try {
|
||||
devLogger.log("[SubscriptionsManager] awaiting nostrService initial load...");
|
||||
await nostrService.awaitInitialLoad();
|
||||
devLogger.log("[SubscriptionsManager] nostrService initial load done.");
|
||||
} catch (error) {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] Failed to await nostrService initial load:",
|
||||
@@ -906,7 +912,9 @@ class SubscriptionsManager {
|
||||
|
||||
try {
|
||||
this.isRunningFeed = true;
|
||||
devLogger.log("[SubscriptionsManager] Calling engine.run('subscriptions')...");
|
||||
const result = await engine.run("subscriptions", runOptions);
|
||||
devLogger.log("[SubscriptionsManager] engine.run complete. Items:", result?.items?.length);
|
||||
|
||||
const videos = Array.isArray(result?.items)
|
||||
? result.items.map((item) => item?.video).filter(Boolean)
|
||||
|
||||
Reference in new issue
Block a user