uploaded stuff

This commit is contained in:
WhatDidYouExpect 2025-08-17 00:35:49 +02:00
commit 9ce49bcf1c
2 changed files with 181 additions and 0 deletions

102
LastFM.svelte Normal file
View file

@ -0,0 +1,102 @@
<!-- Planned to make it a vinyl but got lazy and made it a CD-->
<script>
import { onMount } from 'svelte';
import { track, loading, error, fetchTrack } from '../stores/trackStore.js';
onMount(() => {
if ($track) {
console.log('Loaded cached song');
} else {
fetchTrack();
}
const interval = setInterval(() => {
if (!$track) {
fetchTrack();
}
}, 2000);
return () => clearInterval(interval);
});
</script>
{#if $loading}
<p>Loading latest track...</p>
{:else if $error}
<p style="color:red">Error: {$error}</p>
{:else if $track}
<div class="track-container">
<a href={$track.url} target="_blank" rel="noopener noreferrer" class="track-link">
<div class="vinyl">
<img src={$track.image} alt="Album cover" />
</div>
<div class="track-info">
<div class="track-name">{$track.name}</div>
<div class="track-artist">{$track.artist}{$track.album}</div>
</div>
</a>
</div>
{:else}
<p>No track info available.</p>
{/if}
<style>
.track-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 20px 0;
}
.track-link {
text-decoration: none;
color: inherit;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.vinyl {
width: 64px;
height: 64px;
border-radius: 50%;
overflow: hidden;
border: 2px solid black;
box-shadow: 0 0 5px rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
position: relative;
animation: spin 5s linear infinite;
}
.vinyl::after {
content: '';
position: absolute;
width: 12px;
height: 12px;
background: black;
border-radius: 50%;
z-index: 2;
}
.track-info {
text-align: center;
}
.track-name {
font-weight: bold;
}
.track-artist {
font-size: 0.9rem;
color: gray;
}
</style>

79
trackStore.js Normal file
View file

@ -0,0 +1,79 @@
import { writable } from 'svelte/store';
export const track = writable(null);
export const loading = writable(false);
export const error = writable(null);
const CACHE_EXPIRY_MS = 60 * 1000;
function getCachedTrack() {
if (typeof window === 'undefined') return null;
const cached = localStorage.getItem('cachedTrack');
if (!cached) return null;
try {
const parsed = JSON.parse(cached);
if (!parsed.timestamp || !parsed.data) return null;
const age = Date.now() - parsed.timestamp;
if (age < CACHE_EXPIRY_MS) {
return parsed.data;
} else {
localStorage.removeItem('cachedTrack');
return null;
}
} catch {
localStorage.removeItem('cachedTrack');
return null;
}
}
if (typeof window !== 'undefined') {
const cachedTrack = getCachedTrack();
if (cachedTrack) {
track.set(cachedTrack);
}
}
export async function fetchTrack() {
if (typeof window !== 'undefined' && getCachedTrack()) {
console.log('%c CACHED - skip fetching', 'font-weight: bold; color: orange;');
return;
}
loading.set(true);
error.set(null);
try {
const res = await fetch('https://lastfm-last-played.biancarosa.com.br/expect69420/latest-song');
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`);
const data = await res.json();
const normalizedTrack = {
name: data.track.name,
artist: data.track.artist['#text'],
album: data.track.album['#text'],
url: data.track.url,
nowPlaying: data.track['@attr']?.nowplaying === 'true',
image: data.track.image.find(img => img.size === 'medium')?.['#text'] || ''
};
track.set(normalizedTrack);
if (typeof window !== 'undefined') {
localStorage.setItem('cachedTrack', JSON.stringify({
timestamp: Date.now(),
data: normalizedTrack
}));
}
} catch (e) {
error.set(e.message);
track.set(null);
if (typeof window !== 'undefined') {
localStorage.removeItem('cachedTrack');
}
} finally {
loading.set(false);
}
}