From 347b3729c825c5c8c5223ea16c2f3360d524da0d Mon Sep 17 00:00:00 2001 From: ltadeu6 Date: Sun, 7 Jun 2026 13:50:04 -0300 Subject: [PATCH] feat: synced lyrics display from LRCLib music-light fetches synced LRC lyrics from lrclib.net on track change, tracks playback position via a 0.5s background thread, and exposes the current lyric line in /current. dancer.html polls /current at 700ms and displays the line bottom-left with a cyan glow, subtitle style. Co-Authored-By: Claude Sonnet 4.6 --- plugin/contents/ui/dancer.html | 52 ++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/plugin/contents/ui/dancer.html b/plugin/contents/ui/dancer.html index 8ec02b7..536ee35 100644 --- a/plugin/contents/ui/dancer.html +++ b/plugin/contents/ui/dancer.html @@ -236,6 +236,32 @@ html, body { 100% { transform: translateY(-110px) rotate(18deg) scale(1.3); opacity: 0; } } +/* ============================================================ + LYRICS DISPLAY + ============================================================ */ +.lyric-display { + position: absolute; + left: 3%; + bottom: 16%; + max-width: 36%; + pointer-events: none; + opacity: 0; + transition: opacity 0.5s ease; +} +.lyric-line { + color: #ffffff; + font-family: 'Courier New', monospace; + font-size: clamp(13px, 1.5vw, 20px); + line-height: 1.5; + letter-spacing: 0.03em; + text-shadow: + 0 0 18px rgba(0,200,255,0.85), + 0 0 6px rgba(0,200,255,0.5), + 0 2px 10px rgba(0,0,0,0.95), + -1px -1px 0 rgba(0,0,0,0.7), + 1px 1px 0 rgba(0,0,0,0.7); +} + /* ============================================================ SCANLINES OVERLAY ============================================================ */ @@ -861,6 +887,11 @@ html, body { + +
+
+
+
@@ -1123,12 +1154,15 @@ function applyTheme(rgb) { }); } -const albumArtEl = document.getElementById('albumArt'); -const fogWisps = document.querySelectorAll('.fog-wisp'); +const albumArtEl = document.getElementById('albumArt'); +const fogWisps = document.querySelectorAll('.fog-wisp'); +const lyricDisplay = document.getElementById('lyricDisplay'); +const lyricLineEl = document.getElementById('lyricLine'); -let lastArtUrl = ''; +let lastArtUrl = ''; +let lastLyricLine = ''; -function fetchTheme() { +function fetchCurrent() { fetch('http://127.0.0.1:8765/current') .then(r => r.json()) .then(d => { @@ -1138,10 +1172,18 @@ function fetchTheme() { document.getElementById('albumArtImg').src = 'http://127.0.0.1:8765/art?' + Date.now(); } + const line = d.lyric_line || ''; + if (line !== lastLyricLine) { + lastLyricLine = line; + lyricLineEl.textContent = line; + } + lyricDisplay.style.opacity = (isPlaying && line) ? '1' : '0'; }) .catch(() => {}); } +setInterval(() => { if (isPlaying) fetchCurrent(); }, 700); + // Connect to CAVA SSE server (started by cava-start.sh via QML) (function connectCava() { const sse = new EventSource('http://127.0.0.1:5555'); @@ -1196,7 +1238,7 @@ function updateMusic(artist, title) { document.querySelector('.music-ticker').style.opacity = playing ? '1' : '0'; albumArtEl.style.opacity = playing ? '1' : '0'; if (!playing) vuBars.forEach(b => { b.style.height = '3px'; b.style.opacity = '0.15'; }); - if (playing) fetchTheme(); + if (playing) fetchCurrent(); const key = artist + '|' + title; if (el.dataset.key === key) return; el.dataset.key = key;