mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c7c0e488d | |||
| a7430dae31 | |||
| 98e8bda45d | |||
| 96221c8fa7 | |||
| 8c7cac369a | |||
| f1c011f677 | |||
| 351464c52d | |||
| da8ba31a88 | |||
| d8a8880e48 | |||
| fe36535aee | |||
| 67eec51e5f | |||
| a7f21db563 | |||
| 6c360c3c19 | |||
| 4d7779eae1 | |||
| 71b307e4a6 | |||
| a3a67d20a9 | |||
| 1c22461ee4 | |||
| 7785874605 | |||
| 9147b041f3 |
@@ -30,6 +30,7 @@ const config: UserConfig = {
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'/@/i18n': resolve('src/i18n'),
|
||||
'/@/main': resolve('src/main'),
|
||||
'/@/shared': resolve('src/shared'),
|
||||
},
|
||||
@@ -39,6 +40,7 @@ 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'] },
|
||||
{ ignores: ['**/node_modules', '**/dist', '**/out', '**/*-schema.d.ts'] },
|
||||
tseslint.configs.recommended,
|
||||
perfectionist.configs['recommended-natural'],
|
||||
eslintPluginReact.configs.flat.recommended,
|
||||
|
||||
+8
-3
@@ -27,6 +27,8 @@
|
||||
"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",
|
||||
@@ -71,9 +73,9 @@
|
||||
"@mantine/hooks": "^8.2.8",
|
||||
"@mantine/modals": "^8.2.8",
|
||||
"@mantine/notifications": "^8.2.8",
|
||||
"@tanstack/react-query": "^4.32.1",
|
||||
"@tanstack/react-query-devtools": "^4.32.1",
|
||||
"@tanstack/react-query-persist-client": "^4.32.1",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"@tanstack/react-query-devtools": "^5.83.0",
|
||||
"@tanstack/react-query-persist-client": "^5.83.0",
|
||||
"@ts-rest/core": "^3.23.0",
|
||||
"@xhayper/discord-rpc": "^1.3.0",
|
||||
"audiomotion-analyzer": "^4.5.0",
|
||||
@@ -103,6 +105,7 @@
|
||||
"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",
|
||||
@@ -135,6 +138,7 @@
|
||||
"@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",
|
||||
@@ -155,6 +159,7 @@
|
||||
"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
+226
-122
@@ -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: ^4.32.1
|
||||
version: 4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(react@19.1.0)
|
||||
'@tanstack/react-query-devtools':
|
||||
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)
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-query-persist-client':
|
||||
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))
|
||||
specifier: ^5.83.0
|
||||
version: 5.83.0(@tanstack/react-query@5.83.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,6 +155,9 @@ 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
|
||||
@@ -246,6 +249,9 @@ 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
|
||||
@@ -266,7 +272,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))
|
||||
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))
|
||||
concurrently:
|
||||
specifier: ^7.1.0
|
||||
version: 7.6.0
|
||||
@@ -284,7 +290,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))
|
||||
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))
|
||||
eslint:
|
||||
specifier: ^9.24.0
|
||||
version: 9.27.0
|
||||
@@ -306,6 +312,9 @@ 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)
|
||||
@@ -335,7 +344,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)
|
||||
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)
|
||||
vite-plugin-conditional-import:
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7
|
||||
@@ -344,7 +353,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))
|
||||
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))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1040,6 +1049,16 @@ 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'}
|
||||
@@ -1163,39 +1182,31 @@ packages:
|
||||
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@tanstack/match-sorter-utils@8.19.4':
|
||||
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
|
||||
engines: {node: '>=12'}
|
||||
'@tanstack/query-core@5.83.0':
|
||||
resolution: {integrity: sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==}
|
||||
|
||||
'@tanstack/query-core@4.36.1':
|
||||
resolution: {integrity: sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==}
|
||||
'@tanstack/query-devtools@5.81.2':
|
||||
resolution: {integrity: sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg==}
|
||||
|
||||
'@tanstack/query-persist-client-core@4.36.1':
|
||||
resolution: {integrity: sha512-eocgCeI7D7TRv1IUUBMfVwOI0wdSmMkBIbkKhqEdTrnUHUQEeOaYac8oeZk2cumAWJdycu6P/wB+WqGynTnzXg==}
|
||||
'@tanstack/query-persist-client-core@5.83.0':
|
||||
resolution: {integrity: sha512-hdKgHkr1MYnwZX+QHj/9JjXZx9gL2RUCD5xSX0EHZiqUQhMk4Gcryq9xosn8LmYRMlhkjk7n9uV+X4UXRvgoIg==}
|
||||
|
||||
'@tanstack/react-query-devtools@4.36.1':
|
||||
resolution: {integrity: sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw==}
|
||||
'@tanstack/react-query-devtools@5.83.0':
|
||||
resolution: {integrity: sha512-yfp8Uqd3I1jgx8gl0lxbSSESu5y4MO2ThOPBnGNTYs0P+ZFu+E9g5IdOngyUGuo6Uz6Qa7p9TLdZEX3ntik2fQ==}
|
||||
peerDependencies:
|
||||
'@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': ^5.83.0
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tanstack/react-query-persist-client@4.36.1':
|
||||
resolution: {integrity: sha512-32I5b9aAu4NCiXZ7Te/KEQLfHbYeTNriVPrKYcvEThnZ9tlW01vLcSoxpUIsMYRsembvJUUAkzYBAiZHLOd6pQ==}
|
||||
'@tanstack/react-query-persist-client@5.83.0':
|
||||
resolution: {integrity: sha512-uEqJnSbqlvzlhYJ+RU+2c2DmbbT7cw6eFjiewEXZFXaSGWNjvUG02LePrwL8cdLlRQFcZKas30IdckboOoVg9Q==}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': ^4.36.1
|
||||
'@tanstack/react-query': ^5.83.0
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tanstack/react-query@4.36.1':
|
||||
resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==}
|
||||
'@tanstack/react-query@5.83.0':
|
||||
resolution: {integrity: sha512-/XGYhZ3foc5H0VM2jLSD/NyBRIOK4q9kfeml4+0x2DlL6xVuAcVEW+hTlTapAmejObg0i3eNqhkr2dT+eciwoQ==}
|
||||
peerDependencies:
|
||||
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
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tootallnate/once@2.0.0':
|
||||
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
|
||||
@@ -1269,6 +1280,9 @@ 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:
|
||||
@@ -1428,6 +1442,10 @@ 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'}
|
||||
@@ -1674,6 +1692,9 @@ 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==}
|
||||
|
||||
@@ -1752,6 +1773,9 @@ 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==}
|
||||
|
||||
@@ -1800,10 +1824,6 @@ 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==}
|
||||
|
||||
@@ -2701,6 +2721,10 @@ 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==}
|
||||
|
||||
@@ -2870,10 +2894,6 @@ 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==}
|
||||
|
||||
@@ -2903,6 +2923,10 @@ 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==}
|
||||
|
||||
@@ -3339,6 +3363,18 @@ 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'}
|
||||
@@ -3402,6 +3438,10 @@ 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==}
|
||||
|
||||
@@ -3470,6 +3510,10 @@ 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'}
|
||||
@@ -3797,9 +3841,6 @@ 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==}
|
||||
|
||||
@@ -4288,9 +4329,9 @@ packages:
|
||||
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
||||
engines: {node: '>= 8.0'}
|
||||
|
||||
superjson@1.13.3:
|
||||
resolution: {integrity: sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==}
|
||||
engines: {node: '>=10'}
|
||||
supports-color@10.0.0:
|
||||
resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
@@ -4489,6 +4530,9 @@ 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==}
|
||||
|
||||
@@ -4744,6 +4788,14 @@ 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'}
|
||||
@@ -4851,7 +4903,7 @@ snapshots:
|
||||
'@babel/traverse': 7.27.1
|
||||
'@babel/types': 7.27.1
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
@@ -4937,7 +4989,7 @@ snapshots:
|
||||
'@babel/parser': 7.27.2
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/types': 7.27.1
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5039,7 +5091,7 @@ snapshots:
|
||||
|
||||
'@electron/get@2.0.3':
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
env-paths: 2.2.1
|
||||
fs-extra: 8.1.0
|
||||
got: 11.8.6
|
||||
@@ -5069,7 +5121,7 @@ snapshots:
|
||||
|
||||
'@electron/notarize@2.5.0':
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 9.1.0
|
||||
promise-retry: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
@@ -5078,7 +5130,7 @@ snapshots:
|
||||
'@electron/osx-sign@1.3.1':
|
||||
dependencies:
|
||||
compare-version: 0.1.2
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 10.1.0
|
||||
isbinaryfile: 4.0.10
|
||||
minimist: 1.2.8
|
||||
@@ -5091,7 +5143,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
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
detect-libc: 2.0.4
|
||||
fs-extra: 10.1.0
|
||||
got: 11.8.6
|
||||
@@ -5110,7 +5162,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@electron/asar': 3.2.18
|
||||
'@malept/cross-spawn-promise': 2.0.0
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
dir-compare: 4.2.0
|
||||
fs-extra: 11.3.1
|
||||
minimatch: 9.0.5
|
||||
@@ -5121,7 +5173,7 @@ snapshots:
|
||||
'@electron/windows-sign@1.2.2':
|
||||
dependencies:
|
||||
cross-dirname: 0.1.0
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 11.3.1
|
||||
minimist: 1.2.8
|
||||
postject: 1.0.0-alpha.6
|
||||
@@ -5214,7 +5266,7 @@ snapshots:
|
||||
'@eslint/config-array@0.20.0':
|
||||
dependencies:
|
||||
'@eslint/object-schema': 2.1.6
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5232,7 +5284,7 @@ snapshots:
|
||||
'@eslint/eslintrc@3.3.1':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
espree: 10.3.0
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
@@ -5337,7 +5389,7 @@ snapshots:
|
||||
|
||||
'@malept/flatpak-bundler@0.4.0':
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 9.1.0
|
||||
lodash: 4.17.21
|
||||
tmp-promise: 3.0.3
|
||||
@@ -5547,6 +5599,29 @@ 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': {}
|
||||
@@ -5621,37 +5696,30 @@ snapshots:
|
||||
dependencies:
|
||||
defer-to-connect: 2.0.1
|
||||
|
||||
'@tanstack/match-sorter-utils@8.19.4':
|
||||
dependencies:
|
||||
remove-accents: 0.5.0
|
||||
'@tanstack/query-core@5.83.0': {}
|
||||
|
||||
'@tanstack/query-core@4.36.1': {}
|
||||
'@tanstack/query-devtools@5.81.2': {}
|
||||
|
||||
'@tanstack/query-persist-client-core@4.36.1':
|
||||
'@tanstack/query-persist-client-core@5.83.0':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 4.36.1
|
||||
'@tanstack/query-core': 5.83.0
|
||||
|
||||
'@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)':
|
||||
'@tanstack/react-query-devtools@5.83.0(@tanstack/react-query@5.83.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)
|
||||
'@tanstack/query-devtools': 5.81.2
|
||||
'@tanstack/react-query': 5.83.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@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-persist-client@5.83.0(@tanstack/react-query@5.83.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@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@4.36.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 4.36.1
|
||||
'@tanstack/query-persist-client-core': 5.83.0
|
||||
'@tanstack/react-query': 5.83.0(react@19.1.0)
|
||||
react: 19.1.0
|
||||
|
||||
'@tanstack/react-query@5.83.0(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.83.0
|
||||
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': {}
|
||||
|
||||
@@ -5732,6 +5800,8 @@ 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
|
||||
@@ -5798,7 +5868,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
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
eslint: 9.27.0
|
||||
typescript: 5.8.3
|
||||
transitivePeerDependencies:
|
||||
@@ -5813,7 +5883,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
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
eslint: 9.27.0
|
||||
ts-api-utils: 2.1.0(typescript@5.8.3)
|
||||
typescript: 5.8.3
|
||||
@@ -5826,7 +5896,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.32.1
|
||||
'@typescript-eslint/visitor-keys': 8.32.1
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
@@ -5852,7 +5922,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))':
|
||||
'@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))':
|
||||
dependencies:
|
||||
'@babel/core': 7.27.1
|
||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.1)
|
||||
@@ -5860,7 +5930,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)
|
||||
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)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -5896,7 +5966,7 @@ snapshots:
|
||||
|
||||
agent-base@6.0.2:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -5933,6 +6003,8 @@ 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: {}
|
||||
@@ -5966,7 +6038,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
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12)
|
||||
dotenv: 16.5.0
|
||||
dotenv-expand: 11.0.7
|
||||
@@ -6186,7 +6258,7 @@ snapshots:
|
||||
|
||||
builder-util-runtime@9.3.1:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
sax: 1.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6199,10 +6271,10 @@ snapshots:
|
||||
builder-util-runtime: 9.3.1
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 10.1.0
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
https-proxy-agent: 7.0.6(supports-color@10.0.0)
|
||||
is-ci: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
sanitize-filename: 1.6.3
|
||||
@@ -6283,6 +6355,8 @@ 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:
|
||||
@@ -6364,6 +6438,8 @@ snapshots:
|
||||
|
||||
colord@2.9.3: {}
|
||||
|
||||
colorette@1.4.0: {}
|
||||
|
||||
colorjs.io@0.5.2: {}
|
||||
|
||||
colors@1.4.0: {}
|
||||
@@ -6418,10 +6494,6 @@ 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
|
||||
|
||||
@@ -6521,9 +6593,11 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
||||
debug@4.4.1:
|
||||
debug@4.4.1(supports-color@10.0.0):
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optionalDependencies:
|
||||
supports-color: 10.0.0
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
@@ -6713,7 +6787,7 @@ snapshots:
|
||||
|
||||
electron-localshortcut@3.2.1:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
electron-is-accelerator: 0.1.2
|
||||
keyboardevent-from-electron-accelerator: 2.0.0
|
||||
keyboardevents-areequal: 0.2.2
|
||||
@@ -6755,7 +6829,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)):
|
||||
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)):
|
||||
dependencies:
|
||||
'@babel/core': 7.27.1
|
||||
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.1)
|
||||
@@ -6763,14 +6837,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)
|
||||
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)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
electron-winstaller@5.4.0:
|
||||
dependencies:
|
||||
'@electron/asar': 3.4.1
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fs-extra: 7.0.1
|
||||
lodash: 4.17.21
|
||||
temp: 0.9.4
|
||||
@@ -7038,7 +7112,7 @@ snapshots:
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 8.3.0
|
||||
eslint-visitor-keys: 4.2.0
|
||||
@@ -7092,7 +7166,7 @@ snapshots:
|
||||
|
||||
extract-zip@2.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
get-stream: 5.2.0
|
||||
yauzl: 2.10.0
|
||||
optionalDependencies:
|
||||
@@ -7499,14 +7573,14 @@ snapshots:
|
||||
dependencies:
|
||||
'@tootallnate/once': 2.0.0
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7518,14 +7592,14 @@ snapshots:
|
||||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.6:
|
||||
https-proxy-agent@7.0.6(supports-color@10.0.0):
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7598,6 +7672,8 @@ snapshots:
|
||||
|
||||
indent-string@4.0.0: {}
|
||||
|
||||
index-to-position@1.1.0: {}
|
||||
|
||||
infer-owner@1.0.4: {}
|
||||
|
||||
inflight@1.0.6:
|
||||
@@ -7758,8 +7834,6 @@ snapshots:
|
||||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
is-what@4.1.16: {}
|
||||
|
||||
isarray@1.0.0: {}
|
||||
|
||||
isarray@2.0.5: {}
|
||||
@@ -7792,6 +7866,8 @@ snapshots:
|
||||
filelist: 1.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
js-levenshtein@1.1.6: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
@@ -8192,6 +8268,22 @@ 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
|
||||
@@ -8265,6 +8357,12 @@ 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
|
||||
@@ -8321,6 +8419,8 @@ 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):
|
||||
@@ -8596,7 +8696,7 @@ snapshots:
|
||||
|
||||
read-binary-file-arch@1.0.6:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -8636,8 +8736,6 @@ 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: {}
|
||||
@@ -8966,7 +9064,7 @@ snapshots:
|
||||
socks-proxy-agent@7.0.0:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
socks: 2.8.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -9157,7 +9255,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
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
fast-glob: 3.3.3
|
||||
fastest-levenshtein: 1.0.16
|
||||
file-entry-cache: 10.1.1
|
||||
@@ -9195,13 +9293,11 @@ snapshots:
|
||||
|
||||
sumchecker@3.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
superjson@1.13.3:
|
||||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
supports-color@10.0.0: {}
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
@@ -9421,6 +9517,8 @@ 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
|
||||
@@ -9529,12 +9627,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)):
|
||||
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)):
|
||||
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)
|
||||
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):
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
fdir: 6.4.4(picomatch@4.0.2)
|
||||
@@ -9548,6 +9646,7 @@ 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: {}
|
||||
|
||||
@@ -9661,6 +9760,11 @@ 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:
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-preset-mantine': {},
|
||||
'postcss-preset-mantine': {
|
||||
mixins: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -227,7 +227,11 @@
|
||||
"songCount": "song count",
|
||||
"title": "title",
|
||||
"toYear": "to year",
|
||||
"trackNumber": "track"
|
||||
"trackNumber": "track",
|
||||
"createdAt": "created at",
|
||||
"updatedAt": "updated at",
|
||||
"type": "type",
|
||||
"email": "email"
|
||||
},
|
||||
"form": {
|
||||
"addServer": {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
} from '.';
|
||||
import { orderSearchResults } from './shared';
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
const SEARCH_URL = 'https://genius.com/api/search/song';
|
||||
|
||||
|
||||
@@ -17,35 +17,12 @@ import {
|
||||
getSearchResults as searchNetease,
|
||||
} from './netease';
|
||||
|
||||
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;
|
||||
};
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSource,
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export type LyricGetQuery = {
|
||||
remoteSongId: string;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// 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 '.';
|
||||
import { orderSearchResults } from './shared';
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
const FETCH_URL = 'https://lrclib.net/api/get';
|
||||
const SEEARCH_URL = 'https://lrclib.net/api/search';
|
||||
|
||||
@@ -1,43 +1,20 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
import { store } from '../settings';
|
||||
import { orderSearchResults } from './shared';
|
||||
|
||||
import {
|
||||
InternetProviderLyricResponse,
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
LyricSource,
|
||||
} from '.';
|
||||
import { store } from '../settings';
|
||||
import { orderSearchResults } from './shared';
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
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;
|
||||
@@ -69,6 +46,30 @@ 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,9 +1,7 @@
|
||||
import Fuse from 'fuse.js';
|
||||
|
||||
import {
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { InternetProviderLyricSearchResponse } from '/@/shared/types/domain/lyric-domain-types';
|
||||
import { LyricSearchQuery } from '/@/shared/types/domain/lyric-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-types';
|
||||
import { ClientEvent, ServerEvent } from '/@/shared/types/remote-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ClientEvent, ServerEvent } from '/@/shared/types/domain/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-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-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.lastPlayedAt,
|
||||
'xesam:lastUsed': song.userLastPlayedDate,
|
||||
'xesam:title': song.name || null,
|
||||
'xesam:trackNumber': song.trackNumber ? song.trackNumber : null,
|
||||
'xesam:useCount':
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
LyricSource,
|
||||
} from '../main/features/core/lyrics';
|
||||
|
||||
import { QueueSong } from '/@/shared/types/domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-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-types';
|
||||
import { PlayerData } from '/@/shared/types/domain/player-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 } from '/@/shared/types/domain-types';
|
||||
import { QueueSong, QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const requestFavorite = (
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
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,11 +4,9 @@ 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 {
|
||||
AuthenticationResponse,
|
||||
ControllerEndpoint,
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
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-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
const c = initContract();
|
||||
|
||||
|
||||
@@ -6,19 +6,13 @@ 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 {
|
||||
albumArtistListSortMap,
|
||||
albumListSortMap,
|
||||
ControllerEndpoint,
|
||||
genreListSortMap,
|
||||
LibraryItem,
|
||||
Played,
|
||||
playlistListSortMap,
|
||||
Song,
|
||||
songListSortMap,
|
||||
sortOrderMap,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
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';
|
||||
|
||||
const formatCommaDelimitedString = (value: string[]) => {
|
||||
return value.join(',');
|
||||
@@ -326,7 +320,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: albumListSortMap.jellyfin[query.sortBy] || 'SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -338,14 +332,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.album(item, apiClientProps.server)),
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getAlbumListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getAlbumList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getArtistList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -360,7 +354,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: albumArtistListSortMap.jellyfin[query.sortBy] || 'SortName,Name',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
UserId: apiClientProps.server?.userId || undefined,
|
||||
},
|
||||
});
|
||||
@@ -373,14 +367,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
items: res.body.Items.map((item) =>
|
||||
jfNormalize.albumArtist(item, apiClientProps.server),
|
||||
),
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getArtistListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getArtistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getDownloadUrl: (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -402,7 +396,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query?.searchTerm,
|
||||
SortBy: genreListSortMap.jellyfin[query.sortBy] || 'SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
UserId: apiClientProps.server?.userId,
|
||||
},
|
||||
});
|
||||
@@ -413,7 +407,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.genre(item, apiClientProps.server)),
|
||||
startIndex: query.startIndex || 0,
|
||||
offset: query.offset || 0,
|
||||
totalRecordCount: res.body?.TotalRecordCount || 0,
|
||||
};
|
||||
},
|
||||
@@ -462,7 +456,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: musicFolders.map(jfNormalize.musicFolder),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: musicFolders?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -509,7 +503,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: playlistListSortMap.jellyfin[query.sortBy],
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -519,14 +513,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.playlist(item, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
getPlaylistListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getPlaylistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getPlaylistSongList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -556,7 +550,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
startIndex: query.startIndex,
|
||||
offset: query.startIndex,
|
||||
totalRecordCount: res.body.TotalRecordCount,
|
||||
};
|
||||
},
|
||||
@@ -606,7 +600,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.Items.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -746,7 +740,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -781,7 +775,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
SearchTerm: query.searchTerm,
|
||||
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
|
||||
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
|
||||
StartIndex: query.startIndex,
|
||||
StartIndex: query.offset,
|
||||
...query._custom?.jellyfin,
|
||||
Years: yearsFilter,
|
||||
},
|
||||
@@ -810,14 +804,14 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
items: items.map((item) =>
|
||||
jfNormalize.song(item, apiClientProps.server, '', query.imageSize),
|
||||
),
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount,
|
||||
};
|
||||
},
|
||||
getSongListCount: async ({ apiClientProps, query }) =>
|
||||
JellyfinController.getSongList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getTags: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -873,7 +867,7 @@ export const JellyfinController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.Items.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||
startIndex: 0,
|
||||
offset: 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-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
|
||||
@@ -4,25 +4,24 @@ 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 { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import { normalize } 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 {
|
||||
albumArtistListSortMap,
|
||||
albumListSortMap,
|
||||
AuthenticationResponse,
|
||||
ControllerEndpoint,
|
||||
genreListSortMap,
|
||||
playlistListSortMap,
|
||||
PlaylistSongListArgs,
|
||||
PlaylistSongListRequest,
|
||||
PlaylistSongListResponse,
|
||||
} from '/@/shared/types/domain/playlist-domain-types';
|
||||
import {
|
||||
ServerFeature,
|
||||
ServerFeatures,
|
||||
ServerListItem,
|
||||
Song,
|
||||
songListSortMap,
|
||||
sortOrderMap,
|
||||
userListSortMap,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature, ServerFeatures } from '/@/shared/types/features-types';
|
||||
} 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';
|
||||
|
||||
const VERSION_INFO: VersionInfo = [
|
||||
['0.55.0', { [ServerFeature.BFR]: [1] }],
|
||||
@@ -271,10 +270,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getAlbumList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: albumListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
artist_id: query.artistIds?.[0],
|
||||
compilation: query.compilation,
|
||||
genre_id: query.genres?.[0],
|
||||
@@ -291,24 +290,24 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((album) => ndNormalize.album(album, apiClientProps.server)),
|
||||
startIndex: query?.startIndex || 0,
|
||||
offset: query?.offset || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getAlbumListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getAlbumList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getArtistList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getAlbumArtistList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: albumArtistListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
name: query.searchTerm,
|
||||
...query._custom?.navidrome,
|
||||
role: query.role || undefined,
|
||||
@@ -333,14 +332,14 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
apiClientProps.server,
|
||||
),
|
||||
),
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getArtistListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getArtistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getDownloadUrl: SubsonicController.getDownloadUrl,
|
||||
getGenreList: async (args) => {
|
||||
@@ -348,10 +347,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getGenreList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: genreListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
name: query.searchTerm,
|
||||
},
|
||||
});
|
||||
@@ -362,7 +361,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((genre) => ndNormalize.genre(genre)),
|
||||
startIndex: query.startIndex || 0,
|
||||
offset: query.offset || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
@@ -398,10 +397,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getPlaylistList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: query.sortBy ? playlistListSortMap.navidrome[query.sortBy] : undefined,
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
q: query.searchTerm,
|
||||
...customQuery,
|
||||
},
|
||||
@@ -413,16 +412,18 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((item) => ndNormalize.playlist(item, apiClientProps.server)),
|
||||
startIndex: query?.startIndex || 0,
|
||||
offset: query?.offset || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getPlaylistListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getPlaylistList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getPlaylistSongList: async (args: PlaylistSongListArgs): Promise<PlaylistSongListResponse> => {
|
||||
getPlaylistSongList: async (
|
||||
args: PlaylistSongListRequest,
|
||||
): Promise<PlaylistSongListResponse> => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getPlaylistSongList({
|
||||
@@ -446,7 +447,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((item) => ndNormalize.song(item, apiClientProps.server)),
|
||||
startIndex: query?.startIndex || 0,
|
||||
offset: query?.startIndex || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
@@ -518,7 +519,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(ssNormalize.song(song, apiClientProps.server));
|
||||
acc.push(normalize.song(song, apiClientProps.server));
|
||||
}
|
||||
|
||||
return acc;
|
||||
@@ -572,10 +573,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getSongList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || -1),
|
||||
_end: query.offset + (query.limit || -1),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: songListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
album_artist_id: query.albumArtistIds,
|
||||
album_id: query.albumIds,
|
||||
artist_id: query.artistIds,
|
||||
@@ -595,14 +596,14 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
items: res.body.data.map((song) =>
|
||||
ndNormalize.song(song, apiClientProps.server, query.imageSize),
|
||||
),
|
||||
startIndex: query?.startIndex || 0,
|
||||
offset: query?.offset || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
getSongListCount: async ({ apiClientProps, query }) =>
|
||||
NavidromeController.getSongList({
|
||||
apiClientProps,
|
||||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
query: { ...query, limit: 1, offset: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getStructuredLyrics: SubsonicController.getStructuredLyrics,
|
||||
getTags: async (args) => {
|
||||
@@ -651,10 +652,10 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
const res = await ndApiClient(apiClientProps).getUserList({
|
||||
query: {
|
||||
_end: query.startIndex + (query.limit || 0),
|
||||
_end: query.offset + (query.limit || 0),
|
||||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: userListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
_start: query.offset,
|
||||
...query._custom?.navidrome,
|
||||
},
|
||||
});
|
||||
@@ -665,7 +666,7 @@ export const NavidromeController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: res.body.data.map((user) => ndNormalize.user(user)),
|
||||
startIndex: query?.startIndex || 0,
|
||||
offset: query?.offset || 0,
|
||||
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import type {
|
||||
import { QueryFunctionContext } from '@tanstack/react-query';
|
||||
|
||||
import { AlbumDetailQuery, AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import {
|
||||
AlbumArtistDetailQuery,
|
||||
AlbumArtistListQuery,
|
||||
AlbumDetailQuery,
|
||||
AlbumListQuery,
|
||||
ArtistListQuery,
|
||||
GenreListQuery,
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
import {
|
||||
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,
|
||||
UserListQuery,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
import { QueryFunctionContext } from '@tanstack/react-query';
|
||||
|
||||
import { LyricSource } from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/song-domain-types';
|
||||
import { UserListQuery } from '/@/shared/types/domain/user-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-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
const c = initContract();
|
||||
|
||||
|
||||
@@ -8,25 +8,18 @@ import { z } from 'zod';
|
||||
|
||||
import { contract, ssApiClient } from '/@/renderer/api/subsonic/subsonic-api';
|
||||
import { randomString } from '/@/renderer/utils';
|
||||
import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import { normalize } from '/@/shared/api/subsonic/subsonic-normalize';
|
||||
import {
|
||||
AlbumListSortType,
|
||||
ssType,
|
||||
SubsonicExtensions,
|
||||
} from '/@/shared/api/subsonic/subsonic-types';
|
||||
import {
|
||||
AlbumListSort,
|
||||
ControllerEndpoint,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
PlaylistListSort,
|
||||
Song,
|
||||
sortAlbumArtistList,
|
||||
sortAlbumList,
|
||||
SortOrder,
|
||||
sortSongList,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeatures } from '/@/shared/types/features-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';
|
||||
|
||||
const ALBUM_LIST_SORT_MAPPING: Record<AlbumListSort, AlbumListSortType | undefined> = {
|
||||
[AlbumListSort.ALBUM_ARTIST]: AlbumListSortType.ALPHABETICAL_BY_ARTIST,
|
||||
@@ -205,11 +198,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
...ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
albums: artist.album?.map((album) => ssNormalize.album(album, apiClientProps.server)),
|
||||
...normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
albums: artist.album?.map((album) => normalize.album(album, apiClientProps.server)),
|
||||
similarArtists:
|
||||
artistInfo?.similarArtist?.map((artist) =>
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
) || null,
|
||||
};
|
||||
},
|
||||
@@ -229,7 +222,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const artists = (res.body.artists?.index || []).flatMap((index) => index.artist);
|
||||
|
||||
let results = artists.map((artist) =>
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
);
|
||||
|
||||
if (query.searchTerm) {
|
||||
@@ -265,7 +258,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get album detail');
|
||||
}
|
||||
|
||||
return ssNormalize.album(res.body.album, apiClientProps.server);
|
||||
return normalize.album(res.body.album, apiClientProps.server);
|
||||
},
|
||||
getAlbumList: async (args) => {
|
||||
const { apiClientProps, query } = args;
|
||||
@@ -274,7 +267,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const res = await ssApiClient(apiClientProps).search3({
|
||||
query: {
|
||||
albumCount: query.limit,
|
||||
albumOffset: query.startIndex,
|
||||
albumOffset: query.offset,
|
||||
artistCount: 0,
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
@@ -289,12 +282,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
res.body.searchResult3?.album?.map((album) =>
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
normalize.album(album, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: results,
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -324,11 +317,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return artist.body.artist.album ?? [];
|
||||
});
|
||||
|
||||
const items = albums.map((album) => ssNormalize.album(album, apiClientProps.server));
|
||||
const items = albums.map((album) => normalize.album(album, apiClientProps.server));
|
||||
|
||||
return {
|
||||
items: sortAlbumList(items, query.sortBy, query.sortOrder),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: albums.length,
|
||||
};
|
||||
}
|
||||
@@ -346,12 +339,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
res.body.starred?.album?.map((album) =>
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
normalize.album(album, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: sortAlbumList(results, query.sortBy, query.sortOrder),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.starred?.album?.length || 0,
|
||||
};
|
||||
}
|
||||
@@ -381,7 +374,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
if (type === AlbumListSortType.BY_YEAR && !fromYear && !toYear) {
|
||||
if (query.sortOrder === SortOrder.ASC) {
|
||||
if (query.sortOrder === ListSortOrder.ASC) {
|
||||
fromYear = 0;
|
||||
toYear = dayjs().year();
|
||||
} else {
|
||||
@@ -395,7 +388,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
fromYear,
|
||||
genre: query.genres?.length ? query.genres[0] : undefined,
|
||||
musicFolderId: query.musicFolderId,
|
||||
offset: query.startIndex,
|
||||
offset: query.offset,
|
||||
size: query.limit,
|
||||
toYear,
|
||||
type,
|
||||
@@ -409,9 +402,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.albumList2.album?.map((album) =>
|
||||
ssNormalize.album(album, apiClientProps.server, 300),
|
||||
normalize.album(album, apiClientProps.server, 300),
|
||||
) || [],
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
},
|
||||
@@ -579,7 +572,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
let results = artists.map((artist) =>
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
normalize.albumArtist(artist, apiClientProps.server, 300),
|
||||
);
|
||||
|
||||
if (query.searchTerm) {
|
||||
@@ -596,7 +589,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: results,
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: results?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -640,11 +633,11 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
break;
|
||||
}
|
||||
|
||||
const genres = results.map(ssNormalize.genre);
|
||||
const genres = results.map(normalize.genre);
|
||||
|
||||
return {
|
||||
items: genres,
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: genres.length,
|
||||
};
|
||||
},
|
||||
@@ -662,7 +655,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
id: folder.id.toString(),
|
||||
name: folder.name,
|
||||
})),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.musicFolders.musicFolder.length,
|
||||
};
|
||||
},
|
||||
@@ -679,7 +672,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get playlist detail');
|
||||
}
|
||||
|
||||
return ssNormalize.playlist(res.body.playlist, apiClientProps.server);
|
||||
return normalize.playlist(res.body.playlist, apiClientProps.server);
|
||||
},
|
||||
getPlaylistList: async ({ apiClientProps, query }) => {
|
||||
const sortOrder = query.sortOrder.toLowerCase() as 'asc' | 'desc';
|
||||
@@ -724,8 +717,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: results.map((playlist) => ssNormalize.playlist(playlist, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
items: results.map((playlist) => normalize.playlist(playlist, apiClientProps.server)),
|
||||
offset: 0,
|
||||
totalRecordCount: results.length,
|
||||
};
|
||||
},
|
||||
@@ -760,7 +753,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
let results =
|
||||
res.body.playlist.entry?.map((song) => ssNormalize.song(song, apiClientProps.server)) ||
|
||||
res.body.playlist.entry?.map((song) => normalize.song(song, apiClientProps.server)) ||
|
||||
[];
|
||||
|
||||
if (query.sortBy && query.sortOrder) {
|
||||
@@ -769,7 +762,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
items: results,
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: results?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -793,8 +786,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const results = res.body.randomSongs?.song || [];
|
||||
|
||||
return {
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)),
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.randomSongs?.song?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -878,7 +871,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return res.body.similarSongs.song.reduce<Song[]>((acc, song) => {
|
||||
if (song.id !== query.songId) {
|
||||
acc.push(ssNormalize.song(song, apiClientProps.server));
|
||||
acc.push(normalize.song(song, apiClientProps.server));
|
||||
}
|
||||
|
||||
return acc;
|
||||
@@ -897,7 +890,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
throw new Error('Failed to get song detail');
|
||||
}
|
||||
|
||||
return ssNormalize.song(res.body.song, apiClientProps.server);
|
||||
return normalize.song(res.body.song, apiClientProps.server);
|
||||
},
|
||||
getSongList: async ({ apiClientProps, query }) => {
|
||||
const fromAlbumPromises: Promise<ServerInferResponses<typeof contract.getAlbum>>[] = [];
|
||||
@@ -912,7 +905,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
songCount: query.limit,
|
||||
songOffset: query.startIndex,
|
||||
songOffset: query.offset,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -923,9 +916,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.searchResult3?.song?.map((song) =>
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
normalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
startIndex: query.startIndex,
|
||||
offset: query.offset,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -936,7 +929,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
count: query.limit,
|
||||
genre: query.genreIds[0],
|
||||
musicFolderId: query.musicFolderId,
|
||||
offset: query.startIndex,
|
||||
offset: query.offset,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -947,8 +940,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
const results = res.body.songsByGenre?.song || [];
|
||||
|
||||
return {
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)) || [],
|
||||
startIndex: 0,
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)) || [],
|
||||
offset: 0,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
}
|
||||
@@ -966,12 +959,12 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
const results =
|
||||
(res.body.starred?.song || []).map((song) =>
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
normalize.song(song, apiClientProps.server),
|
||||
) || [];
|
||||
|
||||
return {
|
||||
items: sortSongList(results, query.sortBy, query.sortOrder),
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: (res.body.starred?.song || []).length || 0,
|
||||
};
|
||||
}
|
||||
@@ -1040,8 +1033,8 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
}
|
||||
|
||||
return {
|
||||
items: results.map((song) => ssNormalize.song(song, apiClientProps.server)),
|
||||
startIndex: 0,
|
||||
items: results.map((song) => normalize.song(song, apiClientProps.server)),
|
||||
offset: 0,
|
||||
totalRecordCount: results.length,
|
||||
};
|
||||
}
|
||||
@@ -1054,7 +1047,7 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
artistOffset: 0,
|
||||
query: query.searchTerm || '',
|
||||
songCount: query.limit,
|
||||
songOffset: query.startIndex,
|
||||
songOffset: query.offset,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1065,9 +1058,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.searchResult3?.song?.map((song) =>
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
normalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: null,
|
||||
};
|
||||
},
|
||||
@@ -1302,9 +1295,9 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
return {
|
||||
items:
|
||||
res.body.topSongs?.song?.map((song) =>
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
normalize.song(song, apiClientProps.server),
|
||||
) || [],
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
totalRecordCount: res.body.topSongs?.song?.length || 0,
|
||||
};
|
||||
},
|
||||
@@ -1372,13 +1365,13 @@ export const SubsonicController: ControllerEndpoint = {
|
||||
|
||||
return {
|
||||
albumArtists: (res.body.searchResult3?.artist || [])?.map((artist) =>
|
||||
ssNormalize.albumArtist(artist, apiClientProps.server),
|
||||
normalize.albumArtist(artist, apiClientProps.server),
|
||||
),
|
||||
albums: (res.body.searchResult3?.album || []).map((album) =>
|
||||
ssNormalize.album(album, apiClientProps.server),
|
||||
normalize.album(album, apiClientProps.server),
|
||||
),
|
||||
songs: (res.body.searchResult3?.song || []).map((song) =>
|
||||
ssNormalize.song(song, apiClientProps.server),
|
||||
normalize.song(song, apiClientProps.server),
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Song } from '/@/shared/types/domain-types';
|
||||
import type { CrossfadeStyle } from '/@/shared/types/types';
|
||||
import type { ReactPlayerProps } from 'react-player';
|
||||
|
||||
@@ -20,9 +19,11 @@ import {
|
||||
gaplessHandler,
|
||||
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
||||
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
||||
import { getServerById, TranscodingConfig, usePlaybackSettings, useSpeed } from '/@/renderer/store';
|
||||
import { 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 = {
|
||||
@@ -57,27 +58,28 @@ 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?: Song): null | string => {
|
||||
const useSongUrl = (
|
||||
transcode: TranscodingConfig,
|
||||
current: boolean,
|
||||
song?: QueueSong,
|
||||
): 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];
|
||||
if (current && prior.current[0] === song._uniqueId) {
|
||||
return prior.current[1] as string;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -85,14 +87,14 @@ const useSongUrl = (transcode: TranscodingConfig, current: boolean, song?: Song)
|
||||
})!;
|
||||
|
||||
// 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;
|
||||
}, [current, song?.uniqueId, song?.serverId, song?.streamUrl, transcode]);
|
||||
}, [song?._serverId, song?._uniqueId, song?.streamUrl, current, 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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const CardControls = ({
|
||||
|
||||
@@ -3,18 +3,21 @@ 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, AlbumArtist, Artist, Playlist, Song } from '/@/shared/types/domain-types';
|
||||
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 { CardRow } from '/@/shared/types/types';
|
||||
|
||||
interface CardRowsProps {
|
||||
data: any;
|
||||
rows: CardRow<Album>[] | CardRow<AlbumArtist>[] | CardRow<Artist>[];
|
||||
rows: CardRow<Album>[] | CardRow<Artist>[];
|
||||
}
|
||||
|
||||
export const CardRows = ({ data, rows }: CardRowsProps) => {
|
||||
|
||||
@@ -8,12 +8,14 @@ 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, AlbumArtist, Artist, LibraryItem } from '/@/shared/types/domain-types';
|
||||
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 { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
controls: {
|
||||
cardRows: CardRow<Album>[] | CardRow<AlbumArtist>[] | CardRow<Artist>[];
|
||||
cardRows: CardRow<Album>[] | CardRow<Artist>[];
|
||||
handleFavorite: (options: {
|
||||
id: string[];
|
||||
isFavorite: boolean;
|
||||
|
||||
@@ -20,7 +20,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
const variants: Variants = {
|
||||
|
||||
@@ -24,13 +24,9 @@ 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,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
RelatedArtist,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { CardRoute, CardRow } from '/@/shared/types/types';
|
||||
|
||||
const getSlidesPerView = (windowWidth: number) => {
|
||||
|
||||
@@ -10,20 +10,17 @@ 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,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
controls: {
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist | Playlist | Song>[];
|
||||
cardRows: CardRow<Album | 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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
export const GridCardControls = ({
|
||||
|
||||
@@ -10,20 +10,17 @@ 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,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { CardRoute, CardRow, Play, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||
|
||||
interface BaseGridCardProps {
|
||||
columnIndex: number;
|
||||
controls: {
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist | Playlist | Song>[];
|
||||
cardRows: CardRow<Album | Artist | Playlist | Song>[];
|
||||
handleFavorite: (options: {
|
||||
id: string[];
|
||||
isFavorite: boolean;
|
||||
|
||||
@@ -14,7 +14,9 @@ import { FixedSizeList } from 'react-window';
|
||||
import styles from './virtual-grid-wrapper.module.css';
|
||||
|
||||
import { GridCard } from '/@/renderer/components/virtual-grid/grid-card';
|
||||
import { Album, AlbumArtist, Artist, LibraryItem } from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
const createItemData = memoize(
|
||||
(
|
||||
@@ -72,7 +74,7 @@ export const VirtualGridWrapper = ({
|
||||
width,
|
||||
...rest
|
||||
}: Omit<FixedSizeListProps, 'children' | 'height' | 'itemSize' | 'ref' | 'width'> & {
|
||||
cardRows: CardRow<Album | AlbumArtist | Artist>[];
|
||||
cardRows: CardRow<Album | Artist>[];
|
||||
columnCount: number;
|
||||
display: ListDisplayType;
|
||||
handleFavorite?: (options: {
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
import InfiniteLoader from 'react-window-infinite-loader';
|
||||
|
||||
import { VirtualGridWrapper } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
|
||||
import { AnyLibraryItem, Genre, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { AnyLibraryItem, LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export type VirtualInfiniteGridRef = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -10,6 +9,7 @@ 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: AlbumArtist | Artist, index: number) => (
|
||||
{value?.map((item: Artist, index: number) => (
|
||||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && <Separator />}
|
||||
{item.id ? (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -10,6 +9,7 @@ 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: AlbumArtist | Artist, index: number) => (
|
||||
{value?.map((item: 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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-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 { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import { Artist } from '/@/shared/types/domain/artist-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: AlbumArtist | Artist, index: number) => (
|
||||
artists.map((artist: Artist, index: number) => (
|
||||
<React.Fragment key={`queue-${rowIndex}-artist-${artist.id}`}>
|
||||
{index > 0 ? SEPARATOR_STRING : null}
|
||||
{artist.id ? (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AlbumArtist, Artist } from '/@/shared/types/domain-types';
|
||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
|
||||
import React from 'react';
|
||||
@@ -8,13 +7,14 @@ 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: AlbumArtist | Artist, index: number) => (
|
||||
{value?.map((item: 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-types';
|
||||
import { Song } from '/@/shared/types/domain/song-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,
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
ServerListItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} 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';
|
||||
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 BaseQuery<any>>({
|
||||
export const useVirtualTable = <TFilter extends BasePaginatedQuery<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-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
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,13 +49,9 @@ 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,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { Play } from '/@/shared/types/types';
|
||||
|
||||
const isFullWidthRow = (node: RowNode) => {
|
||||
@@ -154,8 +150,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,
|
||||
},
|
||||
@@ -169,9 +165,9 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
|
||||
? [detailQuery?.data?.albumArtists[0].id]
|
||||
: undefined,
|
||||
limit: 15,
|
||||
offset: 0,
|
||||
sortBy: AlbumListSort.YEAR,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -179,15 +175,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: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
};
|
||||
|
||||
const relatedAlbumGenresQuery = useAlbumList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
enabled: !!detailQuery?.data?.genres?.[0],
|
||||
gcTime: 1000 * 60,
|
||||
queryKey: queryKeys.albums.related(
|
||||
server?.id || '',
|
||||
albumId,
|
||||
|
||||
@@ -16,7 +16,9 @@ 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, LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
interface AlbumDetailHeaderProps {
|
||||
background: {
|
||||
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
AlbumListQuery,
|
||||
AlbumListResponse,
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
@@ -137,15 +137,11 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const itemData: Album[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, startIndex } = data || {};
|
||||
const { items, offset } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -165,7 +161,7 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
|
||||
limit: take,
|
||||
...filter,
|
||||
...customFilters,
|
||||
startIndex: skip,
|
||||
offset: skip,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.albums.list(server?.id || '', query, id);
|
||||
|
||||
@@ -34,158 +34,154 @@ 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,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { ListDisplayType, Play, TableColumn } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.communityRating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.COMMUNITY_RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.criticRating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.CRITIC_RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.playCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.releaseDate', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RELEASE_DATE,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.artist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_PLAYED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.SONG_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.favorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.releaseYear', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.YEAR,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.albumArtist', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.ALBUM_ARTIST,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_ADDED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.RECENTLY_PLAYED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.favorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.releaseYear', { postProcess: 'titleCase' }),
|
||||
value: AlbumListSort.YEAR,
|
||||
},
|
||||
@@ -299,7 +295,7 @@ export const AlbumListHeaderFilters = ({
|
||||
customFilters,
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as AlbumListSort,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ALBUM,
|
||||
key: pageKey,
|
||||
@@ -337,7 +333,8 @@ export const AlbumListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: { sortOrder: newSortOrder },
|
||||
|
||||
@@ -16,7 +16,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
export const AlbumListTableView = ({ itemCount, tableRef }: any) => {
|
||||
const server = useCurrentServer();
|
||||
|
||||
@@ -14,13 +14,10 @@ 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 {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
interface JellyfinAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
@@ -44,14 +41,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: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
musicFolderId: filter?.musicFolderId,
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
@@ -66,7 +63,7 @@ export const JellyfinAlbumFilters = ({
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
@@ -173,12 +170,12 @@ export const JellyfinAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
|
||||
@@ -16,13 +16,10 @@ 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 {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
interface NavidromeAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
@@ -45,13 +42,13 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
@@ -79,7 +76,7 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
@@ -188,13 +185,13 @@ export const NavidromeAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
// searchTerm: debouncedSearchTerm,
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
|
||||
@@ -14,13 +14,10 @@ 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 {
|
||||
AlbumArtistListSort,
|
||||
AlbumListQuery,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
interface SubsonicAlbumFiltersProps {
|
||||
disableArtistFilter?: boolean;
|
||||
@@ -42,12 +39,12 @@ export const SubsonicAlbumFilters = ({
|
||||
|
||||
const albumArtistListQuery = useAlbumArtistList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: AlbumArtistListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
@@ -75,13 +72,13 @@ export const SubsonicAlbumFilters = ({
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 1,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumDetailQuery } from '/@/shared/types/domain-types';
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumDetailQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
|
||||
export const useAlbumDetail = (args: QueryHookArgs<AlbumDetailQuery>) => {
|
||||
export const useAlbumDetail = (args: RQueryHookArgs<AlbumDetailQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
queryFn: ({ signal }) => {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumListQuery } from '/@/shared/types/domain-types';
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery } from '/@/shared/types/domain/album-domain-types';
|
||||
|
||||
export const useAlbumListCount = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumListCount = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { AlbumListQuery, AlbumListResponse } from '/@/shared/types/domain-types';
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
|
||||
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 { getServerById } from '/@/renderer/store';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery, AlbumListResponse } from '/@/shared/types/domain/album-domain-types';
|
||||
|
||||
export const useAlbumList = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumList = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
@@ -33,9 +33,9 @@ export const useAlbumList = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAlbumListInfinite = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
export const useAlbumListInfinite = (args: RQueryHookArgs<AlbumListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useInfiniteQuery({
|
||||
enabled: !!serverId,
|
||||
@@ -57,7 +57,7 @@ export const useAlbumListInfinite = (args: QueryHookArgs<AlbumListQuery>) => {
|
||||
query: {
|
||||
...query,
|
||||
limit: query.limit || 50,
|
||||
startIndex: pageParam * (query.limit || 50),
|
||||
offset: 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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
const AlbumDetailRoute = () => {
|
||||
const tableRef = useRef<AgGridReactType | null>(null);
|
||||
|
||||
@@ -16,12 +16,9 @@ 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,
|
||||
GenreListSort,
|
||||
LibraryItem,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { Play } from '/@/shared/types/types';
|
||||
|
||||
const AlbumListRoute = () => {
|
||||
@@ -55,13 +52,13 @@ const AlbumListRoute = () => {
|
||||
|
||||
const genreList = useGenreList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 60,
|
||||
gcTime: 1000 * 60 * 60,
|
||||
enabled: !!genreId,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -77,7 +74,7 @@ const AlbumListRoute = () => {
|
||||
|
||||
const itemCountCheck = useAlbumListCount({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
gcTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: {
|
||||
|
||||
@@ -33,7 +33,8 @@ 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, SongDetailResponse } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { SongDetailResponse } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
const DummyAlbumDetailRoute = () => {
|
||||
const cq = useContainerQuery();
|
||||
|
||||
@@ -35,15 +35,10 @@ 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,
|
||||
AlbumArtist,
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { CardRow, Play, TableColumn } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistDetailContentProps {
|
||||
@@ -106,8 +101,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
||||
compilation: false,
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
@@ -121,8 +116,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
||||
compilation: true,
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.DESC,
|
||||
offset: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
@@ -11,7 +11,8 @@ 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 { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
interface AlbumArtistDetailHeaderProps {
|
||||
background?: string;
|
||||
|
||||
+3
-1
@@ -12,7 +12,9 @@ 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 { LibraryItem, QueueSong, SongListQuery } from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
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-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistDetailTopSongsListHeaderProps {
|
||||
|
||||
@@ -17,12 +17,11 @@ 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,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumArtistListGridViewProps {
|
||||
|
||||
@@ -34,91 +34,90 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import {
|
||||
AlbumArtistListQuery,
|
||||
AlbumArtistListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} 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 { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.album', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RECENTLY_ADDED,
|
||||
},
|
||||
// { defaultOrder: SortOrder.DESC, name: 'Release Date', value: AlbumArtistListSort.RELEASE_DATE },
|
||||
// { defaultOrder: ListSortOrder.DESC, name: 'Release Date', value: AlbumArtistListSort.RELEASE_DATE },
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.SONG_COUNT,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: AlbumArtistListSort.RATING,
|
||||
},
|
||||
@@ -270,7 +269,7 @@ export const AlbumArtistListHeaderFilters = ({
|
||||
const updatedFilters = setFilter({
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as AlbumArtistListSort,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ALBUM_ARTIST,
|
||||
key: pageKey,
|
||||
@@ -306,7 +305,8 @@ export const AlbumArtistListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
data: { sortOrder: newSortOrder },
|
||||
itemType: LibraryItem.ALBUM_ARTIST,
|
||||
|
||||
@@ -15,7 +15,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
interface AlbumArtistListTableViewProps {
|
||||
itemCount?: number;
|
||||
|
||||
@@ -18,12 +18,11 @@ import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer, useListStoreActions } from '/@/renderer/store';
|
||||
import { useListStoreByKey } from '/@/renderer/store/list.store';
|
||||
import {
|
||||
AlbumArtist,
|
||||
ArtistListQuery,
|
||||
ArtistListResponse,
|
||||
ArtistListSort,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
interface ArtistListGridViewProps {
|
||||
@@ -56,15 +55,11 @@ export const ArtistListGridView = ({ gridRef, itemCount }: ArtistListGridViewPro
|
||||
const itemData: AlbumArtist[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, startIndex } = data || {};
|
||||
const { items, offset } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -79,7 +74,7 @@ export const ArtistListGridView = ({ gridRef, itemCount }: ArtistListGridViewPro
|
||||
const query: ArtistListQuery = {
|
||||
...filter,
|
||||
limit,
|
||||
startIndex,
|
||||
offset,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.artists.list(server?.id || '', query);
|
||||
|
||||
@@ -33,93 +33,89 @@ 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,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.album', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.duration', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.DURATION,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.random', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RANDOM,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.recentlyAdded', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RECENTLY_ADDED,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.mostPlayed', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.PLAY_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.songCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.SONG_COUNT,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.albumCount', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.ALBUM_COUNT,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.isFavorited', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.FAVORITED,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.NAME,
|
||||
},
|
||||
{
|
||||
defaultOrder: SortOrder.DESC,
|
||||
defaultOrder: ListSortOrder.DESC,
|
||||
name: i18n.t('filter.rating', { postProcess: 'titleCase' }),
|
||||
value: ArtistListSort.RATING,
|
||||
},
|
||||
@@ -144,7 +140,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
const cq = useContainerQuery();
|
||||
const roles = useRoles({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 60 * 2,
|
||||
gcTime: 1000 * 60 * 60 * 2,
|
||||
staleTime: 1000 * 60 * 60 * 2,
|
||||
},
|
||||
query: {},
|
||||
@@ -192,7 +188,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
},
|
||||
query: {
|
||||
limit,
|
||||
startIndex,
|
||||
offset,
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
@@ -228,7 +224,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
},
|
||||
query: {
|
||||
limit,
|
||||
startIndex,
|
||||
offset,
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
@@ -276,7 +272,7 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
const updatedFilters = setFilter({
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as ArtistListSort,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.ARTIST,
|
||||
key: pageKey,
|
||||
@@ -312,7 +308,8 @@ export const ArtistListHeaderFilters = ({ gridRef, tableRef }: ArtistListHeaderF
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
data: { sortOrder: newSortOrder },
|
||||
itemType: LibraryItem.ARTIST,
|
||||
|
||||
@@ -15,7 +15,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
interface ArtistListTableViewProps {
|
||||
itemCount?: number;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistDetailQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const useAlbumArtistDetail = (args: QueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
export const useAlbumArtistDetail = (args: RQueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain-types';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const useAlbumArtistListCount = (args: QueryHookArgs<AlbumArtistListQuery>) => {
|
||||
export const useAlbumArtistListCount = (args: RQueryHookArgs<AlbumArtistListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const useAlbumArtistList = (args: QueryHookArgs<AlbumArtistListQuery>) => {
|
||||
export const useAlbumArtistList = (args: RQueryHookArgs<AlbumArtistListQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id,
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumArtistDetailQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const useAlbumArtistInfo = (args: QueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
export const useAlbumArtistInfo = (args: RQueryHookArgs<AlbumArtistDetailQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain-types';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
|
||||
export const useArtistListCount = (args: QueryHookArgs<ArtistListQuery>) => {
|
||||
export const useArtistListCount = (args: RQueryHookArgs<ArtistListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(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 { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
|
||||
export const useRoles = (args: QueryHookArgs<object>) => {
|
||||
export const useRoles = (args: RQueryHookArgs<object>) => {
|
||||
const { options, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { TopSongListQuery } from '/@/shared/types/domain-types';
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { TopSongListQuery } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export const useTopSongsList = (args: QueryHookArgs<TopSongListQuery>) => {
|
||||
export const useTopSongsList = (args: RQueryHookArgs<TopSongListQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-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-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
const AlbumArtistDetailTopSongsListRoute = () => {
|
||||
const tableRef = useRef<AgGridReactType | null>(null);
|
||||
|
||||
@@ -10,7 +10,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { AlbumArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
const AlbumArtistListRoute = () => {
|
||||
const gridRef = useRef<null | VirtualInfiniteGridRef>(null);
|
||||
@@ -22,7 +23,7 @@ const AlbumArtistListRoute = () => {
|
||||
|
||||
const itemCountCheck = useAlbumArtistListCount({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
gcTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: albumArtistListFilter,
|
||||
|
||||
@@ -10,7 +10,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { ArtistListQuery } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
const ArtistListRoute = () => {
|
||||
const gridRef = useRef<null | VirtualInfiniteGridRef>(null);
|
||||
@@ -22,7 +23,7 @@ const ArtistListRoute = () => {
|
||||
|
||||
const itemCountCheck = useArtistListCount({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
gcTime: 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 {
|
||||
getServerById,
|
||||
useServerById,
|
||||
useAuthStore,
|
||||
useCurrentServer,
|
||||
usePlayerStore,
|
||||
@@ -57,13 +57,12 @@ 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,
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
} from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Play, PlaybackType } from '/@/shared/types/types';
|
||||
|
||||
type ContextMenuContextProps = {
|
||||
@@ -713,7 +712,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
||||
const item = ctx.data[0];
|
||||
const songs = await controller.getSimilarSongs({
|
||||
apiClientProps: {
|
||||
server: getServerById(item.serverId),
|
||||
server: useServerById(item.serverId),
|
||||
signal: undefined,
|
||||
},
|
||||
query: { albumArtistIds: item.albumArtistIds, songId: item.id },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GridOptions, RowNode } from '@ag-grid-community/core';
|
||||
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { createUseExternalEvents } from '/@/shared/utils/create-use-external-events';
|
||||
|
||||
export type ContextMenuEvents = {
|
||||
|
||||
@@ -2,14 +2,11 @@ import { CellContextMenuEvent, GridApi } from '@ag-grid-community/core';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
import { openContextMenu, SetContextMenuItems } from '/@/renderer/features/context-menu/events';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
QueueSong,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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';
|
||||
|
||||
export const useHandleTableContextMenu = (
|
||||
itemType: LibraryItem,
|
||||
|
||||
@@ -5,13 +5,14 @@ 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, ServerType } from '/@/shared/types/domain-types';
|
||||
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
const discordRpc = isElectron() ? window.api.discordRpc : null;
|
||||
@@ -92,7 +93,7 @@ export const useDiscordRpc = () => {
|
||||
if (song.serverType === ServerType.JELLYFIN && song.imageUrl) {
|
||||
activity.largeImageKey = song.imageUrl;
|
||||
} else if (song.serverType === ServerType.NAVIDROME) {
|
||||
const server = getServerById(song.serverId);
|
||||
const server = useServerById(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,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
@@ -74,15 +74,11 @@ export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const itemData: Genre[] = [];
|
||||
|
||||
for (const [, data] of queriesFromCache) {
|
||||
const { items, startIndex } = data || {};
|
||||
const { items, offset } = data || {};
|
||||
|
||||
if (items && items.length !== 1 && startIndex !== undefined) {
|
||||
if (items && items.length !== 1 && offset !== undefined) {
|
||||
let itemIndex = 0;
|
||||
for (
|
||||
let rowIndex = startIndex;
|
||||
rowIndex < startIndex + items.length;
|
||||
rowIndex += 1
|
||||
) {
|
||||
for (let rowIndex = offset; rowIndex < offset + items.length; rowIndex += 1) {
|
||||
itemData[rowIndex] = items[itemIndex];
|
||||
itemIndex += 1;
|
||||
}
|
||||
@@ -101,7 +97,7 @@ export const GenreListGridView = ({ gridRef, itemCount }: any) => {
|
||||
const query: GenreListQuery = {
|
||||
...filter,
|
||||
limit: take,
|
||||
startIndex: skip,
|
||||
offset: skip,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.albums.list(server?.id || '', query);
|
||||
|
||||
@@ -33,33 +33,29 @@ 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,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
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 { ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
const FILTERS = {
|
||||
jellyfin: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
],
|
||||
navidrome: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
],
|
||||
subsonic: [
|
||||
{
|
||||
defaultOrder: SortOrder.ASC,
|
||||
defaultOrder: ListSortOrder.ASC,
|
||||
name: i18n.t('filter.name', { postProcess: 'titleCase' }),
|
||||
value: GenreListSort.NAME,
|
||||
},
|
||||
@@ -137,7 +133,7 @@ export const GenreListHeaderFilters = ({
|
||||
customFilters,
|
||||
data: {
|
||||
sortBy: e.currentTarget.value as GenreListSort,
|
||||
sortOrder: sortOrder || SortOrder.ASC,
|
||||
sortOrder: sortOrder || ListSortOrder.ASC,
|
||||
},
|
||||
itemType: LibraryItem.GENRE,
|
||||
key: pageKey,
|
||||
@@ -175,7 +171,8 @@ export const GenreListHeaderFilters = ({
|
||||
);
|
||||
|
||||
const handleToggleSortOrder = useCallback(() => {
|
||||
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||
const newSortOrder =
|
||||
filter.sortOrder === ListSortOrder.ASC ? ListSortOrder.DESC : ListSortOrder.ASC;
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: { sortOrder: newSortOrder },
|
||||
|
||||
@@ -15,7 +15,8 @@ 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, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
interface GenreListHeaderProps {
|
||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { GENRE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
interface GenreListTableViewProps {
|
||||
itemCount?: number;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { GenreListQuery } from '/@/shared/types/domain-types';
|
||||
import type { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
|
||||
export const useGenreList = (args: QueryHookArgs<GenreListQuery>) => {
|
||||
export const useGenreList = (args: RQueryHookArgs<GenreListQuery>) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useGenreList } from '/@/renderer/features/genres/queries/genre-list-que
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { useListStoreByKey } from '/@/renderer/store/list.store';
|
||||
import { GenreListQuery } from '/@/shared/types/domain-types';
|
||||
import { GenreListQuery } from '/@/shared/types/domain/genre-domain-types';
|
||||
|
||||
const GenreListRoute = () => {
|
||||
const gridRef = useRef<null | VirtualInfiniteGridRef>(null);
|
||||
@@ -23,7 +23,7 @@ const GenreListRoute = () => {
|
||||
query: {
|
||||
...filter,
|
||||
limit: 1,
|
||||
startIndex: 0,
|
||||
offset: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
@@ -2,19 +2,20 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery, AlbumListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||
import { RQueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { useServerById } from '/@/renderer/store';
|
||||
import { AlbumListQuery, AlbumListSort } from '/@/shared/types/domain/album-domain-types';
|
||||
import { ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
|
||||
export const useRecentlyPlayed = (args: QueryHookArgs<Partial<AlbumListQuery>>) => {
|
||||
export const useRecentlyPlayed = (args: RQueryHookArgs<Partial<AlbumListQuery>>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
const server = useServerById(serverId);
|
||||
|
||||
const requestQuery: AlbumListQuery = {
|
||||
limit: 5,
|
||||
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
sortOrder: ListSortOrder.ASC,
|
||||
offset: 0,
|
||||
...query,
|
||||
};
|
||||
|
||||
|
||||
@@ -4,32 +4,24 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { FeatureCarousel } from '/@/renderer/components/feature-carousel/feature-carousel';
|
||||
import { MemoizedSwiperGridCarousel } from '/@/renderer/components/grid-carousel/grid-carousel';
|
||||
import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area';
|
||||
import { useAlbumList } from '/@/renderer/features/albums';
|
||||
import { useRecentlyPlayed } from '/@/renderer/features/home/queries/recently-played-query';
|
||||
import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
|
||||
import { AlbumInfiniteCarousel } from '/@/renderer/features/shared/components/infinite-album-carousel/infinite-album-carousel';
|
||||
import { useSongList } from '/@/renderer/features/songs';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import {
|
||||
HomeItem,
|
||||
useCurrentServer,
|
||||
useGeneralSettings,
|
||||
useWindowSettings,
|
||||
} from '/@/renderer/store';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||
import {
|
||||
AlbumListSort,
|
||||
LibraryItem,
|
||||
ServerType,
|
||||
SongListSort,
|
||||
SortOrder,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { AlbumListSort, AlbumListSortOptions } 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 { SongListSort } from '/@/shared/types/domain/song-domain-types';
|
||||
import { Platform } from '/@/shared/types/types';
|
||||
|
||||
const HomeRoute = () => {
|
||||
@@ -41,198 +33,198 @@ const HomeRoute = () => {
|
||||
const { windowBarStyle } = useWindowSettings();
|
||||
const { homeFeature, homeItems } = useGeneralSettings();
|
||||
|
||||
const feature = useAlbumList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
enabled: homeFeature,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: {
|
||||
limit: 20,
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
// const feature = useAlbumList({
|
||||
// options: {
|
||||
// enabled: homeFeature,
|
||||
// gcTime: 1000 * 60,
|
||||
// staleTime: 1000 * 60,
|
||||
// },
|
||||
// query: {
|
||||
// limit: 20,
|
||||
// offset: 0,
|
||||
// sortBy: AlbumListSort.RANDOM,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// });
|
||||
|
||||
const featureItemsWithImage = useMemo(() => {
|
||||
return feature.data?.items?.filter((item) => item.imageUrl) ?? [];
|
||||
}, [feature.data?.items]);
|
||||
// const featureItemsWithImage = useMemo(() => {
|
||||
// return feature.data?.items?.filter((item) => item.imageUrl) ?? [];
|
||||
// }, [feature.data?.items]);
|
||||
|
||||
const random = useAlbumList({
|
||||
options: {
|
||||
staleTime: 1000 * 60 * 5,
|
||||
},
|
||||
query: {
|
||||
limit: itemsPerPage,
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
// const random = useAlbumList({
|
||||
// options: {
|
||||
// staleTime: 1000 * 60 * 5,
|
||||
// },
|
||||
// query: {
|
||||
// limit: itemsPerPage,
|
||||
// offset: 0,
|
||||
// sortBy: AlbumListSort.RANDOM,
|
||||
// sortOrder: ListSortOrder.ASC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// });
|
||||
|
||||
const recentlyPlayed = useRecentlyPlayed({
|
||||
options: {
|
||||
staleTime: 0,
|
||||
},
|
||||
query: {
|
||||
limit: itemsPerPage,
|
||||
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
// const recentlyPlayed = useRecentlyPlayed({
|
||||
// options: {
|
||||
// staleTime: 0,
|
||||
// },
|
||||
// query: {
|
||||
// limit: itemsPerPage,
|
||||
// offset: 0,
|
||||
// sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// });
|
||||
|
||||
const recentlyAdded = useAlbumList({
|
||||
options: {
|
||||
staleTime: 1000 * 60 * 5,
|
||||
},
|
||||
query: {
|
||||
limit: itemsPerPage,
|
||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
// const recentlyAdded = useAlbumList({
|
||||
// options: {
|
||||
// staleTime: 1000 * 60 * 5,
|
||||
// },
|
||||
// query: {
|
||||
// limit: itemsPerPage,
|
||||
// offset: 0,
|
||||
// sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// });
|
||||
|
||||
const mostPlayedAlbums = useAlbumList({
|
||||
options: {
|
||||
enabled: server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
},
|
||||
query: {
|
||||
limit: itemsPerPage,
|
||||
sortBy: AlbumListSort.PLAY_COUNT,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
// const mostPlayedAlbums = useAlbumList({
|
||||
// options: {
|
||||
// enabled: server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME,
|
||||
// staleTime: 1000 * 60 * 5,
|
||||
// },
|
||||
// query: {
|
||||
// limit: itemsPerPage,
|
||||
// offset: 0,
|
||||
// sortBy: AlbumListSort.PLAY_COUNT,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// });
|
||||
|
||||
const mostPlayedSongs = useSongList(
|
||||
{
|
||||
options: {
|
||||
enabled: server?.type === ServerType.JELLYFIN,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
},
|
||||
query: {
|
||||
limit: itemsPerPage,
|
||||
sortBy: SongListSort.PLAY_COUNT,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
},
|
||||
300,
|
||||
);
|
||||
// const mostPlayedSongs = useSongList(
|
||||
// {
|
||||
// options: {
|
||||
// enabled: server?.type === ServerType.JELLYFIN,
|
||||
// staleTime: 1000 * 60 * 5,
|
||||
// },
|
||||
// query: {
|
||||
// limit: itemsPerPage,
|
||||
// offset: 0,
|
||||
// sortBy: SongListSort.PLAY_COUNT,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// },
|
||||
// serverId: server?.id,
|
||||
// },
|
||||
// 300,
|
||||
// );
|
||||
|
||||
const isLoading =
|
||||
random.isLoading ||
|
||||
recentlyPlayed.isLoading ||
|
||||
recentlyAdded.isLoading ||
|
||||
(server?.type === ServerType.JELLYFIN && mostPlayedSongs.isLoading) ||
|
||||
((server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME) &&
|
||||
mostPlayedAlbums.isLoading);
|
||||
// const isLoading =
|
||||
// random.isLoading ||
|
||||
// recentlyPlayed.isLoading ||
|
||||
// recentlyAdded.isLoading ||
|
||||
// (server?.type === ServerType.JELLYFIN && mostPlayedSongs.isLoading) ||
|
||||
// ((server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME) &&
|
||||
// mostPlayedAlbums.isLoading);
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner container />;
|
||||
}
|
||||
// if (isLoading) {
|
||||
// return <Spinner container />;
|
||||
// }
|
||||
|
||||
const carousels = {
|
||||
[HomeItem.MOST_PLAYED]: {
|
||||
data:
|
||||
server?.type === ServerType.JELLYFIN
|
||||
? mostPlayedSongs?.data?.items
|
||||
: mostPlayedAlbums?.data?.items,
|
||||
itemType: server?.type === ServerType.JELLYFIN ? LibraryItem.SONG : LibraryItem.ALBUM,
|
||||
pagination: {
|
||||
itemsPerPage,
|
||||
},
|
||||
sortBy:
|
||||
server?.type === ServerType.JELLYFIN
|
||||
? SongListSort.PLAY_COUNT
|
||||
: AlbumListSort.PLAY_COUNT,
|
||||
sortOrder: SortOrder.DESC,
|
||||
title: t('page.home.mostPlayed', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
[HomeItem.RANDOM]: {
|
||||
data: random?.data?.items,
|
||||
itemType: LibraryItem.ALBUM,
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: SortOrder.ASC,
|
||||
title: t('page.home.explore', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
[HomeItem.RECENTLY_ADDED]: {
|
||||
data: recentlyAdded?.data?.items,
|
||||
itemType: LibraryItem.ALBUM,
|
||||
pagination: {
|
||||
itemsPerPage,
|
||||
},
|
||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
sortOrder: SortOrder.DESC,
|
||||
title: t('page.home.newlyAdded', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
[HomeItem.RECENTLY_PLAYED]: {
|
||||
data: recentlyPlayed?.data?.items,
|
||||
itemType: LibraryItem.ALBUM,
|
||||
pagination: {
|
||||
itemsPerPage,
|
||||
},
|
||||
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||
sortOrder: SortOrder.DESC,
|
||||
title: t('page.home.recentlyPlayed', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
};
|
||||
// const carousels = {
|
||||
// [HomeItem.MOST_PLAYED]: {
|
||||
// data:
|
||||
// server?.type === ServerType.JELLYFIN
|
||||
// ? mostPlayedSongs?.data?.items
|
||||
// : mostPlayedAlbums?.data?.items,
|
||||
// itemType: server?.type === ServerType.JELLYFIN ? LibraryItem.SONG : LibraryItem.ALBUM,
|
||||
// pagination: {
|
||||
// itemsPerPage,
|
||||
// },
|
||||
// sortBy:
|
||||
// server?.type === ServerType.JELLYFIN
|
||||
// ? SongListSort.PLAY_COUNT
|
||||
// : AlbumListSort.PLAY_COUNT,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// title: t('page.home.mostPlayed', { postProcess: 'sentenceCase' }),
|
||||
// },
|
||||
// [HomeItem.RANDOM]: {
|
||||
// data: random?.data?.items,
|
||||
// itemType: LibraryItem.ALBUM,
|
||||
// sortBy: AlbumListSort.RANDOM,
|
||||
// sortOrder: ListSortOrder.ASC,
|
||||
// title: t('page.home.explore', { postProcess: 'sentenceCase' }),
|
||||
// },
|
||||
// [HomeItem.RECENTLY_ADDED]: {
|
||||
// data: recentlyAdded?.data?.items,
|
||||
// itemType: LibraryItem.ALBUM,
|
||||
// pagination: {
|
||||
// itemsPerPage,
|
||||
// },
|
||||
// sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// title: t('page.home.newlyAdded', { postProcess: 'sentenceCase' }),
|
||||
// },
|
||||
// [HomeItem.RECENTLY_PLAYED]: {
|
||||
// data: recentlyPlayed?.data?.items,
|
||||
// itemType: LibraryItem.ALBUM,
|
||||
// pagination: {
|
||||
// itemsPerPage,
|
||||
// },
|
||||
// sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||
// sortOrder: ListSortOrder.DESC,
|
||||
// title: t('page.home.recentlyPlayed', { postProcess: 'sentenceCase' }),
|
||||
// },
|
||||
// };
|
||||
|
||||
const sortedCarousel = homeItems
|
||||
.filter((item) => {
|
||||
if (item.disabled) {
|
||||
return false;
|
||||
}
|
||||
if (server?.type === ServerType.JELLYFIN && item.id === HomeItem.RECENTLY_PLAYED) {
|
||||
return false;
|
||||
}
|
||||
// const sortedCarousel = homeItems
|
||||
// .filter((item) => {
|
||||
// if (item.disabled) {
|
||||
// return false;
|
||||
// }
|
||||
// if (server?.type === ServerType.JELLYFIN && item.id === HomeItem.RECENTLY_PLAYED) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
})
|
||||
.map((item) => ({
|
||||
...carousels[item.id],
|
||||
uniqueId: item.id,
|
||||
}));
|
||||
// return true;
|
||||
// })
|
||||
// .map((item) => ({
|
||||
// ...carousels[item.id],
|
||||
// uniqueId: item.id,
|
||||
// }));
|
||||
|
||||
const invalidateCarouselQuery = (carousel: {
|
||||
itemType: LibraryItem;
|
||||
sortBy: AlbumListSort | SongListSort;
|
||||
sortOrder: SortOrder;
|
||||
}) => {
|
||||
if (carousel.itemType === LibraryItem.ALBUM) {
|
||||
queryClient.invalidateQueries({
|
||||
exact: false,
|
||||
queryKey: queryKeys.albums.list(server?.id, {
|
||||
limit: itemsPerPage,
|
||||
sortBy: carousel.sortBy,
|
||||
sortOrder: carousel.sortOrder,
|
||||
startIndex: 0,
|
||||
}),
|
||||
});
|
||||
}
|
||||
// const invalidateCarouselQuery = (carousel: {
|
||||
// itemType: LibraryItem;
|
||||
// sortBy: AlbumListSort | SongListSort;
|
||||
// sortOrder: ListSortOrder;
|
||||
// }) => {
|
||||
// if (carousel.itemType === LibraryItem.ALBUM) {
|
||||
// queryClient.invalidateQueries({
|
||||
// exact: false,
|
||||
// queryKey: queryKeys.albums.list(server?.id, {
|
||||
// limit: itemsPerPage,
|
||||
// sortBy: carousel.sortBy,
|
||||
// sortOrder: carousel.sortOrder,
|
||||
// startIndex: 0,
|
||||
// }),
|
||||
// });
|
||||
// }
|
||||
|
||||
if (carousel.itemType === LibraryItem.SONG) {
|
||||
queryClient.invalidateQueries({
|
||||
exact: false,
|
||||
queryKey: queryKeys.songs.list(server?.id, {
|
||||
limit: itemsPerPage,
|
||||
sortBy: carousel.sortBy,
|
||||
sortOrder: carousel.sortOrder,
|
||||
startIndex: 0,
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
// if (carousel.itemType === LibraryItem.SONG) {
|
||||
// queryClient.invalidateQueries({
|
||||
// exact: false,
|
||||
// queryKey: queryKeys.songs.list(server?.id, {
|
||||
// limit: itemsPerPage,
|
||||
// sortBy: carousel.sortBy,
|
||||
// sortOrder: carousel.sortOrder,
|
||||
// startIndex: 0,
|
||||
// }),
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
return (
|
||||
<AnimatedPage>
|
||||
@@ -255,8 +247,16 @@ const HomeRoute = () => {
|
||||
pt={windowBarStyle === Platform.WEB ? '5rem' : '3rem'}
|
||||
px="2rem"
|
||||
>
|
||||
{homeFeature && <FeatureCarousel data={featureItemsWithImage} />}
|
||||
{sortedCarousel.map((carousel) => (
|
||||
{/* {homeFeature && <FeatureCarousel data={featureItemsWithImage} />} */}
|
||||
|
||||
<AlbumInfiniteCarousel
|
||||
serverId={server?.id ?? ''}
|
||||
sortBy={AlbumListSortOptions.NAME}
|
||||
sortOrder={ListSortOrder.ASC}
|
||||
title={t('page.home.explore', { postProcess: 'sentenceCase' })}
|
||||
/>
|
||||
|
||||
{/* {sortedCarousel.map((carousel) => (
|
||||
<MemoizedSwiperGridCarousel
|
||||
cardRows={[
|
||||
{
|
||||
@@ -320,7 +320,7 @@ const HomeRoute = () => {
|
||||
}}
|
||||
uniqueId={carousel.uniqueId}
|
||||
/>
|
||||
))}
|
||||
))} */}
|
||||
</Stack>
|
||||
</NativeScrollArea>
|
||||
</AnimatedPage>
|
||||
|
||||
@@ -16,18 +16,14 @@ import { Separator } from '/@/shared/components/separator/separator';
|
||||
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
|
||||
import { Table } from '/@/shared/components/table/table';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
AnyLibraryItem,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
RelatedArtist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { AnyLibraryItem, LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export type ItemDetailsModalProps = {
|
||||
item: Album | AlbumArtist | Playlist | Song;
|
||||
item: Album | Playlist | Song;
|
||||
};
|
||||
|
||||
type ItemDetailRow<T> = {
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSource,
|
||||
LyricsOverride,
|
||||
} from '/@/shared/types/domain-types';
|
||||
} from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
interface SearchResultProps {
|
||||
data: InternetProviderLyricSearchResponse;
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Group } from '/@/shared/components/group/group';
|
||||
import { NumberInput } from '/@/shared/components/number-input/number-input';
|
||||
import { Select } from '/@/shared/components/select/select';
|
||||
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
||||
import { LyricsOverride } from '/@/shared/types/domain-types';
|
||||
import { LyricsOverride } from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
interface LyricsActionsProps {
|
||||
index: number;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user