From a5b9e87eb99ba1ed18ac8bf2b5c216fe501dd499 Mon Sep 17 00:00:00 2001
From: minster586 <43217359+minster586@users.noreply.github.com>
Date: Sun, 12 Apr 2026 21:41:35 -0400
Subject: [PATCH] added files
---
index.html | 36 ++++++++++++++
script.js | 128 +++++++++++++++++++++++++++++++++++++++++++++++
style.css | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 307 insertions(+)
create mode 100644 index.html
create mode 100644 script.js
create mode 100644 style.css
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..8e7abb8
--- /dev/null
+++ b/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Radio DJ Now Playing
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..cb437ae
--- /dev/null
+++ b/script.js
@@ -0,0 +1,128 @@
+///////////////
+// PARAMETERS //
+///////////////
+
+const queryString = window.location.search;
+const urlParams = new URLSearchParams(queryString);
+const refreshRate = parseInt(urlParams.get("refreshrate")) || 6; // Default 6 seconds
+
+// Image filename - update this if the backend changes the image path
+const IMAGE_FILENAME = "Album-Art.png";
+
+//////////////////
+// GLOBAL STATE //
+//////////////////
+
+let currentArtist = "";
+let currentTitle = "";
+let refreshInterval = null;
+
+//////////////////
+// REFRESH LOGIC //
+//////////////////
+
+/**
+ * Fetches the artist and title from text files
+ */
+async function fetchSongData() {
+ try {
+ const artistResponse = await fetch("artist.txt");
+ const titleResponse = await fetch("title.txt");
+
+ if (!artistResponse.ok || !titleResponse.ok) {
+ console.error("Failed to fetch song data");
+ return null;
+ }
+
+ const artist = (await artistResponse.text()).trim();
+ const title = (await titleResponse.text()).trim();
+
+ return { artist, title };
+ } catch (error) {
+ console.error("Error fetching song data:", error);
+ return null;
+ }
+}
+
+/**
+ * Updates the DOM elements if the song data has changed
+ */
+function updateSongDisplay(artist, title) {
+ const titleElement = document.querySelector(".song-title");
+ const artistElement = document.querySelector(".song-artist");
+
+ let trackChanged = false;
+
+ // Only update if data has actually changed
+ if (title !== currentTitle) {
+ currentTitle = title;
+ titleElement.classList.add("updating");
+ titleElement.textContent = title || "Unknown Title";
+ trackChanged = true;
+ setTimeout(() => {
+ titleElement.classList.remove("updating");
+ }, 400);
+ }
+
+ if (artist !== currentArtist) {
+ currentArtist = artist;
+ artistElement.classList.add("updating");
+ artistElement.textContent = artist || "Unknown Artist";
+ trackChanged = true;
+ setTimeout(() => {
+ artistElement.classList.remove("updating");
+ }, 400);
+ }
+
+ // Return whether track changed (to trigger image update)
+ return trackChanged;
+}
+
+/**
+ * Updates both the album art and background image with cache-busting timestamp
+ * Only called when track actually changes
+ */
+function updateAlbumArt() {
+ const albumArt = document.querySelector(".album-art");
+ const backgroundImage = document.querySelector(".background-image");
+ const timestamp = new Date().getTime();
+ const imageUrl = `${IMAGE_FILENAME}?v=${timestamp}`;
+
+ albumArt.src = imageUrl;
+ backgroundImage.src = imageUrl;
+}
+
+/**
+ * Main refresh function - fetches data and updates if changed
+ */
+async function refresh() {
+ const data = await fetchSongData();
+ if (data) {
+ const trackChanged = updateSongDisplay(data.artist, data.title);
+ // Only update images when track actually changes
+ if (trackChanged) {
+ updateAlbumArt();
+ }
+ }
+}
+
+///////////////
+// INITIALIZE //
+///////////////
+
+function init() {
+ // Load initial data immediately
+ refresh();
+
+ // Set up refresh interval based on URL parameter or default
+ refreshInterval = setInterval(refresh, refreshRate * 1000);
+
+ console.log(`Radio DJ widget initialized - refreshing every ${refreshRate}s`);
+}
+
+// Start when DOM is ready
+if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", init);
+} else {
+ init();
+}
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..ecfa75f
--- /dev/null
+++ b/style.css
@@ -0,0 +1,143 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ background: #000;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
+}
+
+/* Main widget container */
+.widget-container {
+ position: relative;
+ display: flex;
+ width: 100%;
+ max-width: 650px;
+ aspect-ratio: auto;
+ height: 200px;
+ border-radius: 20px;
+ overflow: hidden;
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.95);
+ margin: 20px;
+}
+
+/* Blurred background layer (z-index: 0) */
+.background-blur {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+ overflow: hidden;
+}
+
+.background-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ filter: blur(40px) brightness(0.6);
+}
+
+/* Dark overlay (z-index: 1) */
+.overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 1;
+ pointer-events: none;
+}
+
+/* Content layer (z-index: 2) */
+.widget-content {
+ position: relative;
+ display: flex;
+ gap: 24px;
+ padding: 20px;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+}
+
+/* Album art box (left) */
+.album-art-box {
+ flex-shrink: 0;
+ width: 140px;
+ height: 140px;
+ border-radius: 10px;
+ overflow: hidden;
+ background: rgba(60, 60, 60, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.6);
+}
+
+.album-art {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+/* Song info box (right) */
+.song-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 4px;
+ min-width: 0;
+ padding: 0 12px;
+}
+
+/* Song title */
+.song-title {
+ font-size: 30px;
+ font-weight: 700;
+ color: #ffffff;
+ text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.9);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ letter-spacing: -0.5px;
+ line-height: 1.1;
+}
+
+/* Song artist */
+.song-artist {
+ font-size: 22px;
+ font-weight: 500;
+ color: #ffffff;
+ text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.9);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ letter-spacing: -0.3px;
+ line-height: 1.1;
+ opacity: 1;
+}
+
+/* Smooth fade animation for updates */
+@keyframes fadeIn {
+ from {
+ opacity: 0.5;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.song-title.updating,
+.song-artist.updating {
+ animation: fadeIn 0.4s ease-in-out;
+}