[+] Playlist page

This commit is contained in:
2025-11-18 16:47:51 +08:00
parent 09ee5336ec
commit cb9a2f7566
6 changed files with 65 additions and 13 deletions
+5 -2
View File
@@ -1,5 +1,8 @@
<script>
let { icon, children, ...rest } = $props();
<script lang="ts">
let { icon, children, ...rest }: {
icon?: string
children?: any
} = $props();
</script>
<button class="hbox h-40px rounded-12px px-16px py-10px gap-8px mfg-on-primary-container mbg-inverse-primary m3-font-label-large" {...rest}>
+14 -5
View File
@@ -1,10 +1,15 @@
<script lang="ts">
import IconButton from "../IconButton.svelte";
let { title, account, settings }: {
interface Icon {
icon: string
onclick: () => void
}
let { title, account, right }: {
title?: string
account?: () => void
settings?: () => void
right?: Icon[]
} = $props()
</script>
@@ -15,7 +20,11 @@
<IconButton icon="i-material-symbols:arrow-back-rounded" onclick={() => history.back()} aria-label="Account" />
{/if}
<div class="m3-font-title-large flex-1">{title}</div>
{#if settings}
<IconButton icon="i-material-symbols:settings-rounded" onclick={settings} aria-label="Settings" />
{/if}
<!--{#if right}-->
<!-- <IconButton icon="i-material-symbols:settings-rounded" onclick={right} aria-label="Settings" />-->
<!-- {/if}-->
{#each right as item}
<IconButton icon={item.icon} onclick={item.onclick} />
{/each}
</div>
+7 -3
View File
@@ -35,7 +35,7 @@ function parsePlaylistRef(ref: string): number {
/**
* Get raw playlist data from cache or netease API.
*/
const getPlaylistRaw = cached('playlists',
export const getPlaylistRaw = cached('playlists',
async (id: number) => {
const pl = ((await ne.playlist_detail({ id })).body as any)
@@ -67,10 +67,10 @@ export const parseBrief = (songData: any): NeteaseSongBrief => ({
/**
* Get a list of songs from a playlist reference.
*/
export async function getSongsFromPlaylist(ref: string): Promise<any[]> {
export async function getSongsFromPlaylist(ref: string): Promise<{meta: any, songs: NeteaseSongBrief[]}> {
const playlistId = parsePlaylistRef(ref)
const plData = await getPlaylistRaw(playlistId)
return plData.playlist.tracks.map(parseBrief)
return {meta: plData.playlist, songs: plData.playlist.tracks.map(parseBrief)}
}
interface NeteaseLyricsResponse { lrc: { lyric: string } }
@@ -85,3 +85,7 @@ export const getLyricsProcessed = cached('lyrics_processed',
return aiParseLyrics(raw.lrc.lyric)
})
await getSongsFromPlaylist("13555799996")
await getSongsFromPlaylist("https://music.163.com/playlist?id=14348145982")
await getSongsFromPlaylist("https://music.163.com/playlist?id=14392963638")
await getSongsFromPlaylist("https://music.163.com/playlist?id=580208139")
+5 -3
View File
@@ -11,7 +11,9 @@
</script>
<AppBar account={() => alert('Account clicked')} settings={() => alert('Settings clicked')} />
<AppBar account={() => alert('Account clicked')} right={[
{icon: "i-material-symbols:settings-rounded", onclick: () => alert('Settings clicked')}
]} />
<div class="vbox gap-16px">
{#if data.last}
@@ -49,13 +51,13 @@
<TitleHeader title="推荐歌单"/>
<div class="p-content hbox gap-8px w-auto overflow-x-auto py-8px">
{#each data.recPlaylists as playlist}
<div class="vbox flex-shrink-0 p-8px gap-8px rounded-12px mbg-surface-container-high">
<a class="vbox flex-shrink-0 p-8px gap-8px rounded-12px mbg-surface-container-high" href="/playlist/{playlist.id}">
<img src="{playlist.coverImgUrl}" alt="" class="size-116px rounded-8px">
<div>
<div class="m3-font-title-small font-bold truncate">{playlist.name}</div>
<div class="m3-font-body-small truncate">{playlist.creator.nickname} 创建</div>
</div>
</div>
</a>
{/each}
</div>
</div>
@@ -0,0 +1,6 @@
import type { PageServerLoad } from './$types';
import { getSongsFromPlaylist, listPlaylists } from "$lib/server/songs.ts";
export const load: PageServerLoad = async ({ params }) => ({
playlist: await getSongsFromPlaylist(params.slug)
})
+28
View File
@@ -0,0 +1,28 @@
<script lang="ts">
import type { PageProps } from "./$types"
import AppBar from "../../../components/appbar/AppBar.svelte";
import Button from "../../../components/Button.svelte";
let { data }: PageProps = $props()
let {meta, songs} = data.playlist
</script>
<AppBar title="歌单详情" right={[
{icon: "i-material-symbols:bookmark-add-outline-rounded", onclick: () => alert('Bookmark clicked')},
{icon: "i-material-symbols:more-vert", onclick: () => alert('More clicked')}
]} />
<div class="hbox px-16px py-8px gap-24px">
<img src="{meta.coverImgUrl}" alt="" class="size-128px rounded-16px">
<div class="vbox flex-1 py-8px self-stretch min-h-full">
<div class="m3-font-headline-small font-bold">{meta.name}</div>
<div class="flex-1">
<div class="m3-font-body-small text-surface-variant">创建者: {meta.creator.nickname}</div>
<div class="m3-font-body-small text-surface-variant">歌曲数: {meta.trackCount}</div>
</div>
<div>
<Button>开始练习</Button>
</div>
</div>
</div>