mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 05:08:04 +00:00
feat: updates
This commit is contained in:
parent
86f088e5c9
commit
3ef7675696
12 changed files with 158 additions and 146 deletions
|
|
@ -84,8 +84,8 @@
|
|||
"prettier": "2.5.1",
|
||||
"prettier-plugin-tailwindcss": "^0.1.8",
|
||||
"qrcode": "^1.5.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-hot-toast": "^2.2.0",
|
||||
"react-query": "^3.34.19",
|
||||
"react-router-dom": "^6.3.0",
|
||||
|
|
|
|||
101
pnpm-lock.yaml
generated
101
pnpm-lock.yaml
generated
|
|
@ -57,8 +57,8 @@ specifiers:
|
|||
prettier: 2.5.1
|
||||
prettier-plugin-tailwindcss: ^0.1.8
|
||||
qrcode: ^1.5.0
|
||||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
react-hot-toast: ^2.2.0
|
||||
react-query: ^3.34.19
|
||||
react-router-dom: ^6.3.0
|
||||
|
|
@ -89,7 +89,7 @@ dependencies:
|
|||
fast-folder-size: 1.6.1
|
||||
|
||||
devDependencies:
|
||||
'@sentry/react': 6.19.3_react@17.0.2
|
||||
'@sentry/react': 6.19.3_react@18.0.0
|
||||
'@types/better-sqlite3': 7.5.0
|
||||
'@types/cookie-parser': 1.4.2
|
||||
'@types/express': 4.17.13
|
||||
|
|
@ -135,19 +135,19 @@ devDependencies:
|
|||
prettier: 2.5.1
|
||||
prettier-plugin-tailwindcss: 0.1.8_prettier@2.5.1
|
||||
qrcode: 1.5.0
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-hot-toast: 2.2.0_383bc679f6b8b3c30a924b2c4a84e8d7
|
||||
react-query: 3.34.19_react-dom@17.0.2+react@17.0.2
|
||||
react-router-dom: 6.3.0_react-dom@17.0.2+react@17.0.2
|
||||
react-use: 17.3.2_react-dom@17.0.2+react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
react-hot-toast: 2.2.0_aee3b59847029cfc9aee5217330a3daf
|
||||
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-use: 17.3.2_react-dom@18.0.0+react@18.0.0
|
||||
rollup: 2.70.1
|
||||
rollup-plugin-visualizer: 5.6.0_rollup@2.70.1
|
||||
sass: 1.49.10
|
||||
tailwindcss: 3.0.23_autoprefixer@10.4.4
|
||||
typescript: 4.6.3
|
||||
unplugin-auto-import: 0.6.9_e121d8abdbc15677ab11cd9085287858
|
||||
valtio: 1.5.0_react@17.0.2+vite@2.9.1
|
||||
valtio: 1.5.0_react@18.0.0+vite@2.9.1
|
||||
valtio-persist: 1.0.2_valtio@1.5.0
|
||||
vite: 2.9.1_sass@1.49.10
|
||||
vite-plugin-resolve: 1.8.0
|
||||
|
|
@ -662,7 +662,7 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@sentry/react/6.19.3_react@17.0.2:
|
||||
/@sentry/react/6.19.3_react@18.0.0:
|
||||
resolution: {integrity: sha512-Zza1RX0+1tFCM1Hfq3Yl50cbc/ml0V/katw4aVZIU6+vEgvk5EuSFKU2LtblmJkpID7x6UwWz+1qgXumZPze6Q==}
|
||||
engines: {node: '>=6'}
|
||||
peerDependencies:
|
||||
|
|
@ -673,7 +673,7 @@ packages:
|
|||
'@sentry/types': 6.19.3
|
||||
'@sentry/utils': 6.19.3
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 17.0.2
|
||||
react: 18.0.0
|
||||
tslib: 1.14.1
|
||||
dev: true
|
||||
|
||||
|
|
@ -5194,7 +5194,7 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
/nano-css/5.3.4_react-dom@17.0.2+react@17.0.2:
|
||||
/nano-css/5.3.4_react-dom@18.0.0+react@18.0.0:
|
||||
resolution: {integrity: sha512-wfcviJB6NOxDIDfr7RFn/GlaN7I/Bhe4d39ZRCJ3xvZX60LVe2qZ+rDqM49nm4YT81gAjzS+ZklhKP/Gnfnubg==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
|
@ -5204,8 +5204,8 @@ packages:
|
|||
csstype: 3.0.11
|
||||
fastest-stable-stringify: 2.0.2
|
||||
inline-style-prefixer: 6.0.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
rtl-css-js: 1.15.0
|
||||
sourcemap-codec: 1.4.8
|
||||
stacktrace-js: 2.0.2
|
||||
|
|
@ -6050,18 +6050,17 @@ packages:
|
|||
minimist: 1.2.6
|
||||
strip-json-comments: 2.0.1
|
||||
|
||||
/react-dom/17.0.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
|
||||
/react-dom/18.0.0_react@18.0.0:
|
||||
resolution: {integrity: sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==}
|
||||
peerDependencies:
|
||||
react: 17.0.2
|
||||
react: ^18.0.0
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
react: 17.0.2
|
||||
scheduler: 0.20.2
|
||||
react: 18.0.0
|
||||
scheduler: 0.21.0
|
||||
dev: true
|
||||
|
||||
/react-hot-toast/2.2.0_383bc679f6b8b3c30a924b2c4a84e8d7:
|
||||
/react-hot-toast/2.2.0_aee3b59847029cfc9aee5217330a3daf:
|
||||
resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
|
|
@ -6069,8 +6068,8 @@ packages:
|
|||
react-dom: '>=16'
|
||||
dependencies:
|
||||
goober: 2.1.8_csstype@3.0.11
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
transitivePeerDependencies:
|
||||
- csstype
|
||||
dev: true
|
||||
|
|
@ -6079,7 +6078,7 @@ packages:
|
|||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
dev: true
|
||||
|
||||
/react-query/3.34.19_react-dom@17.0.2+react@17.0.2:
|
||||
/react-query/3.34.19_react-dom@18.0.0+react@18.0.0:
|
||||
resolution: {integrity: sha512-JO0Ymi58WKmvnhgg6bGIrYIeKb64KsKaPWo8JcGnmK2jJxAs2XmMBzlP75ZepSU7CHzcsWtIIyhMrLbX3pb/3w==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0
|
||||
|
|
@ -6094,8 +6093,8 @@ packages:
|
|||
'@babel/runtime': 7.17.8
|
||||
broadcast-channel: 3.7.0
|
||||
match-sorter: 6.3.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
dev: true
|
||||
|
||||
/react-refresh/0.11.0:
|
||||
|
|
@ -6103,38 +6102,38 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/react-router-dom/6.3.0_react-dom@17.0.2+react@17.0.2:
|
||||
/react-router-dom/6.3.0_react-dom@18.0.0+react@18.0.0:
|
||||
resolution: {integrity: sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
react-dom: '>=16.8'
|
||||
dependencies:
|
||||
history: 5.3.0
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-router: 6.3.0_react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
react-router: 6.3.0_react@18.0.0
|
||||
dev: true
|
||||
|
||||
/react-router/6.3.0_react@17.0.2:
|
||||
/react-router/6.3.0_react@18.0.0:
|
||||
resolution: {integrity: sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
dependencies:
|
||||
history: 5.3.0
|
||||
react: 17.0.2
|
||||
react: 18.0.0
|
||||
dev: true
|
||||
|
||||
/react-universal-interface/0.6.2_react@17.0.2+tslib@2.3.1:
|
||||
/react-universal-interface/0.6.2_react@18.0.0+tslib@2.3.1:
|
||||
resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
tslib: '*'
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
react: 18.0.0
|
||||
tslib: 2.3.1
|
||||
dev: true
|
||||
|
||||
/react-use/17.3.2_react-dom@17.0.2+react@17.0.2:
|
||||
/react-use/17.3.2_react-dom@18.0.0+react@18.0.0:
|
||||
resolution: {integrity: sha512-bj7OD0/1wL03KyWmzFXAFe425zziuTf7q8olwCYBfOeFHY1qfO1FAMjROQLsLZYwG4Rx63xAfb7XAbBrJsZmEw==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0
|
||||
|
|
@ -6146,10 +6145,10 @@ packages:
|
|||
fast-deep-equal: 3.1.3
|
||||
fast-shallow-equal: 1.0.0
|
||||
js-cookie: 2.2.1
|
||||
nano-css: 5.3.4_react-dom@17.0.2+react@17.0.2
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react-universal-interface: 0.6.2_react@17.0.2+tslib@2.3.1
|
||||
nano-css: 5.3.4_react-dom@18.0.0+react@18.0.0
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
react-universal-interface: 0.6.2_react@18.0.0+tslib@2.3.1
|
||||
resize-observer-polyfill: 1.5.1
|
||||
screenfull: 5.2.0
|
||||
set-harmonic-interval: 1.0.1
|
||||
|
|
@ -6158,12 +6157,11 @@ packages:
|
|||
tslib: 2.3.1
|
||||
dev: true
|
||||
|
||||
/react/17.0.2:
|
||||
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
|
||||
/react/18.0.0:
|
||||
resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
dev: true
|
||||
|
||||
/read-config-file/6.2.0:
|
||||
|
|
@ -6473,11 +6471,10 @@ packages:
|
|||
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
|
||||
dev: true
|
||||
|
||||
/scheduler/0.20.2:
|
||||
resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
|
||||
/scheduler/0.21.0:
|
||||
resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
dev: true
|
||||
|
||||
/screenfull/5.2.0:
|
||||
|
|
@ -7455,12 +7452,12 @@ packages:
|
|||
prepend-http: 2.0.0
|
||||
dev: true
|
||||
|
||||
/use-sync-external-store/1.0.0_react@17.0.2:
|
||||
/use-sync-external-store/1.0.0_react@18.0.0:
|
||||
resolution: {integrity: sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0-rc
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
react: 18.0.0
|
||||
dev: true
|
||||
|
||||
/use/3.1.1:
|
||||
|
|
@ -7490,10 +7487,10 @@ packages:
|
|||
valtio: ^1.2.5
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
valtio: 1.5.0_react@17.0.2+vite@2.9.1
|
||||
valtio: 1.5.0_react@18.0.0+vite@2.9.1
|
||||
dev: true
|
||||
|
||||
/valtio/1.5.0_react@17.0.2+vite@2.9.1:
|
||||
/valtio/1.5.0_react@18.0.0+vite@2.9.1:
|
||||
resolution: {integrity: sha512-HfhX/BmRlIlV3AyBKv0nQ5I3SRKOB0giqhF8Gayb8Pnru0HvZQlzRstuXBppHtTBGmuJJOtCGv5jpdUfWEgeqA==}
|
||||
engines: {node: '>=12.7.0'}
|
||||
peerDependencies:
|
||||
|
|
@ -7518,8 +7515,8 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
proxy-compare: 2.1.0
|
||||
react: 17.0.2
|
||||
use-sync-external-store: 1.0.0_react@17.0.2
|
||||
react: 18.0.0
|
||||
use-sync-external-store: 1.0.0_react@18.0.0
|
||||
vite: 2.9.1_sass@1.49.10
|
||||
dev: true
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ export interface FetchPersonalFMResponse {
|
|||
s_ctrp: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export function fetchPersonalFM(): Promise<FetchPersonalFMResponse> {
|
||||
return request({
|
||||
url: '/personal/fm',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 10V18M9 19V19C7.89543 19 7 18.1046 7 17V9.38516C7 9.13073 7.04855 8.87862 7.14305 8.64238L8.39102 5.52246C8.75882 4.60294 9.64939 4 10.6397 4V4C12.2928 4 13.4602 5.61954 12.9374 7.18783L12.2857 9.14286C12.1452 9.56454 12.459 10 12.9035 10H17V10C19.1372 10 20.412 12.382 19.2265 14.1603L16.5229 18.2156C16.1962 18.7057 15.6462 19 15.0573 19H9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M4 14.5V5.5M9 5H8.5C7.39543 5 6.5 5.89543 6.5 7V14.0668C6.5 14.3523 6.56113 14.6345 6.67927 14.8944L8.46709 18.8276C8.79163 19.5416 9.50354 20 10.2878 20H10.8815C12.2002 20 13.158 18.746 12.811 17.4738L12.3445 15.7631C12.171 15.127 12.6499 14.5 13.3093 14.5H17V14.5C19.1704 14.5 20.489 12.1076 19.33 10.2726L16.5517 5.87354C16.2083 5.32974 15.61 5 14.9668 5H9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 538 B |
|
|
@ -5,6 +5,7 @@ import { resizeImage } from '@/utils/common'
|
|||
import SvgIcon from '@/components/SvgIcon'
|
||||
import ArtistInline from '@/components/ArtistsInline'
|
||||
import { State as PlayerState, Mode as PlayerMode } from '@/utils/player'
|
||||
import Skeleton from './Skeleton'
|
||||
|
||||
const MediaControls = () => {
|
||||
const classes =
|
||||
|
|
@ -67,39 +68,64 @@ const FMCard = () => {
|
|||
useEffect(() => {
|
||||
if (coverUrl) {
|
||||
average(coverUrl, { amount: 1, format: 'hex', sample: 1 }).then(color => {
|
||||
const to = colord(color as string)
|
||||
.darken(0.15)
|
||||
.rotate(-5)
|
||||
.toHex()
|
||||
setBackground(`linear-gradient(to bottom right, ${color}, ${to})`)
|
||||
let c = colord(color as string)
|
||||
console.log({ dark: c.isDark(), light: c.isLight() })
|
||||
|
||||
if (c.isLight()) c = c.darken(0.15)
|
||||
else if (c.isDark()) c = c.lighten(0.1)
|
||||
const to = c.darken(0.15).rotate(-5).toHex()
|
||||
setBackground(`linear-gradient(to bottom right, ${c.toHex()}, ${to})`)
|
||||
})
|
||||
} else {
|
||||
setBackground(`linear-gradient(to bottom right, #66ccff, #ee0000)`)
|
||||
}
|
||||
}, [coverUrl])
|
||||
|
||||
return (
|
||||
<div
|
||||
className='relative flex h-[198px] overflow-hidden rounded-2xl p-4'
|
||||
className='relative flex h-[198px] overflow-hidden rounded-2xl bg-gray-100 p-4 dark:bg-gray-800'
|
||||
style={{ background }}
|
||||
>
|
||||
{coverUrl && <img className='rounded-lg shadow-2xl' src={coverUrl} />}
|
||||
{coverUrl ? (
|
||||
<img className='rounded-lg shadow-2xl' src={coverUrl} />
|
||||
) : (
|
||||
<div className='aspect-square h-full rounded-lg bg-gray-200 dark:bg-white/5'></div>
|
||||
)}
|
||||
|
||||
<div className='ml-5 flex w-full flex-col justify-between text-white'>
|
||||
{/* Track info */}
|
||||
<div>
|
||||
<div className='text-xl font-semibold'>{track?.name}</div>
|
||||
<ArtistInline
|
||||
className='line-clamp-2 opacity-75'
|
||||
artists={track?.ar ?? []}
|
||||
/>
|
||||
{track ? (
|
||||
<div className='text-xl font-semibold'>{track?.name}</div>
|
||||
) : (
|
||||
<div className='flex'>
|
||||
<div className='bg-gray-200 text-xl text-transparent dark:bg-white/5'>
|
||||
PLACEHOLDER12345
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{track ? (
|
||||
<ArtistInline
|
||||
className='line-clamp-2 opacity-75'
|
||||
artists={track?.ar ?? []}
|
||||
/>
|
||||
) : (
|
||||
<div className='mt-1 flex'>
|
||||
<div className='bg-gray-200 text-transparent dark:bg-white/5'>
|
||||
PLACEHOLDER
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='-mb-1 flex items-center justify-between'>
|
||||
<MediaControls />
|
||||
{track ? <MediaControls /> : <div className='h-9'></div>}
|
||||
|
||||
{/* FM logo */}
|
||||
<div className='right-4 bottom-5 flex text-white opacity-20'>
|
||||
<div
|
||||
className={classNames(
|
||||
'right-4 bottom-5 flex opacity-20',
|
||||
track ? 'text-white ' : 'text-gray-700 dark:text-white'
|
||||
)}
|
||||
>
|
||||
<SvgIcon name='fm' className='mr-1 h-6 w-6' />
|
||||
<span className='font-semibold'>私人FM</span>
|
||||
</div>
|
||||
|
|
@ -109,11 +135,4 @@ const FMCard = () => {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 不能在player的构造函数中调用initFM
|
||||
* 那样在APP启动时不会加载私人FM的数据
|
||||
* 只能在这里进行数据的初始化
|
||||
*/
|
||||
player.initFM()
|
||||
|
||||
export default FMCard
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ const MediaControls = () => {
|
|||
const state = useMemo(() => playerSnapshot.state, [playerSnapshot.state])
|
||||
const track = useMemo(() => playerSnapshot.track, [playerSnapshot.track])
|
||||
const mode = useMemo(() => playerSnapshot.mode, [playerSnapshot.mode])
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-center gap-2 text-black dark:text-white'>
|
||||
{mode === PlayerMode.PLAYLIST && (
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ import reactQueryClient from '@/utils/reactQueryClient'
|
|||
export function fetchPersonalFMWithReactQuery() {
|
||||
return reactQueryClient.fetchQuery(
|
||||
PersonalFMApiNames.FETCH_PERSONAL_FM,
|
||||
() => {
|
||||
return fetchPersonalFM()
|
||||
async () => {
|
||||
const data = await fetchPersonalFM()
|
||||
if (!data.data?.length) {
|
||||
throw new Error('No data')
|
||||
}
|
||||
return data
|
||||
},
|
||||
{
|
||||
retry: 3,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ export function fetchTracksWithReactQuery(params: FetchTracksParams) {
|
|||
return fetchTracks(params)
|
||||
},
|
||||
{
|
||||
retry: 3,
|
||||
retry: 4,
|
||||
retryDelay: (retryCount: number) => {
|
||||
return retryCount * 500
|
||||
},
|
||||
staleTime: 86400000,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const Header = ({ artist }: { artist: Artist | undefined }) => {
|
|||
<div className='absolute top-0 left-0 z-0 h-[24rem] w-full overflow-hidden'>
|
||||
{coverImage && (
|
||||
<>
|
||||
<img src={coverImage} className='absolute w-full blur-[100px]' />
|
||||
<img src={coverImage} className='absolute w-full blur-[100px]' />
|
||||
<img src={coverImage} className='absolute w-full blur-[100px]' />
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ subscribe(state, () => {
|
|||
})
|
||||
|
||||
export const player = proxy(PlayerCore)
|
||||
player.init()
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
window.player = player
|
||||
}
|
||||
|
||||
// Devtools
|
||||
devtools(state, 'state')
|
||||
|
|
|
|||
|
|
@ -111,3 +111,7 @@ a,
|
|||
button {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
img {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { fetchPersonalFMWithReactQuery } from '@/hooks/usePersonalFM'
|
|||
import { fmTrash } from '@/api/personalFM'
|
||||
import { cacheAudio } from '@/api/yesplaymusic'
|
||||
import { clamp } from 'lodash-es'
|
||||
import axios from 'axios'
|
||||
import { resizeImage } from './common'
|
||||
|
||||
type TrackID = number
|
||||
enum TrackListSourceType {
|
||||
|
|
@ -43,8 +45,6 @@ export class Player {
|
|||
private _progress: number = 0
|
||||
private _progressInterval: ReturnType<typeof setInterval> | undefined
|
||||
private _volume: number = 1 // 0 to 1
|
||||
private _fmTrack: Track | null = null
|
||||
private _fmInited = false
|
||||
|
||||
state: State = State.INITIALIZING
|
||||
mode: Mode = Mode.PLAYLIST
|
||||
|
|
@ -53,9 +53,11 @@ export class Player {
|
|||
fmTrackList: TrackID[] = []
|
||||
shuffle: boolean = false
|
||||
repeatMode: RepeatMode = RepeatMode.OFF
|
||||
fmTrack: Track | null = null
|
||||
|
||||
constructor() {
|
||||
//
|
||||
init() {
|
||||
this.state = State.READY
|
||||
this.initFM()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -105,11 +107,7 @@ export class Player {
|
|||
* Get current playing track
|
||||
*/
|
||||
get track(): Track | null {
|
||||
return this._track ?? null
|
||||
}
|
||||
|
||||
get fmTrack(): Track | null {
|
||||
return this._fmTrack ?? null
|
||||
return this.mode === Mode.FM ? this.fmTrack : this._track
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +142,6 @@ export class Player {
|
|||
* Fetch track details from Netease based on this.trackID
|
||||
*/
|
||||
private async _fetchTrack(trackID: TrackID) {
|
||||
this.state = State.LOADING
|
||||
const response = await fetchTracksWithReactQuery({ ids: [trackID] })
|
||||
if (response.songs.length) {
|
||||
return response.songs[0]
|
||||
|
|
@ -167,9 +164,14 @@ export class Player {
|
|||
* Play a track based on this.trackID
|
||||
*/
|
||||
private async _playTrack() {
|
||||
this.state = State.LOADING
|
||||
const track = await this._fetchTrack(this.trackID)
|
||||
if (track) this._track = track
|
||||
if (track && this.mode === Mode.FM) this._fmTrack = track
|
||||
if (!track) {
|
||||
toast('加载歌曲信息失败')
|
||||
return
|
||||
}
|
||||
if (this.mode === Mode.PLAYLIST) this._track = track
|
||||
if (this.mode === Mode.FM) this.fmTrack = track
|
||||
this._playAudio()
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +206,6 @@ export class Player {
|
|||
}
|
||||
|
||||
private _howlerOnEndCallback() {
|
||||
console.log('_howlerOnEndCallback')
|
||||
if (this.mode !== Mode.FM && this.repeatMode === RepeatMode.ONE) {
|
||||
_howler.seek(0)
|
||||
_howler.play()
|
||||
|
|
@ -221,24 +222,23 @@ export class Player {
|
|||
}
|
||||
|
||||
private async _nextFMTrack() {
|
||||
if (this.fmTrackList.length <= 1) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const response = await fetchPersonalFMWithReactQuery()
|
||||
if (!response?.data?.length) continue
|
||||
this.fmTrackList.shift()
|
||||
this.fmTrackList.push(...response?.data?.map(r => r.id))
|
||||
this.fmTrackList.shift()
|
||||
this._playTrack()
|
||||
|
||||
this._playTrack()
|
||||
break
|
||||
}
|
||||
} else {
|
||||
this.fmTrackList.shift()
|
||||
this._playTrack()
|
||||
if (this.fmTrackList.length <= 1) {
|
||||
const loadMoreTracks = async () => {
|
||||
if (this.fmTrackList.length <= 5) {
|
||||
const response = await fetchPersonalFMWithReactQuery()
|
||||
this.fmTrackList.push(...response?.data?.map(r => r.id))
|
||||
this.fmTrackList.push(...(response?.data?.map(r => r.id) ?? {}))
|
||||
}
|
||||
}
|
||||
const prefetchNextTrack = async () => {
|
||||
const prefetchTrackID = this.fmTrackList[1]
|
||||
const track = await this._fetchTrack(prefetchTrackID)
|
||||
if (track?.al.picUrl) axios.get(resizeImage(track.al.picUrl, 'md'))
|
||||
}
|
||||
|
||||
loadMoreTracks()
|
||||
prefetchNextTrack()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -246,10 +246,14 @@ export class Player {
|
|||
* @param {boolean} fade fade in
|
||||
*/
|
||||
play(fade: boolean = false) {
|
||||
if (_howler.playing()) return
|
||||
if (_howler.playing()) {
|
||||
this.state = State.PLAYING
|
||||
return
|
||||
}
|
||||
|
||||
_howler.play()
|
||||
if (fade) {
|
||||
this.state = State.PLAYING
|
||||
_howler.once('play', () => {
|
||||
_howler.fade(0, this._volume, PLAY_PAUSE_FADE_DURATION)
|
||||
})
|
||||
|
|
@ -303,7 +307,6 @@ export class Player {
|
|||
* Play next track
|
||||
*/
|
||||
nextTrack(forceFM: boolean = false) {
|
||||
console.log(this)
|
||||
if (forceFM || this.mode === Mode.FM) {
|
||||
this.mode = Mode.FM
|
||||
this._nextFMTrack()
|
||||
|
|
@ -343,7 +346,6 @@ export class Player {
|
|||
* @param {null|number=} autoPlayTrackID
|
||||
*/
|
||||
async playAlbum(album: Album, autoPlayTrackID?: null | number) {
|
||||
console.log(album)
|
||||
if (!album?.songs?.length) return
|
||||
this.trackListSource = {
|
||||
type: TrackListSourceType.ALBUM,
|
||||
|
|
@ -364,9 +366,9 @@ export class Player {
|
|||
this.mode = Mode.FM
|
||||
if (
|
||||
this.fmTrackList.length > 0 &&
|
||||
this._fmTrack?.id === this.fmTrackList[0]
|
||||
this.fmTrack?.id === this.fmTrackList[0]
|
||||
) {
|
||||
this._track = this._fmTrack
|
||||
this._track = this.fmTrack
|
||||
this._playAudio()
|
||||
} else {
|
||||
this._playTrack()
|
||||
|
|
@ -375,49 +377,23 @@ export class Player {
|
|||
|
||||
/**
|
||||
* Init personal fm
|
||||
* should only be called in components/FMCard
|
||||
*/
|
||||
async initFM() {
|
||||
if (this._fmInited) return
|
||||
const response = await fetchPersonalFMWithReactQuery()
|
||||
this.fmTrackList.push(...response?.data?.map(r => r.id))
|
||||
this.fmTrackList.push(...(response?.data?.map(r => r.id) ?? {}))
|
||||
|
||||
const trackId = this.fmTrackList[0]
|
||||
const track = await this._fetchTrack(trackId)
|
||||
if (track) this._fmTrack = track
|
||||
this._fmInited = true
|
||||
if (track) this.fmTrack = track
|
||||
}
|
||||
|
||||
/**
|
||||
* Trash current PersonalFMTrack
|
||||
*/
|
||||
async fmTrash() {
|
||||
let trashId = this.fmTrackList.shift() ?? 0
|
||||
if (trashId === 0) return
|
||||
|
||||
if (this.mode === Mode.FM) {
|
||||
await this._nextFMTrack()
|
||||
} else {
|
||||
for (let i = 0; i < 5 && this.fmTrackList.length <= 1; i++) {
|
||||
const response = await fetchPersonalFMWithReactQuery()
|
||||
this.fmTrackList.push(...response?.data?.map(r => r.id))
|
||||
}
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
let track = await this._fetchTrack(this.fmTrackList.at(0) ?? 0)
|
||||
if (track) {
|
||||
this._fmTrack = track
|
||||
break
|
||||
} else {
|
||||
this.fmTrackList.shift()
|
||||
if (this.fmTrackList.length <= 1) {
|
||||
const response = await fetchPersonalFMWithReactQuery()
|
||||
this.fmTrackList.push(...response?.data?.map(r => r.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmTrash(trashId)
|
||||
const trashTrackID = this.fmTrackList[0]
|
||||
fmTrash(trashTrackID)
|
||||
this._nextFMTrack()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -432,3 +408,7 @@ export class Player {
|
|||
}
|
||||
|
||||
export const player = new Player()
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
window.howler = _howler
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue