feat(lyrics): improve player and interlude controls (#42)

* feat(lyrics): support multiple MPRIS players

* feat(lyrics): add interlude font options
This commit is contained in:
rrzt
2026-07-17 19:55:31 -04:00
committed by GitHub
parent 54ac3ed0d6
commit d80bdf0190
5 changed files with 240 additions and 59 deletions
+18 -5
View File
@@ -8,20 +8,23 @@ local showArtist = noctalia.getConfig("show_artist")
local hideWhenPaused = noctalia.getConfig("hide_when_paused")
local showCover = noctalia.getConfig("show_cover")
if showCover == nil then showCover = true end
local activeColor = noctalia.getConfig("active_color") or "primary"
local activeColor = noctalia.getConfig("active_color") or "on_surface"
local inactiveColor = noctalia.getConfig("inactive_color") or "on_surface_variant"
-- These are plugin settings, not per-widget settings.
local scrollMode = noctalia.getConfig("scroll_mode") or "auto"
local marqueeSpeed = tonumber(noctalia.getConfig("marquee_speed")) or 30
local maxLines = tonumber(noctalia.getConfig("max_lines")) or 1
local maxChars = tonumber(noctalia.getConfig("max_chars")) or 24
local maxChars = tonumber(noctalia.getConfig("max_chars")) or 15
local charWidth = tonumber(noctalia.getConfig("char_width")) or 9
local gradientOn = noctalia.getConfig("gradient")
if gradientOn == nil then gradientOn = true end
local animation = noctalia.getConfig("animation") or "karaoke"
local cueText = noctalia.getConfig("cue_text") or "•••••"
if cueText == "" then cueText = "•••••" end
local cueFontMode = noctalia.getConfig("cue_font_mode") or "follow"
local cueFontFamily = noctalia.getConfig("cue_font_family") or "sans-serif"
if cueFontFamily == "" then cueFontFamily = "sans-serif" end
local track = nil
local lyrics = nil
@@ -29,6 +32,7 @@ local cover = nil
local playing = false
local showMode = "auto"
local rendered = false
local playerInstance = ""
local baselinePosition = 0
local baselineClock = os.clock()
@@ -48,6 +52,10 @@ local INTERLUDE_GAP_MS = 7000
local INTRO_MIN_MS = 6000
local INTERLUDE_MIN_MS = 8000
local function shellQuote(value)
return "'" .. tostring(value):gsub("'", "'\\''") .. "'"
end
local function clamp(value, low, high)
return math.min(high, math.max(low, value))
end
@@ -91,7 +99,7 @@ local function getLineInfo()
return {
key = "intro",
index = 0,
line = { text = cueText },
line = { text = cueText, cue = true },
progress = clamp(position / firstTime, 0, 1),
synced = true,
position = position,
@@ -130,7 +138,7 @@ local function getLineInfo()
return {
key = "interlude-" .. tostring(index),
index = index,
line = { text = cueText },
line = { text = cueText, cue = true },
progress = clamp((position - lineEnd) / (nextTime - lineEnd), 0, 1),
synced = true,
position = position,
@@ -221,6 +229,7 @@ local function buildLineRow(line, opts)
opts = opts or {}
local text = type(line) == "table" and line.text or line
local times = type(line) == "table" and line.chars or nil
local isCue = opts.cue or (type(line) == "table" and line.cue == true)
local chars = toChars(text or "")
if #chars == 0 then chars = { " " } end
@@ -273,6 +282,7 @@ local function buildLineRow(line, opts)
color = color,
opacity = alpha,
maxLines = 1,
fontFamily = isCue and cueFontMode == "custom" and cueFontFamily or nil,
})
end
@@ -344,6 +354,7 @@ local function render()
cascade = shownLine == info.line and animation == "cascade",
wave = shownLine == info.line and animation == "wave",
opacity = opacity,
cue = shownLine == info.line and info.cue == true,
})
end
@@ -391,7 +402,8 @@ function onClick()
end
function onRightClick()
noctalia.runAsync("playerctl play-pause", function(result)
if playerInstance == "" then return end
noctalia.runAsync("playerctl --player " .. shellQuote(playerInstance) .. " play-pause", function(result)
if result.exitCode == 0 then
local wasPlaying = playing
if wasPlaying then baselinePosition = getProgressMs() * 1000 end
@@ -412,6 +424,7 @@ function update()
lyrics = noctalia.state.get("lyrics")
cover = noctalia.state.get("cover")
playing = noctalia.state.get("playing") == true
playerInstance = noctalia.state.get("player_instance") or ""
local info = getLineInfo()
local nextKey = info and info.key or "fallback"