Optimize subscription feed retrieval and rendering

This commit is contained in:
thePR0M3TH3AN committed 2025-10-20 21:04:52 -04:00
1 parent a8cea0b147
commit e49483d34d
4 files changed
+139 -11

No files matched your search

+16 -1
View File
@@ -92,12 +92,19 @@ export function createSubscriptionAuthorsSource({ service } = {}) {
return [];
}
const limitCandidate = Number(context?.runtime?.limit);
const limit =
Number.isFinite(limitCandidate) && limitCandidate > 0
? Math.floor(limitCandidate)
: null;
const options = {
blacklistedEventIds: toSet(context?.runtime?.blacklistedEventIds),
isAuthorBlocked:
typeof context?.runtime?.isAuthorBlocked === "function"
? context.runtime.isAuthorBlocked
: () => false,
limit,
};
const authorList = Array.from(authors);
@@ -129,7 +136,15 @@ export function createSubscriptionAuthorsSource({ service } = {}) {
return author && authors.has(author);
});
return filtered.map((video) => ({
const sorted = filtered
.slice()
.sort(
(a, b) => (Number(b?.created_at) || 0) - (Number(a?.created_at) || 0)
);
const limited = limit ? sorted.slice(0, limit) : sorted;
return limited.map((video) => ({
video,
metadata: {
source: "nostr:subscriptions",
+39 -3
View File
@@ -297,6 +297,24 @@ export class NostrService {
index.get(author).push(video);
}
for (const [author, videos] of index.entries()) {
if (!Array.isArray(videos) || videos.length <= 1) {
continue;
}
videos.sort((a, b) => {
const aCreatedCandidate = Number(a?.created_at);
const bCreatedCandidate = Number(b?.created_at);
const aCreated = Number.isFinite(aCreatedCandidate)
? aCreatedCandidate
: 0;
const bCreated = Number.isFinite(bCreatedCandidate)
? bCreatedCandidate
: 0;
return bCreated - aCreated;
});
index.set(author, videos);
}
this.videosByAuthorIndex = index;
this.authorIndexDirty = false;
return this.videosByAuthorIndex;
@@ -400,13 +418,25 @@ export class NostrService {
const index = this.ensureVideosByAuthorIndex();
const collected = [];
const seen = new Set();
const limitCandidate = Number(options?.limit);
const limit =
Number.isFinite(limitCandidate) && limitCandidate > 0
? Math.floor(limitCandidate)
: null;
const perAuthorLimit = limit
? Math.max(limit * 2, limit + 5)
: null;
for (const author of normalizedAuthors) {
const entries = index.get(author);
if (!Array.isArray(entries)) {
if (!Array.isArray(entries) || entries.length === 0) {
continue;
}
for (const video of entries) {
const sliceCount = perAuthorLimit
? Math.min(perAuthorLimit, entries.length)
: entries.length;
for (let idx = 0; idx < sliceCount; idx += 1) {
const video = entries[idx];
if (!video || typeof video !== "object") {
continue;
}
@@ -421,13 +451,19 @@ export class NostrService {
const filtered = this.filterVideos(collected, options);
return filtered.sort((a, b) => {
const sorted = filtered.sort((a, b) => {
const aCreatedCandidate = Number(a?.created_at);
const bCreatedCandidate = Number(b?.created_at);
const aCreated = Number.isFinite(aCreatedCandidate) ? aCreatedCandidate : 0;
const bCreated = Number.isFinite(bCreatedCandidate) ? bCreatedCandidate : 0;
return bCreated - aCreated;
});
if (limit) {
return sorted.slice(0, limit);
}
return sorted;
}
async loadVideos({
+27 -7
View File
@@ -373,7 +373,11 @@ class SubscriptionsManager {
}
const app = getApp();
const runtime = this.buildFeedRuntime({ app, authors: channelHexes });
const runtime = this.buildFeedRuntime({
app,
authors: channelHexes,
limit,
});
const runOptions = {
actorPubkey: userPubkey,
limit,
@@ -410,11 +414,20 @@ class SubscriptionsManager {
"[SubscriptionsManager] Failed to run subscriptions feed:",
error
);
container.innerHTML =
"<p class='text-muted-strong'>Unable to load subscriptions right now.</p>";
this.lastResult = null;
if (container && this.lastResult) {
const fallbackReason = reason
? `${reason}:cached`
: "cached-result";
this.renderSameGridStyle(this.lastResult, containerId, {
limit,
reason: fallbackReason,
});
} else if (container) {
container.innerHTML =
"<p class='text-muted-strong'>Unable to load subscriptions right now.</p>";
}
this.hasRenderedOnce = Boolean(container);
return null;
return this.lastResult;
} finally {
this.isRunningFeed = false;
this.processScheduledRefresh();
@@ -500,7 +513,7 @@ class SubscriptionsManager {
return app?.feedEngine || null;
}
buildFeedRuntime({ app, authors = [] } = {}) {
buildFeedRuntime({ app, authors = [], limit = null } = {}) {
const normalizedAuthors = Array.isArray(authors)
? authors.filter((author) => typeof author === "string" && author)
: [];
@@ -515,11 +528,18 @@ class SubscriptionsManager {
? (pubkey) => app.isAuthorBlocked(pubkey)
: () => false;
const limitCandidate = Number(limit);
const normalizedLimit =
Number.isFinite(limitCandidate) && limitCandidate > 0
? Math.floor(limitCandidate)
: null;
return {
subscriptionAuthors: normalizedAuthors,
authors: normalizedAuthors,
blacklistedEventIds: blacklist,
isAuthorBlocked
isAuthorBlocked,
limit: normalizedLimit
};
}