From f6918f4bc12b692cc3bc8d9d9f951b6121fae2fa Mon Sep 17 00:00:00 2001 From: ThaUnknown <6506529+ThaUnknown@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:45:24 +0200 Subject: [PATCH] fix: 60s cooldown on refocus AL data updates, higher burst ratelimits --- package.json | 2 +- src/lib/modules/anilist/client.ts | 8 +-- src/lib/modules/anilist/refocus.ts | 64 +++++++++++++++++++ src/lib/modules/settings/settings.ts | 1 + .../app/settings/interface/+page.svelte | 6 +- 5 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 src/lib/modules/anilist/refocus.ts diff --git a/package.json b/package.json index 6165928..fa2804d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ui", - "version": "6.4.21", + "version": "6.4.22", "license": "BUSL-1.1", "private": true, "packageManager": "pnpm@9.14.4", diff --git a/src/lib/modules/anilist/client.ts b/src/lib/modules/anilist/client.ts index b683635..ecbca10 100644 --- a/src/lib/modules/anilist/client.ts +++ b/src/lib/modules/anilist/client.ts @@ -1,7 +1,6 @@ import { authExchange } from '@urql/exchange-auth' import { offlineExchange } from '@urql/exchange-graphcache' import { makeDefaultStorage } from '@urql/exchange-graphcache/default-storage' -import { refocusExchange } from '@urql/exchange-refocus' import { Client, fetchExchange, queryStore, type OperationResultState, gql as _gql } from '@urql/svelte' import Bottleneck from 'bottleneck' import lavenshtein from 'js-levenshtein' @@ -11,6 +10,7 @@ import { toast } from 'svelte-sonner' import gql from './gql' import { CommentFrag, Comments, CustomLists, DeleteEntry, DeleteThreadComment, Entry, Following, FullMedia, FullMediaList, IDMedia, SaveThreadComment, Schedule, Search, ThreadFrag, Threads, ToggleFavourite, ToggleLike, UserLists, Viewer } from './queries' +import { refocusExchange } from './refocus' import schema from './schema.json' with { type: 'json' } import { currentSeason, currentYear, lastSeason, lastYear, nextSeason, nextYear } from './util' @@ -56,7 +56,7 @@ class AnilistClient { // fetch: dev ? fetch : (req: RequestInfo | URL, opts?: RequestInit) => this.handleRequest(req, opts), fetch: (req: RequestInfo | URL, opts?: RequestInit) => this.handleRequest(req, opts), exchanges: [ - refocusExchange(), + refocusExchange(60_000), offlineExchange({ schema: schema as Parameters[0]['schema'], storage: this.storage, @@ -253,8 +253,8 @@ class AnilistClient { reservoir: 90, reservoirRefreshAmount: 90, reservoirRefreshInterval: 60 * 1000, - maxConcurrent: 10, - minTime: 100 + maxConcurrent: 3, + minTime: 200 }) rateLimitPromise: Promise | null = null diff --git a/src/lib/modules/anilist/refocus.ts b/src/lib/modules/anilist/refocus.ts new file mode 100644 index 0000000..48db4ef --- /dev/null +++ b/src/lib/modules/anilist/refocus.ts @@ -0,0 +1,64 @@ +import { pipe, tap } from 'wonka' + +import type { Exchange, Operation } from '@urql/core' + +/** Exchange factory that reexecutes operations after a user returns to the tab. + * + * @returns a new refocus {@link Exchange}. + * + * @remarks + * The `refocusExchange` will reexecute `Operation`s with the `cache-and-network` + * policy when a user switches back to your application's browser tab. This can + * effectively update all on-screen data when a user has stayed inactive for a + * long time. + * + * The `cache-and-network` policy will refetch data in the background, but will + * only refetch queries that are currently active. + */ +export const refocusExchange = (minimumTime = 0): Exchange => { + return ({ client, forward }) => + ops$ => { + if (typeof window === 'undefined' || typeof document !== 'object') { + return forward(ops$) + } + + const watchedOperations = new Map() + const observedOperations = new Map() + + let timeout = 0 + + window.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + if (timeout) return + watchedOperations.forEach(op => { + client.reexecuteOperation( + client.createRequestOperation('query', op, { + ...op.context, + requestPolicy: 'cache-and-network' + }) + ) + }) + } else { + // on hide wait for minimumTime before allowing another re-execute + clearTimeout(timeout) + timeout = setTimeout(() => { + timeout = 0 + }, minimumTime) + } + }) + + const processIncomingOperation = (op: Operation) => { + if (op.kind === 'query' && !observedOperations.has(op.key)) { + observedOperations.set(op.key, 1) + watchedOperations.set(op.key, op) + } + + if (op.kind === 'teardown' && observedOperations.has(op.key)) { + observedOperations.delete(op.key) + watchedOperations.delete(op.key) + } + } + + return forward(pipe(ops$, tap(processIncomingOperation))) + } +} diff --git a/src/lib/modules/settings/settings.ts b/src/lib/modules/settings/settings.ts index acdeeb9..8ff0c19 100644 --- a/src/lib/modules/settings/settings.ts +++ b/src/lib/modules/settings/settings.ts @@ -19,5 +19,6 @@ settings.subscribe(settings => { native.transparency(settings.idleAnimation) native.setZoom(settings.uiScale) native.toggleDiscordDetails(settings.showDetailsInRPC) + native.setAngle(settings.angle) if (settings.enableDoH) native.setDOH(settings.doHURL) }) diff --git a/src/routes/app/settings/interface/+page.svelte b/src/routes/app/settings/interface/+page.svelte index 812095a..604923e 100644 --- a/src/routes/app/settings/interface/+page.svelte +++ b/src/routes/app/settings/interface/+page.svelte @@ -34,10 +34,6 @@ vulkan: 'Vulkan', metal: 'Metal' } - - function changeAngle (value: string) { - native.setAngle(value) - }
@@ -53,7 +49,7 @@ {#if !SUPPORTS.isAndroid}
Rendering Settings
- +
UI Settings