Add Album Page
This commit is contained in:
parent
19d35589be
commit
2af920a7ac
3 changed files with 194 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
||||||
import {Md5} from "ts-md5";
|
import {Md5} from "ts-md5";
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
import {Disc} from "radix-icons-svelte";
|
||||||
|
|
||||||
function getIdent(): string {
|
function getIdent(): string {
|
||||||
let cookie = Cookies.get("subsonicPlayerIdent");
|
let cookie = Cookies.get("subsonicPlayerIdent");
|
||||||
|
@ -242,6 +243,27 @@ export interface AlbumID3 {
|
||||||
discTitles?: Array<DiscTitle>
|
discTitles?: Array<DiscTitle>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetAlbumInfo2Response extends OpenSubsonicResponse {
|
||||||
|
albumInfo: AlbumInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AlbumInfo {
|
||||||
|
notes?: string,
|
||||||
|
musicBrainzId?: string,
|
||||||
|
lastFmUrl?: string,
|
||||||
|
smallImageUrl?: string,
|
||||||
|
mediumImageUrl?: string,
|
||||||
|
largeImageUrl?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetAlbumResponse extends OpenSubsonicResponse{
|
||||||
|
album: AlbumID3WithSongs
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AlbumID3WithSongs extends AlbumID3 {
|
||||||
|
song?: Array<Song>,
|
||||||
|
}
|
||||||
|
|
||||||
interface RecordLabel {
|
interface RecordLabel {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {goto} from "$app/navigation";
|
||||||
|
import {
|
||||||
|
type AlbumID3WithSongs,
|
||||||
|
type GetAlbumInfo2Response, type GetAlbumResponse,
|
||||||
|
OpenSubsonic,
|
||||||
|
type Parameter, type Song
|
||||||
|
} from "$lib/opensubsonic";
|
||||||
|
import {queueState} from "$lib/states/play-queue.svelte";
|
||||||
|
import {playbackState, shuffle} from "$lib/states/playback-state.svelte";
|
||||||
|
import {Button} from "$lib/components/ui/button";
|
||||||
|
|
||||||
|
class AlbumData {
|
||||||
|
data: AlbumID3WithSongs = $state({})
|
||||||
|
}
|
||||||
|
|
||||||
|
let { data } = $props();
|
||||||
|
let albumId = $derived(data.albumId);
|
||||||
|
let album = $state(new AlbumData());
|
||||||
|
let loading = $state(true);
|
||||||
|
console.log("album:", data.albumId)
|
||||||
|
|
||||||
|
async function fetchAlbumInfos(): Promise<void> {
|
||||||
|
let parameters: Array<Parameter> = [
|
||||||
|
{key: "id", value: albumId},
|
||||||
|
];
|
||||||
|
|
||||||
|
const infoData: GetAlbumInfo2Response = await OpenSubsonic.get("getAlbumInfo2", parameters);
|
||||||
|
if (infoData) {
|
||||||
|
album.info = infoData.albumInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
const albumResponse: GetAlbumResponse = await OpenSubsonic.get("getAlbum", parameters);
|
||||||
|
if (albumResponse && albumResponse.album.song) {
|
||||||
|
album.data = albumResponse.album;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlbumImage() {
|
||||||
|
if (album.info.mediumImageUrl) {
|
||||||
|
return album.info.mediumImageUrl;
|
||||||
|
}
|
||||||
|
else if (album.info.largeImageUrl) {
|
||||||
|
return album.info.largeImageUrl;
|
||||||
|
}
|
||||||
|
else if (album.info.smallImageUrl) {
|
||||||
|
return album.info.smallImageUrl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let scrollY = $state(0);
|
||||||
|
let scrollYMax = $state(1);
|
||||||
|
|
||||||
|
function updateScroll(self) {
|
||||||
|
scrollY = self.scrollTop;
|
||||||
|
scrollYMax = self.scrollTopMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if(scrollY/scrollYMax > 0.7 && albums.length === 100 && !albums.paginating) {
|
||||||
|
console.log("triggered")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function selectAlbum(albumId) {
|
||||||
|
goto(`/album/${albumId}`);
|
||||||
|
console.log(albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function playSong( song: Song) {
|
||||||
|
queueState.addSong(song);
|
||||||
|
playbackState.pause();
|
||||||
|
playbackState.newSong(queueState.getSong());
|
||||||
|
playbackState.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
let playHover = $state(false);
|
||||||
|
let shuffleHover = $state(false);
|
||||||
|
|
||||||
|
function playAlbum(addToQueue = false) {
|
||||||
|
if (addToQueue) {
|
||||||
|
const queuePosition = queueState.currentIndex;
|
||||||
|
album.data.song.forEach((song) => {
|
||||||
|
queueState.addSong(song);
|
||||||
|
})
|
||||||
|
queueState.setSong(queuePosition);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
queueState.replaceQueue(album.data.song);
|
||||||
|
console.log(queueState.queue);
|
||||||
|
playbackState.pause();
|
||||||
|
playbackState.newSong(queueState.getSong());
|
||||||
|
playbackState.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shuffleAlbum(addToQueue = false) {
|
||||||
|
const shuffledAlbum = shuffle([...album.data.song])
|
||||||
|
if (addToQueue) {
|
||||||
|
const queuePosition = queueState.currentIndex;
|
||||||
|
shuffledAlbum.forEach((song) => {
|
||||||
|
queueState.addSong(song);
|
||||||
|
})
|
||||||
|
queueState.setSong(queuePosition);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
queueState.replaceQueue(shuffledAlbum);
|
||||||
|
console.log(queueState.queue);
|
||||||
|
playbackState.pause();
|
||||||
|
playbackState.newSong(queueState.getSong());
|
||||||
|
playbackState.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchAlbumInfos();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p>Loading</p>
|
||||||
|
{:else}
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<img alt={album.data.name + " Album Cover"} src={getAlbumImage()} height="312px" width="312px" class="rounded-md" />
|
||||||
|
<div>
|
||||||
|
<h1>{album.data.name}</h1>
|
||||||
|
<p>{album.info.notes}</p>
|
||||||
|
<p>{album.info.lastFmUrl}</p>
|
||||||
|
<p>{album.info.musicBrainzId}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex flex-col" onmouseover={() => playHover = true} onmouseleave={() => playHover = false}>
|
||||||
|
<Button onclick={() => playAlbum()}>Play</Button>
|
||||||
|
{#if playHover}
|
||||||
|
<Button onclick={() => playAlbum(true)}>Add To Queue</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col" onmouseover={() => shuffleHover = true} onmouseleave={() => shuffleHover = false}>
|
||||||
|
<Button onclick={() => shuffleAlbum()}>Shuffle</Button>
|
||||||
|
|
||||||
|
{#if shuffleHover}
|
||||||
|
<Button onclick={() => shuffleAlbum(true)}>Add To Queue</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border border-2 p-2 rounded-md">
|
||||||
|
{#each album.data.song as song}
|
||||||
|
<p onclick={() => playSong(song)}>{song.title}</p>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import type { RouteParams } from './$types';
|
||||||
|
|
||||||
|
export const load = ({ params }: { params: RouteParams }) => {
|
||||||
|
return {
|
||||||
|
albumId: params.albumId
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue