Compare commits

...

6 Commits

Author SHA1 Message Date
oHaoDaio d23f7619ec chore: Support pnpm v11 2026-06-09 22:15:47 -07:00
Kendall Garner 44de6f2207 chore: upgrade depdencencies (#2133)
* upgrade depdencencies
2026-06-09 21:18:47 -07:00
BotBlake f6f25154a1 add "enhancement" to exempt-issue-labels (#2061) 2026-06-09 11:22:36 -07:00
Pedro Vieira 880516069d fix: preserve infinite list cache on component remount (fixes random sort reshuffling) (#2097)
* fix: preserve infinite list cache on component remount

When browsing with random sort, navigating to a detail view and coming
back would reshuffle the list. This happens because the list component
unmounts, losing its internal ref guard, and the reset effect re-fetches
all pages — returning a new random order from the server.
2026-06-09 11:21:02 -07:00
Hosted Weblate 95970183db Translated using Weblate
Currently translated at 100.0% (1245 of 1245 strings) (Chinese (Traditional Han script))
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/zh_Hant/

Translated using Weblate

Currently translated at 100.0% (1245 of 1245 strings) (Catalan)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/ca/

Translated using Weblate

Currently translated at 100.0% (1245 of 1245 strings) (Estonian)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/et/

Co-authored-by: Ondo <SparkyOndo@proton.me>
Co-authored-by: rimasx <riks_12@hot.ee>
Co-authored-by: 為什麼不加空格 <c++23@users.noreply.hosted.weblate.org>
2026-06-09 07:01:35 +00:00
Hosted Weblate 3a2c952d2a Translated using Weblate
Currently translated at 75.7% (943 of 1245 strings) (Estonian)
Translation: feishin/Translation
Translate-URL: https://hosted.weblate.org/projects/feishin/translation/et/

Co-authored-by: rimasx <riks_12@hot.ee>
2026-06-07 22:01:21 +02:00
26 changed files with 2789 additions and 2515 deletions
-4
View File
@@ -44,8 +44,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
@@ -129,8 +127,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-4
View File
@@ -19,8 +19,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
@@ -123,8 +121,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-2
View File
@@ -16,8 +16,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-2
View File
@@ -16,8 +16,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-2
View File
@@ -38,8 +38,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-2
View File
@@ -16,8 +16,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
-2
View File
@@ -16,8 +16,6 @@ jobs:
- name: Install Node and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
+1 -1
View File
@@ -43,6 +43,6 @@ jobs:
stale-issue-label: 'stale'
exempt-issue-labels: 'keep,security'
exempt-issue-labels: 'keep,security,enhancement'
stale-pr-label: 'stale'
exempt-pr-labels: 'keep,security'
-2
View File
@@ -12,8 +12,6 @@ jobs:
- name: Install Node.js and PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Install dependencies
run: pnpm install
+1 -4
View File
@@ -3,10 +3,7 @@ FROM node:23-alpine AS builder
WORKDIR /app
# Copy package.json first to cache node_modules
COPY package.json pnpm-lock.yaml .
# Match CI (pnpm/action-setup version: 10). Latest pnpm 11 fails install without approve-builds.
RUN corepack enable && corepack prepare pnpm@10 --activate
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .
RUN pnpm install
+1 -1
View File
@@ -63,7 +63,7 @@ linux:
artifactName: ${productName}-${os}-${arch}.${ext}
toolsets:
appimage: '1.0.2'
appimage: '1.0.3'
npmRebuild: false
+1 -1
View File
@@ -63,7 +63,7 @@ linux:
artifactName: ${productName}-${os}-${arch}.${ext}
toolsets:
appimage: '1.0.2'
appimage: '1.0.3'
npmRebuild: false
publish:
+1 -1
View File
@@ -63,7 +63,7 @@ linux:
artifactName: ${productName}-${os}-${arch}.${ext}
toolsets:
appimage: '1.0.2'
appimage: '1.0.3'
npmRebuild: false
afterAllArtifactBuild: scripts/after-all-artifact-build.mjs
+42 -42
View File
@@ -69,79 +69,78 @@
"postversion": "node ./scripts/update-app-stream.mjs"
},
"resolutions": {
"react-router": "7.14.0",
"xml2js": "0.5.0"
},
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "1.7.7",
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.5",
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.2.0",
"@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/utils": "^4.0.0",
"@mantine/colors-generator": "^9.1.1",
"@mantine/core": "^9.1.1",
"@mantine/dates": "^9.1.1",
"@mantine/form": "^9.1.1",
"@mantine/hooks": "^9.1.1",
"@mantine/modals": "^9.1.1",
"@mantine/notifications": "^9.1.1",
"@radix-ui/react-context-menu": "^2.2.16",
"@tanstack/react-query": "^5.96.2",
"@tanstack/react-query-devtools": "^5.96.2",
"@tanstack/react-query-persist-client": "^5.96.2",
"@mantine/colors-generator": "^9.3.0",
"@mantine/core": "^9.3.0",
"@mantine/dates": "^9.3.0",
"@mantine/form": "^9.3.0",
"@mantine/hooks": "^9.3.0",
"@mantine/modals": "^9.3.0",
"@mantine/notifications": "^9.3.0",
"@radix-ui/react-context-menu": "^2.3.0",
"@tanstack/react-query": "5.96.2",
"@tanstack/react-query-devtools": "5.96.2",
"@tanstack/react-query-persist-client": "5.96.2",
"@ts-rest/core": "^3.52.1",
"@wavesurfer/react": "^1.0.12",
"@xhayper/discord-rpc": "^1.3.3",
"@xhayper/discord-rpc": "^1.3.4",
"audiomotion-analyzer": "^4.5.4",
"axios": "^1.14.0",
"axios": "^1.17.0",
"butterchurn": "3.0.0-beta.5",
"butterchurn-presets": "3.0.0-beta.4",
"cheerio": "^1.2.0",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"dayjs": "^1.11.20",
"dompurify": "^3.3.3",
"dayjs": "^1.11.21",
"dompurify": "^3.4.8",
"electron-debug": "^3.2.0",
"electron-localshortcut": "^3.2.1",
"electron-log": "^5.4.3",
"electron-log": "^5.4.4",
"electron-store": "^8.2.0",
"electron-updater": "^6.8.3",
"electron-updater": "^6.8.9",
"fast-average-color": "9.5.0",
"fast-xml-parser": "^5.5.10",
"fast-xml-parser": "^5.8.0",
"format-duration": "^3.0.2",
"fuse.js": "^7.2.0",
"fuse.js": "^7.4.2",
"i18next": "^25.10.10",
"icecast-metadata-stats": "^0.1.12",
"idb-keyval": "^6.2.2",
"idb-keyval": "^6.2.5",
"immer": "^10.2.0",
"is-electron": "^2.2.2",
"lodash": "^4.18.1",
"md5": "^2.3.0",
"motion": "^12.38.0",
"motion": "^12.40.0",
"mpris-service": "^2.1.2",
"nanoid": "^3.3.11",
"nanoid": "^3.3.12",
"node-mpv": "github:jeffvli/Node-MPV#32b4d64395289ad710c41d481d2707a7acfc228f",
"overlayscrollbars": "^2.14.0",
"overlayscrollbars": "^2.16.0",
"overlayscrollbars-react": "^0.5.6",
"qs": "^6.15.0",
"react": "^19.2.4",
"qs": "^6.15.2",
"react": "^19.2.7",
"react-call": "^1.8.2",
"react-dom": "^19.2.4",
"react-dom": "^19.2.7",
"react-error-boundary": "^5.0.0",
"react-i18next": "^16.6.6",
"react-icons": "^5.6.0",
"react-player": "^2.16.1",
"react-router": "^7.14.0",
"react-router": "^7.17.0",
"react-split-pane": "^3.2.0",
"react-virtualized-auto-sizer": "^1.0.26",
"react-window": "1.8.11",
"react-window-v2": "npm:react-window@^2.2.7",
"semver": "^7.7.4",
"semver": "^7.8.2",
"string-to-color": "^2.2.2",
"wavesurfer.js": "^7.12.5",
"ws": "^8.20.0",
"wavesurfer.js": "^7.12.7",
"ws": "^8.21.0",
"zod": "^3.25.76",
"zustand": "^5.0.12"
"zustand": "^5.0.14"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
@@ -150,8 +149,8 @@
"@types/electron-localshortcut": "^3.1.3",
"@types/lodash": "^4.17.24",
"@types/md5": "^2.3.6",
"@types/node": "^24.12.2",
"@types/react": "^19.2.14",
"@types/node": "^24.13.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react-window": "^1.8.8",
"@types/source-map-support": "^0.5.10",
@@ -160,32 +159,33 @@
"babel-plugin-react-compiler": "^1.0.0",
"concurrently": "^9.2.1",
"cross-env": "^10.1.0",
"electron": "^41.7.0",
"electron-builder": "^26.8.2",
"electron": "^41.7.1",
"electron-builder": "^26.15.0",
"electron-devtools-installer": "^4.0.0",
"electron-vite": "^4.0.1",
"eslint": "^9.39.4",
"eslint-plugin-perfectionist": "^4.15.1",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.4.26",
"i18next-parser": "^9.4.0",
"postcss-preset-mantine": "^1.18.0",
"postcss-simple-vars": "^7.0.1",
"prettier": "^3.8.1",
"prettier": "^3.8.3",
"prettier-plugin-packagejson": "^2.5.22",
"stylelint": "^16.26.1",
"stylelint-config-css-modules": "^4.6.0",
"stylelint-config-recess-order": "^7.7.0",
"stylelint-config-standard": "^39.0.1",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vite": "^7.3.5",
"vite-plugin-conditional-import": "^0.1.7",
"vite-plugin-dynamic-import": "^1.6.0",
"vite-plugin-ejs": "^1.7.0",
"vite-plugin-pwa": "^1.2.0"
"vite-plugin-pwa": "^1.3.0"
},
"packageManager": "pnpm@11.5.2",
"pnpm": {
"onlyBuiltDependencies": [
"electron",
+2186 -2388
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
allowBuilds:
abstract-socket: true
electron: true
electron-winstaller: true
esbuild: true
overrides:
"xml2js": "0.5.0"
"react-router": "7.14.0"
+2 -1
View File
@@ -1182,7 +1182,8 @@
"sleepTimer_setCustom": "Configura el temporitzador",
"sleepTimer_cancel": "Cancel·la el temporitzador",
"albumRadio": "Ràdio d'àlbums",
"scrobbleForceSubmit": "Força l'scrobble"
"scrobbleForceSubmit": "Força l'scrobble",
"sleepTimer_endOfAlbum": "Final de l'àlbum actual"
},
"error": {
"credentialsRequired": "Credencials requerides",
+456 -5
View File
@@ -609,7 +609,7 @@
"updates": "Uuenda",
"cache": "Vahemälu",
"application": "Rakendus",
"queryBuilder": "Päringu koostaja",
"queryBuilder": "Päringukoostaja",
"theme": "Teema",
"controls": "Juhtnupud",
"sidebar": "Külgriba",
@@ -653,8 +653,8 @@
"addNext": "Järgmine",
"addLastShuffled": "Viimane (juhuesitus)",
"addNextShuffled": "Järgmine (juhuesitus)",
"albumRadio": "Albumi raadio",
"artistRadio": "Esitaja raadio",
"albumRadio": "Albumiraadio",
"artistRadio": "Esitajaraadio",
"holdToShuffle": "Hoia all segamiseks",
"favorite": "Lemmik",
"lyrics": "Laulusõnad",
@@ -685,7 +685,7 @@
"skip_forward": "Hüppa edasi",
"stop": "Peata",
"toggleFullscreenPlayer": "Täisekraani lüliti",
"trackRadio": "Pala raadio",
"trackRadio": "Looraadio",
"unfavorite": "Eemalda lemmikutest",
"pause": "Paus",
"viewQueue": "Kuva järjekord",
@@ -952,12 +952,463 @@
"musicbrainz": "Kuva MusicBrainzi linke",
"qobuz_description": "Kuva esitaja/albumi lehtedel Qobuz linke",
"qobuz": "Kuva Qobuzi linke",
"spotify_description": "Kuva artisti/albumi lehtedel Spotify linke"
"spotify_description": "Kuva artisti/albumi lehtedel Spotify linke",
"spotify": "Kuva Spotify linke",
"nativeSpotify_description": "Ava brauseri asemel Spotify rakenduses",
"nativeSpotify": "Kasuta Spotify rakendust",
"neteaseTranslation_description": "Sisselülitamisel otsitakse ja kuvatakse võimaluse korral NetEase'ist pärit tõlgitud laulusõnu",
"neteaseTranslation": "Luba NetEase'i tõlked",
"notify": "Luba lauluteavitused",
"notify_description": "Näita teavitust, kui lugu vahetub",
"pathReplace": "Failitee asendamine",
"pathReplace_description": "Asenda oma serveri vaikimisi failitee",
"pathReplace_optionRemovePrefix": "Eemalda eesliide",
"pathReplace_optionAddPrefix": "Lisa eesliide",
"passwordStore_description": "Millist paroolihoidlat kasutada. Muuda seda juhul, kui paroolide salvestamisega on probleeme",
"passwordStore": "Paroolihoidla",
"playerFilters": "Filtreeri lugusid järjekorrast",
"playerFilters_description": "Jäta lood järjekorda lisamata järgmiste kriteeriumide põhjal",
"playbackStyle_description": "Vali pleieri esitusstiil",
"playbackStyle_optionCrossFade": "Ristvahetus",
"playbackStyle_optionNormal": "Tavaline",
"playbackStyle": "Taasesituse stiil",
"playButtonBehavior_description": "Määrab esitusnupu vaikimisi käitumise lugude järjekorda lisamisel",
"playButtonBehavior_optionAddLast": "$t(player.addLast)",
"playButtonBehavior_optionAddNext": "$t(player.addNext)",
"playButtonBehavior_optionPlay": "$t(player.play)",
"playButtonBehavior_optionPlayShuffled": "$t(player.shuffle)",
"playButtonBehavior": "Esitusnupu käitumine",
"artistRadioCount_description": "Määrab lugude arvu, mis laetakse esitaja- ja looraadio jaoks",
"artistRadioCount": "Esitaja-/looraadio lugude arv",
"imageResolution": "Pildi resolutsioon",
"imageResolution_description": "Rakenduses kasutatavate piltide resolutsioon. Väärtuse 0 puhul kasutatakse pildi algset resolutsiooni",
"imageResolution_optionTable": "Tabel",
"imageResolution_optionItemCard": "Elemendikaart",
"imageResolution_optionSidebar": "Külgriba",
"imageResolution_optionHeader": "Päis",
"imageResolution_optionFullScreenPlayer": "Täisekraanpleier",
"playerbarOpenDrawer_description": "Võimaldab esitusribal klõpsates avada täisekraanpleieri",
"playerbarOpenDrawer": "Esitusriba täisekraani lüliti",
"playerbarSlider": "Esitusriba liugur",
"playerbarSlider_description": "Helilaine kuvamist ei soovitata aeglase või mahupiiranguga internetiühenduse puhul",
"playerbarSliderType_optionSlider": "Liugur",
"playerbarSliderType_optionWaveform": "Helilaine",
"playerbarWaveformAlign": "Helilaine joondus",
"playerbarWaveformAlign_optionTop": "Üleval",
"playerbarWaveformAlign_optionCenter": "Keskel",
"playerbarWaveformAlign_optionBottom": "All",
"playerbarWaveformBarWidth": "Helilaine riba laius",
"playerbarWaveformGap": "Helilaine ribade vahe",
"playerbarWaveformRadius": "Helilaine ribade ümarus",
"playerbarWaveformStretch": "Helilaine venitus",
"playerbarWaveformStretch_description": "Venitab helilainet, et täita kogu olemasolev ala",
"preferLocalLyrics_description": "Eelista kohalikke laulusõnu kaugserveri omadele",
"preferLocalLyrics": "Eelista kohalikke laulusõnu",
"showLyricsInSidebar_description": "Esitusjärjekorrale lisatakse paneel laulusõnade kuvamiseks",
"showLyricsInSidebar": "Kuva laulusõnu pleieri külgribal",
"sidebarPlaylistFolderView": "Kaustavaade",
"sidebarPlaylistFolderView_optionSingle": "Üks kaust",
"showRatings_description": "Määrab, kas kasutajaliideses kuvatakse tärnidega hindamise võimalus",
"showRatings": "Kuva tärnidega hindamine",
"blurExplicitImages": "Hägusta mittesobiliku sisuga pildid",
"blurExplicitImages_description": "Albumi- ja loopildid, millel on mittesobiliku sisu hoiatus, hägustatakse",
"enableGridMultiSelect": "Luba ruudustikus mitme elemendi valimine",
"enableGridMultiSelect_description": "Sisselülitamisel võimaldab see ruudustikuvaates korraga mitut elementi valida. Väljalülitamisel viib pildile klikkimine otse selle elemendi lehele",
"showVisualizerInSidebar_description": "Pleieri külgribale lisatakse paneel, mis kuvab muusika visuaali",
"showVisualizerInSidebar": "Kuva visualiseerija pleieri külgribal",
"combinedLyricsAndVisualizer_description": "Ühenda laulusõnad ja visualiseerija ühte paneeli",
"combinedLyricsAndVisualizer": "Ühenda laulusõnad ja visualiseerija pleieri külgribal",
"preservePitch_description": "Säilitab taasesituse kiiruse muutmisel helikõrguse",
"preservePitch": "Säilita helikõrgus",
"audioFadeOnStatusChange": "Heli hääbumine oleku muutumisel",
"audioFadeOnStatusChange_description": "Lülitab sisse heli sujuva vaibumise ja sissetulemise, kui muusika pannakse mängima või pausile",
"preventSleepOnPlayback_description": "Keela ekraani välja lülitamine muusika esitamisel",
"preventSleepOnPlayback": "Keela unerežiim taasesituse ajal",
"preventSuspendOnPlayback_description": "Keela rakenduse ooterežiim muusika esitamisel",
"preventSuspendOnPlayback": "Keela ooterežiim taasesituse ajal",
"remotePassword_description": "Määrab parooli kaugjuhtimisserveri jaoks. Need sisselogimisandmed edastatakse vaikimisi krüpteerimata, seega on soovitatav valida unikaalne parool, millest pole sul kahju",
"remotePassword": "Kaugjuhtimisserveri parool",
"remotePort_description": "Määrab kaugjuhtimisserveri pordi",
"remotePort": "Kaugjuhtimisserveri port",
"remoteUsername_description": "Määrab kaugjuhtimisserveri kasutajanime. Kui nii kasutajanimi kui ka parool on tühjad, lülitatakse isikutuvastus välja",
"remoteUsername": "Kaugjuhtimisserveri kasutajanimi",
"replayGainClipping_description": "Takista {{ReplayGain}}i põhjustatud heli moonutamine, vähendades automaatselt helitugevust",
"replayGainClipping": "{{ReplayGain}}i moonutuste vältimine",
"replayGainFallback_description": "Rakendatav võimendus (dB), kui failil puuduvad {{ReplayGain}}i sildid",
"replayGainFallback": "{{ReplayGain}}i varuväärtus",
"replayGainMode_description": "Kohandab helitugevust vastavalt faili metaandmetesse salvestatud {{ReplayGain}}i väärtustele",
"replayGainMode_optionAlbum": "$t(entity.album, {\"count\": 1})",
"replayGainMode_optionNone": "$t(common.none)",
"replayGainMode_optionTrack": "$t(entity.track, {\"count\": 1})",
"replayGainMode": "{{ReplayGain}} režiim",
"replayGainPreamp_description": "Kohandab {{ReplayGain}}i väärtustele rakendatavat eelvõimendust",
"replayGainPreamp": "{{ReplayGain}}i eelvõimendus (dB)",
"sampleRate_description": "Vali väljundi diskreetimissagedus juhuks, kui valitud sagedus erineb esitatava meedia omast. Väärtus, mis on väiksem kui 8000, kasutab vaikimisi sagedust",
"sampleRate": "Diskreetimissagedus",
"savePlayQueue_description": "Salvesta esitusjärjekord rakenduse sulgemisel ja taasta see rakenduse avamisel",
"savePlayQueue": "Salvesta esitusjärjekord",
"showSkipButton_description": "Kuva või peida esitusribal kerimise nuppe",
"showSkipButton": "Kuva kerimisnupud",
"showSkipButtons_description": "Kuva või peida esitusribal kerimise nuppe",
"showSkipButtons": "Kuva kerimisnupud",
"sidebarCollapsedNavigation_description": "Kuva või peida navigeerimine ahendatud külgribal",
"sidebarCollapsedNavigation": "Külgriba (ahendatud) navigeerimine",
"sidebarConfiguration_description": "Vali külgriba elemendid ja nende järjekord",
"sidebarConfiguration": "Külgriba seadistus",
"playerItemConfiguration_description": "Vali täisekraanil kuvatava pleieri elemendid ja nende järjekord",
"playerItemConfiguration": "Pleieri elementide seadistus",
"sidebarPlaylistFolders_description": "Loo kaustavaade esitusloenditele, mille nimes sisaldub seadistatud eraldusmärk",
"sidebarPlaylistFolders": "Luba kaustad",
"sidebarPlaylistFolderSeparator_description": "Tähemärk, mis eraldab esitusloendi nimes kaustatasemeid",
"sidebarPlaylistFolderSeparator": "Kaustade eraldusmärk",
"sidebarPlaylistFolderView_description": "Kuidas kuvada kaustu külgribal",
"sidebarPlaylistFolderView_optionTree": "Puuvaade",
"sidebarPlaylistFolderView_optionNavigation": "Navigatsioonivaade",
"sidebarPlaylistFolderTreeIndent_description": "Puuvaate tasemete taane pikslites",
"sidebarPlaylistFolderTreeIndent": "Puuvaate taane",
"sidebarPlaylistFolderTreeLineColor_description": "Puuvaate ühendusjoonte värv (vaiketeema puhul jäta tühjaks)",
"sidebarPlaylistFolderTreeLineColor": "Ühendusjoonte värv",
"sidebarPlaylistList_description": "Kuva või peida esitusloendite loend külgribal",
"sidebarPlaylistList": "Esitusloendid külgribal",
"sidebarPlaylistMode_description": "Kuidas kuvada esitusloendeid külgriba loendis",
"sidebarPlaylistMode": "Külgriba esitusloendite vaade",
"sidebarPlaylistMode_optionCompact": "Kompaktne",
"sidebarPlaylistMode_optionExpanded": "Laiendatud",
"sidebarPlaylistSorting_description": "Lubab esitusloendeid külgribal lohistades käsitsi järjestada, asendades serveri vaikejärjestuse",
"sidebarPlaylistSorting": "Külgriba esitusloendite järjestus",
"sidebarPlaylistListFilterRegex_description": "Peida külgribalt esitusloendid, mis ühtivad selle regulaaravaldisega",
"sidebarPlaylistListFilterRegex_placeholder": "Näiteks ^tänane miks.*",
"sidebarPlaylistListFilterRegex": "Esitusloendite filtri regulaaravaldis",
"sidePlayQueueStyle_description": "Määrab külgriba esitusjärjekorra stiili",
"sidePlayQueueStyle_optionAttached": "Kinnitatud",
"sidePlayQueueStyle_optionDetached": "Eraldatud",
"sidePlayQueueLayout": "Külgriba esitusjärjekorra paigutus",
"sidePlayQueueLayout_description": "Määrab kinnitatud külgriba esitusjärjekorra paigutuse",
"sidePlayQueueLayout_optionHorizontal": "Horisontaalne",
"sidePlayQueueLayout_optionVertical": "Vertikaalne",
"mediaSession_description": "Lubab meediaseansi integratsiooni, kuvades juhtnupud ja metaandmed süsteemsel helitugevuse paneelil ning lukustuskuval. Vajab Web Audio pleierit.",
"mediaSession": "Luba meediaseanss",
"sidePlayQueueStyle": "Külgmise esitusjärjekorra stiil",
"skipDuration_description": "Määrab aja, mille võrra edasi või tagasi hüpata, kasutades esitusriba hüppenuppe",
"skipDuration": "Hüppe kestus",
"skipPlaylistPage_description": "Esitusloendile liikudes ava vaikelehe asemel kohe laulude nimekiri",
"skipPlaylistPage": "Jäta esitusloendi leht vahele",
"startMinimized_description": "Käivita rakendus süsteemisalves",
"startMinimized": "Käivita minimeerituna",
"theme_description": "Määrab rakenduses kasutatava teema",
"theme": "Teema",
"themeDark_description": "Määrab rakenduses kasutatava tumeda teema",
"themeDark": "Teema (tume)",
"themeLight_description": "Määrab rakenduses kasutatava heleda teema",
"themeLight": "Teema (hele)",
"transcode": "Luba transkoodimine",
"transcode_description": "Võimaldab transkoodimise erinevatesse vormingutesse",
"transcodeBitrate_description": "Valib transkoodimise bitikiiruse. 0 tähendab, et server valib ise",
"transcodeBitrate": "Transkoodimise bitikiirus",
"transcodeFormat_description": "Valib transkoodimise vormingu. Jäta tühjaks, et lasta serveril otsustada",
"transcodeFormat": "Transkoodimise vorming",
"translationApiKey_description": "API-võti tõlkimiseks (ainult globaalse teenuse lõpp-punkt)",
"translationApiKey": "Tõlketeenuse API-võti",
"translationApiProvider_description": "Tõlketeenuse API pakkuja",
"translationApiProvider": "Tõlke-API pakkuja",
"translationTargetLanguage_description": "Sihtkeel tõlkimiseks",
"translationTargetLanguage": "Tõlke sihtkeel",
"trayEnabled_description": "Kuva/peida salveikoon/-menüü. Kui keelatud, keelatakse ka süsteemisalve minimeerimine/sulgemine",
"trayEnabled": "Kuva salveikoon",
"useSystemTheme_description": "Järgi süsteemis määratud heledat või tumedat kujundust",
"useSystemTheme": "Kasuta süsteemi teemat",
"volumeWheelStep_description": "Helitugevuse muutmise samm, kui kerida hiirerattaga heliribal",
"volumeWheelStep": "Hiirerattaga muutmise samm",
"volumeWidth_description": "Helitugevuse riba laius",
"volumeWidth": "Heliriba laius",
"waveformLoadingDelay": "Helilaine laadimise viivitus",
"waveformLoadingDelay_description": "Viivitus sekundites enne helilaine laadimist. Suurenda seda väärtust, kui veebipleieri kasutamisel esineb hakkimist.",
"webAudio_description": "Kasuta veebiheli. See võimaldab täpsemaid funktsioone, nagu näiteks ReplayGain. Lülita see välja, kui esineb probleeme",
"webAudio": "Kasuta veebiheli",
"windowBarStyle_description": "Vali akna päiseriba stiil",
"windowBarStyle": "Akna päiseriba stiil",
"zoom_description": "Määrab rakenduse suurenduse protsendi",
"zoom": "Suurenduse protsent",
"queryBuilder": "Päringu koostaja",
"queryBuilderCustomFields_inputLabel": "Nimetus",
"queryBuilderCustomFields_inputTag": "Silt",
"queryBuilderCustomFields": "Kohandatud väljad",
"queryBuilderCustomFields_description": "Lisa kohandatud välju, mida päringukoosturis kasutada"
},
"datetime": {
"minuteShort": "m",
"secondShort": "s",
"hourShort": "t",
"dayShort": "p"
},
"visualizer": {
"options": {
"weightingFilter": {
"z": "Z",
"d": "D",
"c": "C",
"b": "B",
"a": "A",
"none": "Puudub"
},
"colorMode": {
"gradient": "Värviüleminek",
"barIndex": "Riba number",
"barLevel": "Riba tase"
},
"gradient": {
"classic": "Klassikaline",
"prism": "Prisma",
"rainbow": "Vikerkaar",
"steelblue": "Terassinine",
"orangered": "Oranžpunane"
},
"channelLayout": {
"single": "Üksik",
"dualCombined": "Kombineeritud kaksikvaade",
"dualHorizontal": "Horisontaalne kaksikvaade",
"dualVertical": "Vertikaalne kaksikvaade"
},
"frequencyScale": {
"none": "Puudub",
"bark": "Barki skaala",
"linear": "Lineaarne skaala",
"log": "Logaritmiline skaala",
"mel": "Meli skaala"
},
"mode": {
"0": "[0] Eraldatud sagedused",
"1": "[1] 1/24 oktav / 240 sagedusriba",
"2": "[2] 1/12 oktav / 120 sagedusriba",
"3": "[3] 1/8 oktav / 80 sagedusriba",
"4": "[4] 1/6 oktav / 60 sagedusriba",
"5": "[5] 1/4 oktav / 40 sagedusriba",
"6": "[6] 1/3 oktav / 30 sagedusriba",
"7": "[7] Pooloktav / 20 sagedusriba",
"8": "[8] Täisoktav / 10 sagedusriba",
"10": "[10] Joon- / pindgraafik"
}
},
"colors": "Värvid",
"builtIn": "Sisseehitatud",
"custom": "Kohandatud",
"remove": "Eemalda",
"level": "Tase",
"systemAudioConsentAllow": "Luba",
"systemAudioConsentBody": "Visualiseerija vajab töötamiseks juurdepääsu süsteemi helile",
"systemAudioConsentDecline": "Keeldu",
"systemAudioConsentTitle": "Kas lubada ligipääs süsteemi helile?",
"systemAudioCaptureFailed": "Hõivamist ei saanud alustada: {{message}}",
"systemAudioNoAudioTrack": "Heliriba ei tagastatud. Veendu, et lubad küsimisel heli hõive.",
"systemAudioExclusiveModeNotSupported": "Visualiseerija pole saadaval, kui eksklusiivne helirežiim on sisse lülitatud. Lülita MPV seadetes eksklusiivne helirežiim välja ja proovi uuesti.",
"visualizerType": "Visualiseerija tüüp",
"cyclePresets": "Tsükli eelseadistused",
"cycleTime": "Tsükli aeg (sekundites)",
"includeAllPresets": "Kaasa kõik eelseadistused",
"ignoredPresets": "Eiratud eelseadistused",
"selectedPresets": "Valitud eelseadistused",
"randomizeNextPreset": "Vali järgmine eelseadistus juhuslikult",
"blendTime": "Segamisaeg",
"presets": "Eelseadistused",
"selectPreset": "Vali eelseadistus",
"applyPreset": "Rakenda eelseadistus",
"saveAsPreset": "Salvesta eelseadistusena",
"updatePreset": "Uuenda eelseadistus",
"copyConfiguration": "Kopeeri seadistus",
"pasteConfiguration": "Kleebi seadistus",
"pasteConfigurationPlaceholder": "Kleebi JSON-seadistus siia...",
"pasteFromClipboard": "Kleebi lõikelaualt",
"applyConfiguration": "Rakenda seadistus",
"configCopied": "Seadistus kopeeriti lõikelauale",
"configCopyFailed": "Seadistuse kopeerimine nurjus",
"configPasted": "Seadistus rakendati edukalt",
"configPasteFailed": "Seadistuse rakendamine nurjus. Kontrolli vormingut.",
"configPasteReadFailed": "Lõikelaualt lugemine nurjus",
"presetName": "Eelseadistuse nimi",
"presetNamePlaceholder": "Sisesta eelseadistuse nimi",
"general": "Üldine",
"mode": "Režiim",
"mode1To8": "Režiim 18",
"mode10": "Režiim 10",
"barSpace": "Tulpade vahe",
"lineWidth": "Joone paksus",
"fillAlpha": "Täite läbipaistvus",
"channelLayout": "Kanalite paigutus",
"maxFPS": "Suurim FPS",
"opacity": "Läbipaistmatus",
"customGradients": "Kohandatud värviüleminekud",
"addCustomGradient": "Lisa kohandatud värviüleminek",
"gradientName": "Värviülemineku nimi",
"gradientNamePlaceholder": "Värviülemineku nimi",
"vertical": "Vertikaalne",
"horizontal": "Horisontaalne",
"colorStops": "Värvipunktid",
"addColor": "Lisa värv",
"position": "Asukoht",
"pasteGradient": "Aseta värviüleminek",
"pasteGradientPlaceholder": "Aseta värviülemineku JSON siia...",
"colorMode": "Värvirežiim",
"gradient": "Värviüleminek",
"gradientLeft": "Värviüleminek vasakul",
"gradientRight": "Värviüleminek paremal",
"fft": "FFT",
"fftSize": "FFT suurus",
"smoothing": "Sujuvus",
"frequencyRangeAndScaling": "Sagedusvahemik ja skaala",
"minimumFrequency": "Väikseim sagedus",
"maximumFrequency": "Suurim sagedus",
"frequencyScale": "Sagedusskaala",
"sensitivity": "Tundlikkus",
"weightingFilter": "Kaalufilter",
"minimumDecibels": "Minimaalsed detsibellid",
"maximumDecibels": "Maksimaalsed detsibellid",
"linearAmplitude": "Lineaarne amplituud",
"linearBoost": "Lineaarne võimendus",
"peakBehavior": "Tippväärtuste kuvamine",
"showPeaks": "Kuva tippväärtused",
"fadePeaks": "Hajuta tippväärtused",
"peakLine": "Tippväärtuste joon",
"gravity": "Raskusjõud",
"peakFadeTime": "Tippude hajumisaeg (ms)",
"peakHoldTime": "Tippude hoidmisaeg (ms)",
"radialSpectrum": "Ringikujuline spekter",
"radial": "Radiaalne",
"radialInvert": "Radiaalne pööramine",
"spinSpeed": "Pöörlemiskiirus",
"radius": "Raadius",
"reflexMirror": "Peegeldus",
"reflexFit": "Peegelduse sobitamine",
"reflexRatio": "Peegelduse suhe",
"reflexAlpha": "Peegelduse läbipaistvus",
"reflexBrightness": "Peegelduse heledus",
"mirror": "Peegel",
"miscellaneousSettings": "Varia",
"alphaBars": "Läbipaistvad ribad",
"ansiBands": "ANSI ribad",
"ledBars": "LED ribad",
"trueLeds": "Päris LED-id",
"lumiBars": "Lumi ribad",
"outlineBars": "Kontuurribad",
"roundBars": "Ümarad ribad",
"lowResolution": "Madal eraldusvõime",
"splitGradient": "Jagatud värviüleminek",
"showFPS": "Kuva kaadrisagedus",
"showScaleX": "Kuva X-telje skaala",
"noteLabels": "Noodinimed",
"showScaleY": "Kuva Y-telje skaala"
},
"table": {
"column": {
"album": "Album",
"albumArtist": "Albumi esitaja",
"albumCount": "Albumid",
"artist": "Esitaja",
"biography": "Biograafia",
"bitDepth": "Bititihedus",
"bitrate": "Bitikiirus",
"bpm": "BPM",
"codec": "Koodek",
"comment": "Kommentaar",
"dateAdded": "Lisatud",
"discNumber": "Plaat",
"favorite": "Lemmik",
"genre": "Žanr",
"lastPlayed": "Viimati esitatud",
"path": "Asukoht",
"playCount": "Esitusi",
"rating": "Hinne",
"releaseDate": "Ilmumiskuupäev",
"releaseYear": "Aasta",
"sampleRate": "Diskreetimissagedus",
"size": "Suurus",
"title": "Pealkiri",
"trackNumber": "Lugu",
"owner": "Omanik",
"channels": "Kanalid",
"songCount": "Lood"
},
"config": {
"general": {
"advancedSettings": "Täpsemad seaded",
"autoFitColumns": "Mahuta veerud automaatselt",
"autosize": "Mahuta automaatselt",
"moveUp": "Liigu üles",
"moveDown": "Liigu alla",
"pinToLeft": "Kinnita vasakule",
"pinToRight": "Kinnita paremale",
"alignLeft": "Joonda vasakule",
"alignCenter": "Joonda keskele",
"alignRight": "Joonda paremale",
"followCurrentSong": "Jälgi praegust lugu",
"displayType": "Kuvamisviis",
"gap": "$t(common.gap)",
"itemGap": "Elementide vahe (px)",
"itemSize": "Elemendi suurus (px)",
"itemsPerRow": "Elementide arv real",
"size": "$t(common.size)",
"size_default": "Vaikimisi",
"size_compact": "Kompaktne",
"size_large": "Suur",
"tableColumns": "Tabeli veerud",
"pagination": "Lehekülgedeks jagamine",
"pagination_itemsPerPage": "Elementide arv lehel",
"pagination_infinite": "Piiramatu",
"pagination_paginate": "Lehekülgedeks jagatud",
"alternateRowColors": "Erinevat värvi read",
"horizontalBorders": "Ridade piirjooned",
"rowHoverHighlight": "Rea esiletõstmine kursoriga",
"showHeader": "Kuva päis",
"verticalBorders": "Veergude piirjooned"
},
"label": {
"actions": "$t(common.action, {\"count\": 2})",
"album": "$t(entity.album, {\"count\": 1})",
"albumGroup": "Albumirühm",
"albumCount": "$t(entity.album, {\"count\": 2})",
"albumArtist": "$t(entity.albumArtist, {\"count\": 1})",
"artist": "$t(entity.artist, {\"count\": 1})",
"biography": "$t(common.biography)",
"bitDepth": "$t(common.bitDepth)",
"bitrate": "$t(common.bitrate)",
"bpm": "$t(common.bpm)",
"channels": "$t(common.channel, {\"count\": 2})",
"codec": "$t(common.codec)",
"composer": "Helilooja",
"dateAdded": "Lisatud",
"discNumber": "Plaadi number",
"duration": "$t(common.duration)",
"favorite": "$t(common.favorite)",
"genre": "$t(entity.genre, {\"count\": 1})",
"genreBadge": "$t(entity.genre, {\"count\": 1}) (badges)",
"image": "Pilt",
"lastPlayed": "Viimati esitatud",
"note": "$t(common.note)",
"owner": "$t(common.owner)",
"path": "$t(common.path)",
"playCount": "Esitusi",
"rating": "$t(common.rating)",
"releaseDate": "Ilmumiskuupäev",
"rowIndex": "Rea number",
"sampleRate": "$t(common.sampleRate)",
"size": "$t(common.size)",
"songCount": "$t(entity.track, {\"count\": 2})",
"title": "$t(common.title)",
"titleArtist": "$t(common.title) (artist)",
"titleCombined": "$t(common.title) (kombineeritud)",
"trackNumber": "Loo number",
"year": "$t(common.year)"
},
"view": {
"detail": "Detail",
"grid": "Ruudustik",
"list": "Loend",
"table": "Tabel"
}
}
},
"dragDropZone": {
"error_oneFileOnly": "Vali ainult üks fail",
"error_readingFile": "Faili lugemisel tekkis viga: {{errorMessage}}",
"mainText": "Lohista fail siia"
}
}
+28 -28
View File
@@ -5,7 +5,7 @@
"bitrate": "位元率",
"bpm": "BPM",
"clear": "清空",
"collapse": "疊",
"collapse": "疊",
"comingSoon": "即將推出…",
"confirm": "確認",
"decrease": "降低",
@@ -18,9 +18,9 @@
"add": "新增",
"areYouSure": "你確定嗎?",
"ascending": "升冪",
"disable": "用",
"disable": "用",
"disc": "光碟",
"dismiss": "不再顯示",
"dismiss": "不理會",
"duration": "時長",
"edit": "編輯",
"enable": "啟用",
@@ -64,9 +64,9 @@
"cancel": "取消",
"center": "中央",
"channel_other": "聲道",
"configure": "設定",
"configure": "配置",
"create": "建立",
"currentSong": "目前$t(entity.track, {\"count\": 1})",
"currentSong": "當前 $t(entity.track, {\"count\": 1})",
"minimize": "最小化",
"modified": "已修改",
"name": "名稱",
@@ -75,13 +75,13 @@
"noResultsFromQuery": "未查詢到匹配結果",
"note": "注釋",
"additionalParticipants": "額外參與者",
"newVersion": "已安裝新版本 ({{version}})",
"newVersion": "新版本 ({{version}}) 已被安裝",
"viewReleaseNotes": "查看發行註記",
"albumGain": "專輯增益",
"albumPeak": "專輯峰值",
"bitDepth": "位元深度",
"close": "關閉",
"codec": "編",
"codec": "編解碼器",
"mbid": "MusicBrainz ID",
"preview": "預覽",
"reload": "重新載入",
@@ -107,7 +107,7 @@
"explicit": "露骨",
"gridRows": "網格行",
"noFilters": "未設定任何過濾器",
"countSelected": "{{count}}個已選取",
"countSelected": "{{count}} 個已選取",
"retry": "重試",
"example": "範例",
"mood": "情緒",
@@ -204,7 +204,7 @@
},
"appMenu": {
"openBrowserDevtools": "開啟瀏覽器開發者工具",
"collapseSidebar": "疊側邊欄",
"collapseSidebar": "疊側邊欄",
"expandSidebar": "展開側邊欄",
"goBack": "返回",
"goForward": "前進",
@@ -381,7 +381,7 @@
"playbackSpeed": "播放速度",
"playRandom": "隨機播放",
"previous": "上一首",
"queue_clear": "清空播放佇列",
"queue_clear": "清空佇列",
"queue_remove": "移除所選",
"repeat": "循環",
"repeat_all": "全部循環",
@@ -446,7 +446,7 @@
"crossfadeStyle_description": "選擇用於音訊播放器的淡入淡出風格",
"customFontPath": "自訂字型路徑",
"customFontPath_description": "設定應用程式要使用的自訂字型路徑",
"disableLibraryUpdateOnStartup": "用啟動時檢查新版本",
"disableLibraryUpdateOnStartup": "用啟動時檢查新版本",
"discordApplicationId": "{{discord}} 應用程式 ID",
"discordApplicationId_description": "{{discord}} Rich Presence 應用程式 ID(預設為 {{defaultId}}",
"discordIdleStatus": "顯示 Rich Presence 閒置狀態",
@@ -532,8 +532,8 @@
"showSkipButton": "顯示跳過按鈕",
"showSkipButton_description": "在播放條上顯示/隱藏跳過按鈕",
"sidebarPlaylistList": "側邊欄播放清單列表",
"sidebarCollapsedNavigation": "側邊欄(已疊)導航",
"sidebarCollapsedNavigation_description": "在疊的側邊欄中顯示或隱藏導航",
"sidebarCollapsedNavigation": "側邊欄(已疊)導航",
"sidebarCollapsedNavigation_description": "在疊的側邊欄中顯示或隱藏導航",
"sidebarConfiguration": "側邊欄設定",
"sidebarConfiguration_description": "選擇側邊欄包含的項目與順序",
"sidebarPlaylistList_description": "顯示或隱藏側邊欄歌單清單",
@@ -562,7 +562,7 @@
"exitToTray_description": "退出應用程式時最小化到系統匣而非關閉",
"followLyric_description": "滾動歌詞到目前播放位置",
"font": "字型",
"globalMediaHotkeys_description": "啟用或用系統媒體快捷鍵以控制播放",
"globalMediaHotkeys_description": "啟用或用系統媒體快捷鍵以控制播放",
"hotkey_browserBack": "瀏覽器返回",
"hotkey_favoriteCurrentSong": "收藏 $t(common.currentSong)",
"hotkey_playbackStop": "停止",
@@ -573,7 +573,7 @@
"remotePassword": "遠端控制伺服器密碼",
"remotePassword_description": "設定遠端控制伺服器的密碼。這些憑證預設以不安全的方式傳輸,因此您應該使用一個您不在意的唯一密碼",
"remotePort_description": "設定遠端控制伺服器的連接埠",
"remoteUsername_description": "設定遠端控制伺服器的使用者名稱。如果使用者名稱和密碼都為空,則身分驗證將被用",
"remoteUsername_description": "設定遠端控制伺服器的使用者名稱。如果使用者名稱和密碼都為空,則身分驗證將被用",
"replayGainClipping_description": "自動降低增益以防止{{ReplayGain}}造成削波",
"showSkipButtons": "顯示跳過按鈕",
"themeDark_description": "應用程式將使用深色主題",
@@ -933,34 +933,34 @@
"title": "標題",
"trackNumber": "曲目編號",
"size": "大小",
"codec": "編",
"codec": "編解碼器",
"owner": "擁有者",
"bitDepth": "位元深度",
"sampleRate": "取樣率"
}
},
"action": {
"addToFavorites": "新增$t(entity.favorite, {\"count\": 2})",
"clearQueue": "清空播放佇列",
"createPlaylist": "建立$t(entity.playlist, {\"count\": 1})",
"deletePlaylist": "刪除$t(entity.playlist, {\"count\": 1})",
"addToPlaylist": "新增$t(entity.playlist, {\"count\": 1})",
"addToFavorites": "新增$t(entity.favorite, {\"count\": 2})",
"clearQueue": "清空佇列",
"createPlaylist": "建立 $t(entity.playlist, {\"count\": 1})",
"deletePlaylist": "刪除 $t(entity.playlist, {\"count\": 1})",
"addToPlaylist": "新增$t(entity.playlist, {\"count\": 1})",
"deselectAll": "取消全選",
"editPlaylist": "編輯 $t(entity.playlist, {\"count\": 1})",
"goToPage": "前往頁面",
"moveToBottom": "移至底部",
"moveToTop": "移至頂部",
"refresh": "$t(common.refresh)",
"removeFromFavorites": "從$t(entity.favorite, {\"count\": 2})移除",
"removeFromPlaylist": "從$t(entity.playlist, {\"count\": 1})移除",
"removeFromQueue": "從播放佇列中移除",
"removeFromFavorites": "從 $t(entity.favorite, {\"count\": 2}) 移除",
"removeFromPlaylist": "從 $t(entity.playlist, {\"count\": 1}) 移除",
"removeFromQueue": "從佇列中移除",
"setRating": "評分",
"toggleSmartPlaylistEditor": "切換$t(entity.smartPlaylist)編輯器",
"viewPlaylists": "查看$t(entity.playlist, {\"count\": 2})",
"toggleSmartPlaylistEditor": "切換 $t(entity.smartPlaylist) 編輯器",
"viewPlaylists": "查看 $t(entity.playlist, {\"count\": 2})",
"moveToNext": "移至下一項",
"openIn": {
"lastfm": "在Last.fm開啟",
"musicbrainz": "在MusicBrainz開啟",
"lastfm": "在 Last.fm開啟",
"musicbrainz": "在 MusicBrainz 開啟",
"spotify": "在 Spotify 中開啟",
"listenbrainz": "在 ListenBrainz 中開啟",
"qobuz": "在 Qobuz 中開啟"
+1 -1
View File
@@ -72,7 +72,7 @@ export const orderSearchResults = (args: {
searchResults = Array.from(combinedResults.values());
} else {
searchResults = fuse.search<InternetProviderLyricSearchResponse>({
searchResults = fuse.search({
...(params.artist && { artist: params.artist }),
...(params.name && { name: params.name }),
});
@@ -13,7 +13,7 @@ import { useListContext } from '/@/renderer/context/list-context';
import { eventEmitter } from '/@/renderer/events/event-emitter';
import { UserFavoriteEventPayload, UserRatingEventPayload } from '/@/renderer/events/events';
import { getListRefreshMutationKey } from '/@/renderer/features/shared/components/list-refresh-button';
import { LibraryItem } from '/@/shared/types/domain-types';
import { LibraryItem, SortKeyRandom } from '/@/shared/types/domain-types';
export const getListQueryKeyName = (itemType: LibraryItem): string => {
switch (itemType) {
@@ -108,8 +108,19 @@ export const useItemListInfiniteLoader = ({
[serverId, itemType, query],
);
const isRandomSort = query?.sortBy === SortKeyRandom;
const fetchPage = useCallback(
async (pageNumber: number) => {
if (isRandomSort) {
const existingData =
queryClient.getQueryData<InfiniteLoaderCacheData>(dataQueryKey);
if (existingData?.pagesLoaded?.[pageNumber]) {
lastFetchedPageRef.current = Math.max(lastFetchedPageRef.current, pageNumber);
return;
}
}
const startIndex = pageNumber * itemsPerPage;
const queryParams = {
limit: itemsPerPage,
@@ -118,6 +129,7 @@ export const useItemListInfiniteLoader = ({
};
const result = await queryClient.fetchQuery({
gcTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
queryFn: async ({ signal }) => {
const result = await listQueryFn({
apiClientProps: { serverId, signal },
@@ -127,6 +139,7 @@ export const useItemListInfiniteLoader = ({
return result;
},
queryKey: queryKeys[getListQueryKeyName(itemType)].list(serverId, queryParams),
staleTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
});
// Update the query data with the fetched page
@@ -154,13 +167,32 @@ export const useItemListInfiniteLoader = ({
// Track the last fetched page
lastFetchedPageRef.current = Math.max(lastFetchedPageRef.current, pageNumber);
},
[itemsPerPage, query, queryClient, serverId, dataQueryKey, listQueryFn, itemType],
[
itemsPerPage,
query,
queryClient,
serverId,
dataQueryKey,
listQueryFn,
itemType,
isRandomSort,
],
);
// Reset the loaded pages and refetch current page when the query changes
useEffect(() => {
const currentDataQueryKey = JSON.stringify(dataQueryKey);
if (isRandomSort) {
const existingData = queryClient.getQueryData<InfiniteLoaderCacheData | undefined>(
dataQueryKey,
);
if (existingData?.dataMap && existingData.dataMap.size > 0) {
previousDataQueryKeyRef.current = currentDataQueryKey;
return;
}
}
if (previousDataQueryKeyRef.current === currentDataQueryKey || isRefetchingRef.current) {
return;
}
@@ -12,7 +12,7 @@ import { useListContext } from '/@/renderer/context/list-context';
import { eventEmitter } from '/@/renderer/events/event-emitter';
import { UserFavoriteEventPayload, UserRatingEventPayload } from '/@/renderer/events/events';
import { getListRefreshMutationKey } from '/@/renderer/features/shared/components/list-refresh-button';
import { LibraryItem } from '/@/shared/types/domain-types';
import { LibraryItem, SortKeyRandom } from '/@/shared/types/domain-types';
const getQueryKeyName = (itemType: LibraryItem): string => {
switch (itemType) {
@@ -76,6 +76,8 @@ export const useItemListPaginatedLoader = ({
const fetchRange = getFetchRange(currentPage, itemsPerPage);
const startIndex = fetchRange.startIndex;
const isRandomSort = query?.sortBy === SortKeyRandom;
const queryParams = useMemo(
() => ({
limit: itemsPerPage,
@@ -86,7 +88,7 @@ export const useItemListPaginatedLoader = ({
);
const { data } = useQuery({
gcTime: 1000 * 15,
gcTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
placeholderData: { items: getInitialData(itemsPerPage) },
queryFn: async ({ signal }) => {
const result = await listQueryFn({
@@ -97,7 +99,7 @@ export const useItemListPaginatedLoader = ({
return result;
},
queryKey: queryKeys[getQueryKeyName(itemType)].list(serverId, queryParams),
staleTime: 1000 * 15,
staleTime: isRandomSort ? 1000 * 60 * 10 : 1000 * 15,
});
const refreshMutation = useMutation({
@@ -224,25 +224,26 @@ export const PlaylistQueryEditor = ({
return detailQuery?.data?.rules?.order || 'asc';
}, [detailQuery?.data?.rules?.order, detailQuery?.data?.rules?.sort]);
const appliedQuery = appliedJsonState?.query;
const detailQueryRules = detailQuery?.data?.rules;
const effectiveQuery = useMemo(
() =>
appliedJsonState?.query ??
(detailQuery?.data?.rules?.all
? { all: detailQuery.data.rules.all }
: detailQuery?.data?.rules?.any
? { any: detailQuery.data.rules.any }
: detailQuery?.data?.rules),
[appliedJsonState?.query, detailQuery?.data?.rules],
appliedQuery ??
(detailQueryRules?.all
? { all: detailQueryRules.all }
: detailQueryRules?.any
? { any: detailQueryRules.any }
: detailQueryRules),
[appliedQuery, detailQueryRules],
);
const effectiveLimit = appliedJsonState?.limit ?? detailQuery?.data?.rules?.limit;
const effectiveLimitPercent =
appliedJsonState?.limitPercent ?? detailQuery?.data?.rules?.limitPercent;
const appliedSort = appliedJsonState?.sort;
const effectiveSortBy = useMemo(
() =>
(appliedJsonState?.sort ? [appliedJsonState.sort] : parseSortBy()) as
| SongListSort
| SongListSort[],
[appliedJsonState?.sort, parseSortBy],
() => (appliedSort ? [appliedSort] : parseSortBy()) as SongListSort | SongListSort[],
[appliedSort, parseSortBy],
);
const effectiveSortOrder = appliedJsonState?.sort
? appliedJsonState.sort.startsWith('-')
@@ -298,6 +298,7 @@ export const useServerAuthenticated = () => {
await new Promise((resolve) => setTimeout(resolve, NETWORK_RETRY_DELAY_MS));
// Retry authentication
// eslint-disable-next-line react-hooks/immutability
return authenticateServer(serverWithAuth, nextRetry);
}
+1 -1
View File
@@ -189,7 +189,7 @@ const appRouterModals = {
export const AppRouter = () => {
const router = (
<HashRouter unstable_useTransitions={false}>
<HashRouter>
<ModalsProvider modals={appRouterModals}>
<RouterErrorBoundary>
<Routes>
+6 -4
View File
@@ -465,6 +465,8 @@ export const tagListSortMap: TagListSortMap = {
},
};
export const SortKeyRandom = 'random';
export enum AlbumListSort {
ALBUM_ARTIST = 'albumArtist',
ARTIST = 'artist',
@@ -476,7 +478,7 @@ export enum AlbumListSort {
ID = 'id',
NAME = 'name',
PLAY_COUNT = 'playCount',
RANDOM = 'random',
RANDOM = SortKeyRandom,
RATING = 'rating',
RECENTLY_ADDED = 'recentlyAdded',
RECENTLY_PLAYED = 'recentlyPlayed',
@@ -598,7 +600,7 @@ export enum SongListSort {
ID = 'id',
NAME = 'name',
PLAY_COUNT = 'playCount',
RANDOM = 'random',
RANDOM = SortKeyRandom,
RATING = 'rating',
RECENTLY_ADDED = 'recentlyAdded',
RECENTLY_PLAYED = 'recentlyPlayed',
@@ -725,7 +727,7 @@ export enum AlbumArtistListSort {
FAVORITED = 'favorited',
NAME = 'name',
PLAY_COUNT = 'playCount',
RANDOM = 'random',
RANDOM = SortKeyRandom,
RATING = 'rating',
RECENTLY_ADDED = 'recentlyAdded',
RELEASE_DATE = 'releaseDate',
@@ -814,7 +816,7 @@ export enum ArtistListSort {
FAVORITED = 'favorited',
NAME = 'name',
PLAY_COUNT = 'playCount',
RANDOM = 'random',
RANDOM = SortKeyRandom,
RATING = 'rating',
RECENTLY_ADDED = 'recentlyAdded',
RELEASE_DATE = 'releaseDate',