The nari API
main.lua gets a global nari table with everything Nari offers plugins. Background threads
get a smaller version of it.
Basics
Section titled “Basics”| Function | Description |
|---|---|
nari.plugin |
{ id, path, folder, data }: the plugin’s id, its folder as a Godot path (user://plugins/<id>) and as an OS path, and the OS path of its data folder (user://plugin_data/<id>, for files saved with nari.http). |
nari.on(event, handler) |
Calls handler on an event. |
nari.is_ready() |
true once Nari finished starting. |
nari.current() |
The current song, or nil. |
nari.log(...), print(...), nari.warn(...) |
Writes to Nari’s log under the plugin’s name, as LOG or WARN. |
nari.log_color(color) |
Colors the plugin’s name in the log, like "#ff0033" or a Godot color name. |
nari.path(file) |
Godot path of a file in the plugin folder. Paths with :// are returned as they are. |
nari.load(file) |
Loads a file of the plugin: images become textures, sounds (mp3, ogg, wav) become audio streams, anything else goes through Godot’s loader (.gdshader, .tres, .tscn…). res:// paths load Nari’s own files. |
nari.after(seconds, handler) |
Calls handler once after seconds. |
nari.await(value, handler) |
Calls handler(result) when an async GDScript function finishes. See Async functions. |
nari.open_url(url) |
Opens a link in the browser or the app that handles it. false if nothing could open it. |
nari.get(key), nari.set(key, value) |
Data that survives restarts. See Storing data. |
nari.command(name, description, handler) |
Adds a console command. |
Adding to Nari
Section titled “Adding to Nari”| Function | Description |
|---|---|
nari.lyrics_provider(spec) |
Adds a lyrics provider. |
nari.music_provider(spec) |
Adds a music provider and returns it, to emit its signals. |
nari.effect(spec) |
Adds a sound effect to Now Playing’s Effects tab. |
nari.visualizer(file or spec) |
Adds a visualizer. |
nari.analyze(song, options, callback) |
Measures tempo, key, loudness or the waveform of a song. See Audio analysis. |
nari.home_entry(spec) |
Adds an entry to Home. See Building UI. |
nari.now_playing_tab(spec) |
Adds a tab to Now Playing. See Building UI. |
nari.discover_section(spec) |
Adds a section to Discover. See Building UI. |
nari.item_action(spec) |
Adds an option to the menu of songs, albums, artists or playlists. See Building UI. |
nari.webview(spec) |
Opens a web page as a Nari screen. See Building UI. |
nari.setting(spec) |
Adds a setting to the plugin’s settings page. See Settings. |
nari.settings(builder) |
Adds entries to the plugin’s settings page. See Settings. |
nari.settings_entry(category, builder) |
Adds entries to a Settings page: general, library, playback, appearance, lyrics or integrations. See Settings. |
nari.thread(file, options) |
Starts a background thread and returns its handle. |
Network and data
Section titled “Network and data”| Function | Description |
|---|---|
nari.http(request, callback) |
An HTTP request, see below. |
nari.serve(handler, options) |
A small web server on this device. See Web helpers. |
nari.json_encode(value), nari.json_decode(text) |
JSON. |
nari.base64_encode(data, url_safe), nari.base64_decode(text) |
Base64. url_safe uses the URL alphabet without padding (JWT, PKCE). Decoding accepts both. |
nari.md5(text, raw), nari.sha1(text, raw), nari.sha256(text, raw) |
Digests as hex, or as raw bytes when raw is true. |
nari.hmac(algorithm, key, text, raw), nari.hmac_sha256(key, text, raw) |
HMAC with "md5", "sha1" or "sha256". |
nari.cipher(spec) |
AES or Blowfish. See Ciphers. |
nari.modpow(base, exponent, modulus) |
base ^ exponent mod modulus on big numbers given as big-endian bytes, for Diffie-Hellman and RSA. |
nari.random_bytes(count) |
Secure random bytes (up to 4096), for nonces, states and PKCE verifiers. |
HTTP requests
Section titled “HTTP requests”nari.http runs a request on a worker thread and calls callback(response, problem) on the main thread when
it’s done:
nari.http({ method = "POST", -- GET by default url = "https://example.com/api", headers = { ["Content-Type"] = "application/json" }, body = nari.json_encode({ hello = "world" }),}, function(response, problem) if not response then nari.log("request failed: " .. problem) return end nari.log(response.status, response.body)end)responseis{ status, body, headers, attempts }for every answer, 4xx and 5xx included. Header names are lowercase (response.headers["content-type"]), and a header sent several times (likeset-cookie) comes as one value with a line per copy.responseisnil, with aproblem, when the request couldn’t be made: no network, a bad URL, or the 20 second timeout.- Bodies are bytes, so they can carry binary data (protobuf, images) both ways.
- Add
save = "covers/art.jpg"to write the body to a file in the plugin’s data folder instead. It’s only written for 2xx answers, andresponse.pathis its OS path.
Busy servers are retried for you: 429, 502, 503, 504 and network errors are tried up to 2 more times,
waiting what the server asks in Retry-After (up to 60 seconds) or a growing delay. attempts says how many tries
it took. Set retries = 0 to turn it off, or a number up to 10 for more tries.