From caa451af875eb08fd1a59c621b69b75499434f7a Mon Sep 17 00:00:00 2001 From: WardPearce Date: Fri, 13 Feb 2026 15:12:06 +1300 Subject: [PATCH] Improvements to YT backend feed --- materialious/electron/package-lock.json | 4 ++-- materialious/src/lib/api/index.ts | 2 +- .../src/lib/api/youtubejs/subscriptions.ts | 24 +++++++++++++++---- .../src/lib/components/settings/Engine.svelte | 17 +++++++++++-- materialious/src/lib/i18n/locales/en.json | 1 + materialious/src/lib/store.ts | 5 ++++ .../routes/(app)/subscriptions/+page.svelte | 5 +--- 7 files changed, 45 insertions(+), 13 deletions(-) diff --git a/materialious/electron/package-lock.json b/materialious/electron/package-lock.json index c4f81a2e..a8fb768a 100644 --- a/materialious/electron/package-lock.json +++ b/materialious/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "Materialious", - "version": "1.14.3", + "version": "1.14.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Materialious", - "version": "1.14.3", + "version": "1.14.4", "license": "MIT", "dependencies": { "@capacitor-community/electron": "^5.0.0", diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index 8e0aa8f4..d7414cd1 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -252,7 +252,7 @@ export async function getFeed( fetchOptions: RequestInit = {} ): Promise { if (isYTBackend()) { - return getFeedYTjs(); + return getFeedYTjs(maxResults, page); } const path = buildPath('auth/feed'); diff --git a/materialious/src/lib/api/youtubejs/subscriptions.ts b/materialious/src/lib/api/youtubejs/subscriptions.ts index 14fd99e7..807765d7 100644 --- a/materialious/src/lib/api/youtubejs/subscriptions.ts +++ b/materialious/src/lib/api/youtubejs/subscriptions.ts @@ -5,7 +5,11 @@ import { relativeTimestamp } from '$lib/time'; import { get } from 'svelte/store'; import type { Feed, Subscription, Thumbnail } from '../model'; import { getChannelYTjs } from './channel'; -import { engineCooldownYTStore, engineCullYTStore } from '$lib/store'; +import { + engineCooldownYTStore, + engineCullYTStore, + engineMaxConcurrentChannelsStore +} from '$lib/store'; export async function getSubscriptionsYTjs(): Promise { const subscriptions: Subscription[] = []; @@ -134,19 +138,28 @@ export async function parseChannelRSS(channelId: string): Promise { } } -export async function getFeedYTjs(): Promise { +export async function getFeedYTjs(maxResults: number, page: number): Promise { const channelSubscriptions = await localDb.channelSubscriptions.toArray(); const toUpdatePromises: Promise[] = []; const now = new Date(); + + let totalChannelsToParse = 0; for (const channel of channelSubscriptions) { const lastRSSFetch = new Date(channel.lastRSSFetch); const timeDifference = now.getTime() - lastRSSFetch.getTime(); const cooldownTime = get(engineCooldownYTStore) * 60 * 60 * 1000; + if (timeDifference > cooldownTime) { - toUpdatePromises.push(parseChannelRSS(channel.channelId)); + if (totalChannelsToParse < get(engineMaxConcurrentChannelsStore)) { + toUpdatePromises.push(parseChannelRSS(channel.channelId)); + } else { + parseChannelRSS(channel.channelId); + } } + + totalChannelsToParse++; } if (toUpdatePromises) { @@ -166,8 +179,11 @@ export async function getFeedYTjs(): Promise { videos = videos.slice(0, cullAfter); } + const start = (page - 1) * maxResults; + const end = start + maxResults; + return { notifications: [], - videos: videos + videos: videos.slice(start, end) }; } diff --git a/materialious/src/lib/components/settings/Engine.svelte b/materialious/src/lib/components/settings/Engine.svelte index 025af604..58d6e122 100644 --- a/materialious/src/lib/components/settings/Engine.svelte +++ b/materialious/src/lib/components/settings/Engine.svelte @@ -6,6 +6,7 @@ engineCooldownYTStore, engineCullYTStore, engineFallbacksStore, + engineMaxConcurrentChannelsStore, instanceStore } from '$lib/store'; import { useEngineFallback, type EngineFallback } from '$lib/api/misc'; @@ -115,10 +116,22 @@ engineCooldownYTStore.set(Number((event.target as HTMLInputElement).value)); }} value={$engineCooldownYTStore} - name="cull" + name="cooldown" type="number" /> - + + +
+ pending + { + engineMaxConcurrentChannelsStore.set(Number((event.target as HTMLInputElement).value)); + }} + value={$engineMaxConcurrentChannelsStore} + name="concurrent" + type="number" + /> +
{#if $authStore && $instanceStore} diff --git a/materialious/src/lib/i18n/locales/en.json b/materialious/src/lib/i18n/locales/en.json index 2fcc2c38..a43c60a0 100644 --- a/materialious/src/lib/i18n/locales/en.json +++ b/materialious/src/lib/i18n/locales/en.json @@ -179,6 +179,7 @@ "warning": "Advanced settings! For experienced users only. Do not change unless you know what you’re doing.", "cull": "Max feed items", "cooldown": "Re-fetch channel hour cooldown", + "concurrent": "Max amount of channels to parse before feed return", "fallbacks": "Fallbacks", "importExport": "Import/Export subscriptions", "exportToInvidious": "Export to Invidious from Materialious", diff --git a/materialious/src/lib/store.ts b/materialious/src/lib/store.ts index 4caa8eca..3a0ee617 100644 --- a/materialious/src/lib/store.ts +++ b/materialious/src/lib/store.ts @@ -324,6 +324,11 @@ export const engineCooldownYTStore: Writable = persist( createStorage(), 'engineCooldownYT' ); +export const engineMaxConcurrentChannelsStore: Writable = persist( + writable(100), + createStorage(), + 'engineMaxConcurrentChannels' +); export const engineFallbacksStore: Writable = persist( writable([]), diff --git a/materialious/src/routes/(app)/subscriptions/+page.svelte b/materialious/src/routes/(app)/subscriptions/+page.svelte index 95dd99c1..4bcdad88 100644 --- a/materialious/src/routes/(app)/subscriptions/+page.svelte +++ b/materialious/src/routes/(app)/subscriptions/+page.svelte @@ -6,16 +6,13 @@ import ItemsList from '$lib/components/ItemsList.svelte'; import { resolve } from '$app/paths'; import { _ } from '$lib/i18n'; - import { isYTBackend } from '$lib/misc'; let currentPage = 1; let videos: (VideoBase | Video | PlaylistPageVideo)[] = $state($feedCacheStore.subscription); async function loadMore(event: InfiniteEvent) { - // Not supported or needed on YT backend - if (isYTBackend()) return; - currentPage++; + const feed = await getFeed(100, currentPage); if (feed.videos.length === 0) { event.detail.complete();