mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 05:38:04 +00:00
feat: updates
This commit is contained in:
parent
fc1c25f404
commit
7b6579e068
48 changed files with 1155 additions and 777 deletions
16
package.json
16
package.json
|
|
@ -25,7 +25,10 @@
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:ui": "vitest --ui",
|
"test:ui": "vitest --ui",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"test:types": "tsc --noEmit --project src/renderer/tsconfig.json",
|
"test:types": "npm run test:types-renderer && npm run test:types-main && npm run test:types-shared",
|
||||||
|
"test:types-renderer": "tsc --noEmit --project src/renderer/tsconfig.json",
|
||||||
|
"test:types-main": "tsc --noEmit --project src/main/tsconfig.json",
|
||||||
|
"test:types-shared": "tsc --noEmit --project src/shared/tsconfig.json",
|
||||||
"eslint": "eslint --ext .ts,.js ./",
|
"eslint": "eslint --ext .ts,.js ./",
|
||||||
"prettier": "prettier --write './**/*.{ts,js,tsx,jsx}'"
|
"prettier": "prettier --write './**/*.{ts,js,tsx,jsx}'"
|
||||||
},
|
},
|
||||||
|
|
@ -35,7 +38,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/node": "^6.19.6",
|
"@sentry/node": "^6.19.6",
|
||||||
"@sentry/tracing": "^6.19.6",
|
"@sentry/tracing": "^6.19.6",
|
||||||
"NeteaseCloudMusicApi": "^4.5.11",
|
"NeteaseCloudMusicApi": "^4.5.12",
|
||||||
"better-sqlite3": "7.5.1",
|
"better-sqlite3": "7.5.1",
|
||||||
"change-case": "^4.1.2",
|
"change-case": "^4.1.2",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
|
|
@ -46,6 +49,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/react": "^6.19.6",
|
"@sentry/react": "^6.19.6",
|
||||||
|
"@testing-library/react": "^13.1.0",
|
||||||
"@types/better-sqlite3": "^7.5.0",
|
"@types/better-sqlite3": "^7.5.0",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
|
|
@ -56,7 +60,7 @@
|
||||||
"@types/md5": "^2.3.2",
|
"@types/md5": "^2.3.2",
|
||||||
"@types/qrcode": "^1.4.2",
|
"@types/qrcode": "^1.4.2",
|
||||||
"@types/react": "^18.0.5",
|
"@types/react": "^18.0.5",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.19.0",
|
"@typescript-eslint/eslint-plugin": "^5.19.0",
|
||||||
"@typescript-eslint/parser": "^5.19.0",
|
"@typescript-eslint/parser": "^5.19.0",
|
||||||
"@vitejs/plugin-react": "^1.3.1",
|
"@vitejs/plugin-react": "^1.3.1",
|
||||||
|
|
@ -69,13 +73,13 @@
|
||||||
"colord": "^2.9.2",
|
"colord": "^2.9.2",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dayjs": "^1.11.0",
|
"dayjs": "^1.11.1",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"electron": "^18.0.3",
|
"electron": "^18.0.4",
|
||||||
"electron-builder": "^23.0.3",
|
"electron-builder": "^23.0.3",
|
||||||
"electron-devtools-installer": "^3.2.0",
|
"electron-devtools-installer": "^3.2.0",
|
||||||
"electron-rebuild": "^3.2.7",
|
"electron-rebuild": "^3.2.7",
|
||||||
"electron-releases": "^3.985.0",
|
"electron-releases": "^3.987.0",
|
||||||
"esbuild": "^0.14.36",
|
"esbuild": "^0.14.36",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
|
|
|
||||||
206
pnpm-lock.yaml
generated
206
pnpm-lock.yaml
generated
|
|
@ -4,6 +4,7 @@ specifiers:
|
||||||
'@sentry/node': ^6.19.6
|
'@sentry/node': ^6.19.6
|
||||||
'@sentry/react': ^6.19.6
|
'@sentry/react': ^6.19.6
|
||||||
'@sentry/tracing': ^6.19.6
|
'@sentry/tracing': ^6.19.6
|
||||||
|
'@testing-library/react': ^13.1.0
|
||||||
'@types/better-sqlite3': ^7.5.0
|
'@types/better-sqlite3': ^7.5.0
|
||||||
'@types/cookie-parser': ^1.4.2
|
'@types/cookie-parser': ^1.4.2
|
||||||
'@types/express': ^4.17.13
|
'@types/express': ^4.17.13
|
||||||
|
|
@ -14,12 +15,12 @@ specifiers:
|
||||||
'@types/md5': ^2.3.2
|
'@types/md5': ^2.3.2
|
||||||
'@types/qrcode': ^1.4.2
|
'@types/qrcode': ^1.4.2
|
||||||
'@types/react': ^18.0.5
|
'@types/react': ^18.0.5
|
||||||
'@types/react-dom': ^18.0.0
|
'@types/react-dom': ^18.0.1
|
||||||
'@typescript-eslint/eslint-plugin': ^5.19.0
|
'@typescript-eslint/eslint-plugin': ^5.19.0
|
||||||
'@typescript-eslint/parser': ^5.19.0
|
'@typescript-eslint/parser': ^5.19.0
|
||||||
'@vitejs/plugin-react': ^1.3.1
|
'@vitejs/plugin-react': ^1.3.1
|
||||||
'@vitest/ui': ^0.9.3
|
'@vitest/ui': ^0.9.3
|
||||||
NeteaseCloudMusicApi: ^4.5.11
|
NeteaseCloudMusicApi: ^4.5.12
|
||||||
autoprefixer: ^10.4.4
|
autoprefixer: ^10.4.4
|
||||||
axios: ^0.26.1
|
axios: ^0.26.1
|
||||||
better-sqlite3: 7.5.1
|
better-sqlite3: 7.5.1
|
||||||
|
|
@ -31,15 +32,14 @@ specifiers:
|
||||||
concurrently: ^7.1.0
|
concurrently: ^7.1.0
|
||||||
cookie-parser: ^1.4.6
|
cookie-parser: ^1.4.6
|
||||||
cross-env: ^7.0.3
|
cross-env: ^7.0.3
|
||||||
csstype: ^3.0.11
|
dayjs: ^1.11.1
|
||||||
dayjs: ^1.11.0
|
|
||||||
dotenv: ^16.0.0
|
dotenv: ^16.0.0
|
||||||
electron: ^18.0.3
|
electron: ^18.0.4
|
||||||
electron-builder: ^23.0.3
|
electron-builder: ^23.0.3
|
||||||
electron-devtools-installer: ^3.2.0
|
electron-devtools-installer: ^3.2.0
|
||||||
electron-log: ^4.4.6
|
electron-log: ^4.4.6
|
||||||
electron-rebuild: ^3.2.7
|
electron-rebuild: ^3.2.7
|
||||||
electron-releases: ^3.985.0
|
electron-releases: ^3.987.0
|
||||||
electron-store: ^8.0.1
|
electron-store: ^8.0.1
|
||||||
esbuild: ^0.14.36
|
esbuild: ^0.14.36
|
||||||
eslint: ^8.13.0
|
eslint: ^8.13.0
|
||||||
|
|
@ -64,18 +64,17 @@ specifiers:
|
||||||
qrcode: ^1.5.0
|
qrcode: ^1.5.0
|
||||||
react: ^18.0.0
|
react: ^18.0.0
|
||||||
react-dom: ^18.0.0
|
react-dom: ^18.0.0
|
||||||
|
react-ga4: ^1.4.1
|
||||||
react-hot-toast: ^2.2.0
|
react-hot-toast: ^2.2.0
|
||||||
react-query: ^3.34.19
|
react-query: ^3.34.19
|
||||||
react-router-dom: ^6.3.0
|
react-router-dom: ^6.3.0
|
||||||
react-use: ^17.3.2
|
react-use: ^17.3.2
|
||||||
rollup: ^2.70.1
|
|
||||||
rollup-plugin-visualizer: ^5.6.0
|
rollup-plugin-visualizer: ^5.6.0
|
||||||
sass: ^1.50.0
|
sass: ^1.50.0
|
||||||
tailwindcss: ^3.0.24
|
tailwindcss: ^3.0.24
|
||||||
typescript: ^4.6.3
|
typescript: ^4.6.3
|
||||||
unplugin-auto-import: ^0.7.1
|
unplugin-auto-import: ^0.7.1
|
||||||
valtio: ^1.5.2
|
valtio: ^1.5.2
|
||||||
valtio-persist: ^1.0.2
|
|
||||||
vite: ^2.9.5
|
vite: ^2.9.5
|
||||||
vite-plugin-svg-icons: ^2.0.1
|
vite-plugin-svg-icons: ^2.0.1
|
||||||
vitest: ^0.9.3
|
vitest: ^0.9.3
|
||||||
|
|
@ -84,7 +83,7 @@ specifiers:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sentry/node': 6.19.6
|
'@sentry/node': 6.19.6
|
||||||
'@sentry/tracing': 6.19.6
|
'@sentry/tracing': 6.19.6
|
||||||
NeteaseCloudMusicApi: 4.5.11
|
NeteaseCloudMusicApi: 4.5.12
|
||||||
better-sqlite3: 7.5.1
|
better-sqlite3: 7.5.1
|
||||||
change-case: 4.1.2
|
change-case: 4.1.2
|
||||||
cookie-parser: 1.4.6
|
cookie-parser: 1.4.6
|
||||||
|
|
@ -95,6 +94,7 @@ dependencies:
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@sentry/react': 6.19.6_react@18.0.0
|
'@sentry/react': 6.19.6_react@18.0.0
|
||||||
|
'@testing-library/react': 13.1.0_react-dom@18.0.0+react@18.0.0
|
||||||
'@types/better-sqlite3': 7.5.0
|
'@types/better-sqlite3': 7.5.0
|
||||||
'@types/cookie-parser': 1.4.2
|
'@types/cookie-parser': 1.4.2
|
||||||
'@types/express': 4.17.13
|
'@types/express': 4.17.13
|
||||||
|
|
@ -105,7 +105,7 @@ devDependencies:
|
||||||
'@types/md5': 2.3.2
|
'@types/md5': 2.3.2
|
||||||
'@types/qrcode': 1.4.2
|
'@types/qrcode': 1.4.2
|
||||||
'@types/react': 18.0.5
|
'@types/react': 18.0.5
|
||||||
'@types/react-dom': 18.0.0
|
'@types/react-dom': 18.0.1
|
||||||
'@typescript-eslint/eslint-plugin': 5.19.0_f34adc8488d2e4f014fe61432d70cbf2
|
'@typescript-eslint/eslint-plugin': 5.19.0_f34adc8488d2e4f014fe61432d70cbf2
|
||||||
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
|
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
|
||||||
'@vitejs/plugin-react': 1.3.1
|
'@vitejs/plugin-react': 1.3.1
|
||||||
|
|
@ -118,14 +118,13 @@ devDependencies:
|
||||||
colord: 2.9.2
|
colord: 2.9.2
|
||||||
concurrently: 7.1.0
|
concurrently: 7.1.0
|
||||||
cross-env: 7.0.3
|
cross-env: 7.0.3
|
||||||
csstype: 3.0.11
|
dayjs: 1.11.1
|
||||||
dayjs: 1.11.0
|
|
||||||
dotenv: 16.0.0
|
dotenv: 16.0.0
|
||||||
electron: 18.0.3
|
electron: 18.0.4
|
||||||
electron-builder: 23.0.3
|
electron-builder: 23.0.3
|
||||||
electron-devtools-installer: 3.2.0
|
electron-devtools-installer: 3.2.0
|
||||||
electron-rebuild: 3.2.7
|
electron-rebuild: 3.2.7
|
||||||
electron-releases: 3.985.0
|
electron-releases: 3.987.0
|
||||||
esbuild: 0.14.36
|
esbuild: 0.14.36
|
||||||
eslint: 8.13.0
|
eslint: 8.13.0
|
||||||
eslint-plugin-react: 7.29.4_eslint@8.13.0
|
eslint-plugin-react: 7.29.4_eslint@8.13.0
|
||||||
|
|
@ -147,18 +146,17 @@ devDependencies:
|
||||||
qrcode: 1.5.0
|
qrcode: 1.5.0
|
||||||
react: 18.0.0
|
react: 18.0.0
|
||||||
react-dom: 18.0.0_react@18.0.0
|
react-dom: 18.0.0_react@18.0.0
|
||||||
react-hot-toast: 2.2.0_aee3b59847029cfc9aee5217330a3daf
|
react-ga4: 1.4.1
|
||||||
|
react-hot-toast: 2.2.0_react-dom@18.0.0+react@18.0.0
|
||||||
react-query: 3.34.19_react-dom@18.0.0+react@18.0.0
|
react-query: 3.34.19_react-dom@18.0.0+react@18.0.0
|
||||||
react-router-dom: 6.3.0_react-dom@18.0.0+react@18.0.0
|
react-router-dom: 6.3.0_react-dom@18.0.0+react@18.0.0
|
||||||
react-use: 17.3.2_react-dom@18.0.0+react@18.0.0
|
react-use: 17.3.2_react-dom@18.0.0+react@18.0.0
|
||||||
rollup: 2.70.1
|
rollup-plugin-visualizer: 5.6.0
|
||||||
rollup-plugin-visualizer: 5.6.0_rollup@2.70.1
|
|
||||||
sass: 1.50.0
|
sass: 1.50.0
|
||||||
tailwindcss: 3.0.24
|
tailwindcss: 3.0.24
|
||||||
typescript: 4.6.3
|
typescript: 4.6.3
|
||||||
unplugin-auto-import: 0.7.1_05062056c3506028f60dc849695a4e6b
|
unplugin-auto-import: 0.7.1_esbuild@0.14.36+vite@2.9.5
|
||||||
valtio: 1.5.2_react@18.0.0+vite@2.9.5
|
valtio: 1.5.2_react@18.0.0+vite@2.9.5
|
||||||
valtio-persist: 1.0.2_valtio@1.5.2
|
|
||||||
vite: 2.9.5_sass@1.50.0
|
vite: 2.9.5_sass@1.50.0
|
||||||
vite-plugin-svg-icons: 2.0.1_vite@2.9.5
|
vite-plugin-svg-icons: 2.0.1_vite@2.9.5
|
||||||
vitest: 0.9.3_ac1eaec0e6cd6e44c577f894fa1b602e
|
vitest: 0.9.3_ac1eaec0e6cd6e44c577f894fa1b602e
|
||||||
|
|
@ -767,6 +765,34 @@ packages:
|
||||||
defer-to-connect: 2.0.1
|
defer-to-connect: 2.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@testing-library/dom/8.13.0:
|
||||||
|
resolution: {integrity: sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.16.7
|
||||||
|
'@babel/runtime': 7.17.8
|
||||||
|
'@types/aria-query': 4.2.2
|
||||||
|
aria-query: 5.0.0
|
||||||
|
chalk: 4.1.2
|
||||||
|
dom-accessibility-api: 0.5.13
|
||||||
|
lz-string: 1.4.4
|
||||||
|
pretty-format: 27.5.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@testing-library/react/13.1.0_react-dom@18.0.0+react@18.0.0:
|
||||||
|
resolution: {integrity: sha512-neStnDZdhkvZNNmPhhhi8+BXg3YCvjNmd8yGdr44VLVcFUDPForwokJWpDRCh3DvuX/M37Pt94fLwkM7aNut/A==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18.0.0
|
||||||
|
react-dom: ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.17.8
|
||||||
|
'@testing-library/dom': 8.13.0
|
||||||
|
'@types/react-dom': 18.0.1
|
||||||
|
react: 18.0.0
|
||||||
|
react-dom: 18.0.0_react@18.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@tokenizer/token/0.3.0:
|
/@tokenizer/token/0.3.0:
|
||||||
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
||||||
|
|
||||||
|
|
@ -784,6 +810,10 @@ packages:
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/aria-query/4.2.2:
|
||||||
|
resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/better-sqlite3/7.5.0:
|
/@types/better-sqlite3/7.5.0:
|
||||||
resolution: {integrity: sha512-G9ZbMjydW2yj1AgiPlUtdgF3a1qNpLJLudc9ynJCeJByS3XFWpmT9LT+VSHrKHFbxb31CvtYwetLTOvG9zdxdg==}
|
resolution: {integrity: sha512-G9ZbMjydW2yj1AgiPlUtdgF3a1qNpLJLudc9ynJCeJByS3XFWpmT9LT+VSHrKHFbxb31CvtYwetLTOvG9zdxdg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -936,8 +966,8 @@ packages:
|
||||||
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
|
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/node/16.11.26:
|
/@types/node/16.11.27:
|
||||||
resolution: {integrity: sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==}
|
resolution: {integrity: sha512-C1pD3kgLoZ56Uuy5lhfOxie4aZlA3UMGLX9rXteq4WitEZH6Rl80mwactt9QG0w0gLFlN/kLBTFnGXtDVWvWQw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/node/17.0.23:
|
/@types/node/17.0.23:
|
||||||
|
|
@ -970,8 +1000,8 @@ packages:
|
||||||
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/react-dom/18.0.0:
|
/@types/react-dom/18.0.1:
|
||||||
resolution: {integrity: sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg==}
|
resolution: {integrity: sha512-jCwTXvHtRLiyVvKm9aEdHXs8rflVOGd5Sl913JZrPshfXjn8NYsTNZOz70bCsA31IR0TOqwi3ad+X4tSCBoMTw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.0.5
|
'@types/react': 18.0.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -1174,8 +1204,8 @@ packages:
|
||||||
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
|
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/NeteaseCloudMusicApi/4.5.11:
|
/NeteaseCloudMusicApi/4.5.12:
|
||||||
resolution: {integrity: sha512-v/L3I5NA+tCTfD9Nkr0i3igTEHJcvHQeZXM0Sqw1iBCqN6z62qtKoTON9yNSEgIGoZrzFfMyqHloLkv1iBo5sQ==}
|
resolution: {integrity: sha512-tlATnWTyOVH6hAxiH2f+nhgFtWulC1xMTz/7VyRjP/axcoMWff2mEa2Bw9kNl+Wb2bUrP/1oC2GXF41oyWwAJQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -1353,6 +1383,11 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-convert: 2.0.1
|
color-convert: 2.0.1
|
||||||
|
|
||||||
|
/ansi-styles/5.2.0:
|
||||||
|
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/anymatch/3.1.2:
|
/anymatch/3.1.2:
|
||||||
resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
|
resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
@ -1424,6 +1459,11 @@ packages:
|
||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/aria-query/5.0.0:
|
||||||
|
resolution: {integrity: sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==}
|
||||||
|
engines: {node: '>=6.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/arr-diff/4.0.0:
|
/arr-diff/4.0.0:
|
||||||
resolution: {integrity: sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=}
|
resolution: {integrity: sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -2523,8 +2563,8 @@ packages:
|
||||||
engines: {node: '>=0.11'}
|
engines: {node: '>=0.11'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/dayjs/1.11.0:
|
/dayjs/1.11.1:
|
||||||
resolution: {integrity: sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==}
|
resolution: {integrity: sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/debounce-fn/4.0.0:
|
/debounce-fn/4.0.0:
|
||||||
|
|
@ -2617,6 +2657,15 @@ packages:
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/define-properties/1.1.4:
|
||||||
|
resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dependencies:
|
||||||
|
has-property-descriptors: 1.0.0
|
||||||
|
object-keys: 1.1.1
|
||||||
|
dev: true
|
||||||
|
optional: true
|
||||||
|
|
||||||
/define-property/0.2.5:
|
/define-property/0.2.5:
|
||||||
resolution: {integrity: sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=}
|
resolution: {integrity: sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -2781,6 +2830,10 @@ packages:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/dom-accessibility-api/0.5.13:
|
||||||
|
resolution: {integrity: sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/dom-serializer/0.2.2:
|
/dom-serializer/0.2.2:
|
||||||
resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
|
resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -2980,8 +3033,8 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/electron-releases/3.985.0:
|
/electron-releases/3.987.0:
|
||||||
resolution: {integrity: sha512-1HJzI4m6kS0aV45NWqs99eR7ekSAN7JIKsklsV+1eGfcRwwyP6O8c3458rL4vdvlhZ9+QnUM3B0S03+XV5M0Tg==}
|
resolution: {integrity: sha512-Rol/iOHhTdEiVqD5O9p4rLkNSlK82FFX3M99BrNvE7Gs52/mRWJYNdhPuY9d/Cs3jx2H8KJsB49Tfpm4TOqJHw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/electron-store/8.0.1:
|
/electron-store/8.0.1:
|
||||||
|
|
@ -2995,14 +3048,14 @@ packages:
|
||||||
resolution: {integrity: sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==}
|
resolution: {integrity: sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/electron/18.0.3:
|
/electron/18.0.4:
|
||||||
resolution: {integrity: sha512-QRUZkGL8O/8CyDmTLSjBeRsZmGTPlPVeWnnpkdNqgHYYaOc/A881FKMiNzvQ9Cj0a+rUavDdwBUfUL82U3Ay7w==}
|
resolution: {integrity: sha512-xfsozNpFr3WzeM1EFlw2qqiqXbCrgQNBJJMlcC4/DUYVpkF8364SZenX7FFFA42NmwXiOEahkvvho/u7UrAcGg==}
|
||||||
engines: {node: '>= 8.6'}
|
engines: {node: '>= 8.6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@electron/get': 1.14.1
|
'@electron/get': 1.14.1
|
||||||
'@types/node': 16.11.26
|
'@types/node': 16.11.27
|
||||||
extract-zip: 1.7.0
|
extract-zip: 1.7.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
@ -4040,7 +4093,7 @@ packages:
|
||||||
es6-error: 4.1.1
|
es6-error: 4.1.1
|
||||||
matcher: 3.0.0
|
matcher: 3.0.0
|
||||||
roarr: 2.15.4
|
roarr: 2.15.4
|
||||||
semver: 7.3.6
|
semver: 7.3.7
|
||||||
serialize-error: 7.0.1
|
serialize-error: 7.0.1
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
@ -4080,7 +4133,7 @@ packages:
|
||||||
resolution: {integrity: sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==}
|
resolution: {integrity: sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dependencies:
|
dependencies:
|
||||||
define-properties: 1.1.3
|
define-properties: 1.1.4
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|
@ -4096,12 +4149,10 @@ packages:
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/goober/2.1.8_csstype@3.0.11:
|
/goober/2.1.8:
|
||||||
resolution: {integrity: sha512-S0C85gCzcfFCMSdjD/CxyQMt1rbf2qEg6hmDzxk2FfD7+7Ogk55m8ZFUMtqNaZM4VVX/qaU9AzSORG+Gf4ZpAQ==}
|
resolution: {integrity: sha512-S0C85gCzcfFCMSdjD/CxyQMt1rbf2qEg6hmDzxk2FfD7+7Ogk55m8ZFUMtqNaZM4VVX/qaU9AzSORG+Gf4ZpAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
csstype: ^3.0.10
|
csstype: ^3.0.10
|
||||||
dependencies:
|
|
||||||
csstype: 3.0.11
|
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/got/11.8.3:
|
/got/11.8.3:
|
||||||
|
|
@ -4174,6 +4225,13 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/has-property-descriptors/1.0.0:
|
||||||
|
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
|
||||||
|
dependencies:
|
||||||
|
get-intrinsic: 1.1.1
|
||||||
|
dev: true
|
||||||
|
optional: true
|
||||||
|
|
||||||
/has-symbols/1.0.3:
|
/has-symbols/1.0.3:
|
||||||
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -4357,6 +4415,16 @@ packages:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
/https-proxy-agent/5.0.1:
|
||||||
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
agent-base: 6.0.2
|
||||||
|
debug: 4.3.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
/humanize-ms/1.2.1:
|
/humanize-ms/1.2.1:
|
||||||
resolution: {integrity: sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=}
|
resolution: {integrity: sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -4967,7 +5035,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
universalify: 2.0.0
|
universalify: 2.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs: 4.2.9
|
graceful-fs: 4.2.10
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jsx-ast-utils/3.2.2:
|
/jsx-ast-utils/3.2.2:
|
||||||
|
|
@ -5171,6 +5239,11 @@ packages:
|
||||||
resolution: {integrity: sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=}
|
resolution: {integrity: sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lz-string/1.4.4:
|
||||||
|
resolution: {integrity: sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/lzma-native/8.0.6:
|
/lzma-native/8.0.6:
|
||||||
resolution: {integrity: sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==}
|
resolution: {integrity: sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
@ -5902,7 +5975,7 @@ packages:
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
get-uri: 3.0.2
|
get-uri: 3.0.2
|
||||||
http-proxy-agent: 4.0.1
|
http-proxy-agent: 4.0.1
|
||||||
https-proxy-agent: 5.0.0
|
https-proxy-agent: 5.0.1
|
||||||
pac-resolver: 5.0.0
|
pac-resolver: 5.0.0
|
||||||
raw-body: 2.5.1
|
raw-body: 2.5.1
|
||||||
socks-proxy-agent: 5.0.1
|
socks-proxy-agent: 5.0.1
|
||||||
|
|
@ -6230,6 +6303,15 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pretty-format/27.5.1:
|
||||||
|
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
|
||||||
|
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||||
|
dependencies:
|
||||||
|
ansi-regex: 5.0.1
|
||||||
|
ansi-styles: 5.2.0
|
||||||
|
react-is: 17.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/process-nextick-args/2.0.1:
|
/process-nextick-args/2.0.1:
|
||||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
|
||||||
|
|
@ -6372,14 +6454,18 @@ packages:
|
||||||
scheduler: 0.21.0
|
scheduler: 0.21.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/react-hot-toast/2.2.0_aee3b59847029cfc9aee5217330a3daf:
|
/react-ga4/1.4.1:
|
||||||
|
resolution: {integrity: sha512-ioBMEIxd4ePw4YtaloTUgqhQGqz5ebDdC4slEpLgy2sLx1LuZBC9iYCwDymTXzcntw6K1dHX183ulP32nNdG7w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/react-hot-toast/2.2.0_react-dom@18.0.0+react@18.0.0:
|
||||||
resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==}
|
resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16'
|
react: '>=16'
|
||||||
react-dom: '>=16'
|
react-dom: '>=16'
|
||||||
dependencies:
|
dependencies:
|
||||||
goober: 2.1.8_csstype@3.0.11
|
goober: 2.1.8
|
||||||
react: 18.0.0
|
react: 18.0.0
|
||||||
react-dom: 18.0.0_react@18.0.0
|
react-dom: 18.0.0_react@18.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
@ -6390,6 +6476,10 @@ packages:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/react-is/17.0.2:
|
||||||
|
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/react-query/3.34.19_react-dom@18.0.0+react@18.0.0:
|
/react-query/3.34.19_react-dom@18.0.0+react@18.0.0:
|
||||||
resolution: {integrity: sha512-JO0Ymi58WKmvnhgg6bGIrYIeKb64KsKaPWo8JcGnmK2jJxAs2XmMBzlP75ZepSU7CHzcsWtIIyhMrLbX3pb/3w==}
|
resolution: {integrity: sha512-JO0Ymi58WKmvnhgg6bGIrYIeKb64KsKaPWo8JcGnmK2jJxAs2XmMBzlP75ZepSU7CHzcsWtIIyhMrLbX3pb/3w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -6697,7 +6787,7 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/rollup-plugin-visualizer/5.6.0_rollup@2.70.1:
|
/rollup-plugin-visualizer/5.6.0:
|
||||||
resolution: {integrity: sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA==}
|
resolution: {integrity: sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -6706,13 +6796,12 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.2
|
nanoid: 3.3.2
|
||||||
open: 8.4.0
|
open: 8.4.0
|
||||||
rollup: 2.70.1
|
|
||||||
source-map: 0.7.3
|
source-map: 0.7.3
|
||||||
yargs: 17.4.0
|
yargs: 17.4.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/rollup/2.70.1:
|
/rollup/2.70.2:
|
||||||
resolution: {integrity: sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==}
|
resolution: {integrity: sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|
@ -6833,6 +6922,15 @@ packages:
|
||||||
lru-cache: 7.8.1
|
lru-cache: 7.8.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/semver/7.3.7:
|
||||||
|
resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
lru-cache: 6.0.0
|
||||||
|
dev: true
|
||||||
|
optional: true
|
||||||
|
|
||||||
/send/0.17.2:
|
/send/0.17.2:
|
||||||
resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==}
|
resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
@ -7715,7 +7813,7 @@ packages:
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/unplugin-auto-import/0.7.1_05062056c3506028f60dc849695a4e6b:
|
/unplugin-auto-import/0.7.1_esbuild@0.14.36+vite@2.9.5:
|
||||||
resolution: {integrity: sha512-9865OV9eP99PNxHR2mtTDExeN01m4M9boT5U2BtIwsU1wDRsaFIYWLwcCBEjvXzXfTTC2NNMskhHGVAMfL2WgA==}
|
resolution: {integrity: sha512-9865OV9eP99PNxHR2mtTDExeN01m4M9boT5U2BtIwsU1wDRsaFIYWLwcCBEjvXzXfTTC2NNMskhHGVAMfL2WgA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -7729,7 +7827,7 @@ packages:
|
||||||
local-pkg: 0.4.1
|
local-pkg: 0.4.1
|
||||||
magic-string: 0.26.1
|
magic-string: 0.26.1
|
||||||
resolve: 1.22.0
|
resolve: 1.22.0
|
||||||
unplugin: 0.6.2_05062056c3506028f60dc849695a4e6b
|
unplugin: 0.6.2_esbuild@0.14.36+vite@2.9.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- esbuild
|
- esbuild
|
||||||
- rollup
|
- rollup
|
||||||
|
|
@ -7737,7 +7835,7 @@ packages:
|
||||||
- webpack
|
- webpack
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/unplugin/0.6.2_05062056c3506028f60dc849695a4e6b:
|
/unplugin/0.6.2_esbuild@0.14.36+vite@2.9.5:
|
||||||
resolution: {integrity: sha512-+QONc2uBFQbeo4x5mlJHjTKjR6pmuchMpGVrWhwdGFFMb4ttFZ4E9KqhOOrNcm3Q8NNyB1vJ4s5e36IZC7UWYw==}
|
resolution: {integrity: sha512-+QONc2uBFQbeo4x5mlJHjTKjR6pmuchMpGVrWhwdGFFMb4ttFZ4E9KqhOOrNcm3Q8NNyB1vJ4s5e36IZC7UWYw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
esbuild: '>=0.13'
|
esbuild: '>=0.13'
|
||||||
|
|
@ -7756,7 +7854,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar: 3.5.3
|
chokidar: 3.5.3
|
||||||
esbuild: 0.14.36
|
esbuild: 0.14.36
|
||||||
rollup: 2.70.1
|
|
||||||
vite: 2.9.5_sass@1.50.0
|
vite: 2.9.5_sass@1.50.0
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
webpack-virtual-modules: 0.4.3
|
webpack-virtual-modules: 0.4.3
|
||||||
|
|
@ -7880,15 +7977,6 @@ packages:
|
||||||
source-map: 0.7.3
|
source-map: 0.7.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/valtio-persist/1.0.2_valtio@1.5.2:
|
|
||||||
resolution: {integrity: sha512-OBVEUZTS1heiA5R3j8CPDuXIMmmjIvq/4CiO+pElXd7f7b7nR3vIH5qql35hXw/AkLdftqTUcVCNVf6yAJ1ypA==}
|
|
||||||
peerDependencies:
|
|
||||||
valtio: ^1.2.5
|
|
||||||
dependencies:
|
|
||||||
lodash: 4.17.21
|
|
||||||
valtio: 1.5.2_react@18.0.0+vite@2.9.5
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/valtio/1.5.2_react@18.0.0+vite@2.9.5:
|
/valtio/1.5.2_react@18.0.0+vite@2.9.5:
|
||||||
resolution: {integrity: sha512-4oqGO+7xSKZJJgLsfwRdzQxxy4hiOjiE0IZv0xoNNLtJQ+Y6mtWoEl0Y0JyUCrU/HBmY+0W/yL3lwjrpTBCJ/w==}
|
resolution: {integrity: sha512-4oqGO+7xSKZJJgLsfwRdzQxxy4hiOjiE0IZv0xoNNLtJQ+Y6mtWoEl0Y0JyUCrU/HBmY+0W/yL3lwjrpTBCJ/w==}
|
||||||
engines: {node: '>=12.7.0'}
|
engines: {node: '>=12.7.0'}
|
||||||
|
|
@ -7970,7 +8058,7 @@ packages:
|
||||||
esbuild: 0.14.36
|
esbuild: 0.14.36
|
||||||
postcss: 8.4.12
|
postcss: 8.4.12
|
||||||
resolve: 1.22.0
|
resolve: 1.22.0
|
||||||
rollup: 2.70.1
|
rollup: 2.70.2
|
||||||
sass: 1.50.0
|
sass: 1.50.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
export enum APIs {
|
|
||||||
UserPlaylist = 'user/playlist',
|
|
||||||
UserAccount = 'user/account',
|
|
||||||
Personalized = 'personalized',
|
|
||||||
RecommendResource = 'recommend/resource',
|
|
||||||
Likelist = 'likelist',
|
|
||||||
SongDetail = 'song/detail',
|
|
||||||
SongUrl = 'song/url',
|
|
||||||
Album = 'album',
|
|
||||||
PlaylistDetail = 'playlist/detail',
|
|
||||||
Artists = 'artists',
|
|
||||||
ArtistAlbum = 'artist/album',
|
|
||||||
Lyric = 'lyric',
|
|
||||||
CoverColor = 'cover_color',
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
export enum IpcChannels {
|
|
||||||
ClearAPICache = 'clear-api-cache',
|
|
||||||
Minimize = 'minimize',
|
|
||||||
MaximizeOrUnmaximize = 'maximize-or-unmaximize',
|
|
||||||
Close = 'close',
|
|
||||||
IsMaximized = 'is-maximized',
|
|
||||||
GetApiCacheSync = 'get-api-cache-sync',
|
|
||||||
DevDbExportJson = 'dev-db-export-json',
|
|
||||||
CacheCoverColor = 'cache-cover-color',
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { db, Tables } from './db'
|
import { db, Tables } from './db'
|
||||||
import type { FetchTracksResponse } from '../renderer/api/track'
|
import type { FetchTracksResponse } from '@/shared/api/Track'
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import * as musicMetadata from 'music-metadata'
|
import * as musicMetadata from 'music-metadata'
|
||||||
import { APIs } from './CacheAPIsName'
|
import { APIs, APIsParams, APIsResponse } from '../shared/CacheAPIs'
|
||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -18,6 +18,8 @@ class Cache {
|
||||||
case APIs.UserAccount:
|
case APIs.UserAccount:
|
||||||
case APIs.Personalized:
|
case APIs.Personalized:
|
||||||
case APIs.RecommendResource:
|
case APIs.RecommendResource:
|
||||||
|
case APIs.UserAlbums:
|
||||||
|
case APIs.UserArtists:
|
||||||
case APIs.Likelist: {
|
case APIs.Likelist: {
|
||||||
if (!data) return
|
if (!data) return
|
||||||
db.upsert(Tables.AccountData, {
|
db.upsert(Tables.AccountData, {
|
||||||
|
|
@ -27,7 +29,7 @@ class Cache {
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.SongDetail: {
|
case APIs.Track: {
|
||||||
if (!data.songs) return
|
if (!data.songs) return
|
||||||
const tracks = (data as FetchTracksResponse).songs.map(t => ({
|
const tracks = (data as FetchTracksResponse).songs.map(t => ({
|
||||||
id: t.id,
|
id: t.id,
|
||||||
|
|
@ -47,7 +49,7 @@ class Cache {
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.PlaylistDetail: {
|
case APIs.Playlist: {
|
||||||
if (!data.playlist) return
|
if (!data.playlist) return
|
||||||
db.upsert(Tables.Playlist, {
|
db.upsert(Tables.Playlist, {
|
||||||
id: data.playlist.id,
|
id: data.playlist.id,
|
||||||
|
|
@ -56,7 +58,7 @@ class Cache {
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.Artists: {
|
case APIs.Artist: {
|
||||||
if (!data.artist) return
|
if (!data.artist) return
|
||||||
db.upsert(Tables.Artist, {
|
db.upsert(Tables.Artist, {
|
||||||
id: data.artist.id,
|
id: data.artist.id,
|
||||||
|
|
@ -108,7 +110,7 @@ class Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(api: string, query: any): any {
|
get<T extends keyof APIsParams>(api: T, params: any): any {
|
||||||
switch (api) {
|
switch (api) {
|
||||||
case APIs.UserPlaylist:
|
case APIs.UserPlaylist:
|
||||||
case APIs.UserAccount:
|
case APIs.UserAccount:
|
||||||
|
|
@ -119,15 +121,13 @@ class Cache {
|
||||||
if (data?.json) return JSON.parse(data.json)
|
if (data?.json) return JSON.parse(data.json)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.SongDetail: {
|
case APIs.Track: {
|
||||||
const ids: string[] = query?.ids.split(',')
|
const ids: number[] = params?.ids
|
||||||
|
.split(',')
|
||||||
|
.map((id: string) => Number(id))
|
||||||
if (ids.length === 0) return
|
if (ids.length === 0) return
|
||||||
|
|
||||||
let isIDsValid = true
|
if (ids.includes(NaN)) return
|
||||||
ids.forEach(id => {
|
|
||||||
if (id === '' || isNaN(Number(id))) isIDsValid = false
|
|
||||||
})
|
|
||||||
if (!isIDsValid) return
|
|
||||||
|
|
||||||
const tracksRaw = db.findMany(Tables.Track, ids)
|
const tracksRaw = db.findMany(Tables.Track, ids)
|
||||||
|
|
||||||
|
|
@ -138,7 +138,6 @@ class Cache {
|
||||||
const track = tracksRaw.find(t => t.id === Number(id)) as any
|
const track = tracksRaw.find(t => t.id === Number(id)) as any
|
||||||
return JSON.parse(track.json)
|
return JSON.parse(track.json)
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
songs: tracks,
|
songs: tracks,
|
||||||
|
|
@ -146,8 +145,8 @@ class Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case APIs.Album: {
|
case APIs.Album: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
const data = db.find(Tables.Album, query.id)
|
const data = db.find(Tables.Album, params.id)
|
||||||
if (data?.json)
|
if (data?.json)
|
||||||
return {
|
return {
|
||||||
resourceState: true,
|
resourceState: true,
|
||||||
|
|
@ -157,22 +156,22 @@ class Cache {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.PlaylistDetail: {
|
case APIs.Playlist: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
const data = db.find(Tables.Playlist, query.id)
|
const data = db.find(Tables.Playlist, params.id)
|
||||||
if (data?.json) return JSON.parse(data.json)
|
if (data?.json) return JSON.parse(data.json)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.Artists: {
|
case APIs.Artist: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
const data = db.find(Tables.Artist, query.id)
|
const data = db.find(Tables.Artist, params.id)
|
||||||
if (data?.json) return JSON.parse(data.json)
|
if (data?.json) return JSON.parse(data.json)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.ArtistAlbum: {
|
case APIs.ArtistAlbum: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
|
|
||||||
const artistAlbumsRaw = db.find(Tables.ArtistAlbum, query.id)
|
const artistAlbumsRaw = db.find(Tables.ArtistAlbum, params.id)
|
||||||
if (!artistAlbumsRaw?.json) return
|
if (!artistAlbumsRaw?.json) return
|
||||||
const artistAlbums = JSON.parse(artistAlbumsRaw.json)
|
const artistAlbums = JSON.parse(artistAlbumsRaw.json)
|
||||||
|
|
||||||
|
|
@ -186,21 +185,21 @@ class Cache {
|
||||||
return artistAlbums
|
return artistAlbums
|
||||||
}
|
}
|
||||||
case APIs.Lyric: {
|
case APIs.Lyric: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
const data = db.find(Tables.Lyric, query.id)
|
const data = db.find(Tables.Lyric, params.id)
|
||||||
if (data?.json) return JSON.parse(data.json)
|
if (data?.json) return JSON.parse(data.json)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case APIs.CoverColor: {
|
case APIs.CoverColor: {
|
||||||
if (isNaN(Number(query?.id))) return
|
if (isNaN(Number(params?.id))) return
|
||||||
return db.find(Tables.CoverColor, query.id)?.color
|
return db.find(Tables.CoverColor, params.id)?.color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getForExpress(api: string, req: Request) {
|
getForExpress(api: string, req: Request) {
|
||||||
// Get track detail cache
|
// Get track detail cache
|
||||||
if (api === APIs.SongDetail) {
|
if (api === APIs.Track) {
|
||||||
const cache = this.get(api, req.query)
|
const cache = this.get(api, req.query)
|
||||||
if (cache) {
|
if (cache) {
|
||||||
log.debug(`[cache] Cache hit for ${req.path}`)
|
log.debug(`[cache] Cache hit for ${req.path}`)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export interface TablesStructures {
|
||||||
[Tables.Audio]: {
|
[Tables.Audio]: {
|
||||||
id: number
|
id: number
|
||||||
br: number
|
br: number
|
||||||
|
type: 'mp3' | 'flac' | 'ogg' | 'wav' | 'm4a' | 'aac' | 'unknown'
|
||||||
source: 'netease' | 'migu' | 'kuwo' | 'kugou' | 'youtube'
|
source: 'netease' | 'migu' | 'kuwo' | 'kugou' | 'youtube'
|
||||||
url: string
|
url: string
|
||||||
updatedAt: number
|
updatedAt: number
|
||||||
|
|
@ -155,10 +156,7 @@ class DB {
|
||||||
upsertMany(data)
|
upsertMany(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<T extends TableNames>(
|
delete<T extends TableNames>(table: T, key: TablesStructures[T]['id']) {
|
||||||
table: T,
|
|
||||||
key: TablesStructures[T]['id']
|
|
||||||
) {
|
|
||||||
return this.sqlite.prepare(`DELETE FROM ${table} WHERE id = ?`).run(key)
|
return this.sqlite.prepare(`DELETE FROM ${table} WHERE id = ?`).run(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,6 @@ const isMac = process.platform === 'darwin'
|
||||||
const isLinux = process.platform === 'linux'
|
const isLinux = process.platform === 'linux'
|
||||||
const isDev = process.env.NODE_ENV === 'development'
|
const isDev = process.env.NODE_ENV === 'development'
|
||||||
|
|
||||||
log.info('[index] Main process start')
|
|
||||||
|
|
||||||
// Disable GPU Acceleration for Windows 7
|
|
||||||
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
|
|
||||||
|
|
||||||
// Set application name for Windows 10+ notifications
|
|
||||||
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
|
|
||||||
|
|
||||||
if (!app.requestSingleInstanceLock()) {
|
|
||||||
app.quit()
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TypedElectronStore {
|
interface TypedElectronStore {
|
||||||
window: {
|
window: {
|
||||||
width: number
|
width: number
|
||||||
|
|
@ -40,115 +27,138 @@ interface TypedElectronStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = new Store<TypedElectronStore>({
|
class Main {
|
||||||
defaults: {
|
win: BrowserWindow | null = null
|
||||||
window: {
|
store = new Store<TypedElectronStore>({
|
||||||
width: 1440,
|
defaults: {
|
||||||
height: 960,
|
window: {
|
||||||
|
width: 1440,
|
||||||
|
height: 960,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
let win: BrowserWindow | null = null
|
|
||||||
|
|
||||||
async function createWindow() {
|
|
||||||
// Create window
|
|
||||||
|
|
||||||
const options: BrowserWindowConstructorOptions = {
|
|
||||||
title: 'Main window',
|
|
||||||
webPreferences: {
|
|
||||||
preload: join(__dirname, 'rendererPreload.js'),
|
|
||||||
},
|
|
||||||
width: store.get('window.width'),
|
|
||||||
height: store.get('window.height'),
|
|
||||||
minWidth: 1080,
|
|
||||||
minHeight: 720,
|
|
||||||
vibrancy: 'fullscreen-ui',
|
|
||||||
titleBarStyle: 'hiddenInset',
|
|
||||||
frame: !(isWindows || isLinux), // TODO: 适用于linux下独立的启用开关
|
|
||||||
}
|
|
||||||
if (store.get('window')) {
|
|
||||||
options.x = store.get('window.x')
|
|
||||||
options.y = store.get('window.y')
|
|
||||||
}
|
|
||||||
win = new BrowserWindow(options)
|
|
||||||
|
|
||||||
// Web server
|
|
||||||
const url = `http://localhost:${process.env.ELECTRON_WEB_SERVER_PORT}`
|
|
||||||
win.loadURL(url)
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
win.webContents.openDevTools()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make all links open with the browser, not with the application
|
|
||||||
win.webContents.setWindowOpenHandler(({ url }) => {
|
|
||||||
if (url.startsWith('https:')) shell.openExternal(url)
|
|
||||||
return { action: 'deny' }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Save window position
|
constructor() {
|
||||||
const saveBounds = () => {
|
log.info('[index] Main process start')
|
||||||
const bounds = win?.getBounds()
|
|
||||||
if (bounds) {
|
// Disable GPU Acceleration for Windows 7
|
||||||
store.set('window', bounds)
|
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
|
||||||
|
|
||||||
|
// Set application name for Windows 10+ notifications
|
||||||
|
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
|
||||||
|
|
||||||
|
// Make sure the app only run on one instance
|
||||||
|
if (!app.requestSingleInstanceLock()) {
|
||||||
|
app.quit()
|
||||||
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
log.info('[index] App ready')
|
||||||
|
this.createWindow()
|
||||||
|
this.handleAppEvents()
|
||||||
|
this.handleWindowEvents()
|
||||||
|
initIpcMain(this.win)
|
||||||
|
this.initDevTools()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
win.on('resized', saveBounds)
|
|
||||||
win.on('moved', saveBounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
app.whenReady().then(async () => {
|
initDevTools() {
|
||||||
log.info('[index] App ready')
|
if (!isDev || !this.win) return
|
||||||
createWindow()
|
|
||||||
handleWindowEvents()
|
|
||||||
initIpcMain(win)
|
|
||||||
|
|
||||||
// Install devtool extension
|
// Install devtool extension
|
||||||
if (isDev) {
|
|
||||||
const {
|
const {
|
||||||
default: installExtension,
|
default: installExtension,
|
||||||
REACT_DEVELOPER_TOOLS,
|
REACT_DEVELOPER_TOOLS,
|
||||||
REDUX_DEVTOOLS,
|
REDUX_DEVTOOLS,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
} = require('electron-devtools-installer')
|
} = require('electron-devtools-installer')
|
||||||
installExtension(REACT_DEVELOPER_TOOLS.id).catch(err =>
|
installExtension(REACT_DEVELOPER_TOOLS.id).catch((err: any) =>
|
||||||
log.info('An error occurred: ', err)
|
log.info('An error occurred: ', err)
|
||||||
)
|
)
|
||||||
installExtension(REDUX_DEVTOOLS.id).catch(err =>
|
installExtension(REDUX_DEVTOOLS.id).catch((err: any) =>
|
||||||
log.info('An error occurred: ', err)
|
log.info('An error occurred: ', err)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
this.win.webContents.openDevTools()
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
createWindow() {
|
||||||
win = null
|
const options: BrowserWindowConstructorOptions = {
|
||||||
if (process.platform !== 'darwin') app.quit()
|
title: 'YesPlayMusic',
|
||||||
})
|
webPreferences: {
|
||||||
|
preload: join(__dirname, 'rendererPreload.js'),
|
||||||
|
},
|
||||||
|
width: this.store.get('window.width'),
|
||||||
|
height: this.store.get('window.height'),
|
||||||
|
minWidth: 1080,
|
||||||
|
minHeight: 720,
|
||||||
|
vibrancy: 'fullscreen-ui',
|
||||||
|
titleBarStyle: 'hiddenInset',
|
||||||
|
frame: !(isWindows || isLinux), // TODO: 适用于linux下独立的启用开关
|
||||||
|
}
|
||||||
|
if (this.store.get('window')) {
|
||||||
|
options.x = this.store.get('window.x')
|
||||||
|
options.y = this.store.get('window.y')
|
||||||
|
}
|
||||||
|
this.win = new BrowserWindow(options)
|
||||||
|
|
||||||
app.on('second-instance', () => {
|
// Web server
|
||||||
if (win) {
|
const url = `http://localhost:${process.env.ELECTRON_WEB_SERVER_PORT}`
|
||||||
// Focus on the main window if the user tried to open another
|
this.win.loadURL(url)
|
||||||
if (win.isMinimized()) win.restore()
|
|
||||||
win.focus()
|
// Make all links open with the browser, not with the application
|
||||||
|
this.win.webContents.setWindowOpenHandler(({ url }) => {
|
||||||
|
if (url.startsWith('https:')) shell.openExternal(url)
|
||||||
|
return { action: 'deny' }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
handleWindowEvents() {
|
||||||
const allWindows = BrowserWindow.getAllWindows()
|
if (!this.win) return
|
||||||
if (allWindows.length) {
|
|
||||||
allWindows[0].focus()
|
// Window maximize and minimize
|
||||||
} else {
|
this.win.on('maximize', () => {
|
||||||
createWindow()
|
this.win && this.win.webContents.send('is-maximized', true)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.win.on('unmaximize', () => {
|
||||||
|
this.win && this.win.webContents.send('is-maximized', false)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Save window position
|
||||||
|
const saveBounds = () => {
|
||||||
|
const bounds = this.win?.getBounds()
|
||||||
|
if (bounds) {
|
||||||
|
this.store.set('window', bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.win.on('resized', saveBounds)
|
||||||
|
this.win.on('moved', saveBounds)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const handleWindowEvents = () => {
|
handleAppEvents() {
|
||||||
win?.on('maximize', () => {
|
app.on('window-all-closed', () => {
|
||||||
win?.webContents.send('is-maximized', true)
|
this.win = null
|
||||||
})
|
if (process.platform !== 'darwin') app.quit()
|
||||||
|
})
|
||||||
|
|
||||||
win?.on('unmaximize', () => {
|
app.on('second-instance', () => {
|
||||||
win?.webContents.send('is-maximized', false)
|
if (!this.win) return
|
||||||
})
|
// Focus on the main window if the user tried to open another
|
||||||
|
if (this.win.isMinimized()) this.win.restore()
|
||||||
|
this.win.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
const allWindows = BrowserWindow.getAllWindows()
|
||||||
|
if (allWindows.length) {
|
||||||
|
allWindows[0].focus()
|
||||||
|
} else {
|
||||||
|
this.createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new Main()
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,33 @@
|
||||||
import { BrowserWindow, ipcMain, app } from 'electron'
|
import { BrowserWindow, ipcMain, app } from 'electron'
|
||||||
import { db, Tables } from './db'
|
import { db, Tables } from './db'
|
||||||
import { IpcChannels } from './IpcChannelsName'
|
import { IpcChannels, IpcChannelsParams } from '../shared/IpcChannels'
|
||||||
import cache from './cache'
|
import cache from './cache'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { APIs } from './CacheAPIsName'
|
import { APIs } from '../shared/CacheAPIs'
|
||||||
|
|
||||||
|
const on = <T extends keyof IpcChannelsParams>(
|
||||||
|
channel: T,
|
||||||
|
listener: (event: Electron.IpcMainEvent, params: IpcChannelsParams[T]) => void
|
||||||
|
) => {
|
||||||
|
ipcMain.on(channel, listener)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理需要win对象的事件
|
* 处理需要win对象的事件
|
||||||
* @param {BrowserWindow} win
|
* @param {BrowserWindow} win
|
||||||
*/
|
*/
|
||||||
export function initIpcMain(win: BrowserWindow | null) {
|
export function initIpcMain(win: BrowserWindow | null) {
|
||||||
ipcMain.on(IpcChannels.Minimize, () => {
|
on(IpcChannels.Minimize, () => {
|
||||||
win?.minimize()
|
win?.minimize()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on(IpcChannels.MaximizeOrUnmaximize, () => {
|
on(IpcChannels.MaximizeOrUnmaximize, () => {
|
||||||
if (!win) return
|
if (!win) return
|
||||||
win.isMaximized() ? win.unmaximize() : win.maximize()
|
win.isMaximized() ? win.unmaximize() : win.maximize()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on(IpcChannels.Close, () => {
|
on(IpcChannels.Close, () => {
|
||||||
app.exit()
|
app.exit()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +35,7 @@ export function initIpcMain(win: BrowserWindow | null) {
|
||||||
/**
|
/**
|
||||||
* 清除API缓存
|
* 清除API缓存
|
||||||
*/
|
*/
|
||||||
ipcMain.on(IpcChannels.ClearAPICache, () => {
|
on(IpcChannels.ClearAPICache, () => {
|
||||||
db.truncate(Tables.Track)
|
db.truncate(Tables.Track)
|
||||||
db.truncate(Tables.Album)
|
db.truncate(Tables.Album)
|
||||||
db.truncate(Tables.Artist)
|
db.truncate(Tables.Artist)
|
||||||
|
|
@ -42,7 +49,7 @@ ipcMain.on(IpcChannels.ClearAPICache, () => {
|
||||||
/**
|
/**
|
||||||
* Get API cache
|
* Get API cache
|
||||||
*/
|
*/
|
||||||
ipcMain.on(IpcChannels.GetApiCacheSync, (event, args) => {
|
on(IpcChannels.GetApiCacheSync, (event, args) => {
|
||||||
const { api, query } = args
|
const { api, query } = args
|
||||||
const data = cache.get(api, query)
|
const data = cache.get(api, query)
|
||||||
event.returnValue = data
|
event.returnValue = data
|
||||||
|
|
@ -51,8 +58,8 @@ ipcMain.on(IpcChannels.GetApiCacheSync, (event, args) => {
|
||||||
/**
|
/**
|
||||||
* 缓存封面颜色
|
* 缓存封面颜色
|
||||||
*/
|
*/
|
||||||
ipcMain.on(IpcChannels.CacheCoverColor, (event, args) => {
|
on(IpcChannels.CacheCoverColor, (event, args) => {
|
||||||
const { id, color } = args.query
|
const { id, color } = args
|
||||||
cache.set(APIs.CoverColor, { id, color })
|
cache.set(APIs.CoverColor, { id, color })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -60,7 +67,7 @@ ipcMain.on(IpcChannels.CacheCoverColor, (event, args) => {
|
||||||
* 导出tables到json文件,方便查看table大小(dev环境)
|
* 导出tables到json文件,方便查看table大小(dev环境)
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
ipcMain.on(IpcChannels.DevDbExportJson, () => {
|
on(IpcChannels.DevDbExportJson, () => {
|
||||||
const tables = [
|
const tables = [
|
||||||
Tables.ArtistAlbum,
|
Tables.ArtistAlbum,
|
||||||
Tables.Playlist,
|
Tables.Playlist,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
const { contextBridge, ipcRenderer } = require('electron')
|
const { contextBridge, ipcRenderer } = require('electron')
|
||||||
const log = require('electron-log')
|
const log = require('electron-log')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,92 +6,119 @@ import cache from './cache'
|
||||||
import fileUpload from 'express-fileupload'
|
import fileUpload from 'express-fileupload'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
log.info('[server] starting http server')
|
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === 'development'
|
const isDev = process.env.NODE_ENV === 'development'
|
||||||
const isProd = process.env.NODE_ENV === 'production'
|
const isProd = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
class Server {
|
||||||
const neteaseApi = require('NeteaseCloudMusicApi') as (params: any) => any[]
|
port = Number(
|
||||||
|
isProd
|
||||||
|
? process.env.ELECTRON_WEB_SERVER_PORT ?? 42710
|
||||||
|
: process.env.ELECTRON_DEV_NETEASE_API_PORT ?? 3000
|
||||||
|
)
|
||||||
|
app = express()
|
||||||
|
|
||||||
const app = express()
|
constructor() {
|
||||||
app.use(cookieParser())
|
log.info('[server] starting http server')
|
||||||
app.use(fileUpload())
|
this.app.use(cookieParser())
|
||||||
|
this.app.use(fileUpload())
|
||||||
|
this.neteaseHandler()
|
||||||
|
this.cacheAudioHandler()
|
||||||
|
this.serveStaticForProd()
|
||||||
|
this.listen()
|
||||||
|
}
|
||||||
|
|
||||||
Object.entries(neteaseApi).forEach(([name, handler]) => {
|
neteaseHandler() {
|
||||||
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) return
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const neteaseApi = require('NeteaseCloudMusicApi') as (params: any) => any[]
|
||||||
|
|
||||||
name = pathCase(name)
|
Object.entries(neteaseApi).forEach(([name, handler]) => {
|
||||||
|
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) return
|
||||||
|
|
||||||
const wrappedHandler = async (req: Request, res: Response) => {
|
name = pathCase(name)
|
||||||
log.debug(`[server] Handling request: ${req.path}`)
|
|
||||||
|
|
||||||
// Get from cache
|
const wrappedHandler = async (req: Request, res: Response) => {
|
||||||
const cacheData = await cache.getForExpress(name, req)
|
log.debug(`[server] Handling request: ${req.path}`)
|
||||||
if (cacheData) return res.json(cacheData)
|
|
||||||
|
|
||||||
// Request netease api
|
// Get from cache
|
||||||
try {
|
const cacheData = await cache.getForExpress(name, req)
|
||||||
const result = await handler({
|
if (cacheData) return res.json(cacheData)
|
||||||
...req.query,
|
|
||||||
cookie: req.cookies,
|
|
||||||
})
|
|
||||||
|
|
||||||
cache.set(name, result.body, req.query)
|
// Request netease api
|
||||||
return res.send(result.body)
|
try {
|
||||||
} catch (error) {
|
const result = await handler({
|
||||||
return res.status(500).send(error)
|
...req.query,
|
||||||
|
cookie: req.cookies,
|
||||||
|
})
|
||||||
|
|
||||||
|
cache.set(name, result.body, req.query)
|
||||||
|
return res.send(result.body)
|
||||||
|
} catch (error: any) {
|
||||||
|
if ([400, 301].includes(error.status)) {
|
||||||
|
return res.status(error.status).send(error.body)
|
||||||
|
}
|
||||||
|
return res.status(500).send(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.app.get(`/netease/${name}`, wrappedHandler)
|
||||||
|
this.app.post(`/netease/${name}`, wrappedHandler)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
serveStaticForProd() {
|
||||||
|
if (isProd) {
|
||||||
|
this.app.use('/', express.static(path.join(__dirname, '../renderer/')))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get(`/netease/${name}`, wrappedHandler)
|
cacheAudioHandler() {
|
||||||
app.post(`/netease/${name}`, wrappedHandler)
|
this.app.get(
|
||||||
})
|
'/yesplaymusic/audio/:filename',
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
cache.getAudio(req.params.filename, res)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.app.post(
|
||||||
|
'/yesplaymusic/audio/:id',
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
const id = Number(req.params.id)
|
||||||
|
const { url } = req.query
|
||||||
|
if (isNaN(id)) {
|
||||||
|
return res.status(400).send({ error: 'Invalid param id' })
|
||||||
|
}
|
||||||
|
if (!url) {
|
||||||
|
return res.status(400).send({ error: 'Invalid query url' })
|
||||||
|
}
|
||||||
|
|
||||||
// Cache audio
|
if (
|
||||||
app.get(
|
!req.files ||
|
||||||
'/yesplaymusic/audio/:filename',
|
Object.keys(req.files).length === 0 ||
|
||||||
async (req: Request, res: Response) => {
|
!req.files.file
|
||||||
cache.getAudio(req.params.filename, res)
|
) {
|
||||||
}
|
return res.status(400).send('No audio were uploaded.')
|
||||||
)
|
}
|
||||||
app.post('/yesplaymusic/audio/:id', async (req: Request, res: Response) => {
|
if ('length' in req.files.file) {
|
||||||
const id = Number(req.params.id)
|
return res.status(400).send('Only can upload one audio at a time.')
|
||||||
const { url } = req.query
|
}
|
||||||
if (isNaN(id)) {
|
|
||||||
return res.status(400).send({ error: 'Invalid param id' })
|
try {
|
||||||
}
|
await cache.setAudio(req.files.file.data, {
|
||||||
if (!url) {
|
id: id,
|
||||||
return res.status(400).send({ error: 'Invalid query url' })
|
source: 'netease',
|
||||||
|
})
|
||||||
|
res.status(200).send('Audio cached!')
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).send({ error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.files || Object.keys(req.files).length === 0 || !req.files.file) {
|
listen() {
|
||||||
return res.status(400).send('No audio were uploaded.')
|
this.app.listen(this.port, () => {
|
||||||
}
|
log.info(`[server] API server listening on port ${this.port}`)
|
||||||
if ('length' in req.files.file) {
|
|
||||||
return res.status(400).send('Only can upload one audio at a time.')
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await cache.setAudio(req.files.file.data, {
|
|
||||||
id: id,
|
|
||||||
source: 'netease',
|
|
||||||
})
|
})
|
||||||
res.status(200).send('Audio cached!')
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).send({ error })
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if (isProd) {
|
|
||||||
app.use('/', express.static(path.join(__dirname, '../renderer/')))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = Number(
|
export default new Server()
|
||||||
isProd
|
|
||||||
? process.env.ELECTRON_WEB_SERVER_PORT ?? 42710
|
|
||||||
: process.env.ELECTRON_DEV_NETEASE_API_PORT ?? 3000
|
|
||||||
)
|
|
||||||
app.listen(port, () => {
|
|
||||||
log.info(`[server] API server listening on port ${port}`)
|
|
||||||
})
|
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,5 @@
|
||||||
"@/*": ["../*"]
|
"@/*": ["../*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["./**/*.ts"]
|
"include": ["./**/*.ts", "../shared/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,12 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum AlbumApiNames {
|
FetchAlbumParams,
|
||||||
FETCH_ALBUM = 'fetchAlbum',
|
FetchAlbumResponse,
|
||||||
}
|
LikeAAlbumParams,
|
||||||
|
LikeAAlbumResponse,
|
||||||
|
} from '@/shared/api/Album'
|
||||||
|
|
||||||
// 专辑详情
|
// 专辑详情
|
||||||
export interface FetchAlbumParams {
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
export interface FetchAlbumResponse {
|
|
||||||
code: number
|
|
||||||
resourceState: boolean
|
|
||||||
album: Album
|
|
||||||
songs: Track[]
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
export function fetchAlbum(
|
export function fetchAlbum(
|
||||||
params: FetchAlbumParams,
|
params: FetchAlbumParams,
|
||||||
noCache: boolean
|
noCache: boolean
|
||||||
|
|
@ -28,13 +20,6 @@ export function fetchAlbum(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LikeAAlbumParams {
|
|
||||||
t: 1 | 2
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
export interface LikeAAlbumResponse {
|
|
||||||
code: number
|
|
||||||
}
|
|
||||||
export function likeAAlbum(
|
export function likeAAlbum(
|
||||||
params: LikeAAlbumParams
|
params: LikeAAlbumParams
|
||||||
): Promise<LikeAAlbumResponse> {
|
): Promise<LikeAAlbumResponse> {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,12 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum ArtistApiNames {
|
FetchArtistParams,
|
||||||
FETCH_ARTIST = 'fetchArtist',
|
FetchArtistResponse,
|
||||||
FETCH_ARTIST_ALBUMS = 'fetchArtistAlbums',
|
FetchArtistAlbumsParams,
|
||||||
}
|
FetchArtistAlbumsResponse,
|
||||||
|
} from '@/shared/api/Artist'
|
||||||
|
|
||||||
// 歌手详情
|
// 歌手详情
|
||||||
export interface FetchArtistParams {
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
export interface FetchArtistResponse {
|
|
||||||
code: number
|
|
||||||
more: boolean
|
|
||||||
artist: Artist
|
|
||||||
hotSongs: Track[]
|
|
||||||
}
|
|
||||||
export function fetchArtist(
|
export function fetchArtist(
|
||||||
params: FetchArtistParams,
|
params: FetchArtistParams,
|
||||||
noCache: boolean
|
noCache: boolean
|
||||||
|
|
@ -29,17 +21,6 @@ export function fetchArtist(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取歌手的专辑列表
|
// 获取歌手的专辑列表
|
||||||
export interface FetchArtistAlbumsParams {
|
|
||||||
id: number
|
|
||||||
limit?: number // default: 50
|
|
||||||
offset?: number // default: 0
|
|
||||||
}
|
|
||||||
export interface FetchArtistAlbumsResponse {
|
|
||||||
code: number
|
|
||||||
hotAlbums: Album[]
|
|
||||||
more: boolean
|
|
||||||
artist: Artist
|
|
||||||
}
|
|
||||||
export function fetchArtistAlbums(
|
export function fetchArtistAlbums(
|
||||||
params: FetchArtistAlbumsParams
|
params: FetchArtistAlbumsParams
|
||||||
): Promise<FetchArtistAlbumsResponse> {
|
): Promise<FetchArtistAlbumsResponse> {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { fetchUserAccountResponse } from '@/renderer/api/user'
|
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import { FetchUserAccountResponse } from '@/shared/api/User'
|
||||||
|
|
||||||
// 手机号登录
|
// 手机号登录
|
||||||
interface LoginWithPhoneParams {
|
interface LoginWithPhoneParams {
|
||||||
|
|
@ -30,7 +30,7 @@ export interface LoginWithEmailParams {
|
||||||
password?: string
|
password?: string
|
||||||
md5_password?: string
|
md5_password?: string
|
||||||
}
|
}
|
||||||
export interface loginWithEmailResponse extends fetchUserAccountResponse {
|
export interface loginWithEmailResponse extends FetchUserAccountResponse {
|
||||||
code: number
|
code: number
|
||||||
cookie: string
|
cookie: string
|
||||||
loginType: number
|
loginType: number
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,15 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum PlaylistApiNames {
|
FetchPlaylistParams,
|
||||||
FETCH_PLAYLIST = 'fetchPlaylist',
|
FetchPlaylistResponse,
|
||||||
FETCH_RECOMMENDED_PLAYLISTS = 'fetchRecommendedPlaylists',
|
FetchRecommendedPlaylistsParams,
|
||||||
FETCH_DAILY_RECOMMEND_PLAYLISTS = 'fetchDailyRecommendPlaylists',
|
FetchRecommendedPlaylistsResponse,
|
||||||
LIKE_A_PLAYLIST = 'likeAPlaylist',
|
FetchDailyRecommendPlaylistsResponse,
|
||||||
}
|
LikeAPlaylistParams,
|
||||||
|
LikeAPlaylistResponse,
|
||||||
|
} from '@/shared/api/Playlists'
|
||||||
|
|
||||||
// 歌单详情
|
// 歌单详情
|
||||||
export interface FetchPlaylistParams {
|
|
||||||
id: number
|
|
||||||
s?: number // 歌单最近的 s 个收藏者
|
|
||||||
}
|
|
||||||
export interface FetchPlaylistResponse {
|
|
||||||
code: number
|
|
||||||
playlist: Playlist
|
|
||||||
privileges: unknown // TODO: unknown type
|
|
||||||
relatedVideos: null
|
|
||||||
resEntrance: null
|
|
||||||
sharedPrivilege: null
|
|
||||||
urls: null
|
|
||||||
}
|
|
||||||
export function fetchPlaylist(
|
export function fetchPlaylist(
|
||||||
params: FetchPlaylistParams,
|
params: FetchPlaylistParams,
|
||||||
noCache: boolean
|
noCache: boolean
|
||||||
|
|
@ -39,15 +28,6 @@ export function fetchPlaylist(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 推荐歌单
|
// 推荐歌单
|
||||||
interface FetchRecommendedPlaylistsParams {
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
export interface FetchRecommendedPlaylistsResponse {
|
|
||||||
code: number
|
|
||||||
category: number
|
|
||||||
hasTaste: boolean
|
|
||||||
result: Playlist[]
|
|
||||||
}
|
|
||||||
export function fetchRecommendedPlaylists(
|
export function fetchRecommendedPlaylists(
|
||||||
params: FetchRecommendedPlaylistsParams
|
params: FetchRecommendedPlaylistsParams
|
||||||
): Promise<FetchRecommendedPlaylistsResponse> {
|
): Promise<FetchRecommendedPlaylistsResponse> {
|
||||||
|
|
@ -59,12 +39,7 @@ export function fetchRecommendedPlaylists(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每日推荐歌单(需要登录)
|
// 每日推荐歌单(需要登录)
|
||||||
export interface FetchDailyRecommendPlaylistsResponse {
|
|
||||||
code: number
|
|
||||||
featureFirst: boolean
|
|
||||||
haveRcmdSongs: boolean
|
|
||||||
recommend: Playlist[]
|
|
||||||
}
|
|
||||||
export function fetchDailyRecommendPlaylists(): Promise<FetchDailyRecommendPlaylistsResponse> {
|
export function fetchDailyRecommendPlaylists(): Promise<FetchDailyRecommendPlaylistsResponse> {
|
||||||
return request({
|
return request({
|
||||||
url: '/recommend/resource',
|
url: '/recommend/resource',
|
||||||
|
|
@ -72,13 +47,6 @@ export function fetchDailyRecommendPlaylists(): Promise<FetchDailyRecommendPlayl
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LikeAPlaylistParams {
|
|
||||||
t: 1 | 2
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
export interface LikeAPlaylistResponse {
|
|
||||||
code: number
|
|
||||||
}
|
|
||||||
export function likeAPlaylist(
|
export function likeAPlaylist(
|
||||||
params: LikeAPlaylistParams
|
params: LikeAPlaylistParams
|
||||||
): Promise<LikeAPlaylistResponse> {
|
): Promise<LikeAPlaylistResponse> {
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,13 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum SearchApiNames {
|
SearchParams,
|
||||||
SEARCH = 'search',
|
SearchResponse,
|
||||||
MULTI_MATCH_SEARCH = 'multiMatchSearch',
|
SearchTypes,
|
||||||
}
|
MultiMatchSearchParams,
|
||||||
|
MultiMatchSearchResponse,
|
||||||
|
} from '@/shared/api/Search'
|
||||||
|
|
||||||
// 搜索
|
// 搜索
|
||||||
export enum SearchTypes {
|
|
||||||
SINGLE = '1',
|
|
||||||
ALBUM = '10',
|
|
||||||
ARTIST = '100',
|
|
||||||
PLAYLIST = '1000',
|
|
||||||
USER = '1002',
|
|
||||||
MV = '1004',
|
|
||||||
LYRICS = '1006',
|
|
||||||
RADIO = '1009',
|
|
||||||
VIDEO = '1014',
|
|
||||||
ALL = '1018',
|
|
||||||
}
|
|
||||||
export interface SearchParams {
|
|
||||||
keywords: string
|
|
||||||
limit?: number // 返回数量 , 默认为 30
|
|
||||||
offset?: number // 偏移数量,用于分页 , 如 : 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
|
||||||
type: keyof typeof SearchTypes // type: 搜索类型
|
|
||||||
}
|
|
||||||
interface SearchResponse {
|
|
||||||
code: number
|
|
||||||
result: {
|
|
||||||
album: {
|
|
||||||
albums: Album[]
|
|
||||||
more: boolean
|
|
||||||
moreText: string
|
|
||||||
resourceIds: number[]
|
|
||||||
}
|
|
||||||
artist: {
|
|
||||||
artists: Artist[]
|
|
||||||
more: boolean
|
|
||||||
moreText: string
|
|
||||||
resourceIds: number[]
|
|
||||||
}
|
|
||||||
playList: {
|
|
||||||
playLists: Playlist[]
|
|
||||||
more: boolean
|
|
||||||
moreText: string
|
|
||||||
resourceIds: number[]
|
|
||||||
}
|
|
||||||
song: {
|
|
||||||
songs: Track[]
|
|
||||||
more: boolean
|
|
||||||
moreText: string
|
|
||||||
resourceIds: number[]
|
|
||||||
}
|
|
||||||
user: {
|
|
||||||
users: User[]
|
|
||||||
more: boolean
|
|
||||||
moreText: string
|
|
||||||
resourceIds: number[]
|
|
||||||
}
|
|
||||||
circle: unknown
|
|
||||||
new_mlog: unknown
|
|
||||||
order: string[]
|
|
||||||
rec_type: null
|
|
||||||
rec_query: null[]
|
|
||||||
sim_query: unknown
|
|
||||||
voice: unknown
|
|
||||||
voiceList: unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function search(params: SearchParams): Promise<SearchResponse> {
|
export function search(params: SearchParams): Promise<SearchResponse> {
|
||||||
return request({
|
return request({
|
||||||
url: '/search',
|
url: '/search',
|
||||||
|
|
@ -79,19 +20,6 @@ export function search(params: SearchParams): Promise<SearchResponse> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索多重匹配
|
// 搜索多重匹配
|
||||||
export interface MultiMatchSearchParams {
|
|
||||||
keywords: string
|
|
||||||
}
|
|
||||||
interface MultiMatchSearchResponse {
|
|
||||||
code: number
|
|
||||||
result: {
|
|
||||||
album: Album[]
|
|
||||||
artist: Artist[]
|
|
||||||
playlist: Playlist[]
|
|
||||||
orpheus: unknown
|
|
||||||
orders: Array<'artist' | 'album'>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function multiMatchSearch(
|
export function multiMatchSearch(
|
||||||
params: MultiMatchSearchParams
|
params: MultiMatchSearchParams
|
||||||
): Promise<MultiMatchSearchResponse> {
|
): Promise<MultiMatchSearchResponse> {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,16 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum TrackApiNames {
|
FetchAudioSourceParams,
|
||||||
FETCH_TRACKS = 'fetchTracks',
|
FetchAudioSourceResponse,
|
||||||
FETCH_AUDIO_SOURCE = 'fetchAudioSource',
|
FetchLyricParams,
|
||||||
FETCH_LYRIC = 'fetchLyric',
|
FetchLyricResponse,
|
||||||
}
|
FetchTracksParams,
|
||||||
|
FetchTracksResponse,
|
||||||
|
LikeATrackParams,
|
||||||
|
LikeATrackResponse,
|
||||||
|
} from '@/shared/api/Track'
|
||||||
|
|
||||||
// 获取歌曲详情
|
// 获取歌曲详情
|
||||||
export interface FetchTracksParams {
|
|
||||||
ids: number[]
|
|
||||||
}
|
|
||||||
export interface FetchTracksResponse {
|
|
||||||
code: number
|
|
||||||
songs: Track[]
|
|
||||||
privileges: {
|
|
||||||
[key: string]: unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function fetchTracks(
|
export function fetchTracks(
|
||||||
params: FetchTracksParams
|
params: FetchTracksParams
|
||||||
): Promise<FetchTracksResponse> {
|
): Promise<FetchTracksResponse> {
|
||||||
|
|
@ -30,39 +24,6 @@ export function fetchTracks(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取音源URL
|
// 获取音源URL
|
||||||
export interface FetchAudioSourceParams {
|
|
||||||
id: number
|
|
||||||
br?: number // bitrate, default 999000,320000 = 320kbps
|
|
||||||
}
|
|
||||||
export interface FetchAudioSourceResponse {
|
|
||||||
code: number
|
|
||||||
data: {
|
|
||||||
br: number
|
|
||||||
canExtend: boolean
|
|
||||||
code: number
|
|
||||||
encodeType: 'mp3' | null
|
|
||||||
expi: number
|
|
||||||
fee: number
|
|
||||||
flag: number
|
|
||||||
freeTimeTrialPrivilege: {
|
|
||||||
[key: string]: unknown
|
|
||||||
}
|
|
||||||
freeTrialPrivilege: {
|
|
||||||
[key: string]: unknown
|
|
||||||
}
|
|
||||||
freeTrialInfo: null
|
|
||||||
gain: number
|
|
||||||
id: number
|
|
||||||
level: 'standard' | 'null'
|
|
||||||
md5: string | null
|
|
||||||
payed: number
|
|
||||||
size: number
|
|
||||||
type: 'mp3' | null
|
|
||||||
uf: null
|
|
||||||
url: string | null
|
|
||||||
urlSource: number
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
export function fetchAudioSource(
|
export function fetchAudioSource(
|
||||||
params: FetchAudioSourceParams
|
params: FetchAudioSourceParams
|
||||||
): Promise<FetchAudioSourceResponse> {
|
): Promise<FetchAudioSourceResponse> {
|
||||||
|
|
@ -74,43 +35,6 @@ export function fetchAudioSource(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取歌词
|
// 获取歌词
|
||||||
export interface FetchLyricParams {
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
export interface FetchLyricResponse {
|
|
||||||
code: number
|
|
||||||
sgc: boolean
|
|
||||||
sfy: boolean
|
|
||||||
qfy: boolean
|
|
||||||
lyricUser?: {
|
|
||||||
id: number
|
|
||||||
status: number
|
|
||||||
demand: number
|
|
||||||
userid: number
|
|
||||||
nickname: string
|
|
||||||
uptime: number
|
|
||||||
}
|
|
||||||
transUser?: {
|
|
||||||
id: number
|
|
||||||
status: number
|
|
||||||
demand: number
|
|
||||||
userid: number
|
|
||||||
nickname: string
|
|
||||||
uptime: number
|
|
||||||
}
|
|
||||||
lrc: {
|
|
||||||
version: number
|
|
||||||
lyric: string
|
|
||||||
}
|
|
||||||
klyric?: {
|
|
||||||
version: number
|
|
||||||
lyric: string
|
|
||||||
}
|
|
||||||
tlyric?: {
|
|
||||||
version: number
|
|
||||||
lyric: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function fetchLyric(
|
export function fetchLyric(
|
||||||
params: FetchLyricParams
|
params: FetchLyricParams
|
||||||
): Promise<FetchLyricResponse> {
|
): Promise<FetchLyricResponse> {
|
||||||
|
|
@ -121,15 +45,7 @@ export function fetchLyric(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LikeATrackParams {
|
// 收藏歌曲
|
||||||
id: number
|
|
||||||
like: boolean
|
|
||||||
}
|
|
||||||
export interface LikeATrackResponse {
|
|
||||||
code: number
|
|
||||||
playlistId: number
|
|
||||||
songs: Track[]
|
|
||||||
}
|
|
||||||
export function likeATrack(
|
export function likeATrack(
|
||||||
params: LikeATrackParams
|
params: LikeATrackParams
|
||||||
): Promise<LikeATrackResponse> {
|
): Promise<LikeATrackResponse> {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import request from '@/renderer/utils/request'
|
import request from '@/renderer/utils/request'
|
||||||
|
import {
|
||||||
export enum UserApiNames {
|
FetchUserAccountResponse,
|
||||||
FETCH_USER_ACCOUNT = 'fetchUserAccount',
|
FetchUserPlaylistsParams,
|
||||||
FETCH_USER_LIKED_TRACKS_IDS = 'fetchUserLikedTracksIDs',
|
FetchUserPlaylistsResponse,
|
||||||
FETCH_USER_PLAYLISTS = 'fetchUserPlaylists',
|
FetchUserLikedTracksIDsParams,
|
||||||
FETCH_USER_ALBUMS = 'fetchUserAlbums',
|
FetchUserLikedTracksIDsResponse,
|
||||||
FETCH_USER_ARTIST = 'fetchUserArtists',
|
FetchUserAlbumsParams,
|
||||||
}
|
FetchUserAlbumsResponse,
|
||||||
|
FetchUserArtistsResponse,
|
||||||
|
} from '@/shared/api/User'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户详情
|
* 获取用户详情
|
||||||
|
|
@ -26,64 +28,7 @@ export function userDetail(uid: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取账号详情
|
// 获取账号详情
|
||||||
export interface fetchUserAccountResponse {
|
export function fetchUserAccount(): Promise<FetchUserAccountResponse> {
|
||||||
code: number
|
|
||||||
account: {
|
|
||||||
anonimousUser: boolean
|
|
||||||
ban: number
|
|
||||||
baoyueVersion: number
|
|
||||||
createTime: number
|
|
||||||
donateVersion: number
|
|
||||||
id: number
|
|
||||||
paidFee: boolean
|
|
||||||
status: number
|
|
||||||
tokenVersion: number
|
|
||||||
type: number
|
|
||||||
userName: string
|
|
||||||
vipType: number
|
|
||||||
whitelistAuthority: number
|
|
||||||
} | null
|
|
||||||
profile: {
|
|
||||||
userId: number
|
|
||||||
userType: number
|
|
||||||
nickname: string
|
|
||||||
avatarImgId: number
|
|
||||||
avatarUrl: string
|
|
||||||
backgroundImgId: number
|
|
||||||
backgroundUrl: string
|
|
||||||
signature: string
|
|
||||||
createTime: number
|
|
||||||
userName: string
|
|
||||||
accountType: number
|
|
||||||
shortUserName: string
|
|
||||||
birthday: number
|
|
||||||
authority: number
|
|
||||||
gender: number
|
|
||||||
accountStatus: number
|
|
||||||
province: number
|
|
||||||
city: number
|
|
||||||
authStatus: number
|
|
||||||
description: string | null
|
|
||||||
detailDescription: string | null
|
|
||||||
defaultAvatar: boolean
|
|
||||||
expertTags: [] | null
|
|
||||||
experts: [] | null
|
|
||||||
djStatus: number
|
|
||||||
locationStatus: number
|
|
||||||
vipType: number
|
|
||||||
followed: boolean
|
|
||||||
mutual: boolean
|
|
||||||
authenticated: boolean
|
|
||||||
lastLoginTime: number
|
|
||||||
lastLoginIP: string
|
|
||||||
remarkName: string | null
|
|
||||||
viptypeVersion: number
|
|
||||||
authenticationTypes: number
|
|
||||||
avatarDetail: string | null
|
|
||||||
anchor: boolean
|
|
||||||
} | null
|
|
||||||
}
|
|
||||||
export function fetchUserAccount(): Promise<fetchUserAccountResponse> {
|
|
||||||
return request({
|
return request({
|
||||||
url: '/user/account',
|
url: '/user/account',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|
@ -94,17 +39,6 @@ export function fetchUserAccount(): Promise<fetchUserAccountResponse> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户歌单
|
// 获取用户歌单
|
||||||
export interface FetchUserPlaylistsParams {
|
|
||||||
uid: number
|
|
||||||
offset: number
|
|
||||||
limit?: number // default 30
|
|
||||||
}
|
|
||||||
export interface FetchUserPlaylistsResponse {
|
|
||||||
code: number
|
|
||||||
more: boolean
|
|
||||||
version: string
|
|
||||||
playlist: Playlist[]
|
|
||||||
}
|
|
||||||
export function fetchUserPlaylists(
|
export function fetchUserPlaylists(
|
||||||
params: FetchUserPlaylistsParams
|
params: FetchUserPlaylistsParams
|
||||||
): Promise<FetchUserPlaylistsResponse> {
|
): Promise<FetchUserPlaylistsResponse> {
|
||||||
|
|
@ -115,14 +49,6 @@ export function fetchUserPlaylists(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchUserLikedTracksIDsParams {
|
|
||||||
uid: number
|
|
||||||
}
|
|
||||||
export interface FetchUserLikedTracksIDsResponse {
|
|
||||||
code: number
|
|
||||||
checkPoint: number
|
|
||||||
ids: number[]
|
|
||||||
}
|
|
||||||
export function fetchUserLikedTracksIDs(
|
export function fetchUserLikedTracksIDs(
|
||||||
params: FetchUserLikedTracksIDsParams
|
params: FetchUserLikedTracksIDsParams
|
||||||
): Promise<FetchUserLikedTracksIDsResponse> {
|
): Promise<FetchUserLikedTracksIDsResponse> {
|
||||||
|
|
@ -153,17 +79,6 @@ export function dailySignin(type = 0) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchUserAlbumsParams {
|
|
||||||
offset?: number // default 0
|
|
||||||
limit?: number // default 25
|
|
||||||
}
|
|
||||||
export interface FetchUserAlbumsResponse {
|
|
||||||
code: number
|
|
||||||
hasMore: boolean
|
|
||||||
paidCount: number
|
|
||||||
count: number
|
|
||||||
data: Album[]
|
|
||||||
}
|
|
||||||
export function fetchUserAlbums(
|
export function fetchUserAlbums(
|
||||||
params: FetchUserAlbumsParams
|
params: FetchUserAlbumsParams
|
||||||
): Promise<FetchUserAlbumsResponse> {
|
): Promise<FetchUserAlbumsResponse> {
|
||||||
|
|
@ -178,12 +93,6 @@ export function fetchUserAlbums(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取收藏的歌手
|
// 获取收藏的歌手
|
||||||
export interface FetchUserArtistsResponse {
|
|
||||||
code: number
|
|
||||||
hasMore: boolean
|
|
||||||
count: number
|
|
||||||
data: Artist[]
|
|
||||||
}
|
|
||||||
export function fetchUserArtists(): Promise<FetchUserArtistsResponse> {
|
export function fetchUserArtists(): Promise<FetchUserArtistsResponse> {
|
||||||
return request({
|
return request({
|
||||||
url: '/artist/sublist',
|
url: '/artist/sublist',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { player } from '@/renderer/store'
|
import { player } from '@/renderer/store'
|
||||||
import SvgIcon from './SvgIcon'
|
import SvgIcon from './SvgIcon'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
|
||||||
const Controls = () => {
|
const Controls = () => {
|
||||||
const [isMaximized, setIsMaximized] = useState(false)
|
const [isMaximized, setIsMaximized] = useState(false)
|
||||||
|
|
|
||||||
22
src/renderer/global.d.ts
vendored
22
src/renderer/global.d.ts
vendored
|
|
@ -1,17 +1,25 @@
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannelsParams, IpcChannelsReturns } from '@/shared/IpcChannels'
|
||||||
import { ElectronLog } from 'electron-log'
|
import { ElectronLog } from 'electron-log'
|
||||||
|
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
// Expose some Api through preload script
|
|
||||||
ipcRenderer?: {
|
ipcRenderer?: {
|
||||||
sendSync: (channel: IpcChannels, ...args: any[]) => any
|
sendSync: <T extends keyof IpcChannelsParams>(
|
||||||
send: (channel: IpcChannels, ...args: any[]) => void
|
channel: T,
|
||||||
on: (
|
params?: IpcChannelsParams[T]
|
||||||
channel: IpcChannels,
|
) => IpcChannelsReturns[T]
|
||||||
listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void
|
send: <T extends keyof IpcChannelsParams>(
|
||||||
|
channel: T,
|
||||||
|
params?: IpcChannelsParams[T]
|
||||||
|
) => void
|
||||||
|
on: <T extends keyof IpcChannelsParams>(
|
||||||
|
channel: T,
|
||||||
|
listener: (
|
||||||
|
event: Electron.IpcRendererEvent,
|
||||||
|
value: IpcChannelsReturns[T]
|
||||||
|
) => void
|
||||||
) => void
|
) => void
|
||||||
}
|
}
|
||||||
env?: {
|
env?: {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
import { fetchAlbum } from '@/renderer/api/album'
|
import { fetchAlbum } from '@/renderer/api/album'
|
||||||
import { AlbumApiNames } from '@/renderer/api/album'
|
|
||||||
import type { FetchAlbumParams, FetchAlbumResponse } from '@/renderer/api/album'
|
|
||||||
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import {
|
||||||
|
FetchAlbumParams,
|
||||||
|
AlbumApiNames,
|
||||||
|
FetchAlbumResponse,
|
||||||
|
} from '@/shared/api/Album'
|
||||||
|
|
||||||
const fetch = async (params: FetchAlbumParams, noCache?: boolean) => {
|
const fetch = async (params: FetchAlbumParams, noCache?: boolean) => {
|
||||||
const album = await fetchAlbum(params, !!noCache)
|
const album = await fetchAlbum(params, !!noCache)
|
||||||
|
|
@ -21,7 +25,7 @@ export default function useAlbum(params: FetchAlbumParams, noCache?: boolean) {
|
||||||
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
placeholderData: (): FetchAlbumResponse =>
|
placeholderData: (): FetchAlbumResponse =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'album',
|
api: APIs.Album,
|
||||||
query: {
|
query: {
|
||||||
id: params.id,
|
id: params.id,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { fetchArtist } from '@/renderer/api/artist'
|
import { fetchArtist } from '@/renderer/api/artist'
|
||||||
import { ArtistApiNames } from '@/renderer/api/artist'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import type {
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import {
|
||||||
FetchArtistParams,
|
FetchArtistParams,
|
||||||
|
ArtistApiNames,
|
||||||
FetchArtistResponse,
|
FetchArtistResponse,
|
||||||
} from '@/renderer/api/artist'
|
} from '@/shared/api/Artist'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
|
||||||
|
|
||||||
export default function useArtist(
|
export default function useArtist(
|
||||||
params: FetchArtistParams,
|
params: FetchArtistParams,
|
||||||
|
|
@ -18,7 +19,7 @@ export default function useArtist(
|
||||||
staleTime: 5 * 60 * 1000, // 5 mins
|
staleTime: 5 * 60 * 1000, // 5 mins
|
||||||
placeholderData: (): FetchArtistResponse =>
|
placeholderData: (): FetchArtistResponse =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'artists',
|
api: APIs.Artist,
|
||||||
query: {
|
query: {
|
||||||
id: params.id,
|
id: params.id,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { fetchArtistAlbums } from '@/renderer/api/artist'
|
import { fetchArtistAlbums } from '@/renderer/api/artist'
|
||||||
import { ArtistApiNames } from '@/renderer/api/artist'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import type {
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import {
|
||||||
FetchArtistAlbumsParams,
|
FetchArtistAlbumsParams,
|
||||||
|
ArtistApiNames,
|
||||||
FetchArtistAlbumsResponse,
|
FetchArtistAlbumsResponse,
|
||||||
} from '@/renderer/api/artist'
|
} from '@/shared/api/Artist'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
|
||||||
|
|
||||||
export default function useUserAlbums(params: FetchArtistAlbumsParams) {
|
export default function useUserAlbums(params: FetchArtistAlbumsParams) {
|
||||||
return useQuery(
|
return useQuery(
|
||||||
|
|
@ -18,7 +19,7 @@ export default function useUserAlbums(params: FetchArtistAlbumsParams) {
|
||||||
staleTime: 3600000,
|
staleTime: 3600000,
|
||||||
placeholderData: (): FetchArtistAlbumsResponse =>
|
placeholderData: (): FetchArtistAlbumsResponse =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'artist/album',
|
api: APIs.ArtistAlbum,
|
||||||
query: {
|
query: {
|
||||||
id: params.id,
|
id: params.id,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
import { TrackApiNames, fetchLyric } from '@/renderer/api/track'
|
import { fetchLyric } from '@/renderer/api/track'
|
||||||
import type { FetchLyricParams, FetchLyricResponse } from '@/renderer/api/track'
|
|
||||||
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import {
|
||||||
|
FetchLyricParams,
|
||||||
|
FetchLyricResponse,
|
||||||
|
TrackApiNames,
|
||||||
|
} from '@/shared/api/Track'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
|
||||||
export default function useLyric(params: FetchLyricParams) {
|
export default function useLyric(params: FetchLyricParams) {
|
||||||
return useQuery(
|
return useQuery(
|
||||||
|
|
@ -15,7 +20,7 @@ export default function useLyric(params: FetchLyricParams) {
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
initialData: (): FetchLyricResponse | undefined =>
|
initialData: (): FetchLyricResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'lyric',
|
api: APIs.Lyric,
|
||||||
query: {
|
query: {
|
||||||
id: params.id,
|
id: params.id,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { fetchPlaylist } from '@/renderer/api/playlist'
|
import { fetchPlaylist } from '@/renderer/api/playlist'
|
||||||
import { PlaylistApiNames } from '@/renderer/api/playlist'
|
|
||||||
import type {
|
|
||||||
FetchPlaylistParams,
|
|
||||||
FetchPlaylistResponse,
|
|
||||||
} from '@/renderer/api/playlist'
|
|
||||||
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import {
|
||||||
|
FetchPlaylistParams,
|
||||||
|
PlaylistApiNames,
|
||||||
|
FetchPlaylistResponse,
|
||||||
|
} from '@/shared/api/Playlists'
|
||||||
|
|
||||||
const fetch = (params: FetchPlaylistParams, noCache?: boolean) => {
|
const fetch = (params: FetchPlaylistParams, noCache?: boolean) => {
|
||||||
return fetchPlaylist(params, !!noCache)
|
return fetchPlaylist(params, !!noCache)
|
||||||
|
|
@ -23,7 +24,7 @@ export default function usePlaylist(
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): FetchPlaylistResponse | undefined =>
|
placeholderData: (): FetchPlaylistResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'playlist/detail',
|
api: APIs.Playlist,
|
||||||
query: {
|
query: {
|
||||||
id: params.id,
|
id: params.id,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
|
import { fetchAudioSource, fetchTracks } from '@/renderer/api/track'
|
||||||
|
import type {} from '@/renderer/api/track'
|
||||||
|
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import {
|
import {
|
||||||
TrackApiNames,
|
|
||||||
fetchAudioSource,
|
|
||||||
fetchTracks,
|
|
||||||
} from '@/renderer/api/track'
|
|
||||||
import type {
|
|
||||||
FetchAudioSourceParams,
|
FetchAudioSourceParams,
|
||||||
FetchTracksParams,
|
FetchTracksParams,
|
||||||
FetchTracksResponse,
|
FetchTracksResponse,
|
||||||
} from '@/renderer/api/track'
|
TrackApiNames,
|
||||||
import reactQueryClient from '@/renderer/utils/reactQueryClient'
|
} from '@/shared/api/Track'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
|
||||||
export default function useTracks(params: FetchTracksParams) {
|
export default function useTracks(params: FetchTracksParams) {
|
||||||
return useQuery(
|
return useQuery(
|
||||||
|
|
@ -23,7 +22,7 @@ export default function useTracks(params: FetchTracksParams) {
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
initialData: (): FetchTracksResponse | undefined =>
|
initialData: (): FetchTracksResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'song/detail',
|
api: APIs.Track,
|
||||||
query: {
|
query: {
|
||||||
ids: params.ids.join(','),
|
ids: params.ids.join(','),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { TrackApiNames, fetchTracks } from '@/renderer/api/track'
|
import { FetchTracksParams, TrackApiNames } from '@/shared/api/Track'
|
||||||
import type { FetchTracksParams } from '@/renderer/api/track'
|
import { fetchTracks } from 'api/track'
|
||||||
|
|
||||||
// 100 tracks each page
|
// 100 tracks each page
|
||||||
const offset = 100
|
const offset = 100
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import { fetchUserAccount, fetchUserAccountResponse } from '@/renderer/api/user'
|
import { fetchUserAccount } from '@/renderer/api/user'
|
||||||
import { UserApiNames } from '@/renderer/api/user'
|
import { UserApiNames, FetchUserAccountResponse } from '@/shared/api/User'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
|
||||||
export default function useUser() {
|
export default function useUser() {
|
||||||
return useQuery(UserApiNames.FETCH_USER_ACCOUNT, fetchUserAccount, {
|
return useQuery(UserApiNames.FETCH_USER_ACCOUNT, fetchUserAccount, {
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): fetchUserAccountResponse | undefined =>
|
placeholderData: (): FetchUserAccountResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'user/account',
|
api: APIs.UserAccount,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import { likeAAlbum } from '@/renderer/api/album'
|
import { likeAAlbum } from '@/renderer/api/album'
|
||||||
import type {
|
|
||||||
FetchUserAlbumsParams,
|
|
||||||
FetchUserAlbumsResponse,
|
|
||||||
} from '@/renderer/api/user'
|
|
||||||
import { UserApiNames, fetchUserAlbums } from '@/renderer/api/user'
|
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
import useUser from './useUser'
|
import useUser from './useUser'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import {
|
||||||
|
FetchUserAlbumsParams,
|
||||||
|
UserApiNames,
|
||||||
|
FetchUserAlbumsResponse,
|
||||||
|
} from '@/shared/api/User'
|
||||||
|
import { fetchUserAlbums } from 'api/user'
|
||||||
|
|
||||||
export default function useUserAlbums(params: FetchUserAlbumsParams = {}) {
|
export default function useUserAlbums(params: FetchUserAlbumsParams = {}) {
|
||||||
const { data: user } = useUser()
|
const { data: user } = useUser()
|
||||||
|
|
@ -17,7 +19,7 @@ export default function useUserAlbums(params: FetchUserAlbumsParams = {}) {
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): FetchUserAlbumsResponse | undefined =>
|
placeholderData: (): FetchUserAlbumsResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'album/sublist',
|
api: APIs.UserAlbums,
|
||||||
query: params,
|
query: params,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import type { FetchUserArtistsResponse } from '@/renderer/api/user'
|
import { fetchUserArtists } from '@/renderer/api/user'
|
||||||
import { UserApiNames, fetchUserArtists } from '@/renderer/api/user'
|
import { UserApiNames, FetchUserArtistsResponse } from '@/shared/api/User'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
|
||||||
export default function useUserArtists() {
|
export default function useUserArtists() {
|
||||||
return useQuery([UserApiNames.FETCH_USER_ARTIST], fetchUserArtists, {
|
return useQuery([UserApiNames.FETCH_USER_ARTIST], fetchUserArtists, {
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): FetchUserArtistsResponse =>
|
placeholderData: (): FetchUserArtistsResponse =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'album/sublist',
|
api: APIs.UserArtists,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
import type { FetchUserLikedTracksIDsResponse } from '@/renderer/api/user'
|
|
||||||
import { UserApiNames, fetchUserLikedTracksIDs } from '@/renderer/api/user'
|
|
||||||
import { likeATrack } from '@/renderer/api/track'
|
import { likeATrack } from '@/renderer/api/track'
|
||||||
import useUser from './useUser'
|
import useUser from './useUser'
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { fetchUserLikedTracksIDs } from 'api/user'
|
||||||
|
import {
|
||||||
|
FetchUserLikedTracksIDsResponse,
|
||||||
|
UserApiNames,
|
||||||
|
} from '@/shared/api/User'
|
||||||
|
|
||||||
export default function useUserLikedTracksIDs() {
|
export default function useUserLikedTracksIDs() {
|
||||||
const { data: user } = useUser()
|
const { data: user } = useUser()
|
||||||
|
|
@ -17,7 +21,7 @@ export default function useUserLikedTracksIDs() {
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): FetchUserLikedTracksIDsResponse | undefined =>
|
placeholderData: (): FetchUserLikedTracksIDsResponse | undefined =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'likelist',
|
api: APIs.Likelist,
|
||||||
query: {
|
query: {
|
||||||
uid,
|
uid,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { likeAPlaylist } from '@/renderer/api/playlist'
|
import { likeAPlaylist } from '@/renderer/api/playlist'
|
||||||
import type { FetchUserPlaylistsResponse } from '@/renderer/api/user'
|
|
||||||
import { UserApiNames, fetchUserPlaylists } from '@/renderer/api/user'
|
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
import useUser from './useUser'
|
import useUser from './useUser'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { fetchUserPlaylists } from 'api/user'
|
||||||
|
import { FetchUserPlaylistsResponse, UserApiNames } from '@/shared/api/User'
|
||||||
|
|
||||||
export default function useUserPlaylists() {
|
export default function useUserPlaylists() {
|
||||||
const { data: user } = useUser()
|
const { data: user } = useUser()
|
||||||
|
|
@ -33,7 +34,7 @@ export default function useUserPlaylists() {
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
placeholderData: (): FetchUserPlaylistsResponse =>
|
placeholderData: (): FetchUserPlaylistsResponse =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'user/playlist',
|
api: APIs.UserPlaylist,
|
||||||
query: {
|
query: {
|
||||||
uid: params.uid,
|
uid: params.uid,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import {
|
import {
|
||||||
PlaylistApiNames,
|
|
||||||
fetchRecommendedPlaylists,
|
fetchRecommendedPlaylists,
|
||||||
fetchDailyRecommendPlaylists,
|
fetchDailyRecommendPlaylists,
|
||||||
} from '@/renderer/api/playlist'
|
} from '@/renderer/api/playlist'
|
||||||
import CoverRow from '@/renderer/components/CoverRow'
|
import CoverRow from '@/renderer/components/CoverRow'
|
||||||
import DailyTracksCard from '@/renderer/components/DailyTracksCard'
|
import DailyTracksCard from '@/renderer/components/DailyTracksCard'
|
||||||
import FMCard from '@/renderer/components/FMCard'
|
import FMCard from '@/renderer/components/FMCard'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { PlaylistApiNames } from '@/shared/api/Playlists'
|
||||||
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const {
|
const {
|
||||||
|
|
@ -19,7 +20,7 @@ export default function Home() {
|
||||||
retry: false,
|
retry: false,
|
||||||
placeholderData: () =>
|
placeholderData: () =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'recommend/resource',
|
api: APIs.RecommendResource,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -35,7 +36,7 @@ export default function Home() {
|
||||||
{
|
{
|
||||||
placeholderData: () =>
|
placeholderData: () =>
|
||||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||||
api: 'personalized',
|
api: APIs.Personalized,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
import {
|
import { multiMatchSearch, search } from '@/renderer/api/search'
|
||||||
multiMatchSearch,
|
|
||||||
search,
|
|
||||||
SearchApiNames,
|
|
||||||
SearchTypes,
|
|
||||||
} from '@/renderer/api/search'
|
|
||||||
import Cover from '@/renderer/components/Cover'
|
import Cover from '@/renderer/components/Cover'
|
||||||
import TrackGrid from '@/renderer/components/TracksGrid'
|
import TrackGrid from '@/renderer/components/TracksGrid'
|
||||||
import { player } from '@/renderer/store'
|
import { player } from '@/renderer/store'
|
||||||
import { resizeImage } from '@/renderer/utils/common'
|
import { resizeImage } from '@/renderer/utils/common'
|
||||||
|
import { SearchTypes, SearchApiNames } from '@/shared/api/Search'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
const Artists = ({ artists }: { artists: Artist[] }) => {
|
const Artists = ({ artists }: { artists: Artist[] }) => {
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import {
|
||||||
getCoverColor,
|
getCoverColor,
|
||||||
storage,
|
storage,
|
||||||
} from '@/renderer/utils/common'
|
} from '@/renderer/utils/common'
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import { APIs } from '@/main/CacheAPIsName'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
|
|
||||||
test('resizeImage', () => {
|
test('resizeImage', () => {
|
||||||
expect(resizeImage('https://test.com/test.jpg', 'xs')).toBe(
|
expect(resizeImage('https://test.com/test.jpg', 'xs')).toBe(
|
||||||
|
|
@ -62,28 +62,48 @@ test('formatDuration', () => {
|
||||||
expect(formatDuration(0, 'zh-CN', 'hh[hr] mm[min]')).toBe('0 分钟')
|
expect(formatDuration(0, 'zh-CN', 'hh[hr] mm[min]')).toBe('0 分钟')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('cacheCoverColor', () => {
|
describe('cacheCoverColor', () => {
|
||||||
vi.stubGlobal('ipcRenderer', {
|
test('cache with valid url', () => {
|
||||||
send: (channel: IpcChannels, ...args: any[]) => {
|
vi.stubGlobal('ipcRenderer', {
|
||||||
expect(channel).toBe(IpcChannels.CacheCoverColor)
|
send: (channel: IpcChannels, ...args: any[]) => {
|
||||||
expect(args[0].api).toBe(APIs.CoverColor)
|
expect(channel).toBe(IpcChannels.CacheCoverColor)
|
||||||
expect(args[0].query).toEqual({
|
expect(args[0].api).toBe(APIs.CoverColor)
|
||||||
id: '109951165911363',
|
expect(args[0].query).toEqual({
|
||||||
color: '#fff',
|
id: '109951165911363',
|
||||||
})
|
color: '#fff',
|
||||||
},
|
})
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
|
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
|
||||||
expect(
|
|
||||||
cacheCoverColor(
|
cacheCoverColor(
|
||||||
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256',
|
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256',
|
||||||
'#fff'
|
'#fff'
|
||||||
)
|
)
|
||||||
)
|
|
||||||
expect(sendSpy).toHaveBeenCalledTimes(1)
|
|
||||||
|
|
||||||
vi.stubGlobal('ipcRenderer', undefined)
|
expect(sendSpy).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
vi.stubGlobal('ipcRenderer', undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache with invalid url', () => {
|
||||||
|
vi.stubGlobal('ipcRenderer', {
|
||||||
|
send: (channel: IpcChannels, ...args: any[]) => {
|
||||||
|
expect(channel).toBe(IpcChannels.CacheCoverColor)
|
||||||
|
expect(args[0].api).toBe(APIs.CoverColor)
|
||||||
|
expect(args[0].query).toEqual({
|
||||||
|
id: '',
|
||||||
|
color: '#fff',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
|
||||||
|
cacheCoverColor('not a valid url', '#fff')
|
||||||
|
expect(sendSpy).toHaveBeenCalledTimes(0)
|
||||||
|
|
||||||
|
vi.stubGlobal('ipcRenderer', undefined)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('calcCoverColor', async () => {
|
test('calcCoverColor', async () => {
|
||||||
|
|
@ -117,7 +137,6 @@ test('calcCoverColor', async () => {
|
||||||
)
|
)
|
||||||
).toBe('#808080')
|
).toBe('#808080')
|
||||||
|
|
||||||
expect(sendSpy).toHaveBeenCalledTimes(1)
|
|
||||||
vi.stubGlobal('ipcRenderer', undefined)
|
vi.stubGlobal('ipcRenderer', undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -174,6 +193,10 @@ describe('getCoverColor', () => {
|
||||||
expect(sendSpy).toHaveBeenCalledTimes(1)
|
expect(sendSpy).toHaveBeenCalledTimes(1)
|
||||||
vi.stubGlobal('ipcRenderer', undefined)
|
vi.stubGlobal('ipcRenderer', undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('invalid url', async () => {
|
||||||
|
expect(await getCoverColor('not a valid url')).toBe(undefined)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('storage', () => {
|
test('storage', () => {
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,5 @@
|
||||||
"@/*": ["../*"]
|
"@/*": ["../*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["./**/*.ts", "./**/*.tsx"]
|
"include": ["./**/*.ts", "./**/*.tsx", "../shared/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { IpcChannels } from '@/main/IpcChannelsName'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import duration from 'dayjs/plugin/duration'
|
import duration from 'dayjs/plugin/duration'
|
||||||
import { APIs } from '@/main/CacheAPIsName'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
import { average } from 'color.js'
|
import { average } from 'color.js'
|
||||||
import { colord } from 'colord'
|
import { colord } from 'colord'
|
||||||
|
|
||||||
|
|
@ -110,7 +110,13 @@ export function scrollToTop(smooth = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCoverColor(coverUrl: string) {
|
export async function getCoverColor(coverUrl: string) {
|
||||||
const id = new URL(coverUrl).pathname.split('/').pop()?.split('.')[0]
|
let id: string | undefined
|
||||||
|
try {
|
||||||
|
id = new URL(coverUrl).pathname.split('/').pop()?.split('.')[0]
|
||||||
|
} catch (e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const colorFromCache = window.ipcRenderer?.sendSync(
|
const colorFromCache = window.ipcRenderer?.sendSync(
|
||||||
IpcChannels.GetApiCacheSync,
|
IpcChannels.GetApiCacheSync,
|
||||||
{
|
{
|
||||||
|
|
@ -124,14 +130,18 @@ export async function getCoverColor(coverUrl: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function cacheCoverColor(coverUrl: string, color: string) {
|
export async function cacheCoverColor(coverUrl: string, color: string) {
|
||||||
const id = new URL(coverUrl).pathname.split('/').pop()?.split('.')[0]
|
let id: string | undefined
|
||||||
|
try {
|
||||||
|
id = new URL(coverUrl).pathname.split('/').pop()?.split('.')[0]
|
||||||
|
} catch (e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id || isNaN(Number(id))) return
|
||||||
|
|
||||||
window.ipcRenderer?.send(IpcChannels.CacheCoverColor, {
|
window.ipcRenderer?.send(IpcChannels.CacheCoverColor, {
|
||||||
api: APIs.CoverColor,
|
id: Number(id),
|
||||||
query: {
|
color,
|
||||||
id,
|
|
||||||
color,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { FetchLyricResponse } from '@/renderer/api/track'
|
import { FetchLyricResponse } from '@/shared/api/Track'
|
||||||
|
|
||||||
export function lyricParser(lrc: FetchLyricResponse) {
|
export function lyricParser(lrc: FetchLyricResponse) {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
72
src/shared/CacheAPIs.ts
Normal file
72
src/shared/CacheAPIs.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { FetchArtistAlbumsResponse, FetchArtistResponse } from './api/Artist'
|
||||||
|
import { FetchAlbumResponse } from './api/Album'
|
||||||
|
import {
|
||||||
|
FetchUserAccountResponse,
|
||||||
|
FetchUserAlbumsResponse,
|
||||||
|
FetchUserArtistsResponse,
|
||||||
|
FetchUserLikedTracksIDsResponse,
|
||||||
|
FetchUserPlaylistsResponse,
|
||||||
|
} from './api/User'
|
||||||
|
import {
|
||||||
|
FetchAudioSourceResponse,
|
||||||
|
FetchLyricResponse,
|
||||||
|
FetchTracksResponse,
|
||||||
|
} from './api/Track'
|
||||||
|
import {
|
||||||
|
FetchPlaylistResponse,
|
||||||
|
FetchRecommendedPlaylistsResponse,
|
||||||
|
} from './api/Playlists'
|
||||||
|
|
||||||
|
export const enum APIs {
|
||||||
|
Album = 'album',
|
||||||
|
Artist = 'artists',
|
||||||
|
ArtistAlbum = 'artist/album',
|
||||||
|
CoverColor = 'cover_color',
|
||||||
|
Likelist = 'likelist',
|
||||||
|
Lyric = 'lyric',
|
||||||
|
Personalized = 'personalized',
|
||||||
|
Playlist = 'playlist/detail',
|
||||||
|
RecommendResource = 'recommend/resource',
|
||||||
|
SongUrl = 'song/url',
|
||||||
|
Track = 'song/detail',
|
||||||
|
UserAccount = 'user/account',
|
||||||
|
UserAlbums = 'album/sublist',
|
||||||
|
UserArtists = 'artist/sublist',
|
||||||
|
UserPlaylist = 'user/playlist',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIsParams {
|
||||||
|
[APIs.Album]: { id: number }
|
||||||
|
[APIs.Artist]: { id: number }
|
||||||
|
[APIs.ArtistAlbum]: { id: number }
|
||||||
|
[APIs.CoverColor]: { id: number }
|
||||||
|
[APIs.Likelist]: void
|
||||||
|
[APIs.Lyric]: { id: number }
|
||||||
|
[APIs.Personalized]: void
|
||||||
|
[APIs.Playlist]: { id: number }
|
||||||
|
[APIs.RecommendResource]: void
|
||||||
|
[APIs.SongUrl]: { id: string }
|
||||||
|
[APIs.Track]: { ids: string }
|
||||||
|
[APIs.UserAccount]: void
|
||||||
|
[APIs.UserAlbums]: void
|
||||||
|
[APIs.UserArtists]: void
|
||||||
|
[APIs.UserPlaylist]: void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIsResponse {
|
||||||
|
[APIs.Album]: FetchAlbumResponse
|
||||||
|
[APIs.Artist]: FetchArtistResponse
|
||||||
|
[APIs.ArtistAlbum]: FetchArtistAlbumsResponse
|
||||||
|
[APIs.CoverColor]: string | undefined
|
||||||
|
[APIs.Likelist]: FetchUserLikedTracksIDsResponse
|
||||||
|
[APIs.Lyric]: FetchLyricResponse
|
||||||
|
[APIs.Personalized]: FetchRecommendedPlaylistsResponse
|
||||||
|
[APIs.Playlist]: FetchPlaylistResponse
|
||||||
|
[APIs.RecommendResource]: FetchRecommendedPlaylistsResponse
|
||||||
|
[APIs.SongUrl]: FetchAudioSourceResponse
|
||||||
|
[APIs.Track]: FetchTracksResponse
|
||||||
|
[APIs.UserAccount]: FetchUserAccountResponse
|
||||||
|
[APIs.UserAlbums]: FetchUserAlbumsResponse
|
||||||
|
[APIs.UserArtists]: FetchUserArtistsResponse
|
||||||
|
[APIs.UserPlaylist]: FetchUserPlaylistsResponse
|
||||||
|
}
|
||||||
40
src/shared/IpcChannels.ts
Normal file
40
src/shared/IpcChannels.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { APIs } from './CacheAPIs'
|
||||||
|
|
||||||
|
export const enum IpcChannels {
|
||||||
|
ClearAPICache = 'clear-api-cache',
|
||||||
|
Minimize = 'minimize',
|
||||||
|
MaximizeOrUnmaximize = 'maximize-or-unmaximize',
|
||||||
|
Close = 'close',
|
||||||
|
IsMaximized = 'is-maximized',
|
||||||
|
GetApiCacheSync = 'get-api-cache-sync',
|
||||||
|
DevDbExportJson = 'dev-db-export-json',
|
||||||
|
CacheCoverColor = 'cache-cover-color',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IpcChannelsParams {
|
||||||
|
[IpcChannels.ClearAPICache]: void
|
||||||
|
[IpcChannels.Minimize]: void
|
||||||
|
[IpcChannels.MaximizeOrUnmaximize]: void
|
||||||
|
[IpcChannels.Close]: void
|
||||||
|
[IpcChannels.IsMaximized]: void
|
||||||
|
[IpcChannels.GetApiCacheSync]: {
|
||||||
|
api: APIs
|
||||||
|
query?: any
|
||||||
|
}
|
||||||
|
[IpcChannels.DevDbExportJson]: void
|
||||||
|
[IpcChannels.CacheCoverColor]: {
|
||||||
|
id: number
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IpcChannelsReturns {
|
||||||
|
[IpcChannels.ClearAPICache]: void
|
||||||
|
[IpcChannels.Minimize]: void
|
||||||
|
[IpcChannels.MaximizeOrUnmaximize]: void
|
||||||
|
[IpcChannels.Close]: void
|
||||||
|
[IpcChannels.IsMaximized]: boolean
|
||||||
|
[IpcChannels.GetApiCacheSync]: any
|
||||||
|
[IpcChannels.DevDbExportJson]: void
|
||||||
|
[IpcChannels.CacheCoverColor]: void
|
||||||
|
}
|
||||||
23
src/shared/api/Album.ts
Normal file
23
src/shared/api/Album.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
export enum AlbumApiNames {
|
||||||
|
FETCH_ALBUM = 'fetchAlbum',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 专辑详情
|
||||||
|
export interface FetchAlbumParams {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
export interface FetchAlbumResponse {
|
||||||
|
code: number
|
||||||
|
resourceState: boolean
|
||||||
|
album: Album
|
||||||
|
songs: Track[]
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LikeAAlbumParams {
|
||||||
|
t: 1 | 2
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
export interface LikeAAlbumResponse {
|
||||||
|
code: number
|
||||||
|
}
|
||||||
28
src/shared/api/Artist.ts
Normal file
28
src/shared/api/Artist.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
export enum ArtistApiNames {
|
||||||
|
FETCH_ARTIST = 'fetchArtist',
|
||||||
|
FETCH_ARTIST_ALBUMS = 'fetchArtistAlbums',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 歌手详情
|
||||||
|
export interface FetchArtistParams {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
export interface FetchArtistResponse {
|
||||||
|
code: number
|
||||||
|
more: boolean
|
||||||
|
artist: Artist
|
||||||
|
hotSongs: Track[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取歌手的专辑列表
|
||||||
|
export interface FetchArtistAlbumsParams {
|
||||||
|
id: number
|
||||||
|
limit?: number // default: 50
|
||||||
|
offset?: number // default: 0
|
||||||
|
}
|
||||||
|
export interface FetchArtistAlbumsResponse {
|
||||||
|
code: number
|
||||||
|
hotAlbums: Album[]
|
||||||
|
more: boolean
|
||||||
|
artist: Artist
|
||||||
|
}
|
||||||
48
src/shared/api/Playlists.ts
Normal file
48
src/shared/api/Playlists.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
export enum PlaylistApiNames {
|
||||||
|
FETCH_PLAYLIST = 'fetchPlaylist',
|
||||||
|
FETCH_RECOMMENDED_PLAYLISTS = 'fetchRecommendedPlaylists',
|
||||||
|
FETCH_DAILY_RECOMMEND_PLAYLISTS = 'fetchDailyRecommendPlaylists',
|
||||||
|
LIKE_A_PLAYLIST = 'likeAPlaylist',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 歌单详情
|
||||||
|
export interface FetchPlaylistParams {
|
||||||
|
id: number
|
||||||
|
s?: number // 歌单最近的 s 个收藏者
|
||||||
|
}
|
||||||
|
export interface FetchPlaylistResponse {
|
||||||
|
code: number
|
||||||
|
playlist: Playlist
|
||||||
|
privileges: unknown // TODO: unknown type
|
||||||
|
relatedVideos: null
|
||||||
|
resEntrance: null
|
||||||
|
sharedPrivilege: null
|
||||||
|
urls: null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推荐歌单
|
||||||
|
export interface FetchRecommendedPlaylistsParams {
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
export interface FetchRecommendedPlaylistsResponse {
|
||||||
|
code: number
|
||||||
|
category: number
|
||||||
|
hasTaste: boolean
|
||||||
|
result: Playlist[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每日推荐歌单(需要登录)
|
||||||
|
export interface FetchDailyRecommendPlaylistsResponse {
|
||||||
|
code: number
|
||||||
|
featureFirst: boolean
|
||||||
|
haveRcmdSongs: boolean
|
||||||
|
recommend: Playlist[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LikeAPlaylistParams {
|
||||||
|
t: 1 | 2
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
export interface LikeAPlaylistResponse {
|
||||||
|
code: number
|
||||||
|
}
|
||||||
82
src/shared/api/Search.ts
Normal file
82
src/shared/api/Search.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
export enum SearchApiNames {
|
||||||
|
SEARCH = 'search',
|
||||||
|
MULTI_MATCH_SEARCH = 'multiMatchSearch',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
export enum SearchTypes {
|
||||||
|
SINGLE = '1',
|
||||||
|
ALBUM = '10',
|
||||||
|
ARTIST = '100',
|
||||||
|
PLAYLIST = '1000',
|
||||||
|
USER = '1002',
|
||||||
|
MV = '1004',
|
||||||
|
LYRICS = '1006',
|
||||||
|
RADIO = '1009',
|
||||||
|
VIDEO = '1014',
|
||||||
|
ALL = '1018',
|
||||||
|
}
|
||||||
|
export interface SearchParams {
|
||||||
|
keywords: string
|
||||||
|
limit?: number // 返回数量 , 默认为 30
|
||||||
|
offset?: number // 偏移数量,用于分页 , 如 : 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||||
|
type: keyof typeof SearchTypes // type: 搜索类型
|
||||||
|
}
|
||||||
|
export interface SearchResponse {
|
||||||
|
code: number
|
||||||
|
result: {
|
||||||
|
album: {
|
||||||
|
albums: Album[]
|
||||||
|
more: boolean
|
||||||
|
moreText: string
|
||||||
|
resourceIds: number[]
|
||||||
|
}
|
||||||
|
artist: {
|
||||||
|
artists: Artist[]
|
||||||
|
more: boolean
|
||||||
|
moreText: string
|
||||||
|
resourceIds: number[]
|
||||||
|
}
|
||||||
|
playList: {
|
||||||
|
playLists: Playlist[]
|
||||||
|
more: boolean
|
||||||
|
moreText: string
|
||||||
|
resourceIds: number[]
|
||||||
|
}
|
||||||
|
song: {
|
||||||
|
songs: Track[]
|
||||||
|
more: boolean
|
||||||
|
moreText: string
|
||||||
|
resourceIds: number[]
|
||||||
|
}
|
||||||
|
user: {
|
||||||
|
users: User[]
|
||||||
|
more: boolean
|
||||||
|
moreText: string
|
||||||
|
resourceIds: number[]
|
||||||
|
}
|
||||||
|
circle: unknown
|
||||||
|
new_mlog: unknown
|
||||||
|
order: string[]
|
||||||
|
rec_type: null
|
||||||
|
rec_query: null[]
|
||||||
|
sim_query: unknown
|
||||||
|
voice: unknown
|
||||||
|
voiceList: unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索多重匹配
|
||||||
|
export interface MultiMatchSearchParams {
|
||||||
|
keywords: string
|
||||||
|
}
|
||||||
|
export interface MultiMatchSearchResponse {
|
||||||
|
code: number
|
||||||
|
result: {
|
||||||
|
album: Album[]
|
||||||
|
artist: Artist[]
|
||||||
|
playlist: Playlist[]
|
||||||
|
orpheus: unknown
|
||||||
|
orders: Array<'artist' | 'album'>
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/shared/api/Track.ts
Normal file
104
src/shared/api/Track.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
export enum TrackApiNames {
|
||||||
|
FETCH_TRACKS = 'fetchTracks',
|
||||||
|
FETCH_AUDIO_SOURCE = 'fetchAudioSource',
|
||||||
|
FETCH_LYRIC = 'fetchLyric',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取歌曲详情
|
||||||
|
export interface FetchTracksParams {
|
||||||
|
ids: number[]
|
||||||
|
}
|
||||||
|
export interface FetchTracksResponse {
|
||||||
|
code: number
|
||||||
|
songs: Track[]
|
||||||
|
privileges: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取音源URL
|
||||||
|
|
||||||
|
export interface FetchAudioSourceParams {
|
||||||
|
id: number
|
||||||
|
br?: number // bitrate, default 999000,320000 = 320kbps
|
||||||
|
}
|
||||||
|
export interface FetchAudioSourceResponse {
|
||||||
|
code: number
|
||||||
|
data: {
|
||||||
|
br: number
|
||||||
|
canExtend: boolean
|
||||||
|
code: number
|
||||||
|
encodeType: 'mp3' | null
|
||||||
|
expi: number
|
||||||
|
fee: number
|
||||||
|
flag: number
|
||||||
|
freeTimeTrialPrivilege: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
freeTrialPrivilege: {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
freeTrialInfo: null
|
||||||
|
gain: number
|
||||||
|
id: number
|
||||||
|
level: 'standard' | 'null'
|
||||||
|
md5: string | null
|
||||||
|
payed: number
|
||||||
|
size: number
|
||||||
|
type: 'mp3' | null
|
||||||
|
uf: null
|
||||||
|
url: string | null
|
||||||
|
urlSource: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取歌词
|
||||||
|
|
||||||
|
export interface FetchLyricParams {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
export interface FetchLyricResponse {
|
||||||
|
code: number
|
||||||
|
sgc: boolean
|
||||||
|
sfy: boolean
|
||||||
|
qfy: boolean
|
||||||
|
lyricUser?: {
|
||||||
|
id: number
|
||||||
|
status: number
|
||||||
|
demand: number
|
||||||
|
userid: number
|
||||||
|
nickname: string
|
||||||
|
uptime: number
|
||||||
|
}
|
||||||
|
transUser?: {
|
||||||
|
id: number
|
||||||
|
status: number
|
||||||
|
demand: number
|
||||||
|
userid: number
|
||||||
|
nickname: string
|
||||||
|
uptime: number
|
||||||
|
}
|
||||||
|
lrc: {
|
||||||
|
version: number
|
||||||
|
lyric: string
|
||||||
|
}
|
||||||
|
klyric?: {
|
||||||
|
version: number
|
||||||
|
lyric: string
|
||||||
|
}
|
||||||
|
tlyric?: {
|
||||||
|
version: number
|
||||||
|
lyric: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收藏歌曲
|
||||||
|
export interface LikeATrackParams {
|
||||||
|
id: number
|
||||||
|
like: boolean
|
||||||
|
}
|
||||||
|
export interface LikeATrackResponse {
|
||||||
|
code: number
|
||||||
|
playlistId: number
|
||||||
|
songs: Track[]
|
||||||
|
}
|
||||||
108
src/shared/api/User.ts
Normal file
108
src/shared/api/User.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
export enum UserApiNames {
|
||||||
|
FETCH_USER_ACCOUNT = 'fetchUserAccount',
|
||||||
|
FETCH_USER_LIKED_TRACKS_IDS = 'fetchUserLikedTracksIDs',
|
||||||
|
FETCH_USER_PLAYLISTS = 'fetchUserPlaylists',
|
||||||
|
FETCH_USER_ALBUMS = 'fetchUserAlbums',
|
||||||
|
FETCH_USER_ARTIST = 'fetchUserArtists',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取账号详情
|
||||||
|
export interface FetchUserAccountResponse {
|
||||||
|
code: number
|
||||||
|
account: {
|
||||||
|
anonimousUser: boolean
|
||||||
|
ban: number
|
||||||
|
baoyueVersion: number
|
||||||
|
createTime: number
|
||||||
|
donateVersion: number
|
||||||
|
id: number
|
||||||
|
paidFee: boolean
|
||||||
|
status: number
|
||||||
|
tokenVersion: number
|
||||||
|
type: number
|
||||||
|
userName: string
|
||||||
|
vipType: number
|
||||||
|
whitelistAuthority: number
|
||||||
|
} | null
|
||||||
|
profile: {
|
||||||
|
userId: number
|
||||||
|
userType: number
|
||||||
|
nickname: string
|
||||||
|
avatarImgId: number
|
||||||
|
avatarUrl: string
|
||||||
|
backgroundImgId: number
|
||||||
|
backgroundUrl: string
|
||||||
|
signature: string
|
||||||
|
createTime: number
|
||||||
|
userName: string
|
||||||
|
accountType: number
|
||||||
|
shortUserName: string
|
||||||
|
birthday: number
|
||||||
|
authority: number
|
||||||
|
gender: number
|
||||||
|
accountStatus: number
|
||||||
|
province: number
|
||||||
|
city: number
|
||||||
|
authStatus: number
|
||||||
|
description: string | null
|
||||||
|
detailDescription: string | null
|
||||||
|
defaultAvatar: boolean
|
||||||
|
expertTags: [] | null
|
||||||
|
experts: [] | null
|
||||||
|
djStatus: number
|
||||||
|
locationStatus: number
|
||||||
|
vipType: number
|
||||||
|
followed: boolean
|
||||||
|
mutual: boolean
|
||||||
|
authenticated: boolean
|
||||||
|
lastLoginTime: number
|
||||||
|
lastLoginIP: string
|
||||||
|
remarkName: string | null
|
||||||
|
viptypeVersion: number
|
||||||
|
authenticationTypes: number
|
||||||
|
avatarDetail: string | null
|
||||||
|
anchor: boolean
|
||||||
|
} | null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户歌单
|
||||||
|
export interface FetchUserPlaylistsParams {
|
||||||
|
uid: number
|
||||||
|
offset: number
|
||||||
|
limit?: number // default 30
|
||||||
|
}
|
||||||
|
export interface FetchUserPlaylistsResponse {
|
||||||
|
code: number
|
||||||
|
more: boolean
|
||||||
|
version: string
|
||||||
|
playlist: Playlist[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FetchUserLikedTracksIDsParams {
|
||||||
|
uid: number
|
||||||
|
}
|
||||||
|
export interface FetchUserLikedTracksIDsResponse {
|
||||||
|
code: number
|
||||||
|
checkPoint: number
|
||||||
|
ids: number[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FetchUserAlbumsParams {
|
||||||
|
offset?: number // default 0
|
||||||
|
limit?: number // default 25
|
||||||
|
}
|
||||||
|
export interface FetchUserAlbumsResponse {
|
||||||
|
code: number
|
||||||
|
hasMore: boolean
|
||||||
|
paidCount: number
|
||||||
|
count: number
|
||||||
|
data: Album[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取收藏的歌手
|
||||||
|
export interface FetchUserArtistsResponse {
|
||||||
|
code: number
|
||||||
|
hasMore: boolean
|
||||||
|
count: number
|
||||||
|
data: Artist[]
|
||||||
|
}
|
||||||
19
src/shared/tsconfig.json
Normal file
19
src/shared/tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"skipDefaultLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["../*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["./**/*.ts"]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue