feat: updates

This commit is contained in:
qier222 2022-04-02 16:54:37 +08:00
parent 86f088e5c9
commit 3ef7675696
No known key found for this signature in database
GPG key ID: 9C85007ED905F14D
12 changed files with 158 additions and 146 deletions

View file

@ -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
View file

@ -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

View file

@ -91,7 +91,6 @@ export interface FetchPersonalFMResponse {
s_ctrp: string
}[]
}
export function fetchPersonalFM(): Promise<FetchPersonalFMResponse> {
return request({
url: '/personal/fm',

View file

@ -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

Before After
Before After

View file

@ -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>
{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

View file

@ -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 && (

View file

@ -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,

View file

@ -34,7 +34,10 @@ export function fetchTracksWithReactQuery(params: FetchTracksParams) {
return fetchTracks(params)
},
{
retry: 3,
retry: 4,
retryDelay: (retryCount: number) => {
return retryCount * 500
},
staleTime: 86400000,
}
)

View file

@ -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')

View file

@ -111,3 +111,7 @@ a,
button {
cursor: default;
}
img {
-webkit-user-drag: none;
}

View file

@ -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._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
}