commit d8aa765bf78235aab1491b499e6438b1ccbd2813 Author: ari melody Date: Fri Aug 1 14:41:23 2025 +0100 basic impl.; no websockets yet! diff --git a/public/default-artwork.png b/public/default-artwork.png new file mode 100644 index 0000000..8e19b8c Binary files /dev/null and b/public/default-artwork.png differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..5e3db20 --- /dev/null +++ b/public/index.html @@ -0,0 +1,23 @@ + + + + + + + + + +
+
+
+ +
+
+

Unknown Track

+

Unknown Artist • Unknown Album

+
+
+
+ + + diff --git a/public/main.css b/public/main.css new file mode 100644 index 0000000..db7055b --- /dev/null +++ b/public/main.css @@ -0,0 +1,87 @@ +:root { + --ticker-width: 600px; +} + +body { + margin: 0; + padding: 0; + font-family: 'Inter', sans-serif; + background: #888; +} + +#music-ticker { + /* width: fit-content; */ + max-width: var(--ticker-width); + margin: 32px; + padding: 8px; + display: flex; + flex-direction: row; + gap: 10px; + border-radius: 8px; + + &.outline { + border: 1px solid white; + outline: 1px solid black; + } + + .artwork-container { + width: 64px; + min-width: 64px; + height: 64px; + border-radius: 4px; + overflow: hidden; + + img { + width: 100%; + height: 100%; + display: block; + object-fit: cover; + } + } + + #metadata { + min-width: 0; + flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: center; + color: #fff; + text-shadow: 1px 1px 0 #000a; + overflow-x: clip; + } + + h1 { + width: fit-content; + min-width: 0; + margin: -2px 0; + overflow-x: hidden; + white-space: nowrap; + font-size: 30px; + } + + p { + width: fit-content; + min-width: 0; + margin: -2px 0; + overflow-x: hidden; + white-space: nowrap; + font-size: 22px; + font-weight: 600; + } + + .marquee { + animation: 20s ease-in-out infinite marquee; + } +} + +@keyframes marquee { + 20% { + transform: translateX(0); + } + 60% { + transform: translateX(calc(-100% + var(--ticker-width) - 74px)); + } + 80% { + transform: translateX(calc(-100% + var(--ticker-width) - 74px)); + } +} diff --git a/public/main.js b/public/main.js new file mode 100644 index 0000000..4b755f6 --- /dev/null +++ b/public/main.js @@ -0,0 +1,39 @@ +import Stateful from './silver.min.js'; + +const musicMeta = new Stateful({ + artworkURL: 'https://arimelody.space/uploads/musicart/free2play.png', + title: 'falling asleep - house version', + artist: 'ari melody', + album: 'free2play', +}); + +const elArtwork = document.getElementById('artwork'); +const elTitle = document.getElementById('title'); +const elArtistAlbum = document.getElementById('artist-album'); +const elMetadata = document.getElementById('metadata'); + +function setMetadata(artworkURL, title, artist, album) { + musicMeta.set({ artworkURL, title, artist, album }); +} + +document.addEventListener('readystatechange', () => { + musicMeta.onUpdate(value => { + elArtwork.src = value.artworkURL; + elTitle.innerText = value.title; + elArtistAlbum.innerText = `${value.artist} • ${value.album}`; + document.title = `Now playing: ${value.artist} - ${value.title}`; + console.log(`Now playing: ${value.artist} - ${value.title}`); + + const maxWidth = elMetadata.getBoundingClientRect().width; + elTitle.classList.remove('marquee'); + elArtistAlbum.classList.remove('marquee'); + if (elTitle.getBoundingClientRect().width > maxWidth) { + elTitle.classList.add('marquee'); + } + if (elArtistAlbum.getBoundingClientRect().width > maxWidth) { + elArtistAlbum.classList.add('marquee'); + } + }); +}); + +window.setMetadata = setMetadata; diff --git a/public/silver.min.js b/public/silver.min.js new file mode 100644 index 0000000..2ec8e0d --- /dev/null +++ b/public/silver.min.js @@ -0,0 +1,2 @@ +export default class Stateful{#e;#t=[];constructor(e){this.#e=e}get(){return this.#e}set(e){let t=this.#e;this.#e=e;for(let s in this.#t)this.#t[s](e,t)}update(e){this.set(e(this.#e))}onUpdate(e){return this.#t.push(e),e}removeListener(e){this.#t=this.#t.filter((t=>t!==e))}} +