mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2025-01-19 23:12:44 +08:00
feat: 音乐库增加查看收藏的专辑/歌单/歌手功能
This commit is contained in:
parent
bbd5299341
commit
2e41001d02
|
@ -4,6 +4,8 @@ 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',
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +101,7 @@ export interface FetchUserPlaylistsParams {
|
|||
}
|
||||
export interface FetchUserPlaylistsResponse {
|
||||
code: number
|
||||
more: false
|
||||
more: boolean
|
||||
version: string
|
||||
playlist: Playlist[]
|
||||
}
|
||||
|
@ -151,40 +153,44 @@ export function dailySignin(type = 0) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收藏的专辑(需要登录)
|
||||
* 说明 : 调用此接口可获取到用户收藏的专辑
|
||||
* - limit : 返回数量 , 默认为 25
|
||||
* - offset : 偏移数量,用于分页 , 如 :( 页数 -1)*25, 其中 25 为 limit 的值 , 默认为 0
|
||||
* @param {Object} params
|
||||
* @param {number} params.limit
|
||||
* @param {number=} params.offset
|
||||
*/
|
||||
// export function likedAlbums(params) {
|
||||
// return request({
|
||||
// url: '/album/sublist',
|
||||
// method: 'get',
|
||||
// params: {
|
||||
// limit: params.limit,
|
||||
// timestamp: new Date().getTime(),
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
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(params: FetchUserAlbumsParams) {
|
||||
return request({
|
||||
url: '/album/sublist',
|
||||
method: 'get',
|
||||
params: {
|
||||
...params,
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收藏的歌手(需要登录)
|
||||
* 说明 : 调用此接口可获取到用户收藏的歌手
|
||||
*/
|
||||
// export function likedArtists(params) {
|
||||
// return request({
|
||||
// url: '/artist/sublist',
|
||||
// method: 'get',
|
||||
// params: {
|
||||
// limit: params.limit,
|
||||
// timestamp: new Date().getTime(),
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
// 获取收藏的歌手
|
||||
export interface FetchUserArtistsResponse {
|
||||
code: number
|
||||
hasMore: boolean
|
||||
count: number
|
||||
data: Artist[]
|
||||
}
|
||||
export function fetchUserArtists(): Promise<FetchUserArtistsResponse> {
|
||||
return request({
|
||||
url: '/artist/sublist',
|
||||
method: 'get',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收藏的MV(需要登录)
|
||||
|
|
|
@ -21,7 +21,7 @@ const Cover = ({
|
|||
{showHover && (
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute top-2 z-[-1] h-full w-full scale-x-[.92] scale-y-[.96] rounded-xl bg-cover opacity-0 blur-lg filter transition duration-300 group-hover:opacity-60',
|
||||
'absolute top-2 z-[-1] h-full w-full scale-x-[.92] scale-y-[.96] bg-cover opacity-0 blur-lg filter transition duration-300 group-hover:opacity-60',
|
||||
roundedClass
|
||||
)}
|
||||
style={{
|
||||
|
|
|
@ -38,7 +38,12 @@ const getSubtitleText = (
|
|||
subtitle: Subtitle
|
||||
) => {
|
||||
const nickname = 'creator' in item ? item.creator.nickname : 'someone'
|
||||
const artist = 'artist' in item ? item.artist.name : 'unknown'
|
||||
const artist =
|
||||
'artist' in item
|
||||
? item.artist.name
|
||||
: 'artists' in item
|
||||
? item.artists?.[0]?.name
|
||||
: 'unknown'
|
||||
const copywriter = 'copywriter' in item ? item.copywriter : 'unknown'
|
||||
const releaseYear =
|
||||
('publishTime' in item &&
|
||||
|
@ -125,10 +130,10 @@ const CoverRow = ({
|
|||
|
||||
<div
|
||||
className={classNames(
|
||||
'grid gap-x-6 gap-y-7',
|
||||
'grid',
|
||||
className,
|
||||
!className &&
|
||||
'grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6'
|
||||
'grid-cols-3 gap-x-6 gap-y-7 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6'
|
||||
)}
|
||||
>
|
||||
{renderItems.map((item, index) => (
|
||||
|
@ -146,6 +151,7 @@ const CoverRow = ({
|
|||
onClick={() => goTo(item.id)}
|
||||
imageUrl={getImageUrl(item)}
|
||||
showPlayButton={true}
|
||||
roundedClass={artists ? 'rounded-full' : 'rounded-xl'}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -163,9 +169,14 @@ const CoverRow = ({
|
|||
</Skeleton>
|
||||
</div>
|
||||
) : (
|
||||
<span className='line-clamp-2 leading-tight '>
|
||||
<span
|
||||
className={classNames(
|
||||
'line-clamp-2 leading-tight',
|
||||
artists && 'mt-3 text-center'
|
||||
)}
|
||||
>
|
||||
{/* Playlist private icon */}
|
||||
{(item as Playlist).privacy && (
|
||||
{(item as Playlist).privacy === 10 && (
|
||||
<SvgIcon
|
||||
name='lock'
|
||||
className='mr-1 mb-1 inline-block h-3 w-3 text-gray-300'
|
||||
|
@ -197,9 +208,11 @@ const CoverRow = ({
|
|||
PLACEHOLDER
|
||||
</Skeleton>
|
||||
) : (
|
||||
<div className='flex text-[12px] text-gray-500 dark:text-gray-400'>
|
||||
<span>{getSubtitleText(item, subtitle)}</span>
|
||||
</div>
|
||||
!artists && (
|
||||
<div className='flex text-[12px] text-gray-500 dark:text-gray-400'>
|
||||
<span>{getSubtitleText(item, subtitle)}</span>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
16
src/renderer/hooks/useUserAlbums.ts
Normal file
16
src/renderer/hooks/useUserAlbums.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import type { FetchUserAlbumsParams, FetchUserAlbumsResponse } from '@/api/user'
|
||||
import { UserApiNames, fetchUserAlbums } from '@/api/user'
|
||||
|
||||
export default function useUserAlbums(params: FetchUserAlbumsParams) {
|
||||
return useQuery(
|
||||
[UserApiNames.FETCH_USER_ALBUMS, params],
|
||||
() => fetchUserAlbums(params),
|
||||
{
|
||||
placeholderData: (): FetchUserAlbumsResponse =>
|
||||
window.ipcRenderer?.sendSync('getApiCacheSync', {
|
||||
api: 'album/sublist',
|
||||
query: params,
|
||||
}),
|
||||
}
|
||||
)
|
||||
}
|
11
src/renderer/hooks/useUserArtists.ts
Normal file
11
src/renderer/hooks/useUserArtists.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import type { FetchUserArtistsResponse } from '@/api/user'
|
||||
import { UserApiNames, fetchUserArtists } from '@/api/user'
|
||||
|
||||
export default function useUserArtists() {
|
||||
return useQuery([UserApiNames.FETCH_USER_ARTIST], fetchUserArtists, {
|
||||
placeholderData: (): FetchUserArtistsResponse =>
|
||||
window.ipcRenderer?.sendSync('getApiCacheSync', {
|
||||
api: 'album/sublist',
|
||||
}),
|
||||
})
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import CoverRow, { Subtitle } from '@/components/CoverRow'
|
||||
import SvgIcon from '@/components/SvgIcon'
|
||||
import useUserAlbums from '@/hooks/useUserAlbums'
|
||||
import useLyric from '@/hooks/useLyric'
|
||||
import usePlaylist from '@/hooks/usePlaylist'
|
||||
import useUser from '@/hooks/useUser'
|
||||
|
@ -6,6 +8,7 @@ import useUserPlaylists from '@/hooks/useUserPlaylists'
|
|||
import { player } from '@/store'
|
||||
import { resizeImage } from '@/utils/common'
|
||||
import { sample, chunk } from 'lodash-es'
|
||||
import useUserArtists from '@/hooks/useUserArtists'
|
||||
|
||||
const LikedTracksCard = ({ className }: { className?: string }) => {
|
||||
const navigate = useNavigate()
|
||||
|
@ -122,8 +125,116 @@ const OtherCard = ({
|
|||
)
|
||||
}
|
||||
|
||||
const Playlists = () => {
|
||||
const { data: user } = useUser()
|
||||
|
||||
const { data: playlists } = useUserPlaylists({
|
||||
uid: user?.account?.id ?? 0,
|
||||
offset: 0,
|
||||
})
|
||||
return (
|
||||
<div>
|
||||
<CoverRow
|
||||
playlists={playlists?.playlist?.slice(1) ?? []}
|
||||
subtitle={Subtitle.CREATOR}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Albums = () => {
|
||||
const { data: albums } = useUserAlbums({
|
||||
limit: 1000,
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CoverRow albums={albums?.data ?? []} subtitle={Subtitle.ARTIST} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Artists = () => {
|
||||
const { data: artists } = useUserArtists()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CoverRow artists={artists?.data ?? []} subtitle={Subtitle.ARTIST} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const MVs = () => {
|
||||
return <div>施工中</div>
|
||||
}
|
||||
|
||||
const Podcasts = () => {
|
||||
return <div>施工中</div>
|
||||
}
|
||||
interface TabsType {
|
||||
playlist: string
|
||||
album: string
|
||||
artist: string
|
||||
mv: string
|
||||
podcast: string
|
||||
}
|
||||
|
||||
const TabHeader = ({
|
||||
activeTab,
|
||||
tabs,
|
||||
setActiveTab,
|
||||
}: {
|
||||
activeTab: keyof TabsType
|
||||
tabs: TabsType
|
||||
setActiveTab: (tab: keyof TabsType) => void
|
||||
}) => {
|
||||
return (
|
||||
<div className='mt-10 flex text-lg'>
|
||||
{Object.entries(tabs).map(([id, name]) => (
|
||||
<div
|
||||
key={id}
|
||||
onClick={() => setActiveTab(id as keyof TabsType)}
|
||||
className={classNames(
|
||||
'btn-pressed-animation mr-3 rounded-lg px-3.5 py-1.5 font-medium',
|
||||
activeTab === id
|
||||
? 'bg-black/[.04]'
|
||||
: 'btn-hover-animation after:bg-black/[.04] dark:after:bg-white/10'
|
||||
)}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Tabs = () => {
|
||||
return <div></div>
|
||||
const tabs = {
|
||||
playlist: '全部歌单',
|
||||
album: '专辑',
|
||||
artist: '艺人',
|
||||
mv: 'MV',
|
||||
podcast: '播客',
|
||||
}
|
||||
|
||||
const [activeTab, setActiveTab] = useState<keyof TabsType>('playlist')
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabHeader
|
||||
activeTab={activeTab}
|
||||
tabs={tabs}
|
||||
setActiveTab={setActiveTab}
|
||||
/>
|
||||
<div className='mt-6'>
|
||||
{activeTab === 'playlist' && <Playlists />}
|
||||
{activeTab === 'album' && <Albums />}
|
||||
{activeTab === 'artist' && <Artists />}
|
||||
{activeTab === 'mv' && <MVs />}
|
||||
{activeTab === 'podcast' && <Podcasts />}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const Library = () => {
|
||||
|
@ -148,6 +259,8 @@ const Library = () => {
|
|||
<OtherCard name='最近播放' icon='playlist' className='' />
|
||||
<OtherCard name='听歌排行' icon='music-library' className='' />
|
||||
</div>
|
||||
|
||||
<Tabs />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user