diff --git a/plugin/contents/ui/dancer.html b/plugin/contents/ui/dancer.html index 0602200..75b0ab3 100644 --- a/plugin/contents/ui/dancer.html +++ b/plugin/contents/ui/dancer.html @@ -237,38 +237,29 @@ html, body { } /* ============================================================ - LYRICS DISPLAY — verse karaoke + LYRICS DISPLAY ============================================================ */ .lyric-display { position: absolute; left: 2%; top: 4%; - width: 38%; - height: 150px; /* 5 visible slots × 30px */ - overflow: hidden; + max-width: 36%; pointer-events: none; opacity: 0; transition: opacity 0.5s ease; - -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 15%, black 85%, transparent 100%); - mask-image: linear-gradient(to bottom, transparent 0%, black 15%, black 85%, transparent 100%); } -.lyric-ctx { - position: absolute; - left: 0; - width: 100%; - height: 30px; - line-height: 30px; +.lyric-line { + color: #ffffff; font-family: 'Courier New', monospace; - letter-spacing: 0.02em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - transition: - top 0.5s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.45s ease, - font-size 0.35s ease, - color 0.35s ease, - text-shadow 0.35s ease; + font-size: clamp(16px, 1.3vw, 18px); + line-height: 1.5; + letter-spacing: 0.03em; + text-shadow: + 0 0 18px var(--theme-color, rgba(0,200,255,0.85)), + 0 0 6px var(--theme-color, 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); } /* ============================================================ @@ -896,8 +887,10 @@ html, body { - -
+ +
+
+
@@ -1170,98 +1163,13 @@ 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 = ''; - -/* ── verse display ── */ -const SLOT_H = 30; -const CENTER_PX = 60; // top of the active slot within the 150px container - -const ACTIVE_SHADOW = - '0 0 18px var(--theme-color,rgba(0,200,255,0.85)),' + - '0 0 6px var(--theme-color,rgba(0,200,255,0.5)),' + - '0 2px 10px rgba(0,0,0,0.95)'; - -const VERSE_STYLES = [ - { opacity:'0.2', fontSize:'clamp(11px,0.85vw,13px)', color:'#777', shadow:'' }, // dist -2 - { opacity:'0.48', fontSize:'clamp(13px,1.0vw,15px)', color:'#bbb', shadow:'' }, // dist -1 - { opacity:'1', fontSize:'clamp(16px,1.3vw,18px)', color:'#fff', shadow: ACTIVE_SHADOW }, // dist 0 - { opacity:'0.48', fontSize:'clamp(13px,1.0vw,15px)', color:'#bbb', shadow:'' }, // dist +1 - { opacity:'0.2', fontSize:'clamp(11px,0.85vw,13px)', color:'#777', shadow:'' }, // dist +2 -]; - -let verseEls = []; -let currentVerseKey = ''; -let currentVerseActive = -1; - -function applyVerseStyle(el, dist) { - if (dist < -2 || dist > 2) { - el.style.opacity = '0'; el.style.fontSize = 'clamp(11px,0.85vw,13px)'; - el.style.color = '#777'; el.style.textShadow = ''; return; - } - const p = VERSE_STYLES[dist + 2]; - el.style.opacity = p.opacity; - el.style.fontSize = p.fontSize; - el.style.color = p.color; - el.style.textShadow = p.shadow; -} - -function positionVerseEls(verse_active) { - verseEls.forEach((el, i) => { - const dist = i - verse_active; - el.style.top = (CENTER_PX + dist * SLOT_H) + 'px'; - applyVerseStyle(el, dist); - }); -} - -function buildVerse(verse_lines, verse_active) { - lyricDisplay.innerHTML = ''; - verseEls = verse_lines.map(text => { - const el = document.createElement('div'); - el.className = 'lyric-ctx'; - el.textContent = text; - el.style.transition = 'none'; - lyricDisplay.appendChild(el); - return el; - }); - positionVerseEls(verse_active); - requestAnimationFrame(() => requestAnimationFrame(() => { - verseEls.forEach(el => { el.style.transition = ''; }); - })); -} - -function updateLyricVerse(verse_lines, verse_active) { - if (!verse_lines || !verse_lines.length || verse_active < 0 || !isPlaying) { - lyricDisplay.style.opacity = '0'; - currentVerseKey = ''; - currentVerseActive = -1; - return; - } - const verseKey = verse_lines.join('\x00'); - - if (verseKey !== currentVerseKey) { - currentVerseKey = verseKey; - currentVerseActive = verse_active; - if (lyricDisplay.style.opacity === '1') { - lyricDisplay.style.opacity = '0'; - setTimeout(() => { - buildVerse(verse_lines, verse_active); - lyricDisplay.style.opacity = '1'; - }, 500); - } else { - buildVerse(verse_lines, verse_active); - lyricDisplay.style.opacity = '1'; - } - } else if (verse_active !== currentVerseActive) { - currentVerseActive = verse_active; - positionVerseEls(verse_active); - } else { - lyricDisplay.style.opacity = '1'; - } -} +let lastArtUrl = ''; +let lastLyricLine = ''; function fetchCurrent() { fetch('http://127.0.0.1:8765/current') @@ -1273,7 +1181,12 @@ function fetchCurrent() { document.getElementById('albumArtImg').src = 'http://127.0.0.1:8765/art?' + Date.now(); } - updateLyricVerse(d.verse_lines || [], d.verse_active ?? -1); + const line = d.lyric_line || ''; + if (line !== lastLyricLine) { + lastLyricLine = line; + lyricLineEl.textContent = line; + } + lyricDisplay.style.opacity = (isPlaying && line) ? '1' : '0'; }) .catch(() => {}); } @@ -1333,12 +1246,7 @@ function updateMusic(artist, title) { document.querySelector('.robot-wrap').style.opacity = playing ? '1' : '0'; 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'; }); - lyricDisplay.style.opacity = '0'; - currentVerseKey = ''; - currentVerseActive = -1; - } + if (!playing) vuBars.forEach(b => { b.style.height = '3px'; b.style.opacity = '0.15'; }); if (playing) fetchCurrent(); const key = artist + '|' + title; if (el.dataset.key === key) return; diff --git a/plugin/contents/ui/get-playing.sh b/plugin/contents/ui/get-playing.sh deleted file mode 100644 index 47a942e..0000000 --- a/plugin/contents/ui/get-playing.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -for player in $(playerctl -l 2>/dev/null); do - if [ "$(playerctl --player "$player" status 2>/dev/null)" = "Playing" ]; then - playerctl --player "$player" metadata --format "{{status}}||{{artist}}||{{title}}" 2>/dev/null - exit 0 - fi -done -printf "||" diff --git a/plugin/contents/ui/main.qml b/plugin/contents/ui/main.qml index 7402871..173dcae 100644 --- a/plugin/contents/ui/main.qml +++ b/plugin/contents/ui/main.qml @@ -38,7 +38,7 @@ WallpaperItem { Plasma5Support.DataSource { id: musicSource engine: "executable" - connectedSources: ["bash " + Qt.resolvedUrl("get-playing.sh").toString().replace("file://", "")] + connectedSources: ["playerctl metadata --format '{{status}}||{{artist}}||{{title}}' 2>/dev/null || echo '||'"] interval: 2000 onNewData: function(sourceName, data) {