mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 20:40:15 +02:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4134af0340 | |||
| 29a43ca185 | |||
| e452f86170 | |||
| ec765dca6a | |||
| 64a3752b54 | |||
| 24069d285f | |||
| 77fe886da4 | |||
| ef16e1403d | |||
| ff6dda7b06 | |||
| 479aa2e22d | |||
| ab8c3ad0ec | |||
| dc03a432fe | |||
| 751ad55d02 | |||
| 78dc89303d | |||
| 4328d8860e | |||
| 58a36b3bba | |||
| 618e5d8da8 | |||
| be6ec49cfa | |||
| 65ecdc7666 | |||
| da42fd78d2 |
@@ -30,7 +30,6 @@ const config: UserConfig = {
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/i18n': resolve('src/i18n'),
|
||||
'/@/main': resolve('src/main'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
@@ -40,7 +39,6 @@ const config: UserConfig = {
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/i18n': resolve('src/i18n'),
|
||||
'/@/preload': resolve('src/preload'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import eslintPluginReactHooks from 'eslint-plugin-react-hooks';
|
||||
import eslintPluginReactRefresh from 'eslint-plugin-react-refresh';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['**/node_modules', '**/dist', '**/out', '**/*-schema.d.ts'] },
|
||||
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
|
||||
tseslint.configs.recommended,
|
||||
perfectionist.configs['recommended-natural'],
|
||||
eslintPluginReact.configs.flat.recommended,
|
||||
|
||||
+4
-9
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "feishin",
|
||||
"version": "0.20.0",
|
||||
"version": "0.20.1",
|
||||
"description": "A modern self-hosted music player.",
|
||||
"keywords": [
|
||||
"subsonic",
|
||||
@@ -27,8 +27,6 @@
|
||||
"dev": "electron-vite dev",
|
||||
"dev:remote": "vite dev --config remote.vite.config.ts",
|
||||
"dev:watch": "electron-vite dev --watch",
|
||||
"generate-api": "pnpm run generate-api:subsonic",
|
||||
"generate-api:subsonic": "openapi-typescript https://opensubsonic.netlify.app/docs/openapi/openapi.json -o ./src/shared/api/subsonic/subsonic-schema.d.ts",
|
||||
"i18next": "i18next -c src/i18n/i18next-parser.config.js",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "pnpm run lint-code && pnpm run lint-styles",
|
||||
@@ -73,9 +71,9 @@
|
||||
"@mantine/hooks": "^8.2.8",
|
||||
"@mantine/modals": "^8.2.8",
|
||||
"@mantine/notifications": "^8.2.8",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"@tanstack/react-query-devtools": "^5.83.0",
|
||||
"@tanstack/react-query-persist-client": "^5.83.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",
|
||||
"@xhayper/discord-rpc": "^1.3.0",
|
||||
"audiomotion-analyzer": "^4.5.0",
|
||||
@@ -105,7 +103,6 @@
|
||||
"mpris-service": "^2.1.2",
|
||||
"nanoid": "^3.3.3",
|
||||
"node-mpv": "github:jeffvli/Node-MPV#32b4d64395289ad710c41d481d2707a7acfc228f",
|
||||
"openapi-fetch": "^0.14.0",
|
||||
"overlayscrollbars": "^2.11.1",
|
||||
"overlayscrollbars-react": "^0.5.6",
|
||||
"qs": "^6.14.0",
|
||||
@@ -138,7 +135,6 @@
|
||||
"@types/lodash": "^4.17.18",
|
||||
"@types/md5": "^2.3.5",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/qs": "^6.14.0",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@types/react-window": "^1.8.5",
|
||||
@@ -159,7 +155,6 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"i18next-parser": "^9.0.2",
|
||||
"openapi-typescript": "^7.8.0",
|
||||
"postcss-preset-mantine": "^1.17.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.14",
|
||||
|
||||
Generated
+122
-226
@@ -60,14 +60,14 @@ importers:
|
||||
specifier: ^8.2.8
|
||||
version: 8.2.8(@mantine/core@8.2.8(@mantine/hooks@8.2.8(react@19.1.0))(@types/react@18.3.23)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@8.2.8(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(react@19.1.0)
|
||||
specifier: ^4.32.1
|
||||
version: 4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-query-devtools':
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)
|
||||
specifier: ^4.32.1
|
||||
version: 4.36.1(@tanstack/react-query@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-query-persist-client':
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)
|
||||
specifier: ^4.32.1
|
||||
version: 4.36.1(@tanstack/react-query@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
||||
'@ts-rest/core':
|
||||
specifier: ^3.23.0
|
||||
version: 3.52.1(@types/node@22.15.32)(zod@3.25.23)
|
||||
@@ -155,9 +155,6 @@ importers:
|
||||
node-mpv:
|
||||
specifier: github:jeffvli/Node-MPV#32b4d64395289ad710c41d481d2707a7acfc228f
|
||||
version: https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f
|
||||
openapi-fetch:
|
||||
specifier: ^0.14.0
|
||||
version: 0.14.0
|
||||
overlayscrollbars:
|
||||
specifier: ^2.11.1
|
||||
version: 2.11.3
|
||||
@@ -249,9 +246,6 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^22.15.32
|
||||
version: 22.15.32
|
||||
'@types/qs':
|
||||
specifier: ^6.14.0
|
||||
version: 6.14.0
|
||||
'@types/react':
|
||||
specifier: ^18.3.23
|
||||
version: 18.3.23
|
||||
@@ -272,7 +266,7 @@ importers:
|
||||
version: 8.18.1
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^4.3.4
|
||||
version: 4.5.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0))
|
||||
version: 4.5.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2))
|
||||
concurrently:
|
||||
specifier: ^7.1.0
|
||||
version: 7.6.0
|
||||
@@ -290,7 +284,7 @@ importers:
|
||||
version: 3.2.1
|
||||
electron-vite:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0))
|
||||
version: 3.1.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2))
|
||||
eslint:
|
||||
specifier: ^9.24.0
|
||||
version: 9.27.0
|
||||
@@ -312,9 +306,6 @@ importers:
|
||||
i18next-parser:
|
||||
specifier: ^9.0.2
|
||||
version: 9.3.0
|
||||
openapi-typescript:
|
||||
specifier: ^7.8.0
|
||||
version: 7.8.0(typescript@5.8.3)
|
||||
postcss-preset-mantine:
|
||||
specifier: ^1.17.0
|
||||
version: 1.17.0(postcss@8.5.3)
|
||||
@@ -344,7 +335,7 @@ importers:
|
||||
version: 5.8.3
|
||||
vite:
|
||||
specifier: ^6.3.5
|
||||
version: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)
|
||||
version: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)
|
||||
vite-plugin-conditional-import:
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7
|
||||
@@ -353,7 +344,7 @@ importers:
|
||||
version: 1.6.0
|
||||
vite-plugin-ejs:
|
||||
specifier: ^1.7.0
|
||||
version: 1.7.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0))
|
||||
version: 1.7.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1049,16 +1040,6 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
|
||||
'@redocly/ajv@8.11.2':
|
||||
resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==}
|
||||
|
||||
'@redocly/config@0.22.2':
|
||||
resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==}
|
||||
|
||||
'@redocly/openapi-core@1.34.3':
|
||||
resolution: {integrity: sha512-3arRdUp1fNx55itnjKiUhO6t4Mf91TsrTIYINDNLAZPS0TPd5YpiXRctwjel0qqWoOOhjA34cZ3m4dksLDFUYg==}
|
||||
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
|
||||
|
||||
'@remix-run/router@1.23.0':
|
||||
resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -1182,31 +1163,39 @@ packages:
|
||||
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@tanstack/query-core@5.83.0':
|
||||
resolution: {integrity: sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==}
|
||||
'@tanstack/match-sorter-utils@8.19.4':
|
||||
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tanstack/query-devtools@5.81.2':
|
||||
resolution: {integrity: sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg==}
|
||||
'@tanstack/query-core@4.36.1':
|
||||
resolution: {integrity: sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==}
|
||||
|
||||
'@tanstack/query-persist-client-core@5.83.0':
|
||||
resolution: {integrity: sha512-hdKgHkr1MYnwZX+QHj/9JjXZx9gL2RUCD5xSX0EHZiqUQhMk4Gcryq9xosn8LmYRMlhkjk7n9uV+X4UXRvgoIg==}
|
||||
'@tanstack/query-persist-client-core@4.36.1':
|
||||
resolution: {integrity: sha512-eocgCeI7D7TRv1IUUBMfVwOI0wdSmMkBIbkKhqEdTrnUHUQEeOaYac8oeZk2cumAWJdycu6P/wB+WqGynTnzXg==}
|
||||
|
||||
'@tanstack/react-query-devtools@5.83.0':
|
||||
resolution: {integrity: sha512-yfp8Uqd3I1jgx8gl0lxbSSESu5y4MO2ThOPBnGNTYs0P+ZFu+E9g5IdOngyUGuo6Uz6Qa7p9TLdZEX3ntik2fQ==}
|
||||
'@tanstack/react-query-devtools@4.36.1':
|
||||
resolution: {integrity: sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw==}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': ^5.83.0
|
||||
react: ^18 || ^19
|
||||
'@tanstack/react-query': ^4.36.1
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
|
||||
'@tanstack/react-query-persist-client@5.83.0':
|
||||
resolution: {integrity: sha512-uEqJnSbqlvzlhYJ+RU+2c2DmbbT7cw6eFjiewEXZFXaSGWNjvUG02LePrwL8cdLlRQFcZKas30IdckboOoVg9Q==}
|
||||
'@tanstack/react-query-persist-client@4.36.1':
|
||||
resolution: {integrity: sha512-32I5b9aAu4NCiXZ7Te/KEQLfHbYeTNriVPrKYcvEThnZ9tlW01vLcSoxpUIsMYRsembvJUUAkzYBAiZHLOd6pQ==}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': ^5.83.0
|
||||
react: ^18 || ^19
|
||||
'@tanstack/react-query': ^4.36.1
|
||||
|
||||
'@tanstack/react-query@5.83.0':
|
||||
resolution: {integrity: sha512-/XGYhZ3foc5H0VM2jLSD/NyBRIOK4q9kfeml4+0x2DlL6xVuAcVEW+hTlTapAmejObg0i3eNqhkr2dT+eciwoQ==}
|
||||
'@tanstack/react-query@4.36.1':
|
||||
resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-native: '*'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
|
||||
'@tootallnate/once@2.0.0':
|
||||
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
|
||||
@@ -1280,9 +1269,6 @@ packages:
|
||||
'@types/prop-types@15.7.14':
|
||||
resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
|
||||
|
||||
'@types/qs@6.14.0':
|
||||
resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==}
|
||||
|
||||
'@types/react-dom@18.3.7':
|
||||
resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==}
|
||||
peerDependencies:
|
||||
@@ -1442,10 +1428,6 @@ packages:
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
ansi-colors@4.1.3:
|
||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1692,9 +1674,6 @@ packages:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
change-case@5.4.4:
|
||||
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
|
||||
|
||||
charenc@0.0.2:
|
||||
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
|
||||
|
||||
@@ -1773,9 +1752,6 @@ packages:
|
||||
colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
|
||||
colorette@1.4.0:
|
||||
resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
|
||||
|
||||
colorjs.io@0.5.2:
|
||||
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
|
||||
|
||||
@@ -1824,6 +1800,10 @@ packages:
|
||||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
copy-anything@3.0.5:
|
||||
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
|
||||
engines: {node: '>=12.13'}
|
||||
|
||||
core-util-is@1.0.2:
|
||||
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
|
||||
|
||||
@@ -2721,10 +2701,6 @@ packages:
|
||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
index-to-position@1.1.0:
|
||||
resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
infer-owner@1.0.4:
|
||||
resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
|
||||
|
||||
@@ -2894,6 +2870,10 @@ packages:
|
||||
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-what@4.1.16:
|
||||
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
|
||||
engines: {node: '>=12.13'}
|
||||
|
||||
isarray@1.0.0:
|
||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||
|
||||
@@ -2923,10 +2903,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
js-levenshtein@1.1.6:
|
||||
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
@@ -3363,18 +3339,6 @@ packages:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
openapi-fetch@0.14.0:
|
||||
resolution: {integrity: sha512-PshIdm1NgdLvb05zp8LqRQMNSKzIlPkyMxYFxwyHR+UlKD4t2nUjkDhNxeRbhRSEd3x5EUNh2w5sJYwkhOH4fg==}
|
||||
|
||||
openapi-typescript-helpers@0.0.15:
|
||||
resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==}
|
||||
|
||||
openapi-typescript@7.8.0:
|
||||
resolution: {integrity: sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^5.x
|
||||
|
||||
optionator@0.9.4:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@@ -3438,10 +3402,6 @@ packages:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
parse-json@8.3.0:
|
||||
resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
|
||||
|
||||
@@ -3510,10 +3470,6 @@ packages:
|
||||
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
|
||||
engines: {node: '>=10.4.0'}
|
||||
|
||||
pluralize@8.0.0:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
possible-typed-array-names@1.1.0:
|
||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3841,6 +3797,9 @@ packages:
|
||||
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
remove-accents@0.5.0:
|
||||
resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==}
|
||||
|
||||
remove-trailing-separator@1.1.0:
|
||||
resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==}
|
||||
|
||||
@@ -4329,9 +4288,9 @@ packages:
|
||||
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
||||
engines: {node: '>= 8.0'}
|
||||
|
||||
supports-color@10.0.0:
|
||||
resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==}
|
||||
engines: {node: '>=18'}
|
||||
superjson@1.13.3:
|
||||
resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
@@ -4530,9 +4489,6 @@ packages:
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
|
||||
uri-js-replace@1.0.1:
|
||||
resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==}
|
||||
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
@@ -4788,14 +4744,6 @@ packages:
|
||||
yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
|
||||
yaml-ast-parser@0.0.43:
|
||||
resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==}
|
||||
|
||||
yaml@2.8.0:
|
||||
resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
|
||||
engines: {node: '>= 14.6'}
|
||||
hasBin: true
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4903,7 +4851,7 @@ snapshots:
|
||||
'@babel/traverse': 7.27.1
|
||||
'@babel/types': 7.27.1
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
@@ -4989,7 +4937,7 @@ snapshots:
|
||||
'@babel/parser': 7.27.2
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/types': 7.27.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5091,7 +5039,7 @@ snapshots:
|
||||
|
||||
'@electron/get@2.0.3':
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
env-paths: 2.2.1
|
||||
fs-extra: 8.1.0
|
||||
got: 11.8.6
|
||||
@@ -5121,7 +5069,7 @@ snapshots:
|
||||
|
||||
'@electron/notarize@2.5.0':
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 9.1.0
|
||||
promise-retry: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
@@ -5130,7 +5078,7 @@ snapshots:
|
||||
'@electron/osx-sign@1.3.1':
|
||||
dependencies:
|
||||
compare-version: 0.1.2
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 10.1.0
|
||||
isbinaryfile: 4.0.10
|
||||
minimist: 1.2.8
|
||||
@@ -5143,7 +5091,7 @@ snapshots:
|
||||
'@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2
|
||||
'@malept/cross-spawn-promise': 2.0.0
|
||||
chalk: 4.1.2
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
detect-libc: 2.0.4
|
||||
fs-extra: 10.1.0
|
||||
got: 11.8.6
|
||||
@@ -5162,7 +5110,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@electron/asar': 3.2.18
|
||||
'@malept/cross-spawn-promise': 2.0.0
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
dir-compare: 4.2.0
|
||||
fs-extra: 11.3.1
|
||||
minimatch: 9.0.5
|
||||
@@ -5173,7 +5121,7 @@ snapshots:
|
||||
'@electron/windows-sign@1.2.2':
|
||||
dependencies:
|
||||
cross-dirname: 0.1.0
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 11.3.1
|
||||
minimist: 1.2.8
|
||||
postject: 1.0.0-alpha.6
|
||||
@@ -5266,7 +5214,7 @@ snapshots:
|
||||
'@eslint/config-array@0.20.0':
|
||||
dependencies:
|
||||
'@eslint/object-schema': 2.1.6
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5284,7 +5232,7 @@ snapshots:
|
||||
'@eslint/eslintrc@3.3.1':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
espree: 10.3.0
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
@@ -5389,7 +5337,7 @@ snapshots:
|
||||
|
||||
'@malept/flatpak-bundler@0.4.0':
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 9.1.0
|
||||
lodash: 4.17.21
|
||||
tmp-promise: 3.0.3
|
||||
@@ -5599,29 +5547,6 @@ snapshots:
|
||||
'@babel/runtime': 7.27.1
|
||||
react: 19.1.0
|
||||
|
||||
'@redocly/ajv@8.11.2':
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
uri-js-replace: 1.0.1
|
||||
|
||||
'@redocly/config@0.22.2': {}
|
||||
|
||||
'@redocly/openapi-core@1.34.3(supports-color@10.0.0)':
|
||||
dependencies:
|
||||
'@redocly/ajv': 8.11.2
|
||||
'@redocly/config': 0.22.2
|
||||
colorette: 1.4.0
|
||||
https-proxy-agent: 7.0.6(supports-color@10.0.0)
|
||||
js-levenshtein: 1.1.6
|
||||
js-yaml: 4.1.0
|
||||
minimatch: 5.1.6
|
||||
pluralize: 8.0.0
|
||||
yaml-ast-parser: 0.0.43
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@remix-run/router@1.23.0': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.9': {}
|
||||
@@ -5696,30 +5621,37 @@ snapshots:
|
||||
dependencies:
|
||||
defer-to-connect: 2.0.1
|
||||
|
||||
'@tanstack/query-core@5.83.0': {}
|
||||
|
||||
'@tanstack/query-devtools@5.81.2': {}
|
||||
|
||||
'@tanstack/query-persist-client-core@5.83.0':
|
||||
'@tanstack/match-sorter-utils@8.19.4':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.83.0
|
||||
remove-accents: 0.5.0
|
||||
|
||||
'@tanstack/react-query-devtools@5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)':
|
||||
'@tanstack/query-core@4.36.1': {}
|
||||
|
||||
'@tanstack/query-persist-client-core@4.36.1':
|
||||
dependencies:
|
||||
'@tanstack/query-devtools': 5.81.2
|
||||
'@tanstack/react-query': 5.83.0(react@19.1.0)
|
||||
'@tanstack/query-core': 4.36.1
|
||||
|
||||
'@tanstack/react-query-devtools@4.36.1(@tanstack/react-query@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/match-sorter-utils': 8.19.4
|
||||
'@tanstack/react-query': 4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
superjson: 1.13.3
|
||||
use-sync-external-store: 1.5.0(react@19.1.0)
|
||||
|
||||
'@tanstack/react-query-persist-client@5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)':
|
||||
'@tanstack/react-query-persist-client@4.36.1(@tanstack/react-query@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
|
||||
dependencies:
|
||||
'@tanstack/query-persist-client-core': 5.83.0
|
||||
'@tanstack/react-query': 5.83.0(react@19.1.0)
|
||||
react: 19.1.0
|
||||
'@tanstack/query-persist-client-core': 4.36.1
|
||||
'@tanstack/react-query': 4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
|
||||
'@tanstack/react-query@5.83.0(react@19.1.0)':
|
||||
'@tanstack/react-query@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.83.0
|
||||
'@tanstack/query-core': 4.36.1
|
||||
react: 19.1.0
|
||||
use-sync-external-store: 1.5.0(react@19.1.0)
|
||||
optionalDependencies:
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
'@tootallnate/once@2.0.0': {}
|
||||
|
||||
@@ -5800,8 +5732,6 @@ snapshots:
|
||||
|
||||
'@types/prop-types@15.7.14': {}
|
||||
|
||||
'@types/qs@6.14.0': {}
|
||||
|
||||
'@types/react-dom@18.3.7(@types/react@18.3.23)':
|
||||
dependencies:
|
||||
'@types/react': 18.3.23
|
||||
@@ -5868,7 +5798,7 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.32.1
|
||||
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
||||
'@typescript-eslint/visitor-keys': 8.32.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
eslint: 9.27.0
|
||||
typescript: 5.8.3
|
||||
transitivePeerDependencies:
|
||||
@@ -5883,7 +5813,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
|
||||
'@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.8.3)
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
eslint: 9.27.0
|
||||
ts-api-utils: 2.1.0(typescript@5.8.3)
|
||||
typescript: 5.8.3
|
||||
@@ -5896,7 +5826,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.32.1
|
||||
'@typescript-eslint/visitor-keys': 8.32.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
@@ -5922,7 +5852,7 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.32.1
|
||||
eslint-visitor-keys: 4.2.0
|
||||
|
||||
'@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0))':
|
||||
'@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2))':
|
||||
dependencies:
|
||||
'@babel/core': 7.27.1
|
||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.1)
|
||||
@@ -5930,7 +5860,7 @@ snapshots:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.9
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.17.0
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -5966,7 +5896,7 @@ snapshots:
|
||||
|
||||
agent-base@6.0.2:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -6003,8 +5933,6 @@ snapshots:
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
ansi-colors@4.1.3: {}
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.1.0: {}
|
||||
@@ -6038,7 +5966,7 @@ snapshots:
|
||||
builder-util-runtime: 9.3.1
|
||||
chromium-pickle-js: 0.2.0
|
||||
config-file-ts: 0.2.8-rc1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12)
|
||||
dotenv: 16.5.0
|
||||
dotenv-expand: 11.0.7
|
||||
@@ -6258,7 +6186,7 @@ snapshots:
|
||||
|
||||
builder-util-runtime@9.3.1:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
sax: 1.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6271,10 +6199,10 @@ snapshots:
|
||||
builder-util-runtime: 9.3.1
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 10.1.0
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6(supports-color@10.0.0)
|
||||
https-proxy-agent: 7.0.6
|
||||
is-ci: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
sanitize-filename: 1.6.3
|
||||
@@ -6355,8 +6283,6 @@ snapshots:
|
||||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
change-case@5.4.4: {}
|
||||
|
||||
charenc@0.0.2: {}
|
||||
|
||||
cheerio-select@2.1.0:
|
||||
@@ -6438,8 +6364,6 @@ snapshots:
|
||||
|
||||
colord@2.9.3: {}
|
||||
|
||||
colorette@1.4.0: {}
|
||||
|
||||
colorjs.io@0.5.2: {}
|
||||
|
||||
colors@1.4.0: {}
|
||||
@@ -6494,6 +6418,10 @@ snapshots:
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
copy-anything@3.0.5:
|
||||
dependencies:
|
||||
is-what: 4.1.16
|
||||
|
||||
core-util-is@1.0.2:
|
||||
optional: true
|
||||
|
||||
@@ -6593,11 +6521,9 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
||||
debug@4.4.1(supports-color@10.0.0):
|
||||
debug@4.4.1:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optionalDependencies:
|
||||
supports-color: 10.0.0
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
@@ -6787,7 +6713,7 @@ snapshots:
|
||||
|
||||
electron-localshortcut@3.2.1:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
electron-is-accelerator: 0.1.2
|
||||
keyboardevent-from-electron-accelerator: 2.0.0
|
||||
keyboardevents-areequal: 0.2.2
|
||||
@@ -6829,7 +6755,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
electron-vite@3.1.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)):
|
||||
electron-vite@3.1.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)):
|
||||
dependencies:
|
||||
'@babel/core': 7.27.1
|
||||
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.1)
|
||||
@@ -6837,14 +6763,14 @@ snapshots:
|
||||
esbuild: 0.25.4
|
||||
magic-string: 0.30.17
|
||||
picocolors: 1.1.1
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
electron-winstaller@5.4.0:
|
||||
dependencies:
|
||||
'@electron/asar': 3.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fs-extra: 7.0.1
|
||||
lodash: 4.17.21
|
||||
temp: 0.9.4
|
||||
@@ -7112,7 +7038,7 @@ snapshots:
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 8.3.0
|
||||
eslint-visitor-keys: 4.2.0
|
||||
@@ -7166,7 +7092,7 @@ snapshots:
|
||||
|
||||
extract-zip@2.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
get-stream: 5.2.0
|
||||
yauzl: 2.10.0
|
||||
optionalDependencies:
|
||||
@@ -7573,14 +7499,14 @@ snapshots:
|
||||
dependencies:
|
||||
'@tootallnate/once': 2.0.0
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7592,14 +7518,14 @@ snapshots:
|
||||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.6(supports-color@10.0.0):
|
||||
https-proxy-agent@7.0.6:
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7672,8 +7598,6 @@ snapshots:
|
||||
|
||||
indent-string@4.0.0: {}
|
||||
|
||||
index-to-position@1.1.0: {}
|
||||
|
||||
infer-owner@1.0.4: {}
|
||||
|
||||
inflight@1.0.6:
|
||||
@@ -7834,6 +7758,8 @@ snapshots:
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
is-what@4.1.16: {}
|
||||
|
||||
isarray@1.0.0: {}
|
||||
|
||||
isarray@2.0.5: {}
|
||||
@@ -7866,8 +7792,6 @@ snapshots:
|
||||
filelist: 1.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
js-levenshtein@1.1.6: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
@@ -8268,22 +8192,6 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
openapi-fetch@0.14.0:
|
||||
dependencies:
|
||||
openapi-typescript-helpers: 0.0.15
|
||||
|
||||
openapi-typescript-helpers@0.0.15: {}
|
||||
|
||||
openapi-typescript@7.8.0(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@redocly/openapi-core': 1.34.3(supports-color@10.0.0)
|
||||
ansi-colors: 4.1.3
|
||||
change-case: 5.4.4
|
||||
parse-json: 8.3.0
|
||||
supports-color: 10.0.0
|
||||
typescript: 5.8.3
|
||||
yargs-parser: 21.1.1
|
||||
|
||||
optionator@0.9.4:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
@@ -8357,12 +8265,6 @@ snapshots:
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
|
||||
parse-json@8.3.0:
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
index-to-position: 1.1.0
|
||||
type-fest: 4.41.0
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -8419,8 +8321,6 @@ snapshots:
|
||||
base64-js: 1.5.1
|
||||
xmlbuilder: 15.1.1
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
possible-typed-array-names@1.1.0: {}
|
||||
|
||||
postcss-js@4.0.1(postcss@8.5.3):
|
||||
@@ -8696,7 +8596,7 @@ snapshots:
|
||||
|
||||
read-binary-file-arch@1.0.6:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -8736,6 +8636,8 @@ snapshots:
|
||||
gopd: 1.2.0
|
||||
set-function-name: 2.0.2
|
||||
|
||||
remove-accents@0.5.0: {}
|
||||
|
||||
remove-trailing-separator@1.1.0: {}
|
||||
|
||||
replace-ext@2.0.0: {}
|
||||
@@ -9064,7 +8966,7 @@ snapshots:
|
||||
socks-proxy-agent@7.0.0:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
socks: 2.8.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -9255,7 +9157,7 @@ snapshots:
|
||||
cosmiconfig: 9.0.0(typescript@5.8.3)
|
||||
css-functions-list: 3.2.3
|
||||
css-tree: 3.1.0
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
fast-glob: 3.3.3
|
||||
fastest-levenshtein: 1.0.16
|
||||
file-entry-cache: 10.1.1
|
||||
@@ -9293,11 +9195,13 @@ snapshots:
|
||||
|
||||
sumchecker@3.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
supports-color@10.0.0: {}
|
||||
superjson@1.13.3:
|
||||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
@@ -9517,8 +9421,6 @@ snapshots:
|
||||
escalade: 3.2.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
uri-js-replace@1.0.1: {}
|
||||
|
||||
uri-js@4.4.1:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
@@ -9627,12 +9529,12 @@ snapshots:
|
||||
fast-glob: 3.3.3
|
||||
magic-string: 0.30.17
|
||||
|
||||
vite-plugin-ejs@1.7.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)):
|
||||
vite-plugin-ejs@1.7.0(vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)):
|
||||
dependencies:
|
||||
ejs: 3.1.10
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0)
|
||||
vite: 6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)
|
||||
|
||||
vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2)(yaml@2.8.0):
|
||||
vite@6.3.5(@types/node@22.15.32)(sass-embedded@1.89.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.2):
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
fdir: 6.4.4(picomatch@4.0.2)
|
||||
@@ -9646,7 +9548,6 @@ snapshots:
|
||||
sass-embedded: 1.89.0
|
||||
sugarss: 4.0.1(postcss@8.5.3)
|
||||
terser: 5.39.2
|
||||
yaml: 2.8.0
|
||||
|
||||
void-elements@3.1.0: {}
|
||||
|
||||
@@ -9760,11 +9661,6 @@ snapshots:
|
||||
|
||||
yallist@4.0.0: {}
|
||||
|
||||
yaml-ast-parser@0.0.43: {}
|
||||
|
||||
yaml@2.8.0:
|
||||
optional: true
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
yargs@17.7.2:
|
||||
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-preset-mantine': {
|
||||
mixins: {},
|
||||
},
|
||||
'postcss-preset-mantine': {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -75,7 +75,9 @@
|
||||
"download": "descarregar",
|
||||
"showDetails": "informació",
|
||||
"numberSelected": "{{count}} seleccionat",
|
||||
"shareItem": "comparteix l'element"
|
||||
"shareItem": "comparteix l'element",
|
||||
"goToAlbumArtist": "Ves a $t(entity.albumArtist_one)",
|
||||
"goToAlbum": "ves a $t(entity.album_one)"
|
||||
},
|
||||
"genreList": {
|
||||
"title": "$t(entity.genre_other)",
|
||||
@@ -641,7 +643,10 @@
|
||||
"discordDisplayType": "tipus de pantalla d'activitat de {{discord}}",
|
||||
"discordDisplayType_description": "canvia què escolteu al vostre estat",
|
||||
"discordDisplayType_songname": "nom de la cançó",
|
||||
"discordDisplayType_artistname": "nom de l'artista"
|
||||
"discordDisplayType_artistname": "nom de l'artista",
|
||||
"hotkey_navigateHome": "ves a l'inici",
|
||||
"preventSleepOnPlayback": "evitar entrar en repòs durant la reproducció",
|
||||
"preventSleepOnPlayback_description": "evita que la pantalla s'adormi mentre la música es reprodueix"
|
||||
},
|
||||
"table": {
|
||||
"column": {
|
||||
|
||||
@@ -277,7 +277,10 @@
|
||||
"discordDisplayType": "typ zobrazení stavu {{discord}}",
|
||||
"discordDisplayType_description": "změní, co posloucháte, ve vašem stavu",
|
||||
"discordDisplayType_songname": "název skladby",
|
||||
"discordDisplayType_artistname": "jména umělců"
|
||||
"discordDisplayType_artistname": "jména umělců",
|
||||
"hotkey_navigateHome": "přejít domů",
|
||||
"preventSleepOnPlayback": "zabránit uspání při přehrávání",
|
||||
"preventSleepOnPlayback_description": "zabránit uspání displeje během přehrávání hudby"
|
||||
},
|
||||
"action": {
|
||||
"editPlaylist": "upravit $t(entity.playlist_one)",
|
||||
@@ -625,7 +628,9 @@
|
||||
"playSimilarSongs": "$t(player.playSimilarSongs)",
|
||||
"download": "stáhnout",
|
||||
"playShuffled": "$t(player.shuffle)",
|
||||
"moveToNext": "$t(action.moveToNext)"
|
||||
"moveToNext": "$t(action.moveToNext)",
|
||||
"goToAlbum": "přejít na $t(entity.album_one)",
|
||||
"goToAlbumArtist": "přejít na $t(entity.albumArtist_one)"
|
||||
},
|
||||
"home": {
|
||||
"mostPlayed": "nejpřehrávanější",
|
||||
|
||||
@@ -227,11 +227,7 @@
|
||||
"songCount": "song count",
|
||||
"title": "title",
|
||||
"toYear": "to year",
|
||||
"trackNumber": "track",
|
||||
"createdAt": "created at",
|
||||
"updatedAt": "updated at",
|
||||
"type": "type",
|
||||
"email": "email"
|
||||
"trackNumber": "track"
|
||||
},
|
||||
"form": {
|
||||
"addServer": {
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
"artists": "$t(entity.artist_other)",
|
||||
"albumArtists": "$t(entity.albumArtist_other)",
|
||||
"shared": "partagé $t(entity.playlist_other)",
|
||||
"myLibrary": "ma bibliothèque"
|
||||
"myLibrary": "Bibliothèque"
|
||||
},
|
||||
"fullscreenPlayer": {
|
||||
"config": {
|
||||
@@ -331,7 +331,9 @@
|
||||
"showDetails": "obtenir des informations",
|
||||
"download": "télécharger",
|
||||
"playShuffled": "$t(player.shuffle)",
|
||||
"moveToNext": "$t(action.moveToNext)"
|
||||
"moveToNext": "$t(action.moveToNext)",
|
||||
"goToAlbumArtist": "aller à l'$t(entity.albumArtist_one)",
|
||||
"goToAlbum": "aller à l'$t(entity.album_one)"
|
||||
},
|
||||
"albumArtistList": {
|
||||
"title": "$t(entity.albumArtist_other)"
|
||||
@@ -499,7 +501,7 @@
|
||||
"sidebarCollapsedNavigation_description": "affiche ou cache la navigation dans la barre latérale réduite",
|
||||
"sidebarConfiguration": "configuration de la barre latérale",
|
||||
"sidebarConfiguration_description": "sélectionnez les éléments et l'ordre dans lequel ils seront affichés dans la barre latérale",
|
||||
"sidebarPlaylistList": "liste de listes de lecture de la barre latérale",
|
||||
"sidebarPlaylistList": "liste des listes de lecture de la barre latérale",
|
||||
"sidebarCollapsedNavigation": "navigation de la barre latéral (réduite)",
|
||||
"skipDuration": "durée de l'avance rapide",
|
||||
"sidePlayQueueStyle_optionAttached": "attaché",
|
||||
@@ -546,7 +548,7 @@
|
||||
"clearQueryCache": "vide le cache de feishin",
|
||||
"clearCache": "vider le cache navigateur",
|
||||
"buttonSize_description": "la taille des boutons de la barre de lecture",
|
||||
"clearQueryCache_description": "un 'soft clear' de Feishin. Cela actualisera les liste de lecture, les métadonnées des titres, et réinitialisera les paroles enregistrées. Les paramètres, identifiants du serveur et images mises en cache seront conservés",
|
||||
"clearQueryCache_description": "un 'soft clear' de Feishin. cela actualisera les liste de lecture, les métadonnées des titres, et réinitialisera les paroles enregistrées. les paramètres, identifiants du serveur et images mises en cache seront conservés",
|
||||
"clearCache_description": "un 'hard clear' de feishin. en plus de vider le cache de feishin, vide le cache du navigateur (images sauvegardées et autres ressources). les identifiants serveurs et paramètres sont conservés",
|
||||
"buttonSize": "taille des boutons du lecteur",
|
||||
"clearCacheSuccess": "le cache a été vidé",
|
||||
@@ -627,7 +629,10 @@
|
||||
"discordDisplayType": "type d'affichage du status {{discord}}",
|
||||
"discordDisplayType_description": "change ce que vous écoutez dans votre statut",
|
||||
"discordDisplayType_songname": "nom du morceau",
|
||||
"discordDisplayType_artistname": "nom(s) d’artiste"
|
||||
"discordDisplayType_artistname": "nom(s) d’artiste",
|
||||
"hotkey_navigateHome": "aller à l'accueil",
|
||||
"preventSleepOnPlayback_description": "Empêche la mise en veille du lecteur lorsque la musique est en cours de lecture",
|
||||
"preventSleepOnPlayback": "Empêche la mise en veille lors de la lecture"
|
||||
},
|
||||
"form": {
|
||||
"deletePlaylist": {
|
||||
|
||||
+31
-10
@@ -114,12 +114,14 @@
|
||||
"codec": "codec",
|
||||
"mbid": "MusicBrainz ID",
|
||||
"preview": "anteprima",
|
||||
"reload": "ricarica",
|
||||
"reload": "aggiorna",
|
||||
"share": "condividi",
|
||||
"tags": "tags",
|
||||
"trackGain": "normalizzazione (gain) del brano",
|
||||
"trackPeak": "picco di volume del brano",
|
||||
"translation": "traduzione"
|
||||
"translation": "traduzione",
|
||||
"bitDepth": "bit depth (profondità di bit)",
|
||||
"sampleRate": "sample rate (frequenza di campionamento)"
|
||||
},
|
||||
"player": {
|
||||
"repeat_all": "ripeti coda",
|
||||
@@ -231,7 +233,7 @@
|
||||
"hotkey_toggleShuffle": "attiva/disattiva mescolamento",
|
||||
"theme": "tema",
|
||||
"playbackStyle_description": "selezione lo stile di riproduzione da usare per il player audio",
|
||||
"discordRichPresence_description": "abilita lo status del playback nello stato attività di {{discord}}. Le chiavi immagine sono: {{icon}}, {{playing}} e {{paused}}",
|
||||
"discordRichPresence_description": "abilita lo stato di riproduzione nello stato attività di {{discord}}. Le chiavi immagine sono: {{icon}}, {{playing}} e {{paused}}",
|
||||
"mpvExecutablePath": "percorso eseguibile mpv",
|
||||
"audioDevice": "device audio",
|
||||
"hotkey_rate2": "voto 2 stelle",
|
||||
@@ -266,7 +268,7 @@
|
||||
"customFontPath": "percorso font personalizzato",
|
||||
"followLyric": "segui testo corrente",
|
||||
"crossfadeDuration": "durata dissolvenza",
|
||||
"discordIdleStatus": "visualizza lo stato attività in stato inattivo",
|
||||
"discordIdleStatus": "mostra lo stato attività di Discord quando non stai riproducendo",
|
||||
"audioPlayer": "player audio",
|
||||
"hotkey_zoomOut": "rimpicciolisci layout",
|
||||
"hotkey_rate0": "rimuovi voto",
|
||||
@@ -331,12 +333,12 @@
|
||||
"customCssNotice": "Attenzione: sebbene ci sia una certa sanitizzazione (vengono bloccati url() e content:), l’uso di CSS personalizzati può comunque comportare dei rischi modificando l’interfaccia.",
|
||||
"customCss": "css personalizzato",
|
||||
"customCss_description": "contenuto CSS personalizzato. Nota: le proprietà content e gli URL remoti non sono consentiti. Di seguito è mostrata un’anteprima del tuo contenuto. Sono presenti anche altri campi non impostati da te a causa della sanitizzazione.",
|
||||
"discordPausedStatus": "mostra rich presence di Discord quando la riproduzione è in pausa",
|
||||
"discordPausedStatus": "mostra lo stato attività di Discord quando la riproduzione è in pausa",
|
||||
"discordPausedStatus_description": "quando abilitato, verrà mostrato lo stato del lettore in standby/pausa (nessun brano in riproduzione)",
|
||||
"discordListening": "mostra stato come in ascolto",
|
||||
"discordListening_description": "mostra lo stato come in ascolto invece che in riproduzione",
|
||||
"discordServeImage": "recupera le immagini di {{discord}} dal server",
|
||||
"discordServeImage_description": "condividi la copertina per la rich presence di {{discord}} direttamente dal server, disponibile solo per Jellyfin e Navidrome",
|
||||
"discordServeImage_description": "condividi la copertina per lo stato attività di {{discord}} direttamente dal server, disponibile solo per Jellyfin e Navidrome",
|
||||
"doubleClickBehavior": "aggiungi alla coda tutte le tracce cercate, con un doppio clic",
|
||||
"doubleClickBehavior_description": "se attivato, tutte le tracce corrispondenti alla ricerca verranno aggiunte alla coda. altrimenti, verrà aggiunta alla coda solo la traccia selezionata",
|
||||
"externalLinks": "mostra link esterni",
|
||||
@@ -393,7 +395,16 @@
|
||||
"webAudio_description": "usa audio web. abilita funzionalità avanzate come ReplayGain. disabilita se riscontri problemi",
|
||||
"preservePitch": "mantieni tono (pitch)",
|
||||
"preservePitch_description": "mantiene il tono (pitch) durante la modifica della velocità di riproduzione",
|
||||
"volumeWidth_description": "larghezza del cursore del volume"
|
||||
"volumeWidth_description": "larghezza del cursore del volume",
|
||||
"discordDisplayType_description": "modifica cosa stai ascoltando nel tuo stato",
|
||||
"discordDisplayType_songname": "titolo traccia",
|
||||
"discordDisplayType_artistname": "nome artisti",
|
||||
"hotkey_navigateHome": "vai alla schermata iniziale",
|
||||
"notify": "abilita notifiche delle tracce",
|
||||
"notify_description": "mostra una notifica quando cambia la traccia riprodotta",
|
||||
"preventSleepOnPlayback": "non sospendere in riproduzione",
|
||||
"preventSleepOnPlayback_description": "non sospendere il sistema quando la riproduzione è attiva",
|
||||
"discordDisplayType": "stile dello stato su {{discord}}"
|
||||
},
|
||||
"error": {
|
||||
"remotePortWarning": "riavvia il server per applicare la nuova porta",
|
||||
@@ -418,7 +429,8 @@
|
||||
"badAlbum": "stai visualizzando questa pagina perché questa canzone non fa parte di un album. probabilmente vedi questo messaggio perché hai una canzone posizionata direttamente nella cartella principale della tua libreria musicale. jellyfin raggruppa le tracce solo se si trovano all’interno di una cartella.",
|
||||
"badValue": "opzione non valida \"{{value}}\". valore inesistente",
|
||||
"networkError": "si è verificato un errore di rete",
|
||||
"openError": "impossibile aprire il file"
|
||||
"openError": "impossibile aprire il file",
|
||||
"notificationDenied": "i permessi per le notifiche non sono stati concessi. questa configurazione non ha effetto"
|
||||
},
|
||||
"filter": {
|
||||
"mostPlayed": "più riprodotti",
|
||||
@@ -513,7 +525,9 @@
|
||||
"openBrowserDevtools": "apri devtools browser",
|
||||
"quit": "$t(common.quit)",
|
||||
"goBack": "torna indietro",
|
||||
"goForward": "vai avanti"
|
||||
"goForward": "vai avanti",
|
||||
"privateModeOff": "disabilita modalità privata",
|
||||
"privateModeOn": "abilita modalità privata"
|
||||
},
|
||||
"contextMenu": {
|
||||
"addToPlaylist": "$t(action.addToPlaylist)",
|
||||
@@ -537,7 +551,9 @@
|
||||
"playSimilarSongs": "$t(player.playSimilarSongs)",
|
||||
"playShuffled": "$t(player.shuffle)",
|
||||
"shareItem": "condividi elemento",
|
||||
"showDetails": "mostra info"
|
||||
"showDetails": "mostra info",
|
||||
"goToAlbum": "vai a $t(entity.album_one)",
|
||||
"goToAlbumArtist": "vai a $t(entity.albumArtist_one)"
|
||||
},
|
||||
"home": {
|
||||
"mostPlayed": "più riprodotti",
|
||||
@@ -674,6 +690,11 @@
|
||||
"success": "link di condivisione copiato negli appunti (o clicca qui per aprirlo)",
|
||||
"expireInvalid": "la scadenza deve essere nel futuro",
|
||||
"createFailed": "condivisione fallita (è abilitata la condivisione?)"
|
||||
},
|
||||
"privateMode": {
|
||||
"enabled": "la modalità privata è abilitata: lo stato di riproduzione viene ora nascosto alle integrazioni esterne",
|
||||
"disabled": "la modalità privata è disabilitata: lo stato di riproduzione è ora visibile alle integrazioni esterne abilitate",
|
||||
"title": "modalità privata"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
|
||||
+239
-2
@@ -93,7 +93,7 @@
|
||||
"path": "cesta",
|
||||
"playerMustBePaused": "prehrávač musí byť pozastavený",
|
||||
"preview": "náhľad",
|
||||
"previousSong": "predchádzajúci $t(entity.track_one)",
|
||||
"previousSong": "predchádzajúca $t(entity.track_one)",
|
||||
"quit": "ukončiť",
|
||||
"random": "náhodne",
|
||||
"rating": "hodnotenie",
|
||||
@@ -589,6 +589,243 @@
|
||||
"globalMediaHotkeys_description": "povoliť alebo zakázať použitie vašich klávesových skratiek médií na ovládanie prehrávania",
|
||||
"homeConfiguration": "konfigurácia domovskej stránky",
|
||||
"homeConfiguration_description": "konfigurovať, aké položky sú zobrazené a v akom poradí na domovskej stránke",
|
||||
"homeFeature": "carousel odporúčania na domovskej stránke"
|
||||
"homeFeature": "carousel odporúčania na domovskej stránke",
|
||||
"homeFeature_description": "povoľuje zobrazenie veľkoformátového odporúčaného carouselu na domovskej stránke",
|
||||
"hotkey_browserBack": "naspäť v prehliadači",
|
||||
"hotkey_browserForward": "dopredu v prehliadači",
|
||||
"hotkey_favoriteCurrentSong": "obľúbené $t(common.currentSong)",
|
||||
"hotkey_favoritePreviousSong": "obľúbené $t(common.previousSong)",
|
||||
"hotkey_globalSearch": "globálne vyhľadávanie",
|
||||
"hotkey_localSearch": "vyhľadávanie na stránke",
|
||||
"hotkey_navigateHome": "navigovať domov",
|
||||
"hotkey_playbackNext": "nasledujúca skladba",
|
||||
"hotkey_playbackPause": "pozastaviť",
|
||||
"hotkey_playbackPlay": "prehrať",
|
||||
"hotkey_playbackPlayPause": "hrať / pozastaviť",
|
||||
"hotkey_playbackPrevious": "predchádzajúca skladba",
|
||||
"hotkey_playbackStop": "zastaviť",
|
||||
"hotkey_rate0": "bez hodnotenia",
|
||||
"hotkey_rate1": "hodnotené 1 hviezdou",
|
||||
"hotkey_rate2": "hodnotené 2 hviezdami",
|
||||
"hotkey_rate3": "hodnotené 3 hviezdami",
|
||||
"hotkey_rate4": "hodotené 4 hviezdami",
|
||||
"hotkey_rate5": "hodnotené 5 hviezdami",
|
||||
"hotkey_skipBackward": "preskočiť dozadu",
|
||||
"hotkey_skipForward": "preskočiť dopredu",
|
||||
"hotkey_toggleCurrentSongFavorite": "prepnúť $t(common.currentSong) obľúbené",
|
||||
"hotkey_toggleFullScreenPlayer": "prepnúť prehrávač na celú obrazovku",
|
||||
"hotkey_togglePreviousSongFavorite": "prepnúť $t(common.previousSong) obľúbené",
|
||||
"hotkey_toggleQueue": "prepnúť frontu",
|
||||
"hotkey_toggleRepeat": "prepnúť opakovanie",
|
||||
"hotkey_toggleShuffle": "prepnúť náhodné prehrávanie",
|
||||
"hotkey_unfavoriteCurrentSong": "odobrať z obľúbených $t(common.currentSong)",
|
||||
"hotkey_unfavoritePreviousSong": "odobrať z obľúbených $t(common.previousSong)",
|
||||
"hotkey_volumeDown": "znížiť hlasitosť",
|
||||
"hotkey_volumeMute": "stíšiť hlasitosť",
|
||||
"hotkey_volumeUp": "zvýšiť hlasitosť",
|
||||
"hotkey_zoomIn": "priblížiť",
|
||||
"hotkey_zoomOut": "vzdialiť",
|
||||
"imageAspectRatio": "použiť pôvodný pomer strán obalu albumu",
|
||||
"language": "jazyk",
|
||||
"language_description": "nastaví jazyk aplikácie ($t(common.restartRequired))",
|
||||
"lastfm": "zobraziť last.fm odkazy",
|
||||
"lastfm_description": "zobraziť last.fm odkazy na stránky interpreta/albumu",
|
||||
"lastfmApiKey": "{{lastfm}} API kľúč",
|
||||
"lastfmApiKey_description": "API kľúč pre {{lastfm}}. vyžaduje sa obálky albumov",
|
||||
"lyricFetch": "stiahnuť texty skladieb z internetu",
|
||||
"lyricFetch_description": "stiahnuť texty skladieb z rôznych internetových zdrojov",
|
||||
"lyricFetchProvider": "poskytovatelia pre sťahovanie textov skladieb",
|
||||
"lyricFetchProvider_description": "vybrať poskytovateľov pre sťahovanie textov skladieb. poradie poskytovateľov určuje poradie, v ktorom sa budú používať",
|
||||
"lyricOffset": "posunutie textu skladieb (ms)",
|
||||
"lyricOffset_description": "posunutie textu voči skladbe vyjadrené v milisekundách",
|
||||
"notify": "povoliť notifikácie o skladbách",
|
||||
"notify_description": "zobraziť notifikácie pri zmene aktuálnej skladby",
|
||||
"minimizeToTray": "minimalizovať do lišty",
|
||||
"minimizeToTray_description": "minimalizovať aplikáciu do systémovej lišty",
|
||||
"minimumScrobblePercentage": "minimálna dĺžka pre skroblovanie (percentá)",
|
||||
"minimumScrobblePercentage_description": "minimálna časť skladby v percentách, ktorá musí byť prehraná pred tým, než je skroblovaná",
|
||||
"minimumScrobbleSeconds": "minimálna dĺžka skroblovania (sekundy)",
|
||||
"minimumScrobbleSeconds_description": "minimálna dĺžka časti skladby, ktorá musí byť prehraná pred tým, než je skladba skroblovaná",
|
||||
"mpvExecutablePath": "cesta k spustiteľnému súboru mpv",
|
||||
"mpvExecutablePath_description": "nastavuje cestu k spustiteľnému súboru mpv. ak je prázdna, použije sa predvolená cesta",
|
||||
"mpvExtraParameters": "parametre mpv",
|
||||
"mpvExtraParameters_help": "jeden na riadok",
|
||||
"musicbrainz": "zobraziť linky na musicbrainz",
|
||||
"musicbrainz_description": "zobrazí linky na stránky interpreta/albumu na musicbrainz, ak je vyplnené mbid",
|
||||
"neteaseTranslation": "Povoliť NetEasy preklady",
|
||||
"neteaseTranslation_description": "Ak sú povolené, aplikácia stiahne a zobrazí preložené texty skladieb z NetEasy, ak sú dostupné.",
|
||||
"passwordStore": "ukladanie hesiel/utajených údajov",
|
||||
"passwordStore_description": "aký spôsob ukladania hesiel/utajených údajov použiť. ak máte problém s ukladaním hesiel, skúste zmeniť nastavenie.",
|
||||
"playbackStyle": "štýl prehrávania",
|
||||
"playbackStyle_description": "vyberte štýl prehrávania pre prehrávač skladieb",
|
||||
"playbackStyle_optionCrossFade": "crossfade",
|
||||
"playbackStyle_optionNormal": "normálny",
|
||||
"playButtonBehavior": "správanie sa tlačidla prehrávania",
|
||||
"playButtonBehavior_description": "nastaví predvolené správanie sa tlačidla prehrávania pri pridávaní skladieb do fronty",
|
||||
"playButtonBehavior_optionAddLast": "$t(player.addLast)",
|
||||
"playButtonBehavior_optionAddNext": "$t(player.addNext)",
|
||||
"playButtonBehavior_optionPlay": "$t(player.play)",
|
||||
"playButtonBehavior_optionPlayShuffled": "$t(player.shuffle)",
|
||||
"playerAlbumArtResolution": "rozlíšenie obrázka albumu",
|
||||
"playerAlbumArtResolution_description": "rozlíšenie zobrazenia náhľadu veľkých obrázkov albumov. pri väčšom rozlíšení budú krajšie, ale môže sa spomaliť ich načítavanie. predvolené je 0, čo znamená automatické",
|
||||
"playerbarOpenDrawer": "zobrazenie na celú obrazovku panelom prehrávača",
|
||||
"playerbarOpenDrawer_description": "umožní kliknutím na panel prehrávača prepnúť zobrazenie prehrávača na celú obrazovku",
|
||||
"remotePassword": "heslo servera vzdialeného ovládania",
|
||||
"remotePassword_description": "nastaví heslo pre server diaľkového ovládania. Jeho obsah je odosielaný bez zabezpečenia, preto by ste si mali zvoliť jedinečné heslo, ktoré pre vás nie je dôležité",
|
||||
"remotePort": "port servera diaľkového ovládania",
|
||||
"remotePort_description": "nastaví port servera diaľkového ovládania",
|
||||
"remoteUsername": "používateľské meno servera diaľkového ovládania",
|
||||
"remoteUsername_description": "nasstaví používateľské meno servera diaľkového ovládania. v prípade, ak sú používateľské meno aj heslo prázdne, je overovanie pri prihlásení vypnuté",
|
||||
"replayGainClipping": "clipping {{ReplayGain}}",
|
||||
"replayGainClipping_description": "Zabraňuje clipping-u spôsobenému {{ReplayGain}} automatickým znížením zosilenia",
|
||||
"replayGainFallback": "fallback {{ReplayGain}}",
|
||||
"replayGainFallback_description": "zosilenie v db, ktoré sa aplikuje, ak súbor nemá {{ReplayGain}} štítky",
|
||||
"replayGainMode": "{{ReplayGain}} režim",
|
||||
"replayGainMode_description": "pozmení zosilenie hlasitosti podľa hodnôt {{ReplayGain}} uložených v metadátach súboru",
|
||||
"replayGainMode_optionAlbum": "$t(entity.album_one)",
|
||||
"replayGainMode_optionNone": "$t(common.none)",
|
||||
"replayGainMode_optionTrack": "$t(entity.track_one)",
|
||||
"replayGainPreamp": "predzosilenie {{ReplayGain}} dB",
|
||||
"replayGainPreamp_description": "pozmení predzosilenie použité na hodnoty {{ReplayGain}}",
|
||||
"sampleRate": "vzorkovacia frekvencia",
|
||||
"sidePlayQueueStyle_optionAttached": "pripojené",
|
||||
"sidePlayQueueStyle_optionDetached": "odpojené",
|
||||
"skipDuration": "dĺžka preskočenia",
|
||||
"skipDuration_description": "určuje časovú dĺžku posunu pri stlačení tlačidla preskočiť na lište prehrávača",
|
||||
"skipPlaylistPage": "preskočiť stránku playlistu",
|
||||
"skipPlaylistPage_description": "pri navigácii v playliste, idete na výber stránky playlistu namiesto predvolenej stránky",
|
||||
"startMinimized": "spistiť mnimalizované",
|
||||
"startMinimized_description": "spustí aplikáciu minimalizovanú do systémovej lišty",
|
||||
"preventSleepOnPlayback": "zabrániť spánku pri prehrávaní",
|
||||
"preventSleepOnPlayback_description": "pri prehávaní hudby zabráni obrazovke v prechode do spánku",
|
||||
"theme": "téma",
|
||||
"theme_description": "nastaví tému aplikácie",
|
||||
"themeDark": "téma (tmavá)",
|
||||
"themeDark_description": "nastaví tmavú tému aplikácie",
|
||||
"themeLight": "téma (svetlá)",
|
||||
"themeLight_description": "nastaví svetlú tému aplikácie",
|
||||
"transcodeNote": "zmena sa prejaví po 1 (web) - 2 (mpv) skladbách",
|
||||
"transcode": "povoliť prekódovanie",
|
||||
"transcode_description": "umožňuje prekódovanie do rôznych formátov",
|
||||
"transcodeBitrate": "bitová frekvencia prekódovania",
|
||||
"transcodeBitrate_description": "určuje bitovú frekvenciu, pri ktorej sa použije prekódovanie. 0 znamená ponechať rozhodnutie na server",
|
||||
"transcodeFormat": "formát prekódovania",
|
||||
"transcodeFormat_description": "učuje výstupný formát prekódovania. ak chcete ponechať rozhodnutie na server, nechajte políčko prázdne",
|
||||
"translationApiProvider": "api poskytovateľa prekladu",
|
||||
"translationApiProvider_description": "api poskytovateľa prekladu",
|
||||
"translationApiKey": "api kľúč prekladu",
|
||||
"translationApiKey_description": "api kľúč pre preklad (Podporuje iba koncové body globálnych služieb)",
|
||||
"translationTargetLanguage": "cieľový jazyk prekladu",
|
||||
"translationTargetLanguage_description": "cieľový jazyk, do ktorého sa prekladá",
|
||||
"trayEnabled": "zobraziť lištu",
|
||||
"trayEnabled_description": "zobraziť/skryť ikonu/ponuku lišty. ak nie je povolené, taktiež vypne minimalizovanie/zavretie do lišty",
|
||||
"useSystemTheme": "použiť systémovú tému",
|
||||
"useSystemTheme_description": "prispôsobiť výber svetlej, či tmavej témy aktuálnej systémovej téme",
|
||||
"volumeWheelStep": "krok zmeny hlasitosti",
|
||||
"volumeWheelStep_description": "veľkosť zmeny hlasitosti pri otočení kolieskom myši o jeden krok na ovládači hlasitosti",
|
||||
"volumeWidth": "šírka posuvného ovládača hlasitosti",
|
||||
"volumeWidth_description": "šírka ovládača hlasitosti",
|
||||
"webAudio": "používať webový výstup",
|
||||
"webAudio_description": "bude sa používať webový výstup, čím povolíte pokročilé funkcie ako replaygain. v prípade problémov voľbu vypnite",
|
||||
"preservePitch": "zachovať výšku",
|
||||
"preservePitch_description": "pri zmene rýchlosti prehrávania zostane výška zachovaná",
|
||||
"windowBarStyle": "štýl okna",
|
||||
"windowBarStyle_description": "vyberte štýl okna",
|
||||
"zoom": "percento priblíženia",
|
||||
"zoom_description": "nastaví percento priblíženia pre aplikáciu",
|
||||
"sampleRate_description": "vyberte výstupnú vzorkovaciu frekvenciu, ktorá sa použije v prípade, ak je vybraná vzorkovacia frekvencia iná ako je u aktuálnej skladby. pri hodnote menšej ako 8000 sa použije predvolená frekvencia",
|
||||
"savePlayQueue": "uložiť frontu prehrávania",
|
||||
"savePlayQueue_description": "uloží frontu prehrávania pri ukončení aplikácie a obnoví ju opäť po jej otvorení",
|
||||
"scrobble": "skroblovať",
|
||||
"scrobble_description": "scroblovať vaše prehrávanie na medálny server",
|
||||
"showSkipButton": "zobraziť tlačítka preskočenia",
|
||||
"showSkipButton_description": "zobrazí alebo skryje tlačítka preskočenia na lište prehrávača",
|
||||
"showSkipButtons": "zobraziť tlačítka preskočenia",
|
||||
"showSkipButtons_description": "zobraziť alebo skryť tlačítka preskočenia na lište prehrávača",
|
||||
"sidebarCollapsedNavigation": "navigácia bočnej lišty (zasunutá)",
|
||||
"sidebarCollapsedNavigation_description": "zobraziť alebo skryť navigovanie na zasunutej bočnej lište",
|
||||
"sidebarConfiguration": "nastavenie bočnej lišty",
|
||||
"sidebarConfiguration_description": "zvoľte položky a ich poradie, v akom sa zabrazia na bočnej lište",
|
||||
"sidebarPlaylistList": "playlist bočnej lišty",
|
||||
"sidebarPlaylistList_description": "zobraziť alebo skryť playlist na bočnej lište",
|
||||
"sidePlayQueueStyle": "štýl bočnej fronty prehrávania",
|
||||
"sidePlayQueueStyle_description": "nastaví štýl bočnej fronty prehrávania"
|
||||
},
|
||||
"table": {
|
||||
"column": {
|
||||
"album": "album",
|
||||
"albumArtist": "interpret albumu",
|
||||
"albumCount": "$t(entity.album_other)",
|
||||
"artist": "$t(entity.artist_one)",
|
||||
"biography": "životopis",
|
||||
"bitrate": "bitrate",
|
||||
"bpm": "bpm",
|
||||
"channels": "$t(common.channel_other)",
|
||||
"codec": "$t(common.codec)",
|
||||
"comment": "komentár",
|
||||
"dateAdded": "dátum pridania",
|
||||
"discNumber": "disk",
|
||||
"favorite": "obľúbené",
|
||||
"genre": "$t(entity.genre_one)",
|
||||
"lastPlayed": "posledne hraný",
|
||||
"path": "cesta",
|
||||
"playCount": "prehratí",
|
||||
"rating": "hodnotenie",
|
||||
"releaseDate": "dátum vydania",
|
||||
"releaseYear": "rok",
|
||||
"size": "$t(common.size)",
|
||||
"songCount": "$t(entity.track_other)",
|
||||
"title": "názov",
|
||||
"trackNumber": "skladba"
|
||||
},
|
||||
"config": {
|
||||
"general": {
|
||||
"autoFitColumns": "automatická šírka stĺpcov",
|
||||
"followCurrentSong": "nasledovať aktuálnu skladbu",
|
||||
"displayType": "typ zobrazenia",
|
||||
"gap": "$t(common.gap)",
|
||||
"itemGap": "medzera položky (px)",
|
||||
"itemSize": "veľkosť položky (px)",
|
||||
"size": "$t(common.size)",
|
||||
"tableColumns": "stĺpce tabuľky"
|
||||
},
|
||||
"label": {
|
||||
"actions": "$t(common.action_other)",
|
||||
"album": "$t(entity.album_one)",
|
||||
"albumArtist": "$t(entity.albumArtist_one)",
|
||||
"artist": "$t(entity.artist_one)",
|
||||
"biography": "$t(common.biography)",
|
||||
"bitrate": "$t(common.bitrate)",
|
||||
"bpm": "$t(common.bpm)",
|
||||
"channels": "$t(common.channel_other)",
|
||||
"codec": "$t(common.codec)",
|
||||
"dateAdded": "dátum pridania",
|
||||
"discNumber": "číslo disku",
|
||||
"duration": "$t(common.duration)",
|
||||
"favorite": "$t(common.favorite)",
|
||||
"genre": "$t(entity.genre_one)",
|
||||
"lastPlayed": "posledne prehraté",
|
||||
"note": "$t(common.note)",
|
||||
"owner": "$t(common.owner)",
|
||||
"path": "$t(common.path)",
|
||||
"playCount": "počet prehraní",
|
||||
"rating": "$t(common.rating)",
|
||||
"releaseDate": "dátum vydania",
|
||||
"rowIndex": "číslo riadku",
|
||||
"size": "$t(common.size)",
|
||||
"songCount": "$t(entity.track_other)",
|
||||
"title": "$t(common.title)",
|
||||
"titleCombined": "$t(common.title) (kombinovaný)",
|
||||
"trackNumber": "číslo skladby",
|
||||
"year": "$t(common.year)"
|
||||
},
|
||||
"view": {
|
||||
"card": "karta",
|
||||
"grid": "mriežka",
|
||||
"list": "zoznam",
|
||||
"poster": "plagát",
|
||||
"table": "tabuľka"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,6 +286,11 @@
|
||||
"updateServer": {
|
||||
"success": "sunucu başarıyla güncellendi",
|
||||
"title": "sunucuyu güncelle"
|
||||
},
|
||||
"privateMode": {
|
||||
"enabled": "gizli mod etkinleştirildi, oynatma durumu artık harici eklentilerden gizlendi",
|
||||
"disabled": "gizli mod devre dışı bırakıldı, oynatma durumu artık etkinleştirilmiş harici eklentiler tarafından görülebilir",
|
||||
"title": "gizli mod"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
@@ -322,7 +327,9 @@
|
||||
"addFavorite": "$t(action.addToFavorites)",
|
||||
"playShuffled": "$t(player.shuffle)",
|
||||
"shareItem": "öğeyi paylaş",
|
||||
"showDetails": "bilgi al"
|
||||
"showDetails": "bilgi al",
|
||||
"goToAlbum": "$t(entity.album_one) sayfasına git",
|
||||
"goToAlbumArtist": "$t(entity.albumArtist_one) sayfasına git"
|
||||
},
|
||||
"manageServers": {
|
||||
"url": "URL",
|
||||
@@ -436,7 +443,9 @@
|
||||
"quit": "$t(common.quit)",
|
||||
"selectServer": "sunucu seç",
|
||||
"settings": "$t(common.setting_other)",
|
||||
"version": "{{version}} sürümü"
|
||||
"version": "{{version}} sürümü",
|
||||
"privateModeOff": "gizli modu kapat",
|
||||
"privateModeOn": "gizli modu aç"
|
||||
}
|
||||
},
|
||||
"player": {
|
||||
@@ -713,7 +722,14 @@
|
||||
"themeLight": "tema (açık)",
|
||||
"themeLight_description": "uygulama için kullanılacak açık temayı ayarlar",
|
||||
"transcodeNote": "1 (web) - 2 (mpv) şarkıdan sonra etkili olur",
|
||||
"transcode": "kod dönüştürmeyi etkinleştir"
|
||||
"transcode": "kod dönüştürmeyi etkinleştir",
|
||||
"discordDisplayType": "{{discord}} varlık gösterge türü",
|
||||
"discordDisplayType_description": "durumunuzda dinlediğiniz şarkı olarak değiştirir",
|
||||
"discordDisplayType_songname": "şarkı ismi",
|
||||
"discordDisplayType_artistname": "Sanatçı adı(ları)",
|
||||
"hotkey_navigateHome": "ana sayfaya git",
|
||||
"preventSleepOnPlayback": "oynatma sırasında uykuyu önle",
|
||||
"preventSleepOnPlayback_description": "müzik çalarken ekranın uyku moduna geçmesini önle"
|
||||
},
|
||||
"table": {
|
||||
"column": {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"editPlaylist": "编辑$t(entity.playlist_one)",
|
||||
"moveToTop": "移至顶部",
|
||||
"clearQueue": "清空播放队列",
|
||||
"addToFavorites": "添加到$t(entity.favorite_other)",
|
||||
"addToPlaylist": "添加到$t(entity.playlist_one)",
|
||||
"addToFavorites": "添加到 $t(entity.favorite_other)",
|
||||
"addToPlaylist": "添加到 $t(entity.playlist_one)",
|
||||
"createPlaylist": "创建$t(entity.playlist_one)",
|
||||
"removeFromPlaylist": "从$t(entity.playlist_one)移除",
|
||||
"viewPlaylists": "查看$t(entity.playlist_other)",
|
||||
@@ -127,13 +127,13 @@
|
||||
"playlist_other": "播放列表",
|
||||
"artist_other": "艺术家",
|
||||
"folderWithCount_other": "{{count}} 个文件夹",
|
||||
"track_other": "乐曲",
|
||||
"track_other": "曲目",
|
||||
"favorite_other": "收藏",
|
||||
"artistWithCount_other": "{{count}} 位艺术家",
|
||||
"folder_other": "文件夹",
|
||||
"smartPlaylist": "智能$t(entity.playlist_one)",
|
||||
"genreWithCount_other": "{{count}} 种流派",
|
||||
"trackWithCount_other": "{{count}} 首乐曲",
|
||||
"trackWithCount_other": "{{count}} 首曲目",
|
||||
"play_other": "{{count}} 次播放",
|
||||
"song_other": "歌曲"
|
||||
},
|
||||
@@ -167,7 +167,7 @@
|
||||
"skip_forward": "向前跳过",
|
||||
"playbackSpeed": "播放速度",
|
||||
"pause": "暂停",
|
||||
"playSimilarSongs": "播放类似的曲目",
|
||||
"playSimilarSongs": "播放类似的歌曲",
|
||||
"viewQueue": "查看播放队列"
|
||||
},
|
||||
"setting": {
|
||||
@@ -205,7 +205,7 @@
|
||||
"enableRemote_description": "启用远程控制服务器,以允许其他设备控制此应用",
|
||||
"remotePort_description": "设置远程服务器端口",
|
||||
"hotkey_skipBackward": "向后跳过",
|
||||
"replayGainMode_description": "根据乐曲元数据中存储的{{ReplayGain}}值调整音量增益",
|
||||
"replayGainMode_description": "根据文件元数据中存储的 {{ReplayGain}} 值调整音量增益",
|
||||
"volumeWheelStep_description": "在音量滑块上滚动鼠标滚轮时要更改的音量大小",
|
||||
"theme_description": "设置应用的主题",
|
||||
"hotkey_playbackPause": "暂停",
|
||||
@@ -290,7 +290,7 @@
|
||||
"playbackStyle_optionNormal": "正常",
|
||||
"windowBarStyle": "窗口顶栏风格",
|
||||
"floatingQueueArea": "显示浮动队列悬停区域",
|
||||
"replayGainFallback_description": "乐曲没有{{ReplayGain}}标签时应用的增益(以分贝为单位)",
|
||||
"replayGainFallback_description": "如果文件没有 {{ReplayGain}} 标签,则在数据库中应用增益",
|
||||
"hotkey_toggleRepeat": "切换循环",
|
||||
"lyricOffset_description": "将歌词偏移指定的毫秒数",
|
||||
"sidebarConfiguration_description": "选择侧边栏包含的项目与顺序",
|
||||
@@ -464,7 +464,7 @@
|
||||
"albumArtist": "$t(entity.albumArtist_one)",
|
||||
"releaseYear": "发布年份",
|
||||
"biography": "个人简介",
|
||||
"songCount": "曲目数量",
|
||||
"songCount": "歌曲数量",
|
||||
"random": "随机",
|
||||
"lastPlayed": "上次播放过",
|
||||
"toYear": "从年份",
|
||||
@@ -599,7 +599,7 @@
|
||||
"trackList": {
|
||||
"title": "$t(entity.track_other)",
|
||||
"genreTracks": "\"{{genre}}\" $t(entity.track_other)",
|
||||
"artistTracks": "{{artist}}的曲目"
|
||||
"artistTracks": "{{artist}} 的曲目"
|
||||
},
|
||||
"albumArtistList": {
|
||||
"title": "$t(entity.albumArtist_other)"
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
} from '.';
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
const SEARCH_URL = 'https://genius.com/api/search/song';
|
||||
|
||||
|
||||
@@ -17,12 +17,35 @@ import {
|
||||
getSearchResults as searchNetease,
|
||||
} from './netease';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSource,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import { Song } from '/@/shared/types/domain-types';
|
||||
|
||||
export enum LyricSource {
|
||||
GENIUS = 'Genius',
|
||||
LRCLIB = 'lrclib.net',
|
||||
NETEASE = 'NetEase',
|
||||
}
|
||||
|
||||
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
||||
lyrics: LyricsResponse;
|
||||
remote: boolean;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export type InternetProviderLyricResponse = {
|
||||
artist: string;
|
||||
id: string;
|
||||
lyrics: string;
|
||||
name: string;
|
||||
source: LyricSource;
|
||||
};
|
||||
|
||||
export type InternetProviderLyricSearchResponse = {
|
||||
artist: string;
|
||||
id: string;
|
||||
name: string;
|
||||
score?: number;
|
||||
source: LyricSource;
|
||||
};
|
||||
|
||||
export type LyricGetQuery = {
|
||||
remoteSongId: string;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
// Credits to https://github.com/tranxuanthang/lrcget for API implementation
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
} from '.';
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
const FETCH_URL = 'https://lrclib.net/api/get';
|
||||
const SEEARCH_URL = 'https://lrclib.net/api/search';
|
||||
|
||||
@@ -1,20 +1,43 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
import { store } from '../settings';
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
} from '.';
|
||||
import { store } from '../settings';
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
const SEARCH_URL = 'https://music.163.com/api/search/get';
|
||||
const LYRICS_URL = 'https://music.163.com/api/song/lyric';
|
||||
|
||||
// Adapted from https://github.com/NyaomiDEV/Sunamu/blob/master/src/main/lyricproviders/netease.ts
|
||||
|
||||
export interface Result {
|
||||
hasMore: boolean;
|
||||
songCount: number;
|
||||
songs: Song[];
|
||||
}
|
||||
|
||||
export interface Song {
|
||||
album: Album;
|
||||
alias: string[];
|
||||
artists: Artist[];
|
||||
copyrightId: number;
|
||||
duration: number;
|
||||
fee: number;
|
||||
ftype: number;
|
||||
id: number;
|
||||
mark: number;
|
||||
mvid: number;
|
||||
name: string;
|
||||
rtype: number;
|
||||
rUrl: null;
|
||||
status: number;
|
||||
transNames?: string[];
|
||||
}
|
||||
|
||||
interface Album {
|
||||
artist: Artist;
|
||||
copyrightId: number;
|
||||
@@ -46,30 +69,6 @@ interface NetEaseResponse {
|
||||
result: Result;
|
||||
}
|
||||
|
||||
interface Result {
|
||||
hasMore: boolean;
|
||||
songCount: number;
|
||||
songs: Song[];
|
||||
}
|
||||
|
||||
interface Song {
|
||||
album: Album;
|
||||
alias: string[];
|
||||
artists: Artist[];
|
||||
copyrightId: number;
|
||||
duration: number;
|
||||
fee: number;
|
||||
ftype: number;
|
||||
id: number;
|
||||
mark: number;
|
||||
mvid: number;
|
||||
name: string;
|
||||
rtype: number;
|
||||
rUrl: null;
|
||||
status: number;
|
||||
transNames?: string[];
|
||||
}
|
||||
|
||||
export async function getLyricsBySongId(songId: string): Promise<null | string> {
|
||||
let result: AxiosResponse<any, any>;
|
||||
try {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import Fuse from 'fuse.js';
|
||||
|
||||
import { InternetProviderLyricSearchResponse } from '/@/shared/types/domain/lyric-domain-types';
|
||||
import { LyricSearchQuery } from '/@/shared/types/domain/lyric-domain-types';
|
||||
import {
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
export const orderSearchResults = (args: {
|
||||
params: LyricSearchQuery;
|
||||
|
||||
@@ -11,8 +11,8 @@ import manifest from './manifest.json';
|
||||
|
||||
import { getMainWindow } from '/@/main/index';
|
||||
import { isLinux } from '/@/main/utils';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ClientEvent, ServerEvent } from '/@/shared/types/domain/remote-types';
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
import { ClientEvent, ServerEvent } from '/@/shared/types/remote-types';
|
||||
import { PlayerRepeat, PlayerStatus, SongState } from '/@/shared/types/types';
|
||||
|
||||
let mprisPlayer: any | undefined;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ipcMain } from 'electron';
|
||||
import Player from 'mpris-service';
|
||||
|
||||
import { getMainWindow } from '/@/main/index';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const mprisPlayer = Player({
|
||||
@@ -168,7 +168,7 @@ ipcMain.on('update-song', (_event, song: QueueSong | undefined) => {
|
||||
'xesam:contentCreated': song.releaseDate,
|
||||
'xesam:discNumber': song.discNumber ? song.discNumber : null,
|
||||
'xesam:genre': song.genres?.length ? song.genres.map((genre: any) => genre.name) : null,
|
||||
'xesam:lastUsed': song.userLastPlayedDate,
|
||||
'xesam:lastUsed': song.lastPlayedAt,
|
||||
'xesam:title': song.name || null,
|
||||
'xesam:trackNumber': song.trackNumber ? song.trackNumber : null,
|
||||
'xesam:useCount':
|
||||
|
||||
+4
-1
@@ -489,7 +489,10 @@ async function createWindow(first = true): Promise<void> {
|
||||
|
||||
const menuBuilder = new MenuBuilder(mainWindow);
|
||||
menuBuilder.buildMenu();
|
||||
Menu.setApplicationMenu(null);
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
Menu.setApplicationMenu(null);
|
||||
}
|
||||
|
||||
// Open URLs in the user's browser
|
||||
mainWindow.webContents.setWindowOpenHandler((edata) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
LyricSource,
|
||||
} from '../main/features/core/lyrics';
|
||||
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
|
||||
const getRemoteLyricsBySong = (song: QueueSong) => {
|
||||
const result = ipcRenderer.invoke('lyric-by-song', song);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron';
|
||||
|
||||
import { PlayerData } from '/@/shared/types/domain/player-domain-types';
|
||||
import { PlayerData } from '/@/shared/types/domain-types';
|
||||
|
||||
const initialize = (data: { extraParameters?: string[]; properties?: Record<string, any> }) => {
|
||||
return ipcRenderer.invoke('player-initialize', data);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron';
|
||||
|
||||
import { QueueSong, QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
import { PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const requestFavorite = (
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
import {
|
||||
ApiController,
|
||||
ApiControllerError,
|
||||
ApiControllerFn,
|
||||
} from '/@/shared/types/adapter/api-controller-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { logger } from '/@/shared/utils/logger';
|
||||
|
||||
export interface LoggingOptions {
|
||||
logErrors?: boolean;
|
||||
logPerformance?: boolean;
|
||||
logRequests?: boolean;
|
||||
logResponses?: boolean;
|
||||
maxRequestSize?: number;
|
||||
maxResponseSize?: number;
|
||||
}
|
||||
|
||||
type LoggedApiControllerFn<TRequest, TResponse> = (
|
||||
request: TRequest,
|
||||
server: ServerListItem,
|
||||
options?: any,
|
||||
) => Promise<[ApiControllerError, null] | [null, TResponse]>;
|
||||
|
||||
export function createLoggedApiController(
|
||||
controller: ApiController,
|
||||
options: LoggingOptions = {},
|
||||
): ApiController {
|
||||
const loggedController: any = {};
|
||||
|
||||
// Log utility functions
|
||||
loggedController._utility = createLoggedUtility(controller._utility);
|
||||
|
||||
// Log all controller methods
|
||||
for (const [sectionKey, section] of Object.entries(controller)) {
|
||||
if (sectionKey === '_utility') continue;
|
||||
|
||||
loggedController[sectionKey] = {};
|
||||
|
||||
for (const [methodKey, method] of Object.entries(section as Record<string, any>)) {
|
||||
if (typeof method === 'function') {
|
||||
const functionName = `${sectionKey}.${methodKey}`;
|
||||
|
||||
if (methodKey === 'authenticate' || methodKey === 'getType') {
|
||||
// Special handling for non-standard API functions
|
||||
loggedController[sectionKey][methodKey] = (...args: any[]) => {
|
||||
logger.info(`[API] ${functionName} called`, {
|
||||
args: JSON.stringify(args, null, 2),
|
||||
});
|
||||
return method(...args);
|
||||
};
|
||||
} else {
|
||||
loggedController[sectionKey][methodKey] = createLoggedFunction(
|
||||
method as ApiControllerFn<any, any>,
|
||||
functionName,
|
||||
options,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
loggedController[sectionKey][methodKey] = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loggedController as ApiController;
|
||||
}
|
||||
|
||||
function createLoggedFunction<TRequest, TResponse>(
|
||||
originalFn: ApiControllerFn<TRequest, TResponse> | undefined,
|
||||
functionName: string,
|
||||
options: LoggingOptions = {},
|
||||
): LoggedApiControllerFn<TRequest, TResponse> | undefined {
|
||||
if (!originalFn) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return async (request: TRequest, requestOptions?: any) => {
|
||||
const startTime = Date.now();
|
||||
const requestId = Math.random().toString(36).substring(2, 15);
|
||||
|
||||
const {
|
||||
logErrors = true,
|
||||
logPerformance = true,
|
||||
logRequests = true,
|
||||
logResponses = true,
|
||||
maxRequestSize = 1000,
|
||||
maxResponseSize = 1000,
|
||||
} = options;
|
||||
|
||||
if (logRequests) {
|
||||
const requestStr = JSON.stringify(request, null, 2);
|
||||
const truncatedRequest =
|
||||
requestStr.length > maxRequestSize
|
||||
? requestStr.substring(0, maxRequestSize) + '...'
|
||||
: requestStr;
|
||||
|
||||
logger.info(`[API] ${functionName} called`, {
|
||||
request: truncatedRequest,
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await originalFn(request, requestOptions);
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
if (result[0]) {
|
||||
// Error response
|
||||
if (logErrors) {
|
||||
const error = result[0] as ApiControllerError;
|
||||
logger.error(`[API] ${functionName} failed`, {
|
||||
duration: logPerformance ? `${duration}ms` : undefined,
|
||||
error: {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
},
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Success response
|
||||
if (logResponses) {
|
||||
const response = result[1];
|
||||
const responseStr = JSON.stringify(response);
|
||||
const truncatedResponse =
|
||||
responseStr.length > maxResponseSize
|
||||
? responseStr.substring(0, maxResponseSize) + '...'
|
||||
: responseStr;
|
||||
|
||||
logger.info(`[API] ${functionName} succeeded`, {
|
||||
duration: logPerformance ? `${duration}ms` : undefined,
|
||||
requestId,
|
||||
response: truncatedResponse,
|
||||
responseSize: responseStr.length,
|
||||
responseType: typeof response,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
if (logErrors) {
|
||||
logger.error(`[API] ${functionName} threw exception`, {
|
||||
duration: logPerformance ? `${duration}ms` : undefined,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
requestId,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createLoggedUtility<T extends Record<string, any>>(utility: T): T {
|
||||
const loggedUtility: any = {};
|
||||
|
||||
for (const [key, value] of Object.entries(utility)) {
|
||||
if (typeof value === 'function') {
|
||||
loggedUtility[key] = (...args: any[]) => {
|
||||
logger.debug(`[API] _utility.${key} called`, {
|
||||
args: JSON.stringify(args, null, 2),
|
||||
});
|
||||
return value(...args);
|
||||
};
|
||||
} else {
|
||||
loggedUtility[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return loggedUtility as T;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { createLoggedApiController } from '/@/renderer/api/api-controller-logger';
|
||||
import { useAuthStore } from '/@/renderer/store';
|
||||
import {
|
||||
createApiClient as subsonicApiClient,
|
||||
authenticate as subsonicAuthenticate,
|
||||
controller as subsonicController,
|
||||
middleware as subsonicMiddleware,
|
||||
} from '/@/shared/api/subsonic/subsonic-controller';
|
||||
import { ApiController } from '/@/shared/types/adapter/api-controller-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
export const serverApiMap = {
|
||||
[ServerType.JELLYFIN]: {
|
||||
apiClient: null,
|
||||
authenticate: null,
|
||||
controller: {},
|
||||
middleware: null,
|
||||
},
|
||||
[ServerType.NAVIDROME]: {
|
||||
apiClient: null,
|
||||
authenticate: null,
|
||||
controller: {},
|
||||
middleware: null,
|
||||
},
|
||||
[ServerType.SUBSONIC]: {
|
||||
apiClient: subsonicApiClient,
|
||||
authenticate: subsonicAuthenticate,
|
||||
controller: subsonicController,
|
||||
middleware: subsonicMiddleware,
|
||||
},
|
||||
};
|
||||
|
||||
const getApiByServer = (serverId: string): ApiController => {
|
||||
const servers = useAuthStore.getState().serverList;
|
||||
const server = servers[serverId];
|
||||
|
||||
if (!server) {
|
||||
throw new Error('No server or api client selected');
|
||||
}
|
||||
|
||||
const { apiClient, controller, middleware } = serverApiMap[server.type];
|
||||
|
||||
if (!apiClient) {
|
||||
throw new Error('No api client found');
|
||||
}
|
||||
|
||||
const client = apiClient(server, middleware);
|
||||
|
||||
return createLoggedApiController(controller(client, server));
|
||||
};
|
||||
|
||||
const getAppApi = () => {
|
||||
const servers = useAuthStore.getState().serverList;
|
||||
|
||||
return Object.entries(servers).reduce(
|
||||
(acc, [id]) => {
|
||||
acc[id] = getApiByServer(id);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, ApiController>,
|
||||
);
|
||||
};
|
||||
|
||||
export const api = {
|
||||
authenticate: (serverType: ServerType) => {
|
||||
const { authenticate } = serverApiMap[serverType];
|
||||
|
||||
if (!serverType || !authenticate) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
return authenticate;
|
||||
},
|
||||
controller: getAppApi(),
|
||||
};
|
||||
@@ -4,9 +4,11 @@ import { NavidromeController } from '/@/renderer/api/navidrome/navidrome-control
|
||||
import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller';
|
||||
import { useAuthStore } from '/@/renderer/store';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
import { ControllerEndpoint } from '/@/shared/types/domain/api-domain-types';
|
||||
import { AuthenticationResponse } from '/@/shared/types/domain/auth-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import {
|
||||
AuthenticationResponse,
|
||||
ControllerEndpoint,
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
type ApiController = {
|
||||
jellyfin: ControllerEndpoint;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { authenticationFailure } from '/@/renderer/api/utils';
|
||||
import { useAuthStore } from '/@/renderer/store';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { getClientType } from '/@/shared/api/utils';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const c = initContract();
|
||||
|
||||
|
||||
@@ -6,13 +6,19 @@ import { JFSongListSort, JFSortOrder } from '/@/shared/api/jellyfin.types';
|
||||
import { jfNormalize } from '/@/shared/api/jellyfin/jellyfin-normalize';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils';
|
||||
import { albumListSortMap } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ControllerEndpoint } from '/@/shared/types/domain/api-domain-types';
|
||||
import { albumArtistListSortMap } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Played } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, sortOrderMap } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song, songListSortMap } from '/@/shared/types/domain/song-domain-types';
|
||||
import {
|
||||
albumArtistListSortMap,
|
||||
albumListSortMap,
|
||||
ControllerEndpoint,
|
||||
genreListSortMap,
|
||||
LibraryItem,
|
||||
Played,
|
||||
playlistListSortMap,
|
||||
Song,
|
||||
songListSortMap,
|
||||
sortOrderMap,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
|
||||
const formatCommaDelimitedString = (value: string[]) => {
|
||||
return value.join(',');
|
||||
@@ -320,7 +326,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: albumListSortMap.jellyfin[query.sortBy] || 'SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -332,14 +338,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.album(item, apiClientProps.server)),
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getAlbumListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getAlbumList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getArtistList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -354,7 +360,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: albumArtistListSortMap.jellyfin[query.sortBy] || 'SortName,Name',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
UserId: apiClientProps.server?.userId || undefined,
|
||||
},
|
||||
});
|
||||
@@ -367,14 +373,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
items: res.body.Items.map((item) =>
|
||||
jfNormalize.albumArtist(item, apiClientProps.server),
|
||||
),
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getArtistListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getArtistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getDownloadUrl: (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -396,7 +402,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query?.searchTerm,
|
||||
SortBy: genreListSortMap.jellyfin[query.sortBy] || 'SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
UserId: apiClientProps.server?.userId,
|
||||
},
|
||||
});
|
||||
@@ -407,7 +413,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.genre(item, apiClientProps.server)),
|
||||
offset: query.offset || 0,
|
||||
startIndex: query.startIndex || 0,
|
||||
totalRecordCount: res.body?.TotalRecordCount || 0,
|
||||
};
|
||||
},
|
||||
@@ -456,7 +462,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: musicFolders.map(jfNormalize.musicFolder),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: musicFolders?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -503,7 +509,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: playlistListSortMap.jellyfin[query.sortBy],
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -513,14 +519,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.playlist(item, apiClientProps.server)),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getPlaylistListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getPlaylistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getPlaylistSongList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -550,7 +556,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
offset: query.startIndex,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
@@ -600,7 +606,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.Items.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -740,7 +746,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -775,7 +781,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.offset,
|
||||
StartIndex: query.startIndex,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -804,14 +810,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
items: items.map((item) =>
|
||||
jfNormalize.song(item, apiClientProps.server, '', query.imageSize),
|
||||
),
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount,
|
||||
};
|
||||
},
|
||||
getSongListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getSongList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getTags: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -867,7 +873,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useAuthStore } from '/@/renderer/store';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import { resultWithHeaders } from '/@/shared/api/utils';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
|
||||
@@ -4,24 +4,25 @@ import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller
|
||||
import { NDSongListSort } from '/@/shared/api/navidrome.types';
|
||||
import { ndNormalize } from '/@/shared/api/navidrome/navidrome-normalize';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import { normalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import { SubsonicExtensions } from '/@/shared/api/subsonic/subsonic-types';
|
||||
import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils';
|
||||
import { albumListSortMap } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ControllerEndpoint } from '/@/shared/types/domain/api-domain-types';
|
||||
import { albumArtistListSortMap } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { AuthenticationResponse } from '/@/shared/types/domain/auth-domain-types';
|
||||
import {
|
||||
PlaylistSongListRequest,
|
||||
albumArtistListSortMap,
|
||||
albumListSortMap,
|
||||
AuthenticationResponse,
|
||||
ControllerEndpoint,
|
||||
genreListSortMap,
|
||||
playlistListSortMap,
|
||||
PlaylistSongListArgs,
|
||||
PlaylistSongListResponse,
|
||||
} from '/@/shared/types/domain/playlist-domain-types';
|
||||
import {
|
||||
ServerFeature,
|
||||
ServerFeatures,
|
||||
ServerListItem,
|
||||
} from '/@/shared/types/domain/server-domain-types';
|
||||
import { sortOrderMap } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song, songListSortMap } from '/@/shared/types/domain/song-domain-types';
|
||||
Song,
|
||||
songListSortMap,
|
||||
sortOrderMap,
|
||||
userListSortMap,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature, ServerFeatures } from '/@/shared/types/features-types';
|
||||
|
||||
const VERSION_INFO: VersionInfo = [
|
||||
['0.55.0', { [ServerFeature.BFR]: [1] }],
|
||||
@@ -270,10 +271,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getAlbumList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: albumListSortMap.navidrome[query.sortBy],
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
artist_id: query.artistIds?.[0],
|
||||
compilation: query.compilation,
|
||||
genre_id: query.genres?.[0],
|
||||
@@ -290,24 +291,24 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((album) => ndNormalize.album(album, apiClientProps.server)),
|
||||
offset: query?.offset || 0,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getAlbumListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getAlbumList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getArtistList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getAlbumArtistList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: albumArtistListSortMap.navidrome[query.sortBy],
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
name: query.searchTerm,
|
||||
...query._custom?.navidrome,
|
||||
role: query.role || undefined,
|
||||
@@ -332,14 +333,14 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
apiClientProps.server,
|
||||
),
|
||||
),
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getArtistListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getArtistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getDownloadUrl: SubsonicController.getDownloadUrl,
|
||||
getGenreList: async (args) => {
|
||||
@@ -347,10 +348,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getGenreList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: genreListSortMap.navidrome[query.sortBy],
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
name: query.searchTerm,
|
||||
},
|
||||
});
|
||||
@@ -361,7 +362,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((genre) => ndNormalize.genre(genre)),
|
||||
offset: query.offset || 0,
|
||||
startIndex: query.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
@@ -397,10 +398,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getPlaylistList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: query.sortBy ? playlistListSortMap.navidrome[query.sortBy] : undefined,
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
q: query.searchTerm,
|
||||
...customQuery,
|
||||
},
|
||||
@@ -412,18 +413,16 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((item) => ndNormalize.playlist(item, apiClientProps.server)),
|
||||
offset: query?.offset || 0,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getPlaylistListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getPlaylistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getPlaylistSongList: async (
|
||||
args: PlaylistSongListRequest,
|
||||
): Promise<PlaylistSongListResponse> => {
|
||||
getPlaylistSongList: async (args: PlaylistSongListArgs): Promise<PlaylistSongListResponse> => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getPlaylistSongList({
|
||||
@@ -447,7 +446,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((item) => ndNormalize.song(item, apiClientProps.server)),
|
||||
offset: query?.startIndex || 0,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
@@ -519,7 +518,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
if (res.status === 200 && res.body.similarSongs?.song) {
|
||||
const similar = res.body.similarSongs.song.reduce<Song[]>((acc, song) => {
|
||||
if (song.id !== query.songId) {
|
||||
acc.push(normalize.song(song, apiClientProps.server));
|
||||
acc.push(ssNormalize.song(song, apiClientProps.server));
|
||||
}
|
||||
|
||||
return acc;
|
||||
@@ -573,10 +572,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getSongList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || -1),
|
||||
_end: query.startIndex + (query.limit || -1),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: songListSortMap.navidrome[query.sortBy],
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
album_artist_id: query.albumArtistIds,
|
||||
album_id: query.albumIds,
|
||||
artist_id: query.artistIds,
|
||||
@@ -596,14 +595,14 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
items: res.body.data.map((song) =>
|
||||
ndNormalize.song(song, apiClientProps.server, query.imageSize),
|
||||
),
|
||||
offset: query?.offset || 0,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getSongListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getSongList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getStructuredLyrics: SubsonicController.getStructuredLyrics,
|
||||
getTags: async (args) => {
|
||||
@@ -652,10 +651,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getUserList({
|
||||
query: {
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: userListSortMap.navidrome[query.sortBy],
|
||||
_start: query.offset,
|
||||
_start: query.startIndex,
|
||||
...query._custom?.navidrome,
|
||||
},
|
||||
});
|
||||
@@ -666,7 +665,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((user) => ndNormalize.user(user)),
|
||||
offset: query?.offset || 0,
|
||||
startIndex: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
import { QueryFunctionContext } from '@tanstack/react-query';
|
||||
|
||||
import { AlbumDetailQuery, AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import {
|
||||
import type {
|
||||
AlbumArtistDetailQuery,
|
||||
AlbumArtistListQuery,
|
||||
AlbumDetailQuery,
|
||||
AlbumListQuery,
|
||||
ArtistListQuery,
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
import {
|
||||
GenreListQuery,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
LyricsQuery,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
import {
|
||||
PlaylistDetailQuery,
|
||||
PlaylistListQuery,
|
||||
PlaylistSongListQuery,
|
||||
} from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { SearchQuery } from '/@/shared/types/domain/search-domain-types';
|
||||
import {
|
||||
RandomSongListQuery,
|
||||
SearchQuery,
|
||||
SimilarSongsQuery,
|
||||
SongDetailQuery,
|
||||
SongListQuery,
|
||||
TopSongListQuery,
|
||||
} from '/@/shared/types/domain/song-domain-types';
|
||||
import { UserListQuery } from '/@/shared/types/domain/user-domain-types';
|
||||
UserListQuery,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
import { QueryFunctionContext } from '@tanstack/react-query';
|
||||
|
||||
import { LyricSource } from '/@/shared/types/domain-types';
|
||||
|
||||
export const splitPaginatedQuery = (key: any) => {
|
||||
const { limit, startIndex, ...filter } = key || {};
|
||||
|
||||
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const c = initContract();
|
||||
|
||||
|
||||
@@ -8,18 +8,25 @@ import { z } from 'zod';
|
||||
|
||||
import { contract, ssApiClient } from '/@/renderer/api/subsonic/subsonic-api';
|
||||
import { randomString } from '/@/renderer/utils';
|
||||
import { normalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import {
|
||||
AlbumListSortType,
|
||||
ssType,
|
||||
SubsonicExtensions,
|
||||
} from '/@/shared/api/subsonic/subsonic-types';
|
||||
import { AlbumListSort, sortAlbumList } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ControllerEndpoint } from '/@/shared/types/domain/api-domain-types';
|
||||
import { sortAlbumArtistList } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { ServerFeatures } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song, sortSongList } from '/@/shared/types/domain/song-domain-types';
|
||||
import {
|
||||
AlbumListSort,
|
||||
ControllerEndpoint,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
PlaylistListSort,
|
||||
Song,
|
||||
sortAlbumArtistList,
|
||||
sortAlbumList,
|
||||
SortOrder,
|
||||
sortSongList,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeatures } from '/@/shared/types/features-types';
|
||||
|
||||
const ALBUM_LIST_SORT_MAPPING: Record<AlbumListSort, AlbumListSortType | undefined> = {
|
||||
[AlbumListSort.ALBUM_ARTIST]: AlbumListSortType.ALPHABETICAL_BY_ARTIST,
|
||||
@@ -198,11 +205,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
...normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
albums: artist.album?.map((album) => normalize.album(album, apiClientProps.server)),
|
||||
...ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
albums: artist.album?.map((album) => ssNormalize.album(album, apiClientProps.server)),
|
||||
similarArtists:
|
||||
artistInfo?.similarArtist?.map((artist) =>
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
) || null,
|
||||
};
|
||||
},
|
||||
@@ -222,7 +229,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const artists = (res.body.artists?.index || []).flatMap((index) => index.artist);
|
||||
|
||||
let results = artists.map((artist) =>
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
);
|
||||
|
||||
if (query.searchTerm) {
|
||||
@@ -258,7 +265,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get album detail');
|
||||
}
|
||||
|
||||
return normalize.album(res.body.album, apiClientProps.server);
|
||||
return ssNormalize.album(res.body.album, apiClientProps.server);
|
||||
},
|
||||
getAlbumList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -267,7 +274,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const res = await ssApiClient(apiClientProps).search3({
|
||||
query: {
|
||||
albumCount: query.limit,
|
||||
albumOffset: query.offset,
|
||||
albumOffset: query.startIndex,
|
||||
artistCount: 0,
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
@@ -282,12 +289,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
res.body.searchResult3?.album?.map((album) =>
|
||||
normalize.album(album, apiClientProps.server),
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: results,
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -317,11 +324,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return artist.body.artist.album ?? [];
|
||||
});
|
||||
|
||||
const items = albums.map((album) => normalize.album(album, apiClientProps.server));
|
||||
const items = albums.map((album) => ssNormalize.album(album, apiClientProps.server));
|
||||
|
||||
return {
|
||||
items: sortAlbumList(items, query.sortBy, query.sortOrder),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: albums.length,
|
||||
};
|
||||
}
|
||||
@@ -339,12 +346,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
res.body.starred?.album?.map((album) =>
|
||||
normalize.album(album, apiClientProps.server),
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: sortAlbumList(results, query.sortBy, query.sortOrder),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.starred?.album?.length || 0,
|
||||
};
|
||||
}
|
||||
@@ -374,7 +381,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
if (type === AlbumListSortType.BY_YEAR && !fromYear && !toYear) {
|
||||
if (query.sortOrder === ListSortOrder.ASC) {
|
||||
if (query.sortOrder === SortOrder.ASC) {
|
||||
fromYear = 0;
|
||||
toYear = dayjs().year();
|
||||
} else {
|
||||
@@ -388,7 +395,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
fromYear,
|
||||
genre: query.genres?.length ? query.genres[0] : undefined,
|
||||
musicFolderId: query.musicFolderId,
|
||||
offset: query.offset,
|
||||
offset: query.startIndex,
|
||||
size: query.limit,
|
||||
toYear,
|
||||
type,
|
||||
@@ -402,9 +409,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.albumList2.album?.map((album) =>
|
||||
normalize.album(album, apiClientProps.server, 300),
|
||||
ssNormalize.album(album, apiClientProps.server, 300),
|
||||
) || [],
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
},
|
||||
@@ -572,7 +579,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
let results = artists.map((artist) =>
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
);
|
||||
|
||||
if (query.searchTerm) {
|
||||
@@ -589,7 +596,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: results,
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: results?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -633,11 +640,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
break;
|
||||
}
|
||||
|
||||
const genres = results.map(normalize.genre);
|
||||
const genres = results.map(ssNormalize.genre);
|
||||
|
||||
return {
|
||||
items: genres,
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: genres.length,
|
||||
};
|
||||
},
|
||||
@@ -655,7 +662,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
id: folder.id.toString(),
|
||||
name: folder.name,
|
||||
})),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.musicFolders.musicFolder.length,
|
||||
};
|
||||
},
|
||||
@@ -672,7 +679,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get playlist detail');
|
||||
}
|
||||
|
||||
return normalize.playlist(res.body.playlist, apiClientProps.server);
|
||||
return ssNormalize.playlist(res.body.playlist, apiClientProps.server);
|
||||
},
|
||||
getPlaylistList: async ({ apiClientProps, query }) => {
|
||||
const sortOrder = query.sortOrder.toLowerCase() as 'asc' | 'desc';
|
||||
@@ -717,8 +724,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: results.map((playlist) => normalize.playlist(playlist, apiClientProps.server)),
|
||||
offset: 0,
|
||||
items: results.map((playlist) => ssNormalize.playlist(playlist, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
totalRecordCount: results.length,
|
||||
};
|
||||
},
|
||||
@@ -753,7 +760,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
let results =
|
||||
res.body.playlist.entry?.map((song) => normalize.song(song, apiClientProps.server)) ||
|
||||
res.body.playlist.entry?.map((song) => ssNormalize.song(song, apiClientProps.server)) ||
|
||||
[];
|
||||
|
||||
if (query.sortBy && query.sortOrder) {
|
||||
@@ -762,7 +769,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: results,
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: results?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -786,8 +793,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const results = res.body.randomSongs?.song || [];
|
||||
|
||||
return {
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)),
|
||||
offset: 0,
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.randomSongs?.song?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -871,7 +878,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return res.body.similarSongs.song.reduce<Song[]>((acc, song) => {
|
||||
if (song.id !== query.songId) {
|
||||
acc.push(normalize.song(song, apiClientProps.server));
|
||||
acc.push(ssNormalize.song(song, apiClientProps.server));
|
||||
}
|
||||
|
||||
return acc;
|
||||
@@ -890,7 +897,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get song detail');
|
||||
}
|
||||
|
||||
return normalize.song(res.body.song, apiClientProps.server);
|
||||
return ssNormalize.song(res.body.song, apiClientProps.server);
|
||||
},
|
||||
getSongList: async ({ apiClientProps, query }) => {
|
||||
const fromAlbumPromises: Promise<ServerInferResponses<typeof contract.getAlbum>>[] = [];
|
||||
@@ -905,7 +912,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
songCount: query.limit,
|
||||
songOffset: query.offset,
|
||||
songOffset: query.startIndex,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -916,9 +923,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.searchResult3?.song?.map((song) =>
|
||||
normalize.song(song, apiClientProps.server),
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
offset: query.offset,
|
||||
startIndex: query.startIndex,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -929,7 +936,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
count: query.limit,
|
||||
genre: query.genreIds[0],
|
||||
musicFolderId: query.musicFolderId,
|
||||
offset: query.offset,
|
||||
offset: query.startIndex,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -940,8 +947,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const results = res.body.songsByGenre?.song || [];
|
||||
|
||||
return {
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)) || [],
|
||||
offset: 0,
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)) || [],
|
||||
startIndex: 0,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -959,12 +966,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
(res.body.starred?.song || []).map((song) =>
|
||||
normalize.song(song, apiClientProps.server),
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: sortSongList(results, query.sortBy, query.sortOrder),
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: (res.body.starred?.song || []).length || 0,
|
||||
};
|
||||
}
|
||||
@@ -1033,8 +1040,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)),
|
||||
offset: 0,
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
totalRecordCount: results.length,
|
||||
};
|
||||
}
|
||||
@@ -1047,7 +1054,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
songCount: query.limit,
|
||||
songOffset: query.offset,
|
||||
songOffset: query.startIndex,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1058,9 +1065,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.searchResult3?.song?.map((song) =>
|
||||
normalize.song(song, apiClientProps.server),
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
},
|
||||
@@ -1295,9 +1302,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.topSongs?.song?.map((song) =>
|
||||
normalize.song(song, apiClientProps.server),
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
offset: 0,
|
||||
startIndex: 0,
|
||||
totalRecordCount: res.body.topSongs?.song?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -1365,13 +1372,13 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
albumArtists: (res.body.searchResult3?.artist || [])?.map((artist) =>
|
||||
normalize.albumArtist(artist, apiClientProps.server),
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server),
|
||||
),
|
||||
albums: (res.body.searchResult3?.album || []).map((album) =>
|
||||
normalize.album(album, apiClientProps.server),
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
),
|
||||
songs: (res.body.searchResult3?.song || []).map((song) =>
|
||||
normalize.song(song, apiClientProps.server),
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Song } from '/@/shared/types/domain-types';
|
||||
import type { CrossfadeStyle } from '/@/shared/types/types';
|
||||
import type { ReactPlayerProps } from 'react-player';
|
||||
|
||||
@@ -19,11 +20,9 @@ import {
|
||||
gaplessHandler,
|
||||
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
||||
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
||||
import { TranscodingConfig, usePlaybackSettings, useSpeed } from '/@/renderer/store';
|
||||
import { getServerById, TranscodingConfig, usePlaybackSettings, useSpeed } from '/@/renderer/store';
|
||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import { PlaybackStyle, PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
export type AudioPlayerProgress = {
|
||||
@@ -58,28 +57,27 @@ const getDuration = (ref: any) => {
|
||||
const EMPTY_SOURCE =
|
||||
'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU2LjM2LjEwMAAAAAAAAAAAAAAA//OEAAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAEAAABIADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV6urq6urq6urq6urq6urq6urq6urq6urq6v////////////////////////////////8AAAAATGF2YzU2LjQxAAAAAAAAAAAAAAAAJAAAAAAAAAAAASDs90hvAAAAAAAAAAAAAAAAAAAA//MUZAAAAAGkAAAAAAAAA0gAAAAATEFN//MUZAMAAAGkAAAAAAAAA0gAAAAARTMu//MUZAYAAAGkAAAAAAAAA0gAAAAAOTku//MUZAkAAAGkAAAAAAAAA0gAAAAANVVV';
|
||||
|
||||
const useSongUrl = (
|
||||
transcode: TranscodingConfig,
|
||||
current: boolean,
|
||||
song?: QueueSong,
|
||||
): null | string => {
|
||||
const useSongUrl = (transcode: TranscodingConfig, current: boolean, song?: Song): null | string => {
|
||||
const prior = useRef(['', '']);
|
||||
|
||||
return useMemo(() => {
|
||||
if (song?._serverId) {
|
||||
if (song?.serverId) {
|
||||
// If we are the current track, we do not want a transcoding
|
||||
// reconfiguration to force a restart.
|
||||
if (current && prior.current[0] === song._uniqueId) {
|
||||
return prior.current[1] as string;
|
||||
if (current && prior.current[0] === song.uniqueId) {
|
||||
return prior.current[1];
|
||||
}
|
||||
|
||||
if (!transcode.enabled) {
|
||||
// transcoding disabled; save the result
|
||||
prior.current = [song._uniqueId, song.streamUrl];
|
||||
prior.current = [song.uniqueId, song.streamUrl];
|
||||
return song.streamUrl;
|
||||
}
|
||||
|
||||
const result = api.controller.getTranscodingUrl({
|
||||
apiClientProps: {
|
||||
server: getServerById(song.serverId),
|
||||
},
|
||||
query: {
|
||||
base: song.streamUrl,
|
||||
...transcode,
|
||||
@@ -87,14 +85,14 @@ const useSongUrl = (
|
||||
})!;
|
||||
|
||||
// transcoding enabled; save the updated result
|
||||
prior.current = [song._uniqueId, result];
|
||||
prior.current = [song.uniqueId, result];
|
||||
return result;
|
||||
}
|
||||
|
||||
// no track; clear result
|
||||
prior.current = ['', ''];
|
||||
return null;
|
||||
}, [song?._serverId, song?._uniqueId, song?.streamUrl, current, transcode]);
|
||||
}, [current, song?.uniqueId, song?.serverId, song?.streamUrl, transcode]);
|
||||
};
|
||||
|
||||
export interface AudioPlayerRef {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const CardControls = ({
|
||||
|
||||
@@ -3,21 +3,18 @@ import formatDuration from 'format-duration';
|
||||
import React from 'react';
|
||||
import { generatePath } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Song } from 'src/main/features/core/lyrics/netease';
|
||||
|
||||
import styles from './card-rows.module.css';
|
||||
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { Album, AlbumArtist, Artist, Playlist, Song } from '/@/shared/types/domain-types';
|
||||
import { CardRow } from '/@/shared/types/types';
|
||||
|
||||
interface CardRowsProps {
|
||||
data: any;
|
||||
rows: CardRow<Album>[] | CardRow<Artist>[];
|
||||
rows: CardRow<Album>[] | CardRow<AlbumArtist>[] | CardRow<Artist>[];
|
||||
}
|
||||
|
||||
export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||
|
||||
@@ -8,14 +8,12 @@ import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Album, AlbumArtist, Artist, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
controls: {
|
||||
cardRows: CardRow<Album>[] | CardRow<Artist>[];
|
||||
cardRows: CardRow<Album>[] | CardRow<AlbumArtist>[] | CardRow<Artist>[];
|
||||
handleFavorite: (options: {
|
||||
id: string[];
|
||||
isFavorite: boolean;
|
||||
|
||||
@@ -20,8 +20,7 @@ import { Image } from '/@/shared/components/image/image';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Album, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
const variants: Variants = {
|
||||
|
||||
@@ -24,9 +24,13 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist, RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
RelatedArtist,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRoute, CardRow } from '/@/shared/types/types';
|
||||
|
||||
const getSlidesPerView = (windowWidth: number) => {
|
||||
|
||||
@@ -10,17 +10,20 @@ import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
controls: {
|
||||
cardRows: CardRow<Album | Artist | Playlist | Song>[];
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist | Playlist | Song>[];
|
||||
handleFavorite: (options: {
|
||||
id: string[];
|
||||
isFavorite: boolean;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
export const GridCardControls = ({
|
||||
|
||||
@@ -10,17 +10,20 @@ import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
controls: {
|
||||
cardRows: CardRow<Album | Artist | Playlist | Song>[];
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist | Playlist | Song>[];
|
||||
handleFavorite: (options: {
|
||||
id: string[];
|
||||
isFavorite: boolean;
|
||||
|
||||
@@ -14,9 +14,7 @@ import { FixedSizeList } from 'react-window';
|
||||
import styles from './virtual-grid-wrapper.module.css';
|
||||
|
||||
import { GridCard } from '/@/renderer/components/virtual-grid/grid-card';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Album, AlbumArtist, Artist, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const createItemData = memoize(
|
||||
(
|
||||
@@ -74,7 +72,7 @@ export const VirtualGridWrapper = ({
|
||||
width,
|
||||
...rest
|
||||
}: Omit<FixedSizeListProps, 'children' | 'height' | 'itemSize' | 'ref' | 'width'> & {
|
||||
cardRows: CardRow<Album | Artist>[];
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist>[];
|
||||
columnCount: number;
|
||||
display: ListDisplayType;
|
||||
handleFavorite?: (options: {
|
||||
|
||||
@@ -14,8 +14,7 @@ import {
|
||||
import InfiniteLoader from 'react-window-infinite-loader';
|
||||
|
||||
import { VirtualGridWrapper } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { AnyLibraryItem, LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { AnyLibraryItem, Genre, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export type VirtualInfiniteGridRef = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -9,7 +10,6 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
if (value === undefined) {
|
||||
@@ -23,7 +23,7 @@ export const AlbumArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
return (
|
||||
<CellContainer position="left">
|
||||
<Text isMuted overflow="hidden" size="md">
|
||||
{value?.map((item: Artist, index: number) => (
|
||||
{value?.map((item: AlbumArtist | Artist, index: number) => (
|
||||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && <Separator />}
|
||||
{item.id ? (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -9,7 +10,6 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
if (value === undefined) {
|
||||
@@ -23,7 +23,7 @@ export const ArtistCell = ({ data, value }: ICellRendererParams) => {
|
||||
return (
|
||||
<CellContainer position="left">
|
||||
<Text isMuted overflow="hidden" size="md">
|
||||
{value?.map((item: Artist, index: number) => (
|
||||
{value?.map((item: AlbumArtist | Artist, index: number) => (
|
||||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && <Separator />}
|
||||
{item.id ? (
|
||||
|
||||
@@ -5,7 +5,7 @@ import styles from './combined-title-cell-controls.module.css';
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const ListCoverControls = ({
|
||||
|
||||
@@ -12,7 +12,7 @@ import { SEPARATOR_STRING } from '/@/shared/api/utils';
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
|
||||
export const CombinedTitleCell = ({
|
||||
context,
|
||||
@@ -74,7 +74,7 @@ export const CombinedTitleCell = ({
|
||||
</Text>
|
||||
<Text isMuted overflow="hidden" size="md">
|
||||
{artists?.length ? (
|
||||
artists.map((artist: Artist, index: number) => (
|
||||
artists.map((artist: AlbumArtist | Artist, index: number) => (
|
||||
<React.Fragment key={`queue-${rowIndex}-artist-${artist.id}`}>
|
||||
{index > 0 ? SEPARATOR_STRING : null}
|
||||
{artist.id ? (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -7,14 +8,13 @@ import { CellContainer } from '/@/renderer/components/virtual-table/cells/generi
|
||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||
import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const GenreCell = ({ data, value }: ICellRendererParams) => {
|
||||
const genrePath = useGenreRoute();
|
||||
return (
|
||||
<CellContainer position="left">
|
||||
<Text isMuted overflow="hidden" size="md">
|
||||
{value?.map((item: Artist, index: number) => (
|
||||
{value?.map((item: AlbumArtist | Artist, index: number) => (
|
||||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && <Separator />}
|
||||
<Text
|
||||
|
||||
@@ -5,7 +5,7 @@ import { MutableRefObject, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import { useAppFocus } from '/@/renderer/hooks';
|
||||
import { useCurrentSong, usePlayerStore } from '/@/renderer/store';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import { Song } from '/@/shared/types/domain-types';
|
||||
import { PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
interface UseCurrentSongRowStylesProps {
|
||||
|
||||
@@ -24,11 +24,11 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { PersistedTableColumn, useListStoreActions } from '/@/renderer/store';
|
||||
import { ListKey, useListStoreByKey } from '/@/renderer/store/list.store';
|
||||
import {
|
||||
BasePaginatedQuery,
|
||||
BasePaginatedResponse,
|
||||
} from '/@/shared/types/adapter/api-controller-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
ServerListItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType, TablePagination } from '/@/shared/types/types';
|
||||
|
||||
export type AgGridFetchFn<TResponse, TFilter> = (
|
||||
@@ -52,7 +52,7 @@ interface UseAgGridProps<TFilter> {
|
||||
|
||||
const BLOCK_SIZE = 500;
|
||||
|
||||
export const useVirtualTable = <TFilter extends BasePaginatedQuery<any>>({
|
||||
export const useVirtualTable = <TFilter extends BaseQuery<any>>({
|
||||
columnType,
|
||||
contextMenu,
|
||||
customFilters,
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/domain-types';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { queryOptions, UseQueryOptions } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api/api-controller';
|
||||
import { AlbumListRequest } from '/@/shared/types/domain/album-domain-types';
|
||||
|
||||
export const getAlbumListQueryKey = (serverId: string, request?: AlbumListRequest) => {
|
||||
if (!request) {
|
||||
return [serverId, 'albums'];
|
||||
}
|
||||
|
||||
return [serverId, 'albums', request];
|
||||
};
|
||||
|
||||
export const getInfiniteAlbumListQueryKey = (serverId: string, request?: AlbumListRequest) => {
|
||||
if (!request) {
|
||||
return [serverId, 'albums', 'infinite'];
|
||||
}
|
||||
|
||||
return [serverId, 'albums', 'infinite', request];
|
||||
};
|
||||
|
||||
export const getAlbumList = async (serverId: string, request: AlbumListRequest) => {
|
||||
const [error, response] = await api.controller[serverId]!.album.getList!({
|
||||
query: request.query,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
export const getAlbumListQuery = (
|
||||
serverId: string,
|
||||
request: AlbumListRequest,
|
||||
options?: UseQueryOptions,
|
||||
) => {
|
||||
return queryOptions({
|
||||
enabled: !!serverId,
|
||||
queryFn: () => getAlbumList(serverId, request),
|
||||
queryKey: getAlbumListQueryKey(serverId, request),
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -49,9 +49,13 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { Popover } from '/@/shared/components/popover/popover';
|
||||
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { AlbumListQuery, AlbumListSort } from '/@/shared/types/domain/album-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumListQuery,
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
const isFullWidthRow = (node: RowNode) => {
|
||||
@@ -150,8 +154,8 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
|
||||
|
||||
const artistQuery = useAlbumList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
enabled: detailQuery?.data?.albumArtists[0]?.id !== undefined,
|
||||
gcTime: 1000 * 60,
|
||||
keepPreviousData: true,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
@@ -165,9 +169,9 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
|
||||
? [detailQuery?.data?.albumArtists[0].id]
|
||||
: undefined,
|
||||
limit: 15,
|
||||
offset: 0,
|
||||
sortBy: AlbumListSort.YEAR,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -175,15 +179,15 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
|
||||
const relatedAlbumGenresRequest: AlbumListQuery = {
|
||||
genres: detailQuery.data?.genres.length ? [detailQuery.data.genres[0].id] : undefined,
|
||||
limit: 15,
|
||||
offset: 0,
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
const relatedAlbumGenresQuery = useAlbumList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
enabled: !!detailQuery?.data?.genres?.[0],
|
||||
gcTime: 1000 * 60,
|
||||
queryKey: queryKeys.albums.related(
|
||||
server?.id || '',
|
||||
albumId,
|
||||
|
||||
@@ -16,9 +16,7 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { AlbumDetailResponse } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { AlbumDetailResponse, LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumDetailHeaderProps {
|
||||
background: {
|
||||
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
AlbumListQuery,
|
||||
AlbumListResponse,
|
||||
AlbumListSort,
|
||||
} from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
@@ -137,11 +137,15 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const itemData: Album[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, offset } = data || {};
|
||||
const { items, startIndex } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -161,7 +165,7 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
limit: take,
|
||||
...filter,
|
||||
...customFilters,
|
||||
offset: skip,
|
||||
startIndex: skip,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.albums.list(server?.id || '', query, id);
|
||||
|
||||
@@ -34,154 +34,158 @@ import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { AlbumListQuery, AlbumListSort } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumListQuery,
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType, Play, TableColumn } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.communityRating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.COMMUNITY_RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.criticRating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.CRITIC_RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.playCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.releaseDate', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RELEASE_DATE,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.artist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_PLAYED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.SONG_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.favorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.releaseYear', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.YEAR,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_PLAYED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.favorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.releaseYear', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.YEAR,
|
||||
},
|
||||
@@ -295,7 +299,7 @@ export const AlbumListHeaderFilters = ({
|
||||
customFilters,
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as AlbumListSort,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ALBUM,
|
||||
key: pageKey,
|
||||
@@ -333,8 +337,7 @@ export const AlbumListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: { sortOrder: newSortOrder },
|
||||
|
||||
@@ -16,8 +16,7 @@ import { titleCase } from '/@/renderer/utils';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { AlbumListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumListHeaderProps {
|
||||
genreId?: string;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { ALBUM_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
export const AlbumListTableView = ({ itemCount, tableRef }: any) => {
|
||||
const server = useCurrentServer();
|
||||
|
||||
@@ -14,10 +14,13 @@ import { SpinnerIcon } from '/@/shared/components/spinner/spinner';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { YesNoSelect } from '/@/shared/components/yes-no-select/yes-no-select';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtistListSort } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { GenreListSort } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
interface JellyfinAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
@@ -41,14 +44,14 @@ export const JellyfinAlbumFilters = ({
|
||||
// TODO - eventually replace with /items/filters endpoint to fetch genres and tags specific to the selected library
|
||||
const genreListQuery = useGenreList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
musicFolderId: filter?.musicFolderId,
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
@@ -63,7 +66,7 @@ export const JellyfinAlbumFilters = ({
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
@@ -170,12 +173,12 @@ export const JellyfinAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
|
||||
@@ -16,10 +16,13 @@ import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Switch } from '/@/shared/components/switch/switch';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { YesNoSelect } from '/@/shared/components/yes-no-select/yes-no-select';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtistListSort } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { GenreListSort } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
interface NavidromeAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
@@ -42,13 +45,13 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
@@ -76,7 +79,7 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
@@ -185,13 +188,13 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
// searchTerm: debouncedSearchTerm,
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
|
||||
@@ -14,10 +14,13 @@ import { SpinnerIcon } from '/@/shared/components/spinner/spinner';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Switch } from '/@/shared/components/switch/switch';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtistListSort } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { GenreListSort } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
interface SubsonicAlbumFiltersProps {
|
||||
disableArtistFilter?: boolean;
|
||||
@@ -39,12 +42,12 @@ export const SubsonicAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
@@ -72,13 +75,13 @@ export const SubsonicAlbumFilters = ({
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumDetailQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumDetailQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumDetail = (args: RQueryHookArgs<AlbumDetailQuery>) => {
|
||||
export const useAlbumDetail = (args: QueryHookArgs<AlbumDetailQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
queryFn: ({ signal }) => {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumListCount = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumListCount = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumListQuery, AlbumListResponse } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery, AlbumListResponse } from '/@/shared/types/domain/album-domain-types';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumList = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumList = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
@@ -33,9 +33,9 @@ export const useAlbumList = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAlbumListInfinite = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumListInfinite = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useInfiniteQuery({
|
||||
enabled: !!serverId,
|
||||
@@ -57,7 +57,7 @@ export const useAlbumListInfinite = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
query: {
|
||||
...query,
|
||||
limit: query.limit || 50,
|
||||
offset: pageParam * (query.limit || 50),
|
||||
startIndex: pageParam * (query.limit || 50),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumDetailRoute = () => {
|
||||
const tableRef = useRef<AgGridReactType | null>(null);
|
||||
|
||||
@@ -16,9 +16,12 @@ import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { queryClient } from '/@/renderer/lib/react-query';
|
||||
import { useCurrentServer, useListFilterByKey } from '/@/renderer/store';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { GenreListSort } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
const AlbumListRoute = () => {
|
||||
@@ -52,13 +55,13 @@ const AlbumListRoute = () => {
|
||||
|
||||
const genreList = useGenreList({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 60,
|
||||
cacheTime: 1000 * 60 * 60,
|
||||
enabled: !!genreId,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -74,7 +77,7 @@ const AlbumListRoute = () => {
|
||||
|
||||
const itemCountCheck = useAlbumListCount({
|
||||
options: {
|
||||
gcTime: 1000 * 60,
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: {
|
||||
|
||||
@@ -33,8 +33,7 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { SongDetailResponse } from '/@/shared/types/domain/song-domain-types';
|
||||
import { LibraryItem, SongDetailResponse } from '/@/shared/types/domain-types';
|
||||
|
||||
const DummyAlbumDetailRoute = () => {
|
||||
const cq = useContainerQuery();
|
||||
|
||||
@@ -35,10 +35,15 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||
import { Album, AlbumListSort } from '/@/shared/types/domain/album-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, Play, TableColumn } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistDetailContentProps {
|
||||
@@ -101,8 +106,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
||||
compilation: false,
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -116,8 +121,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
||||
compilation: true,
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
offset: 0,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
@@ -11,8 +11,7 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumArtistDetailHeaderProps {
|
||||
background?: string;
|
||||
|
||||
+1
-3
@@ -12,9 +12,7 @@ import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/conte
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { SongListQuery } from '/@/shared/types/domain/song-domain-types';
|
||||
import { LibraryItem, QueueSong, SongListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumArtistSongListContentProps {
|
||||
data: QueueSong[];
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { Badge } from '/@/shared/components/badge/badge';
|
||||
import { SpinnerIcon } from '/@/shared/components/spinner/spinner';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistDetailTopSongsListHeaderProps {
|
||||
|
||||
@@ -17,11 +17,12 @@ import { useHandleFavorite } from '/@/renderer/features/shared/hooks/use-handle-
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
|
||||
import {
|
||||
AlbumArtist,
|
||||
AlbumArtistListQuery,
|
||||
AlbumArtistListResponse,
|
||||
AlbumArtistListSort,
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistListGridViewProps {
|
||||
|
||||
@@ -34,90 +34,91 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import {
|
||||
AlbumArtistListQuery,
|
||||
AlbumArtistListSort,
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.album', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RECENTLY_ADDED,
|
||||
},
|
||||
// { defaultOrder: ListSortOrder.DESC, name: 'Release Date', value: AlbumArtistListSort.RELEASE_DATE },
|
||||
// { defaultOrder: SortOrder.DESC, name: 'Release Date', value: AlbumArtistListSort.RELEASE_DATE },
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.SONG_COUNT,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RATING,
|
||||
},
|
||||
@@ -269,7 +270,7 @@ export const AlbumArtistListHeaderFilters = ({
|
||||
const updatedFilters = setFilter({
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as AlbumArtistListSort,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ALBUM_ARTIST,
|
||||
key: pageKey,
|
||||
@@ -305,8 +306,7 @@ export const AlbumArtistListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
data: { sortOrder: newSortOrder },
|
||||
itemType: LibraryItem.ALBUM_ARTIST,
|
||||
|
||||
@@ -15,8 +15,7 @@ import { AlbumArtistListFilter, useCurrentServer } from '/@/renderer/store';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { AlbumArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumArtistListHeaderProps {
|
||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { ARTIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface AlbumArtistListTableViewProps {
|
||||
itemCount?: number;
|
||||
|
||||
@@ -18,11 +18,12 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer, useListStoreActions } from '/@/renderer/store';
|
||||
import { useListStoreByKey } from '/@/renderer/store/list.store';
|
||||
import {
|
||||
AlbumArtist,
|
||||
ArtistListQuery,
|
||||
ArtistListResponse,
|
||||
ArtistListSort,
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
interface ArtistListGridViewProps {
|
||||
@@ -55,11 +56,15 @@ export const ArtistListGridView = ({ gridRef, itemCount }: ArtistListGridViewPro
|
||||
const itemData: AlbumArtist[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, offset } = data || {};
|
||||
const { items, startIndex } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -74,7 +79,7 @@ export const ArtistListGridView = ({ gridRef, itemCount }: ArtistListGridViewPro
|
||||
const query: ArtistListQuery = {
|
||||
...filter,
|
||||
limit,
|
||||
offset,
|
||||
startIndex,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.artists.list(server?.id || '', query);
|
||||
|
||||
@@ -33,89 +33,93 @@ import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Select } from '/@/shared/components/select/select';
|
||||
import { ArtistListQuery, ArtistListSort } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
ArtistListQuery,
|
||||
ArtistListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.album', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RECENTLY_ADDED,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.SONG_COUNT,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
defaultOrder: SortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
@@ -140,7 +144,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
const cq = useContainerQuery();
|
||||
const roles = useRoles({
|
||||
options: {
|
||||
gcTime: 1000 * 60 * 60 * 2,
|
||||
cacheTime: 1000 * 60 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 60 * 2,
|
||||
},
|
||||
query: {},
|
||||
@@ -188,7 +192,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
},
|
||||
query: {
|
||||
limit,
|
||||
offset,
|
||||
startIndex,
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
@@ -224,7 +228,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
},
|
||||
query: {
|
||||
limit,
|
||||
offset,
|
||||
startIndex,
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
@@ -272,7 +276,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
const updatedFilters = setFilter({
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as ArtistListSort,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ARTIST,
|
||||
key: pageKey,
|
||||
@@ -308,8 +312,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
data: { sortOrder: newSortOrder },
|
||||
itemType: LibraryItem.ARTIST,
|
||||
|
||||
@@ -15,8 +15,7 @@ import { ArtistListFilter, useCurrentServer } from '/@/renderer/store';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { ArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface ArtistListHeaderProps {
|
||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { ARTIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface ArtistListTableViewProps {
|
||||
itemCount?: number;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { AlbumArtistDetailQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistDetailQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumArtistDetail = (args: RQueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
export const useAlbumArtistDetail = (args: QueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id && !!query.id,
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
export const useAlbumArtistListCount = (args: RQueryHookArgs<AlbumArtistListQuery>) => {
|
||||
export const useAlbumArtistListCount = (args: QueryHookArgs<AlbumArtistListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { AlbumArtistListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumArtistList = (args: RQueryHookArgs<AlbumArtistListQuery>) => {
|
||||
export const useAlbumArtistList = (args: QueryHookArgs<AlbumArtistListQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { AlbumArtistDetailQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistDetailQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useAlbumArtistInfo = (args: RQueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
export const useAlbumArtistInfo = (args: QueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id && !!query.id,
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
export const useArtistListCount = (args: RQueryHookArgs<ArtistListQuery>) => {
|
||||
export const useArtistListCount = (args: QueryHookArgs<ArtistListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -2,12 +2,12 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useRoles = (args: RQueryHookArgs<object>) => {
|
||||
export const useRoles = (args: QueryHookArgs<object>) => {
|
||||
const { options, serverId } = args;
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { TopSongListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { TopSongListQuery } from '/@/shared/types/domain/song-domain-types';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useTopSongsList = (args: RQueryHookArgs<TopSongListQuery>) => {
|
||||
export const useTopSongsList = (args: QueryHookArgs<TopSongListQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = useServerById(serverId);
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumArtistDetailRoute = () => {
|
||||
const scrollAreaRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useAlbumArtistDetail } from '/@/renderer/features/artists/queries/album
|
||||
import { useTopSongsList } from '/@/renderer/features/artists/queries/top-songs-list-query';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { useCurrentServer } from '/@/renderer/store/auth.store';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumArtistDetailTopSongsListRoute = () => {
|
||||
const tableRef = useRef<AgGridReactType | null>(null);
|
||||
|
||||
@@ -10,8 +10,7 @@ import { useAlbumArtistListCount } from '/@/renderer/features/artists/queries/al
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { useCurrentServer } from '/@/renderer/store/auth.store';
|
||||
import { useListFilterByKey } from '/@/renderer/store/list.store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { AlbumArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumArtistListRoute = () => {
|
||||
const gridRef = useRef<null | VirtualInfiniteGridRef>(null);
|
||||
@@ -23,7 +22,7 @@ const AlbumArtistListRoute = () => {
|
||||
|
||||
const itemCountCheck = useAlbumArtistListCount({
|
||||
options: {
|
||||
gcTime: 1000 * 60,
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: albumArtistListFilter,
|
||||
|
||||
@@ -10,8 +10,7 @@ import { useArtistListCount } from '/@/renderer/features/artists/queries/artist-
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { useCurrentServer } from '/@/renderer/store/auth.store';
|
||||
import { useListFilterByKey } from '/@/renderer/store/list.store';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { ArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
const ArtistListRoute = () => {
|
||||
const gridRef = useRef<null | VirtualInfiniteGridRef>(null);
|
||||
@@ -23,7 +22,7 @@ const ArtistListRoute = () => {
|
||||
|
||||
const itemCountCheck = useArtistListCount({
|
||||
options: {
|
||||
gcTime: 1000 * 60,
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: artistListFilter,
|
||||
|
||||
@@ -37,7 +37,7 @@ import { useRemoveFromPlaylist } from '/@/renderer/features/playlists/mutations/
|
||||
import { useCreateFavorite, useDeleteFavorite, useSetRating } from '/@/renderer/features/shared';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import {
|
||||
useServerById,
|
||||
getServerById,
|
||||
useAuthStore,
|
||||
useCurrentServer,
|
||||
usePlayerStore,
|
||||
@@ -57,12 +57,13 @@ import { Rating } from '/@/shared/components/rating/rating';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { toast } from '/@/shared/components/toast/toast';
|
||||
import { ServerFeature, ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import {
|
||||
AnyLibraryItem,
|
||||
AnyLibraryItems,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain/shared-domain-types';
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
import { Play, PlaybackType } from '/@/shared/types/types';
|
||||
|
||||
type ContextMenuContextProps = {
|
||||
@@ -102,19 +103,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
const [contextMenuRef, setContextMenuRef] = useState<HTMLDivElement | null>(null);
|
||||
const [ratingsRef, setRatingsRef] = useState<HTMLDivElement | null>(null);
|
||||
const [rating, setRating] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
setRating(0);
|
||||
}, [opened]);
|
||||
|
||||
const clickOutsideRef = useClickOutside(
|
||||
() => setOpened(false),
|
||||
['mousedown', 'touchstart'],
|
||||
[contextMenuRef, ratingsRef],
|
||||
);
|
||||
const clickOutsideRef = useClickOutside(() => setOpened(false), ['mousedown', 'touchstart']);
|
||||
|
||||
const viewport = useViewportSize();
|
||||
const server = useCurrentServer();
|
||||
@@ -131,6 +120,24 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
yPos: 0,
|
||||
});
|
||||
|
||||
const [rating, setRating] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (opened && ctx.data.length > 0) {
|
||||
if (ctx.data.length === 1) {
|
||||
setRating(ctx.data[0].userRating ?? 0);
|
||||
} else {
|
||||
const firstRating = ctx.data[0].userRating ?? 0;
|
||||
const allSameRating = ctx.data.every(
|
||||
(item) => (item.userRating ?? 0) === firstRating,
|
||||
);
|
||||
setRating(allSameRating ? firstRating : 0);
|
||||
}
|
||||
} else {
|
||||
setRating(0);
|
||||
}
|
||||
}, [ctx.data, opened]);
|
||||
|
||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -712,7 +719,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
const item = ctx.data[0];
|
||||
const songs = await controller.getSimilarSongs({
|
||||
apiClientProps: {
|
||||
server: useServerById(item.serverId),
|
||||
server: getServerById(item.serverId),
|
||||
signal: undefined,
|
||||
},
|
||||
query: { albumArtistIds: item.albumArtistIds, songId: item.id },
|
||||
@@ -881,7 +888,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
leftIcon: <Icon icon="star" />,
|
||||
onClick: () => {},
|
||||
rightIcon: (
|
||||
<Group ref={setRatingsRef as any}>
|
||||
<Group>
|
||||
<Rating
|
||||
onChange={(e) => {
|
||||
handleUpdateRating(e);
|
||||
@@ -949,7 +956,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
<AnimatePresence>
|
||||
{opened && (
|
||||
<ContextMenu minWidth={125} ref={mergedRef} xPos={ctx.xPos} yPos={ctx.yPos}>
|
||||
<Stack gap={0} ref={setContextMenuRef}>
|
||||
<Stack gap={0}>
|
||||
<Stack gap={0} onClick={closeContextMenu}>
|
||||
{ctx.menuItems?.map((item) => {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GridOptions, RowNode } from '@ag-grid-community/core';
|
||||
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { createUseExternalEvents } from '/@/shared/utils/create-use-external-events';
|
||||
|
||||
export type ContextMenuEvents = {
|
||||
|
||||
@@ -2,11 +2,14 @@ import { CellContextMenuEvent, GridApi } from '@ag-grid-community/core';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
import { openContextMenu, SetContextMenuItems } from '/@/renderer/features/context-menu/events';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
export const useHandleTableContextMenu = (
|
||||
itemType: LibraryItem,
|
||||
|
||||
@@ -5,14 +5,13 @@ import { useCallback, useEffect, useState } from 'react';
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import {
|
||||
DiscordDisplayType,
|
||||
getServerById,
|
||||
useAppStore,
|
||||
useDiscordSettings,
|
||||
useServerById,
|
||||
useGeneralSettings,
|
||||
usePlayerStore,
|
||||
} from '/@/renderer/store';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { QueueSong, ServerType } from '/@/shared/types/domain-types';
|
||||
import { PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const discordRpc = isElectron() ? window.api.discordRpc : null;
|
||||
@@ -93,7 +92,7 @@ export const useDiscordRpc = () => {
|
||||
if (song.serverType === ServerType.JELLYFIN && song.imageUrl) {
|
||||
activity.largeImageKey = song.imageUrl;
|
||||
} else if (song.serverType === ServerType.NAVIDROME) {
|
||||
const server = useServerById(song.serverId);
|
||||
const server = getServerById(song.serverId);
|
||||
|
||||
try {
|
||||
const info = await controller.getAlbumInfo({
|
||||
|
||||
@@ -15,13 +15,13 @@ import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||
import { useCurrentServer, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import {
|
||||
Album,
|
||||
Genre,
|
||||
GenreListQuery,
|
||||
GenreListResponse,
|
||||
} from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
@@ -74,11 +74,15 @@ export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const itemData: Genre[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, offset } = data || {};
|
||||
const { items, startIndex } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -97,7 +101,7 @@ export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const query: GenreListQuery = {
|
||||
...filter,
|
||||
limit: take,
|
||||
offset: skip,
|
||||
startIndex: skip,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.albums.list(server?.id || '', query);
|
||||
|
||||
@@ -33,29 +33,33 @@ import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { GenreListQuery, GenreListSort } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import {
|
||||
GenreListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
defaultOrder: SortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
@@ -133,7 +137,7 @@ export const GenreListHeaderFilters = ({
|
||||
customFilters,
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as GenreListSort,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.GENRE,
|
||||
key: pageKey,
|
||||
@@ -171,8 +175,7 @@ export const GenreListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: { sortOrder: newSortOrder },
|
||||
|
||||
@@ -15,8 +15,7 @@ import { GenreListFilter, useCurrentServer } from '/@/renderer/store';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { GenreListQuery, LibraryItem } from '/@/shared/types/domain-types';
|
||||
|
||||
interface GenreListHeaderProps {
|
||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user