Replace QML CAVA polling with SSE server for smooth bars
DataSource fork+exec was limited to ~1fps. Now cava pipes into a Python SSE server (port 5555) and the HTML connects directly via EventSource, getting updates at up to 60fps without QML overhead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5876701a64
commit
39e7c07309
4 changed files with 59 additions and 22 deletions
45
plugin/contents/ui/cava-server.py
Normal file
45
plugin/contents/ui/cava-server.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Reads CAVA ASCII output from stdin and streams it to the wallpaper
|
||||
via Server-Sent Events on http://127.0.0.1:5555.
|
||||
Run as: cava -p cava.conf | python3 cava-server.py
|
||||
"""
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
|
||||
latest = ""
|
||||
lock = threading.Lock()
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/event-stream")
|
||||
self.send_header("Cache-Control", "no-cache")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.end_headers()
|
||||
last = None
|
||||
try:
|
||||
while True:
|
||||
with lock:
|
||||
cur = latest
|
||||
if cur and cur != last:
|
||||
self.wfile.write(f"data: {cur}\n\n".encode())
|
||||
self.wfile.flush()
|
||||
last = cur
|
||||
time.sleep(0.016) # cap at ~60fps
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
def serve():
|
||||
HTTPServer(("127.0.0.1", 5555), Handler).serve_forever()
|
||||
|
||||
threading.Thread(target=serve, daemon=True).start()
|
||||
|
||||
for line in sys.stdin:
|
||||
with lock:
|
||||
latest = line.strip()
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
# Kill any previous instance tied to this config
|
||||
pkill -f "cava -p.*skeledance" 2>/dev/null
|
||||
pkill -f "cava-server.py" 2>/dev/null
|
||||
sleep 0.2
|
||||
|
||||
CONF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/cava.conf"
|
||||
cava -p "$CONF" | while IFS= read -r line; do
|
||||
printf '%s\n' "$line" > /tmp/skeledance_bars
|
||||
done
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cava -p "$DIR/cava.conf" | python3 "$DIR/cava-server.py"
|
||||
|
|
|
|||
|
|
@ -886,18 +886,25 @@ for (let i = 0; i < VU_COUNT; i++) {
|
|||
vuBars.push(bar);
|
||||
}
|
||||
|
||||
// Called by QML with semicolon-separated CAVA values (0–100 per bar)
|
||||
// Called with semicolon-separated CAVA values (0–100 per bar)
|
||||
function updateBars(raw) {
|
||||
if (!isPlaying) return;
|
||||
const vals = raw.split(';');
|
||||
vuBars.forEach((bar, i) => {
|
||||
const v = Math.min(100, parseInt(vals[i] || 0, 10));
|
||||
const h = Math.max(3, (v / 100) * MAX_BAR_H);
|
||||
const v = Math.min(100, parseInt(vals[i] || 0, 10));
|
||||
const h = Math.max(3, (v / 100) * MAX_BAR_H);
|
||||
bar.style.height = h + 'px';
|
||||
bar.style.opacity = 0.3 + 0.7 * (v / 100);
|
||||
});
|
||||
}
|
||||
|
||||
// Connect to CAVA SSE server (started by cava-start.sh via QML)
|
||||
(function connectCava() {
|
||||
const sse = new EventSource('http://127.0.0.1:5555');
|
||||
sse.onmessage = e => { if (e.data) updateBars(e.data); };
|
||||
sse.onerror = () => { sse.close(); setTimeout(connectCava, 3000); };
|
||||
})();
|
||||
|
||||
/* ============================================================
|
||||
FLOATING MUSIC NOTES
|
||||
============================================================ */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ WallpaperItem {
|
|||
settings {
|
||||
javascriptEnabled: true
|
||||
localContentCanAccessFileUrls: true
|
||||
localContentCanAccessRemoteUrls: true
|
||||
localStorageEnabled: false
|
||||
}
|
||||
|
||||
|
|
@ -51,18 +52,4 @@ WallpaperItem {
|
|||
}
|
||||
}
|
||||
|
||||
// Polls CAVA bars at ~60fps
|
||||
Plasma5Support.DataSource {
|
||||
id: cavaSource
|
||||
engine: "executable"
|
||||
connectedSources: ["cat /tmp/skeledance_bars 2>/dev/null || echo ''"]
|
||||
interval: 80
|
||||
|
||||
onNewData: function(sourceName, data) {
|
||||
var raw = data["stdout"].trim()
|
||||
if (raw !== "") {
|
||||
webView.runJavaScript("updateBars(" + JSON.stringify(raw) + ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue