import dayjs from 'dayjs'
import { NavLink, useParams } from 'react-router-dom'
import Button, { Color as ButtonColor } from '@/web/components/Button'
import CoverRow, { Subtitle } from '@/web/components/CoverRow'
import Skeleton from '@/web/components/Skeleton'
import Icon from '@/web/components/Icon'
import TracksAlbum from '@/web/components/TracksAlbum'
import useAlbum from '@/web/api/hooks/useAlbum'
import useArtistAlbums from '@/web/api/hooks/useArtistAlbums'
import { player } from '@/web/store'
import {
Mode as PlayerMode,
State as PlayerState,
TrackListSourceType,
} from '@/web/utils/player'
import {
formatDate,
formatDuration,
resizeImage,
scrollToTop,
} from '@/web/utils/common'
import useTracks from '@/web/api/hooks/useTracks'
import useUserAlbums, {
useMutationLikeAAlbum,
} from '@/web/api/hooks/useUserAlbums'
import { useMemo, useState } from 'react'
import toast from 'react-hot-toast'
import { useSnapshot } from 'valtio'
const PlayButton = ({
album,
handlePlay,
isLoading,
}: {
album: Album | undefined
handlePlay: () => void
isLoading: boolean
}) => {
const playerSnapshot = useSnapshot(player)
const isThisAlbumPlaying = useMemo(
() =>
playerSnapshot.mode === PlayerMode.TrackList &&
playerSnapshot.trackListSource?.type === TrackListSourceType.Album &&
playerSnapshot.trackListSource?.id === album?.id,
[
playerSnapshot.mode,
playerSnapshot.trackListSource?.type,
playerSnapshot.trackListSource?.id,
album?.id,
]
)
const isPlaying =
isThisAlbumPlaying &&
[PlayerState.Playing, PlayerState.Loading].includes(playerSnapshot.state)
const wrappedHandlePlay = () => {
if (isThisAlbumPlaying) {
player.playOrPause()
} else {
handlePlay()
}
}
return (
)
}
const Header = ({
album,
isLoading,
handlePlay,
}: {
album: Album | undefined
isLoading: boolean
handlePlay: () => void
}) => {
const coverUrl = resizeImage(album?.picUrl || '', 'lg')
const albumDuration = useMemo(() => {
const duration = album?.songs?.reduce((acc, cur) => acc + cur.dt, 0) || 0
return formatDuration(duration, 'zh-CN', 'hh[hr] mm[min]')
}, [album?.songs])
const [isCoverError, setCoverError] = useState(
coverUrl.includes('3132508627578625')
)
const { data: userAlbums } = useUserAlbums()
const isThisAlbumLiked = useMemo(() => {
if (!album) return false
return !!userAlbums?.data?.find(a => a.id === album.id)
}, [album, userAlbums?.data])
const mutationLikeAAlbum = useMutationLikeAAlbum()
return (
<>
{/* Header background */}
{coverUrl && !isCoverError && (
<>

>
)}
{/* Cover */}
{/* Neon shadow */}
{!isLoading && coverUrl && !isCoverError && (
)}
{!isLoading && isCoverError ? (
// Fallback cover
) : (
coverUrl && (

setCoverError(true)}
/>
)
)}
{isLoading &&
}
{/* Info */}
{/* Name */}
{isLoading ? (
PLACEHOLDER
) : (
{album?.name}
)}
{/* Artist */}
{isLoading ? (
PLACEHOLDER
) : (
Album ·{' '}
{album?.artist.name}
)}
{/* Release date & track count & album duration */}
{isLoading ? (
PLACEHOLDER
) : (
{album?.mark === 1056768 && (
)}
{dayjs(album?.publishTime || 0).year()} · {album?.size} 首歌 ·{' '}
{albumDuration}
)}
{/* Description */}
{isLoading ? (
PLACEHOLDER
) : (
{album?.description}
)}
{/* Buttons */}
>
)
}
const MoreAlbum = ({ album }: { album: Album | undefined }) => {
// Fetch artist's albums
const { data: albums, isLoading } = useArtistAlbums({
id: album?.artist.id ?? 0,
limit: 1000,
})
const filteredAlbums = useMemo((): Album[] => {
if (!albums) return []
const allReleases = albums?.hotAlbums || []
const filteredAlbums = allReleases.filter(
album =>
['专辑', 'EP/Single', 'EP'].includes(album.type) && album.size > 1
)
const singles = allReleases.filter(album => album.type === 'Single')
const qualifiedAlbums = [...filteredAlbums, ...singles]
const formatName = (name: string) =>
name.toLowerCase().replace(/(\s|deluxe|edition|\(|\))/g, '')
const uniqueAlbums: Album[] = []
qualifiedAlbums.forEach(a => {
// 去除当前页面的专辑
if (formatName(a.name) === formatName(album?.name ?? '')) return
// 去除重复的专辑(包含 deluxe edition 的专辑会视为重复)
if (
uniqueAlbums.findIndex(aa => {
return formatName(a.name) === formatName(aa.name)
}) !== -1
) {
return
}
// 去除 remix 专辑
if (
a.name.toLowerCase().includes('remix)') ||
a.name.toLowerCase().includes('remixes)')
) {
return
}
uniqueAlbums.push(a)
})
return uniqueAlbums.slice(0, 5)
}, [album?.name, albums])
return (
{!isLoading && albums?.hotAlbums?.length && (
More by{' '}
{album?.artist.name}
)}
)
}
const Album = () => {
const params = useParams()
const { data: album, isLoading } = useAlbum({
id: Number(params.id) || 0,
})
const { data: tracks } = useTracks({
ids: album?.songs?.map(track => track.id) ?? [],
})
const handlePlay = async (trackID: number | null = null) => {
if (!album?.album.id) {
toast('无法播放专辑,该专辑不存在')
return
}
await player.playAlbum(album.album.id, trackID)
}
return (
{album?.album && (
Released {formatDate(album.album.publishTime || 0, 'en')}
{album.album.company && (
© {album.album.company}
)}
)}
{!isLoading &&
}
)
}
export default Album