first commit

This commit is contained in:
Nicholas Tamassia
2023-10-09 17:49:46 -04:00
commit b2790a7151
33 changed files with 3027 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<script>
import '../app.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
</script>
<slot />

2
src/routes/+page.svelte Normal file
View File

@@ -0,0 +1,2 @@
<h1 class="underline text-green-400">Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>

View File

@@ -0,0 +1,40 @@
import { generateURL } from '$lib/Jellyfin-api.js'
export async function load({ fetch, params }) {
const response = await fetch(
generateURL({
type: 'Items',
queryParams: { albumIds: params.id, recursive: true },
})
)
const albumItemsData = await response.json()
// This handles rare circumstances where a song is part of an album but is not meant to be included in the track list
// Example: Xronial Xero (Laur Remix) - Is tagged with the album Xronial Xero, but was a bonus track and not included as part of the album's track list.
const items = albumItemsData.Items.filter((item) => 'IndexNumber' in item)
// Idk if it's efficient, but this is a beautiful one liner that accomplishes 1. Checking whether or not there are multiple discs, 2. Sorting the Items
// primarily by disc number, and secondarily by track number, and 3. Defaulting to just sorting by track number if the album is only one disc.
items.sort((a, b) =>
a?.ParentIndexNumber !== b?.ParentIndexNumber
? a.ParentIndexNumber - b.ParentIndexNumber
: a.IndexNumber - b.IndexNumber
)
const albumData = {
name: items[0].Album,
id: items[0].AlbumId,
artists: items[0].AlbumArtists,
year: items[0].ProductionYear,
discCount: Math.max(...items.map((x) => x?.ParentIndexNumber)),
length: items
.map((x) => x.RunTimeTicks)
.reduce((accumulator, currentValue) => accumulator + currentValue),
}
return {
id: params.id,
albumItemsData: items,
albumData: albumData,
}
}

View File

@@ -0,0 +1,57 @@
<script>
import { fly, slide } from 'svelte/transition'
import { cubicIn, cubicOut } from 'svelte/easing'
import { generateURL } from '$lib/Jellyfin-api.js'
import AlbumBg from '$lib/albumBG.svelte'
import Navbar from '$lib/navbar.svelte'
import ListItem from '$lib/listItem.svelte'
import Header from '$lib/header.svelte'
import MediaPlayer from '$lib/mediaPlayer.svelte'
export let data
let albumImg = generateURL({ type: 'Image', pathParams: { id: data.id } })
// console.log(generateURL({type: 'Items', queryParams: {'albumIds': data.albumData.Id, 'recursive': true}}))
let discArray = Array.from({ length: data.albumData?.discCount ? data.albumData.discCount : 1 }, (_, i) => {
return data.albumItemsData.filter((item) => item?.ParentIndexNumber === i + 1 || !item?.ParentIndexNumber)
})
let mediaPlayerOpen = false
let currentMediaPlayerItem
const playSong = (event) => {
currentMediaPlayerItem = event.detail.item
mediaPlayerOpen = true
}
</script>
<div id="main" class="flex h-screen flex-col" in:fly={{ easing: cubicOut, y: 10, duration: 1000, delay: 400 }} out:fly={{ easing: cubicIn, y: -10, duration: 500 }}>
<AlbumBg {albumImg} />
<Navbar />
<div id="layout" class="no-scrollbar relative m-[0_auto] grid w-full max-w-[92vw] grid-cols-1 gap-0 overflow-y-scroll pt-8 md:grid-cols-[1fr_2fr] md:gap-[4%] md:pt-48">
<img class="rounded object-cover" src={albumImg} alt="Jacket" draggable="false" />
<div class="my-12 flex flex-col gap-4 pr-2">
<Header header={data.albumData.name} artists={data.albumData.artists} year={data.albumData.year} length={data.albumData.length} />
<div class="flex flex-col gap-4">
{#each discArray as disc}
<div>
{#if data.albumData.discCount}
<span class="m-3 block font-notoSans text-lg text-neutral-300">DISC {discArray.indexOf(disc) + 1}</span>
{/if}
<div class="flex w-full flex-col items-center divide-y-[1px] divide-[#353535]">
{#each disc as song}
<ListItem item={song} on:startPlayback={playSong} />
{/each}
</div>
</div>
{/each}
</div>
</div>
</div>
<div class="fixed bottom-0 z-20 w-full">
{#if mediaPlayerOpen}
<div transition:slide={{ duration: 400 }} class="h-screen">
<MediaPlayer currentlyPlaying={currentMediaPlayerItem} playlistItems={data.albumItemsData} on:closeMediaPlayer={() => (mediaPlayerOpen = false)} on:startPlayback={playSong} />
</div>
{/if}
</div>
</div>

View File

@@ -0,0 +1,5 @@
export const load = ({ params }) => {
return {
id: params.id,
}
}

View File

@@ -0,0 +1,39 @@
<script>
import { onMount } from 'svelte';
import { fetchArtistItems } from '$lib/Jellyfin-api.js';
import AlbumCard from '$lib/albumCard.svelte';
export let data;
let artistItems = {
albums: [],
singles: [],
appearances: []
};
onMount(async () => {
artistItems = await fetchArtistItems(data.id);
})
</script>
<div class="grid">
{ #each artistItems.albums as item }
<AlbumCard {item} cardType="albums"/>
{ /each }
</div>
<div class="grid">
{ #each artistItems.singles as item }
<AlbumCard {item} cardType="singles"/>
{ /each }
</div>
<div class="grid">
{ #each artistItems.appearances as item }
<AlbumCard {item} cardType="appearances"/>
{ /each }
</div>
<style>
.grid {
display: grid;
grid-template-columns: repeat(9, 200px);
}
</style>

View File

@@ -0,0 +1,5 @@
export const load = ({ params }) => {
return {
id: params.id,
}
}

View File

@@ -0,0 +1,25 @@
<script>
import { onMount } from 'svelte';
import { fetchSong } from '$lib/Jellyfin-api.js'
export let data;
let fetchedData = {};
onMount(async () => {
fetchedData = await fetchSong(data.id);
});
</script>
<div>
{ #await fetchedData}
<p>Loading</p>
{:then songData}
<p>{songData.Name}</p>
{/await}
</div>
<style>
</style>