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
3ef7675696
commit
744247143b
11 changed files with 195 additions and 68 deletions
|
|
@ -33,7 +33,7 @@ const PlayingTrack = () => {
|
|||
<img
|
||||
onClick={toAlbum}
|
||||
className='aspect-square h-full rounded-md shadow-md'
|
||||
src={resizeImage(track?.al?.picUrl ?? '', 'sm')}
|
||||
src={resizeImage(track.al.picUrl, 'xs')}
|
||||
/>
|
||||
)}
|
||||
{!track?.al?.picUrl && (
|
||||
|
|
|
|||
|
|
@ -49,19 +49,22 @@ const Track = memo(
|
|||
isLiked = false,
|
||||
isSkeleton = false,
|
||||
isHighlight = false,
|
||||
subtitle = undefined,
|
||||
onClick,
|
||||
}: {
|
||||
track: Track
|
||||
isLiked?: boolean
|
||||
isSkeleton?: boolean
|
||||
isHighlight?: boolean
|
||||
subtitle?: string
|
||||
onClick: (e: React.MouseEvent<HTMLElement>, trackID: number) => void
|
||||
}) => {
|
||||
if (enableRenderLog)
|
||||
console.debug(`Rendering TracksAlbum.tsx Track ${track.name}`)
|
||||
|
||||
const subtitle = useMemo(
|
||||
() => track.tns?.at(0) ?? track.alia?.at(0),
|
||||
[track.alia, track.tns]
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={e => onClick(e, track.id)}
|
||||
|
|
@ -125,7 +128,6 @@ const Track = memo(
|
|||
)}
|
||||
{subtitle && (
|
||||
<span
|
||||
title={subtitle}
|
||||
className={classNames(
|
||||
'ml-1',
|
||||
isHighlight ? 'text-brand-500/[.8]' : 'text-gray-400'
|
||||
|
|
@ -259,7 +261,6 @@ const TracksAlbum = ({
|
|||
isLiked={userLikedSongs?.ids?.includes(track.id) ?? false}
|
||||
isSkeleton={false}
|
||||
isHighlight={track.id === playingTrack?.id}
|
||||
subtitle={track.tns?.at(0) ?? track.alia?.at(0)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import ArtistInline from '@/components/ArtistsInline'
|
||||
import Skeleton from '@/components/Skeleton'
|
||||
import { player } from '@/store'
|
||||
import { resizeImage } from '@/utils/common'
|
||||
import SvgIcon from './SvgIcon'
|
||||
|
||||
|
|
@ -7,13 +8,16 @@ const Track = ({
|
|||
track,
|
||||
isSkeleton = false,
|
||||
isHighlight = false,
|
||||
onClick,
|
||||
}: {
|
||||
track: Track
|
||||
isSkeleton: boolean
|
||||
isHighlight: boolean
|
||||
isSkeleton?: boolean
|
||||
isHighlight?: boolean
|
||||
onClick: (e: React.MouseEvent<HTMLElement>, trackID: number) => void
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
onClick={e => onClick(e, track.id)}
|
||||
className={classNames(
|
||||
'group grid w-full rounded-xl after:scale-[.98] after:rounded-xl ',
|
||||
'grid-cols-1 py-1.5 px-2',
|
||||
|
|
@ -27,30 +31,30 @@ const Track = ({
|
|||
<div className='grid grid-cols-[3rem_auto] items-center'>
|
||||
{/* Cover */}
|
||||
<div>
|
||||
{!isSkeleton && (
|
||||
{isSkeleton ? (
|
||||
<Skeleton className='mr-4 h-9 w-9 rounded-md border border-gray-100' />
|
||||
) : (
|
||||
<img
|
||||
src={resizeImage(track.al.picUrl, 'xs')}
|
||||
className='box-content h-9 w-9 rounded-md border border-black border-opacity-[.03]'
|
||||
/>
|
||||
)}
|
||||
{isSkeleton && (
|
||||
<Skeleton className='mr-4 h-9 w-9 rounded-md border border-gray-100' />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Track name & Artists */}
|
||||
<div className='flex flex-col justify-center'>
|
||||
{!isSkeleton && (
|
||||
{isSkeleton ? (
|
||||
<Skeleton className='text-base '>PLACEHOLDER12345</Skeleton>
|
||||
) : (
|
||||
<div
|
||||
v-if='!isSkeleton'
|
||||
className='line-clamp-1 break-all text-base font-semibold dark:text-white'
|
||||
className={classNames(
|
||||
'line-clamp-1 break-all text-base font-semibold ',
|
||||
isHighlight ? 'text-brand-500' : 'text-black dark:text-white'
|
||||
)}
|
||||
>
|
||||
{track.name}
|
||||
</div>
|
||||
)}
|
||||
{isSkeleton && (
|
||||
<Skeleton className='text-base '>PLACEHOLDER12345</Skeleton>
|
||||
)}
|
||||
|
||||
<div className='text-xs text-gray-500 dark:text-gray-400'>
|
||||
{isSkeleton ? (
|
||||
|
|
@ -60,10 +64,23 @@ const Track = ({
|
|||
{track.mark === 1318912 && (
|
||||
<SvgIcon
|
||||
name='explicit'
|
||||
className='mr-1 h-3 w-3 text-gray-300 dark:text-gray-500'
|
||||
className={classNames(
|
||||
'mr-1 h-3 w-3',
|
||||
isHighlight
|
||||
? 'text-brand-500'
|
||||
: 'text-gray-300 dark:text-gray-500'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<ArtistInline artists={track.ar} disableLink={true} />
|
||||
<ArtistInline
|
||||
artists={track.ar}
|
||||
disableLink={true}
|
||||
className={
|
||||
isHighlight
|
||||
? 'text-brand-500'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -84,6 +101,16 @@ const TrackGrid = ({
|
|||
onTrackDoubleClick?: (trackID: number) => void
|
||||
cols?: number
|
||||
}) => {
|
||||
const handleClick = (e: React.MouseEvent<HTMLElement>, trackID: number) => {
|
||||
if (e.detail === 2) onTrackDoubleClick?.(trackID)
|
||||
}
|
||||
|
||||
const playerSnapshot = useSnapshot(player)
|
||||
const playingTrack = useMemo(
|
||||
() => playerSnapshot.track,
|
||||
[playerSnapshot.track]
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
className='grid gap-x-2'
|
||||
|
|
@ -93,10 +120,11 @@ const TrackGrid = ({
|
|||
>
|
||||
{tracks.map((track, index) => (
|
||||
<Track
|
||||
onClick={handleClick}
|
||||
key={track.id}
|
||||
track={track}
|
||||
isSkeleton={isSkeleton}
|
||||
isHighlight={false}
|
||||
isHighlight={track.id === playingTrack?.id}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,17 +13,20 @@ const Track = memo(
|
|||
track,
|
||||
isLiked = false,
|
||||
isSkeleton = false,
|
||||
isPlaying = false,
|
||||
subtitle = undefined,
|
||||
isHighlight = false,
|
||||
onClick,
|
||||
}: {
|
||||
track: Track
|
||||
isLiked?: boolean
|
||||
isSkeleton?: boolean
|
||||
isPlaying?: boolean
|
||||
subtitle?: string
|
||||
isHighlight?: boolean
|
||||
onClick: (e: React.MouseEvent<HTMLElement>, trackID: number) => void
|
||||
}) => {
|
||||
const subtitle = useMemo(
|
||||
() => track.tns?.at(0) ?? track.alia?.at(0),
|
||||
[track.alia, track.tns]
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={e => onClick(e, track.id)}
|
||||
|
|
@ -31,9 +34,9 @@ const Track = memo(
|
|||
'group grid w-full rounded-xl after:scale-[.98] after:rounded-xl ',
|
||||
'grid-cols-12 p-2 pr-4',
|
||||
!isSkeleton &&
|
||||
!isPlaying &&
|
||||
!isHighlight &&
|
||||
'btn-hover-animation after:bg-gray-100 dark:after:bg-white/10',
|
||||
!isSkeleton && isPlaying && 'bg-brand-50 dark:bg-gray-800'
|
||||
!isSkeleton && isHighlight && 'bg-brand-50 dark:bg-gray-800'
|
||||
)}
|
||||
>
|
||||
{/* Track info */}
|
||||
|
|
@ -58,7 +61,7 @@ const Track = memo(
|
|||
<div
|
||||
className={classNames(
|
||||
'line-clamp-1 break-all text-lg font-semibold',
|
||||
isPlaying ? 'text-brand-500' : 'text-black dark:text-white'
|
||||
isHighlight ? 'text-brand-500' : 'text-black dark:text-white'
|
||||
)}
|
||||
>
|
||||
<span>{track.name}</span>
|
||||
|
|
@ -67,7 +70,7 @@ const Track = memo(
|
|||
title={subtitle}
|
||||
className={classNames(
|
||||
'ml-1',
|
||||
isPlaying ? 'text-brand-500/[.8]' : 'text-gray-400'
|
||||
isHighlight ? 'text-brand-500/[.8]' : 'text-gray-400'
|
||||
)}
|
||||
>
|
||||
({subtitle})
|
||||
|
|
@ -79,7 +82,7 @@ const Track = memo(
|
|||
<div
|
||||
className={classNames(
|
||||
'text-sm',
|
||||
isPlaying
|
||||
isHighlight
|
||||
? 'text-brand-500'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
)}
|
||||
|
|
@ -111,7 +114,7 @@ const Track = memo(
|
|||
to={`/album/${track.al.id}`}
|
||||
className={classNames(
|
||||
'hover:underline',
|
||||
isPlaying && 'text-brand-500'
|
||||
isHighlight && 'text-brand-500'
|
||||
)}
|
||||
>
|
||||
{track.al.name}
|
||||
|
|
@ -147,7 +150,7 @@ const Track = memo(
|
|||
<div
|
||||
className={classNames(
|
||||
'min-w-[2.5rem] text-right',
|
||||
isPlaying
|
||||
isHighlight
|
||||
? 'text-brand-500'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,16 @@ export default function useAlbum(params: FetchAlbumParams, noCache?: boolean) {
|
|||
)
|
||||
}
|
||||
|
||||
export function fetchAlbumWithReactQuery(params: FetchAlbumParams) {
|
||||
return reactQueryClient.fetchQuery(
|
||||
[AlbumApiNames.FETCH_ALBUM, params.id],
|
||||
() => fetch(params),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export async function prefetchAlbum(params: FetchAlbumParams) {
|
||||
await reactQueryClient.prefetchQuery(
|
||||
[AlbumApiNames.FETCH_ALBUM, params.id],
|
||||
|
|
|
|||
|
|
@ -28,6 +28,16 @@ export default function usePlaylist(
|
|||
)
|
||||
}
|
||||
|
||||
export function fetchPlaylistWithReactQuery(params: FetchPlaylistParams) {
|
||||
return reactQueryClient.fetchQuery(
|
||||
[PlaylistApiNames.FETCH_PLAYLIST, params],
|
||||
() => fetch(params),
|
||||
{
|
||||
staleTime: 3600000,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export async function prefetchPlaylist(params: FetchPlaylistParams) {
|
||||
await reactQueryClient.prefetchQuery(
|
||||
[PlaylistApiNames.FETCH_PLAYLIST, params],
|
||||
|
|
|
|||
|
|
@ -296,12 +296,11 @@ const Album = () => {
|
|||
})
|
||||
|
||||
const handlePlay = async (trackID: number | null = null) => {
|
||||
const realAlbum = album?.album
|
||||
if (!realAlbum) {
|
||||
toast('Failed to play album')
|
||||
if (!album?.album.id) {
|
||||
toast('无法播放专辑,该专辑不存在')
|
||||
return
|
||||
}
|
||||
await player.playAlbum(realAlbum, trackID)
|
||||
await player.playAlbum(album.album.id, trackID)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import TracksGrid from '@/components/TracksGrid'
|
|||
import CoverRow, { Subtitle } from '@/components/CoverRow'
|
||||
import Skeleton from '@/components/Skeleton'
|
||||
import useTracks from '@/hooks/useTracks'
|
||||
import { player } from '@/store'
|
||||
|
||||
const Header = ({ artist }: { artist: Artist | undefined }) => {
|
||||
const coverImage = resizeImage(artist?.img1v1Url || '', 'md')
|
||||
|
|
@ -51,18 +52,27 @@ const LatestRelease = ({
|
|||
album: Album | undefined
|
||||
isLoading: boolean
|
||||
}) => {
|
||||
const navigate = useNavigate()
|
||||
const toAlbum = () => navigate(`/album/${album?.id}`)
|
||||
return (
|
||||
<div>
|
||||
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
||||
最新发行
|
||||
</div>
|
||||
<div className='flex-grow rounded-xl '>
|
||||
<div className='flex-grow rounded-xl'>
|
||||
{isLoading ? (
|
||||
<Skeleton className='aspect-square w-full rounded-xl'></Skeleton>
|
||||
) : (
|
||||
<Cover imageUrl={album?.picUrl ?? ''} showPlayButton={true} />
|
||||
<Cover
|
||||
imageUrl={album?.picUrl ?? ''}
|
||||
showPlayButton={true}
|
||||
onClick={toAlbum}
|
||||
/>
|
||||
)}
|
||||
<div className='line-clamp-2 line-clamp-1 mt-2 font-semibold leading-tight decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'>
|
||||
<div
|
||||
onClick={toAlbum}
|
||||
className='line-clamp-2 line-clamp-1 mt-2 font-semibold leading-tight decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'
|
||||
>
|
||||
{album?.name}
|
||||
</div>
|
||||
<div className='text-[12px] text-gray-500 dark:text-gray-400'>
|
||||
|
|
@ -84,6 +94,20 @@ const PopularTracks = ({
|
|||
ids: tracks?.slice(0, 10)?.map(t => t.id) ?? [],
|
||||
})
|
||||
|
||||
const handlePlay = useCallback(
|
||||
(trackID: number | null = null) => {
|
||||
if (!tracks?.length) {
|
||||
toast('无法播放歌单')
|
||||
return
|
||||
}
|
||||
player.playAList(
|
||||
tracks.map(t => t.id),
|
||||
trackID
|
||||
)
|
||||
},
|
||||
[tracks]
|
||||
)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
|
||||
|
|
@ -93,6 +117,7 @@ const PopularTracks = ({
|
|||
<TracksGrid
|
||||
tracks={tracksWithExtraInfo?.songs ?? tracks?.slice(0, 10) ?? []}
|
||||
isSkeleton={isLoadingArtist}
|
||||
onTrackDoubleClick={handlePlay}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -215,11 +215,11 @@ const Playlist = () => {
|
|||
|
||||
const handlePlay = useCallback(
|
||||
(trackID: number | null = null) => {
|
||||
if (!playlist) {
|
||||
toast('Failed to play playlist')
|
||||
if (!playlist?.playlist?.id) {
|
||||
toast('无法播放歌单')
|
||||
return
|
||||
}
|
||||
player.playPlaylist(playlist.playlist, trackID)
|
||||
player.playPlaylist(playlist.playlist.id, trackID)
|
||||
},
|
||||
[playlist]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
} from '@/api/search'
|
||||
import Cover from '@/components/Cover'
|
||||
import TrackGrid from '@/components/TracksGrid'
|
||||
import { player } from '@/store'
|
||||
import { resizeImage } from '@/utils/common'
|
||||
|
||||
const Artists = ({ artists }: { artists: Artist[] }) => {
|
||||
|
|
@ -98,6 +99,33 @@ const Search = () => {
|
|||
() => search({ keywords, type: searchType })
|
||||
)
|
||||
|
||||
const handlePlayTracks = useCallback(
|
||||
(trackID: number | null = null) => {
|
||||
const tracks = searchResult?.result.song.songs
|
||||
if (!tracks?.length) {
|
||||
toast('无法播放歌单')
|
||||
return
|
||||
}
|
||||
player.playAList(
|
||||
tracks.map(t => t.id),
|
||||
trackID
|
||||
)
|
||||
},
|
||||
[searchResult?.result.song.songs]
|
||||
)
|
||||
|
||||
const navigate = useNavigate()
|
||||
const navigateBestMatch = (match: Artist | Album) => {
|
||||
if ((match as Artist).albumSize !== undefined) {
|
||||
navigate(`/artist/${match.id}`)
|
||||
return
|
||||
}
|
||||
if ((match as Album).artist !== undefined) {
|
||||
navigate(`/album/${match.id}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='mt-6 mb-8 text-4xl font-semibold dark:text-white'>
|
||||
|
|
@ -111,6 +139,7 @@ const Search = () => {
|
|||
<div className='grid grid-cols-2'>
|
||||
{bestMatch.map(match => (
|
||||
<div
|
||||
onClick={() => navigateBestMatch(match)}
|
||||
key={`${match.id}${match.picUrl}`}
|
||||
className='btn-hover-animation flex items-center p-3 after:rounded-xl after:bg-gray-100 dark:after:bg-white/10'
|
||||
>
|
||||
|
|
@ -154,7 +183,11 @@ const Search = () => {
|
|||
{searchResult?.result.song.songs && (
|
||||
<div className='col-span-2'>
|
||||
<div className='mb-2 text-sm font-medium text-gray-400'>歌曲</div>
|
||||
<TrackGrid tracks={searchResult.result.song.songs} cols={3} />
|
||||
<TrackGrid
|
||||
tracks={searchResult.result.song.songs}
|
||||
cols={3}
|
||||
onTrackDoubleClick={handlePlayTracks}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import { cacheAudio } from '@/api/yesplaymusic'
|
|||
import { clamp } from 'lodash-es'
|
||||
import axios from 'axios'
|
||||
import { resizeImage } from './common'
|
||||
import { fetchPlaylistWithReactQuery } from '@/hooks/usePlaylist'
|
||||
import { fetchAlbumWithReactQuery } from '@/hooks/useAlbum'
|
||||
|
||||
type TrackID = number
|
||||
enum TrackListSourceType {
|
||||
|
|
@ -114,7 +116,7 @@ export class Player {
|
|||
* Get/Set progress of current track
|
||||
*/
|
||||
get progress(): number {
|
||||
return this._progress
|
||||
return this.state === State.LOADING ? 0 : this._progress
|
||||
}
|
||||
set progress(value) {
|
||||
this._progress = value
|
||||
|
|
@ -179,9 +181,10 @@ export class Player {
|
|||
* Play audio via howler
|
||||
*/
|
||||
private async _playAudio() {
|
||||
this._progress = 0
|
||||
const { audio, id } = await this._fetchAudioSource(this.trackID)
|
||||
if (!audio) {
|
||||
toast('Failed to load audio source')
|
||||
toast('无法播放此歌曲')
|
||||
return
|
||||
}
|
||||
Howler.unload()
|
||||
|
|
@ -228,7 +231,7 @@ export class Player {
|
|||
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 () => {
|
||||
|
|
@ -291,6 +294,7 @@ export class Player {
|
|||
* Play previous track
|
||||
*/
|
||||
prevTrack() {
|
||||
this._progress = 0
|
||||
if (this.mode === Mode.FM) {
|
||||
toast('Personal FM not support previous track')
|
||||
return
|
||||
|
|
@ -307,13 +311,14 @@ export class Player {
|
|||
* Play next track
|
||||
*/
|
||||
nextTrack(forceFM: boolean = false) {
|
||||
this._progress = 0
|
||||
if (forceFM || this.mode === Mode.FM) {
|
||||
this.mode = Mode.FM
|
||||
this._nextFMTrack()
|
||||
return
|
||||
}
|
||||
if (this._nextTrackIndex === undefined) {
|
||||
toast('No next track')
|
||||
toast('没有下一首了')
|
||||
this.pause()
|
||||
return
|
||||
}
|
||||
|
|
@ -322,41 +327,54 @@ export class Player {
|
|||
}
|
||||
|
||||
/**
|
||||
* Play a playlist
|
||||
* @param {Playlist} playlist
|
||||
* @param {null|number=} autoPlayTrackID
|
||||
* 播放一个track id列表
|
||||
* @param {number[]} list
|
||||
* @param {null|number} autoPlayTrackID
|
||||
*/
|
||||
async playPlaylist(playlist: Playlist, autoPlayTrackID?: null | number) {
|
||||
if (!playlist?.trackIds?.length) return
|
||||
this.trackListSource = {
|
||||
type: TrackListSourceType.PLAYLIST,
|
||||
id: playlist.id,
|
||||
}
|
||||
playAList(list: TrackID[], autoPlayTrackID?: null | number) {
|
||||
this.mode = Mode.PLAYLIST
|
||||
this.trackList = playlist.trackIds.map(t => t.id)
|
||||
this.trackList = list
|
||||
this._trackIndex = autoPlayTrackID
|
||||
? playlist.trackIds.findIndex(t => t.id === autoPlayTrackID)
|
||||
? list.findIndex(t => t === autoPlayTrackID)
|
||||
: 0
|
||||
this._playTrack()
|
||||
}
|
||||
|
||||
/**
|
||||
* Play am album
|
||||
* @param {Album} album
|
||||
* Play a playlist
|
||||
* @param {number} playlistID
|
||||
* @param {null|number=} autoPlayTrackID
|
||||
*/
|
||||
async playAlbum(album: Album, autoPlayTrackID?: null | number) {
|
||||
async playPlaylist(playlistID: number, autoPlayTrackID?: null | number) {
|
||||
const playlist = await fetchPlaylistWithReactQuery({ id: playlistID })
|
||||
if (!playlist?.playlist?.trackIds?.length) return
|
||||
this.trackListSource = {
|
||||
type: TrackListSourceType.PLAYLIST,
|
||||
id: playlistID,
|
||||
}
|
||||
this.playAList(
|
||||
playlist.playlist.trackIds.map(t => t.id),
|
||||
autoPlayTrackID
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play am album
|
||||
* @param {number} albumID
|
||||
* @param {null|number=} autoPlayTrackID
|
||||
*/
|
||||
async playAlbum(albumID: number, autoPlayTrackID?: null | number) {
|
||||
const album = await fetchAlbumWithReactQuery({ id: albumID })
|
||||
if (!album?.songs?.length) return
|
||||
this.trackListSource = {
|
||||
type: TrackListSourceType.ALBUM,
|
||||
id: album.id,
|
||||
id: albumID,
|
||||
}
|
||||
this.mode = Mode.PLAYLIST
|
||||
this.trackList = album.songs.map(t => t.id)
|
||||
this._trackIndex = autoPlayTrackID
|
||||
? album.songs.findIndex(t => t.id === autoPlayTrackID)
|
||||
: 0
|
||||
this._playTrack()
|
||||
this.playAList(
|
||||
album.songs.map(t => t.id),
|
||||
autoPlayTrackID
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -380,7 +398,7 @@ export class Player {
|
|||
*/
|
||||
async initFM() {
|
||||
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)
|
||||
|
|
@ -401,7 +419,7 @@ export class Player {
|
|||
*/
|
||||
async playTrack(trackID: TrackID) {
|
||||
const index = this.trackList.findIndex(t => t === trackID)
|
||||
if (!index) toast('Failed to play: This track is not in the playlist')
|
||||
if (!index) toast('播放失败,歌曲不在列表内')
|
||||
this._trackIndex = index
|
||||
this._playTrack()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue