From 9995b2e774ea1ba1f723a7bae30566c1036b367a Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Wed, 31 Jan 2024 06:27:56 +0000 Subject: [PATCH] [enhancement]: support clearing query and http cache (#475) * [enhancement]: support clearing query and http cache - Adds the ability to invalidate all queries (useful for forcing refresh, and clearing lyrics which are cached forever) - [Desktop only] adds the ability to clear the Electron HTTP cache (e.g. cached images) * use clearer language * move cache settings to general --- src/i18n/locales/en.json | 5 + src/main/main.ts | 4 + src/main/preload/browser.ts | 7 ++ .../components/general/general-tab.tsx | 10 +- .../components/window/cache-settngs.tsx | 92 +++++++++++++++++++ src/renderer/preload.d.ts | 3 +- 6 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/renderer/features/settings/components/window/cache-settngs.tsx diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index d47480bb..681a1855 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -396,6 +396,11 @@ "audioExclusiveMode_description": "enable exclusive output mode. In this mode, the system is usually locked out, and only mpv will be able to output audio", "audioPlayer": "audio player", "audioPlayer_description": "select the audio player to use for playback", + "clearCache": "Clear browser cache", + "clearCache_description": "A 'hard clear' of Feishin. In addition to clearing Feishin's cache, empty the browser cache (saved images and other assets). Server credentials and settings are preserved.", + "clearQueryCache": "Clear Feishin cache", + "clearQueryCache_description": "A 'soft clear' of Feishin. This will refresh playlists, track metadata, and reset saved lyrics. Settings, server credentials and cached images are preserved.", + "clearCacheSuccess": "cache cleared successfully", "crossfadeDuration": "crossfade duration", "crossfadeDuration_description": "sets the duration of the crossfade effect", "crossfadeStyle": "crossfade style", diff --git a/src/main/main.ts b/src/main/main.ts index 72cf8773..2ca95d90 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -260,6 +260,10 @@ const createWindow = async () => { app.exit(); }); + ipcMain.handle('window-clear-cache', async () => { + return mainWindow?.webContents.session.clearCache(); + }); + ipcMain.on('app-restart', () => { // Fix for .AppImage if (process.env.APPIMAGE) { diff --git a/src/main/preload/browser.ts b/src/main/preload/browser.ts index d24e739a..bf7b5881 100644 --- a/src/main/preload/browser.ts +++ b/src/main/preload/browser.ts @@ -24,7 +24,12 @@ const devtools = () => { ipcRenderer.send('window-dev-tools'); }; +const clearCache = (): Promise => { + return ipcRenderer.invoke('window-clear-cache'); +}; + export const browser = { + clearCache, devtools, exit, maximize, @@ -32,3 +37,5 @@ export const browser = { quit, unmaximize, }; + +export type Browser = typeof browser; diff --git a/src/renderer/features/settings/components/general/general-tab.tsx b/src/renderer/features/settings/components/general/general-tab.tsx index 748648b7..c0caaf5e 100644 --- a/src/renderer/features/settings/components/general/general-tab.tsx +++ b/src/renderer/features/settings/components/general/general-tab.tsx @@ -4,6 +4,8 @@ import { ControlSettings } from '/@/renderer/features/settings/components/genera import { SidebarSettings } from '/@/renderer/features/settings/components/general/sidebar-settings'; import { ThemeSettings } from '/@/renderer/features/settings/components/general/theme-settings'; import { RemoteSettings } from '/@/renderer/features/settings/components/general/remote-settings'; +import { CacheSettings } from '/@/renderer/features/settings/components/window/cache-settngs'; +import isElectron from 'is-electron'; export const GeneralTab = () => { return ( @@ -15,8 +17,14 @@ export const GeneralTab = () => { + {isElectron() && ( + <> + + + + )} - + ); }; diff --git a/src/renderer/features/settings/components/window/cache-settngs.tsx b/src/renderer/features/settings/components/window/cache-settngs.tsx new file mode 100644 index 00000000..7a566334 --- /dev/null +++ b/src/renderer/features/settings/components/window/cache-settngs.tsx @@ -0,0 +1,92 @@ +import { Button } from '@mantine/core'; +import { closeAllModals, openModal } from '@mantine/modals'; +import { useQueryClient } from '@tanstack/react-query'; +import isElectron from 'is-electron'; +import { useTranslation } from 'react-i18next'; +import { ConfirmModal, toast } from '/@/renderer/components'; +import { SettingsOptions } from '/@/renderer/features/settings/components/settings-option'; +import { useCallback, useState } from 'react'; + +const browser = isElectron() ? window.electron.browser : null; + +export const CacheSettings = () => { + const [isClearing, setIsClearing] = useState(false); + const queryClient = useQueryClient(); + const { t } = useTranslation(); + + const clearCache = useCallback( + async (full: boolean) => { + setIsClearing(true); + + try { + queryClient.clear(); + + if (full && browser) { + await browser.clearCache(); + } + + toast.success({ + message: t('setting.clearCacheSuccess', { postProcess: 'sentenceCase' }), + }); + } catch (error) { + console.error(error); + toast.error({ message: (error as Error).message }); + } + + setIsClearing(false); + closeAllModals(); + }, + [queryClient, t], + ); + + const openResetConfirmModal = (full: boolean) => { + const key = full ? 'clearCache' : 'clearQueryCache'; + openModal({ + children: ( + clearCache(full)}> + {t(`common.areYouSure`, { postProcess: 'sentenceCase' })} + + ), + title: t(`setting.${key}`), + }); + }; + + return ( + <> + openResetConfirmModal(false)} + > + {t('common.clear', { postProcess: 'sentenceCase' })} + + } + description={t('setting.clearQueryCache', { + context: 'description', + })} + title={t('setting.clearQueryCache')} + /> + {browser && ( + openResetConfirmModal(true)} + > + {t('common.clear', { postProcess: 'sentenceCase' })} + + } + description={t('setting.clearCache', { + context: 'description', + })} + title={t('setting.clearCache')} + /> + )} + + ); +}; diff --git a/src/renderer/preload.d.ts b/src/renderer/preload.d.ts index c59a59e2..db69c9ba 100644 --- a/src/renderer/preload.d.ts +++ b/src/renderer/preload.d.ts @@ -9,11 +9,12 @@ import { Utils } from '/@/main/preload/utils'; import { LocalSettings } from '/@/main/preload/local-settings'; import { Ipc } from '/@/main/preload/ipc'; import { DiscordRpc } from '/@/main/preload/discord-rpc'; +import { Browser } from '/@/main/preload/browser'; declare global { interface Window { electron: { - browser: any; + browser: Browser; discordRpc: DiscordRpc; ipc?: Ipc; ipcRenderer: {