mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
chore: refactor fetchVideos to use subscribeVideos
Replaced the deprecated `fetchVideos` implementation with a wrapper around the newer `subscribeVideos` method. This reduces code duplication and ensures consistent behavior for video fetching logic. The wrapper maintains the original Promise-based API and ensures NIP-71 metadata is populated before resolving. Added tests in `tests/nostr/client.test.mjs` to verify `fetchVideos` behavior. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
1fbee4219b
commit
911c030437
2 files changed
+65
-75
No files matched your search
+18
-75
@@ -8064,85 +8064,28 @@ export class NostrClient {
|
||||
* @deprecated Use `subscribeVideos` for the main feed to support buffering and streaming.
|
||||
*/
|
||||
async fetchVideos(options = {}) {
|
||||
const requestedLimit = Number(options?.limit);
|
||||
const resolvedLimit = this.clampVideoRequestLimit(requestedLimit, DEFAULT_VIDEO_REQUEST_LIMIT);
|
||||
|
||||
const filter = {
|
||||
kinds: [30078],
|
||||
"#t": ["video"],
|
||||
limit: resolvedLimit,
|
||||
since: 0,
|
||||
};
|
||||
|
||||
const localAll = new Map();
|
||||
// NEW: track invalid
|
||||
const invalidNotes = [];
|
||||
|
||||
try {
|
||||
await Promise.all(
|
||||
this.getHealthyRelays(this.relays).map(async (url) => {
|
||||
const events = await this.pool.list([url], [filter]);
|
||||
for (const evt of events) {
|
||||
if (evt && evt.id) {
|
||||
this.rawEvents.set(evt.id, evt);
|
||||
}
|
||||
const vid = convertEventToVideo(evt);
|
||||
if (vid.invalid) {
|
||||
// Accumulate if invalid
|
||||
invalidNotes.push({ id: vid.id, reason: vid.reason });
|
||||
} else {
|
||||
// Only add if good
|
||||
this.applyRootCreatedAt(vid);
|
||||
const activeKey = getActiveKey(vid);
|
||||
if (vid.deleted) {
|
||||
this.recordTombstone(activeKey, vid.created_at);
|
||||
} else {
|
||||
this.applyTombstoneGuard(vid);
|
||||
}
|
||||
localAll.set(evt.id, vid);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Merge into allEvents
|
||||
for (const [id, vid] of localAll.entries()) {
|
||||
this.allEvents.set(id, vid);
|
||||
this.dirtyEventIds.add(id);
|
||||
this.applyRootCreatedAt(vid);
|
||||
return new Promise((resolve) => {
|
||||
// Default to since: 0 to force full fetch if not specified
|
||||
const effectiveOptions = { ...options };
|
||||
if (effectiveOptions.since === undefined) {
|
||||
effectiveOptions.since = 0;
|
||||
}
|
||||
|
||||
// Rebuild activeMap
|
||||
this.activeMap.clear();
|
||||
for (const [id, video] of this.allEvents.entries()) {
|
||||
if (video.deleted) continue;
|
||||
const activeKey = getActiveKey(video);
|
||||
const existing = this.activeMap.get(activeKey);
|
||||
const sub = this.subscribeVideos(() => {}, effectiveOptions);
|
||||
|
||||
if (!existing || video.created_at > existing.created_at) {
|
||||
this.activeMap.set(activeKey, video);
|
||||
this.applyRootCreatedAt(video);
|
||||
sub.on("eose", async () => {
|
||||
sub.unsub();
|
||||
try {
|
||||
const activeVideos = this.getActiveVideos();
|
||||
await this.populateNip71MetadataForVideos(activeVideos);
|
||||
activeVideos.forEach((video) => this.applyRootCreatedAt(video));
|
||||
resolve(activeVideos);
|
||||
} catch (err) {
|
||||
userLogger.error("fetchVideos error:", err);
|
||||
resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
// OPTIONAL: Log invalid stats
|
||||
if (invalidNotes.length > 0 && isDevMode) {
|
||||
userLogger.warn(
|
||||
`Skipped ${invalidNotes.length} invalid video notes:\n`,
|
||||
invalidNotes.map((n) => `${n.id.slice(0, 8)}.. => ${n.reason}`)
|
||||
);
|
||||
}
|
||||
|
||||
const activeVideos = Array.from(this.activeMap.values()).sort(
|
||||
(a, b) => b.created_at - a.created_at
|
||||
);
|
||||
await this.populateNip71MetadataForVideos(activeVideos);
|
||||
activeVideos.forEach((video) => this.applyRootCreatedAt(video));
|
||||
return activeVideos;
|
||||
} catch (err) {
|
||||
userLogger.error("fetchVideos error:", err);
|
||||
return [];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -165,6 +165,53 @@ describe("NostrClient", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("fetchVideos", () => {
|
||||
it("should delegate to subscribeVideos and return result on eose", async () => {
|
||||
let subOpts = null;
|
||||
// Override subscribeVideos to verify delegation
|
||||
client.subscribeVideos = (cb, opts) => {
|
||||
subOpts = opts;
|
||||
return {
|
||||
on: (evt, handler) => {
|
||||
if (evt === "eose") setTimeout(handler, 0);
|
||||
},
|
||||
unsub: () => {},
|
||||
};
|
||||
};
|
||||
|
||||
// Mock helpers
|
||||
client.getActiveVideos = () => [{ id: "v1" }];
|
||||
client.populateNip71MetadataForVideos = async () => {};
|
||||
client.applyRootCreatedAt = () => {};
|
||||
|
||||
const result = await client.fetchVideos({ limit: 5 });
|
||||
assert.equal(result[0].id, "v1");
|
||||
assert.equal(subOpts.limit, 5);
|
||||
// Ensure we force full fetch by default
|
||||
assert.equal(subOpts.since, 0);
|
||||
});
|
||||
|
||||
it("should respect since parameter if provided", async () => {
|
||||
let subOpts = null;
|
||||
client.subscribeVideos = (cb, opts) => {
|
||||
subOpts = opts;
|
||||
return {
|
||||
on: (evt, handler) => {
|
||||
if (evt === "eose") setTimeout(handler, 0);
|
||||
},
|
||||
unsub: () => {},
|
||||
};
|
||||
};
|
||||
|
||||
client.getActiveVideos = () => [];
|
||||
client.populateNip71MetadataForVideos = async () => {};
|
||||
client.applyRootCreatedAt = () => {};
|
||||
|
||||
await client.fetchVideos({ since: 12345 });
|
||||
assert.equal(subOpts.since, 12345);
|
||||
});
|
||||
});
|
||||
|
||||
describe("publishVideo", () => {
|
||||
it("should throw if not logged in", async () => {
|
||||
await assert.rejects(
|
||||
|
||||
Reference in new issue
Block a user