From ee83fdba7142b8757110d937e67d4336024579b7 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 4 Aug 2023 01:41:45 -0700 Subject: [PATCH] Persist lyrics queries in indexeddb --- package-lock.json | 101 ++++++++++++++---- package.json | 6 +- src/renderer/api/query-keys.ts | 2 +- .../features/lyrics/queries/lyric-query.ts | 4 +- .../features/lyrics/synchronized-lyrics.tsx | 2 +- src/renderer/index.tsx | 55 +++++++++- 6 files changed, 138 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index cea36b5f..0d4b3b1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,9 @@ "@mantine/modals": "^6.0.17", "@mantine/notifications": "^6.0.17", "@mantine/utils": "^6.0.17", - "@tanstack/react-query": "^4.32.0", - "@tanstack/react-query-devtools": "^4.32.0", + "@tanstack/react-query": "^4.32.1", + "@tanstack/react-query-devtools": "^4.32.1", + "@tanstack/react-query-persist-client": "^4.32.1", "@ts-rest/core": "^3.23.0", "axios": "^1.4.0", "clsx": "^2.0.0", @@ -41,6 +42,7 @@ "fuse.js": "^6.6.2", "history": "^5.3.0", "i18next": "^21.6.16", + "idb-keyval": "^6.2.1", "immer": "^9.0.21", "is-electron": "^2.2.2", "lodash": "^4.17.21", @@ -2928,20 +2930,32 @@ } }, "node_modules/@tanstack/query-core": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.32.0.tgz", - "integrity": "sha512-ei4IYwL2kmlKSlCw9WgvV7PpXi0MiswVwfQRxawhJA690zWO3dU49igaQ/UMTl+Jy9jj9dK5IKAYvbX7kUvviQ==", + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.32.1.tgz", + "integrity": "sha512-VEAGHboOFWN/bvf/7cCoeLQfld0AA8n0V/kfc77W+FvxnnSwJufEh6gfjqpX5bRE/DEYfYDYdNtuL3KM+lIs8Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-persist-client-core": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-4.32.1.tgz", + "integrity": "sha512-KgnkNigmOMi2aikxdhCRe0MaAh1Dq94/nNjmcSxfflj9L3v4F9tEQAig/F7m2+jethP1AiIYBax5nN4aqm7NFg==", + "dependencies": { + "@tanstack/query-core": "4.32.1" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.32.0.tgz", - "integrity": "sha512-B8WUMcByYAH9500ENejDCATOmEZhqjtS9wsfiQ3BNa+s+yAynY8SESI8WWHhSqUmjd0pmCSFRP6BOUGSda3QXA==", + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.32.1.tgz", + "integrity": "sha512-lPTfOq6bR6DorPaS018gTMd3zs8r06tlERiVY6BRP9SnDkkl4ckqeANava/jPLWrSZP+EA15loQUTmvZs6k2GA==", "dependencies": { - "@tanstack/query-core": "4.32.0", + "@tanstack/query-core": "4.32.1", "use-sync-external-store": "^1.2.0" }, "funding": { @@ -2963,9 +2977,9 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.32.0.tgz", - "integrity": "sha512-rOmWqzKzRmQrQULV5Ova2FGEEPT76FZA3hz8T+LFkvp3ehw9ugSZ1BosgRJ7AFCeir+5pcNvFwILy4pDK8HpRw==", + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.32.1.tgz", + "integrity": "sha512-/ZgxCfGXLIXUvaIRzrNCP+C4iv1bIleNzXCjGKFZ4qKEifnv5A/SpWE2dG4SBjqXVlIkMAP82lesfoHcsOm+zg==", "dependencies": { "@tanstack/match-sorter-utils": "^8.7.0", "superjson": "^1.10.0", @@ -2976,11 +2990,26 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "4.32.0", + "@tanstack/react-query": "4.32.1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tanstack/react-query-persist-client": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-4.32.1.tgz", + "integrity": "sha512-HtfhSOyMSjdASpPXWBWv9JquUk5b8HjOwbFVmtA8xIDFQm9qS35PikXO2YbBXhuz/LEknRhct/M3PMI/XkRQSg==", + "dependencies": { + "@tanstack/query-persist-client-core": "4.32.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "4.32.1" + } + }, "node_modules/@teamsupercell/typings-for-css-modules-loader": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/@teamsupercell/typings-for-css-modules-loader/-/typings-for-css-modules-loader-2.5.2.tgz", @@ -11481,6 +11510,11 @@ "postcss": "^8.1.0" } }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" + }, "node_modules/identity-obj-proxy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", @@ -25171,29 +25205,45 @@ } }, "@tanstack/query-core": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.32.0.tgz", - "integrity": "sha512-ei4IYwL2kmlKSlCw9WgvV7PpXi0MiswVwfQRxawhJA690zWO3dU49igaQ/UMTl+Jy9jj9dK5IKAYvbX7kUvviQ==" + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.32.1.tgz", + "integrity": "sha512-VEAGHboOFWN/bvf/7cCoeLQfld0AA8n0V/kfc77W+FvxnnSwJufEh6gfjqpX5bRE/DEYfYDYdNtuL3KM+lIs8Q==" + }, + "@tanstack/query-persist-client-core": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-4.32.1.tgz", + "integrity": "sha512-KgnkNigmOMi2aikxdhCRe0MaAh1Dq94/nNjmcSxfflj9L3v4F9tEQAig/F7m2+jethP1AiIYBax5nN4aqm7NFg==", + "requires": { + "@tanstack/query-core": "4.32.1" + } }, "@tanstack/react-query": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.32.0.tgz", - "integrity": "sha512-B8WUMcByYAH9500ENejDCATOmEZhqjtS9wsfiQ3BNa+s+yAynY8SESI8WWHhSqUmjd0pmCSFRP6BOUGSda3QXA==", + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.32.1.tgz", + "integrity": "sha512-lPTfOq6bR6DorPaS018gTMd3zs8r06tlERiVY6BRP9SnDkkl4ckqeANava/jPLWrSZP+EA15loQUTmvZs6k2GA==", "requires": { - "@tanstack/query-core": "4.32.0", + "@tanstack/query-core": "4.32.1", "use-sync-external-store": "^1.2.0" } }, "@tanstack/react-query-devtools": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.32.0.tgz", - "integrity": "sha512-rOmWqzKzRmQrQULV5Ova2FGEEPT76FZA3hz8T+LFkvp3ehw9ugSZ1BosgRJ7AFCeir+5pcNvFwILy4pDK8HpRw==", + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.32.1.tgz", + "integrity": "sha512-/ZgxCfGXLIXUvaIRzrNCP+C4iv1bIleNzXCjGKFZ4qKEifnv5A/SpWE2dG4SBjqXVlIkMAP82lesfoHcsOm+zg==", "requires": { "@tanstack/match-sorter-utils": "^8.7.0", "superjson": "^1.10.0", "use-sync-external-store": "^1.2.0" } }, + "@tanstack/react-query-persist-client": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-4.32.1.tgz", + "integrity": "sha512-HtfhSOyMSjdASpPXWBWv9JquUk5b8HjOwbFVmtA8xIDFQm9qS35PikXO2YbBXhuz/LEknRhct/M3PMI/XkRQSg==", + "requires": { + "@tanstack/query-persist-client-core": "4.32.1" + } + }, "@teamsupercell/typings-for-css-modules-loader": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/@teamsupercell/typings-for-css-modules-loader/-/typings-for-css-modules-loader-2.5.2.tgz", @@ -31792,6 +31842,11 @@ "dev": true, "requires": {} }, + "idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" + }, "identity-obj-proxy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", diff --git a/package.json b/package.json index a2c8015f..cf88d3cf 100644 --- a/package.json +++ b/package.json @@ -261,8 +261,9 @@ "@mantine/modals": "^6.0.17", "@mantine/notifications": "^6.0.17", "@mantine/utils": "^6.0.17", - "@tanstack/react-query": "^4.32.0", - "@tanstack/react-query-devtools": "^4.32.0", + "@tanstack/react-query": "^4.32.1", + "@tanstack/react-query-devtools": "^4.32.1", + "@tanstack/react-query-persist-client": "^4.32.1", "@ts-rest/core": "^3.23.0", "axios": "^1.4.0", "clsx": "^2.0.0", @@ -279,6 +280,7 @@ "fuse.js": "^6.6.2", "history": "^5.3.0", "i18next": "^21.6.16", + "idb-keyval": "^6.2.1", "immer": "^9.0.21", "is-electron": "^2.2.2", "lodash": "^4.17.21", diff --git a/src/renderer/api/query-keys.ts b/src/renderer/api/query-keys.ts index 557ec210..8f3def7f 100644 --- a/src/renderer/api/query-keys.ts +++ b/src/renderer/api/query-keys.ts @@ -208,7 +208,7 @@ export const queryKeys: Record< return [serverId, 'songs', 'list'] as const; }, lyrics: (serverId: string, query?: LyricsQuery) => { - if (query) return [serverId, 'song', 'lyrics', query] as const; + if (query) return [serverId, 'song', 'lyrics', 'select', query] as const; return [serverId, 'song', 'lyrics'] as const; }, lyricsByRemoteId: (searchQuery: { remoteSongId: string; remoteSource: LyricSource }) => { diff --git a/src/renderer/features/lyrics/queries/lyric-query.ts b/src/renderer/features/lyrics/queries/lyric-query.ts index 08336d6a..55a598a7 100644 --- a/src/renderer/features/lyrics/queries/lyric-query.ts +++ b/src/renderer/features/lyrics/queries/lyric-query.ts @@ -86,7 +86,7 @@ export const useSongLyricsBySong = ( const server = getServerById(song?.serverId); return useQuery({ - cacheTime: 1000 * 60 * 10, + cacheTime: Infinity, enabled: !!song && !!server, onError: () => {}, queryFn: async ({ signal }) => { @@ -138,7 +138,7 @@ export const useSongLyricsBySong = ( return null; }, queryKey: queryKeys.songs.lyrics(server?.id || '', query), - staleTime: 1000 * 60 * 2, + staleTime: Infinity, }); }; diff --git a/src/renderer/features/lyrics/synchronized-lyrics.tsx b/src/renderer/features/lyrics/synchronized-lyrics.tsx index 13b43539..fc59501a 100644 --- a/src/renderer/features/lyrics/synchronized-lyrics.tsx +++ b/src/renderer/features/lyrics/synchronized-lyrics.tsx @@ -146,7 +146,7 @@ export const SynchronizedLyrics = ({ 'sychronized-lyrics-scroll-container', ) as HTMLElement; const currentLyric = document.querySelector(`#lyric-${index}`) as HTMLElement; - const offsetTop = currentLyric?.offsetTop - doc?.clientHeight / 2 ?? 0; + const offsetTop = currentLyric.offsetTop - doc.clientHeight / 2 ?? 0; if (currentLyric === null) { lyricRef.current = undefined; diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 49c583a3..0253dff4 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -1,19 +1,68 @@ import { Notifications } from '@mantine/notifications'; -import { QueryClientProvider } from '@tanstack/react-query'; +import { + PersistedClient, + Persister, + PersistQueryClientProvider, +} from '@tanstack/react-query-persist-client'; +import { get, set, del } from 'idb-keyval'; import { createRoot } from 'react-dom/client'; import { App } from './app'; import { queryClient } from './lib/react-query'; + import 'overlayscrollbars/overlayscrollbars.css'; +export function createIDBPersister(idbValidKey: IDBValidKey = 'reactQuery') { + return { + persistClient: async (client: PersistedClient) => { + set(idbValidKey, client); + }, + removeClient: async () => { + await del(idbValidKey); + }, + restoreClient: async () => { + // eslint-disable-next-line no-return-await + return await get(idbValidKey); + }, + } as Persister; +} + +const indexedDbPersister = createIDBPersister('feishin'); + const container = document.getElementById('root')! as HTMLElement; const root = createRoot(container); root.render( - + { + const isSuccess = query.state.status === 'success'; + const isLyricsQueryKey = + query.queryKey.includes('song') && + query.queryKey.includes('lyrics') && + query.queryKey.includes('select'); + + return isSuccess && isLyricsQueryKey; + }, + }, + hydrateOptions: { + defaultOptions: { + queries: { + cacheTime: Infinity, + }, + }, + }, + maxAge: Infinity, + persister: indexedDbPersister, + }} + > - , + , );