Skip to content

Examples

Every plugin in the plugin store has its code a click away, under its View source button. These two cover most of what a music provider can do:

Plugin Shows
YouTube Music A complete music provider: works signed out, signs in through a web view, rotates cookies, loads the library and playlists in a thread, and resolves streams in another one.
Spotify A Spotify Premium provider built on Spotify’s own protocol: OAuth with PKCE in a web view, a TCP session with Diffie-Hellman and a cipher in Lua, and songs streamed through a byte source decrypted with nari.cipher.

A thread sends every song you listen to past its half to a webhook, even with the screen off. A switch in its settings turns it off; it works from main.lua because both sides share the plugin’s data.

main.lua
local worker = nari.thread("scrobbler.lua")
worker:on_error(function(problem) nari.log("scrobbler stopped: " .. problem) end)
nari.settings(function()
return {
{
title = "Scrobbling",
description = "Sends every song you listen to past its half to the webhook",
value = function() return nari.get("paused") and "Off" or "On" end,
action = function() nari.set("paused", not nari.get("paused")) end,
},
}
end)
scrobbler.lua
local WEBHOOK = "https://example.com/scrobble"
local current
local function scrobble(song)
if nari.get("paused") then
return
end
local response, problem = nari.http({
method = "POST",
url = WEBHOOK,
headers = { ["Content-Type"] = "application/json" },
body = nari.json_encode({ title = song.title, artist = song.artist, album = song.album }),
})
nari.log(response and ("scrobbled, status " .. response.status) or problem)
end
nari.on("track", function(song)
current = song
if not song then
return
end
nari.after(math.min(song.duration / 2000, 240), function()
if current and current.id == song.id then
scrobble(song)
end
end)
end)

A button that counts how many times it was pressed, and remembers it between restarts.

main.lua
local count = nari.get("presses") or 0
nari.on("page", function(name, page)
if name ~= "NowPlaying" then
return
end
local button = NariButton.new()
button.text = "Liked " .. count
button.bg_color = ThemeEngine.Colors.AccentBg
button.fg_color = ThemeEngine.Colors.AccentFg
button.custom_minimum_size = Vector2(260, 100)
button.pressed:connect(function()
count = count + 1
nari.set("presses", count)
button.text = "Liked " .. count
end)
page.top:add_child(button)
end)