Command Line Reference
Control the running Sona from a terminal, script or status bar.
For an introduction, see Command line.
Options of sona
Section titled “Options of sona”sona without a command opens Sona, or hands its Apple Music links to the Sona already running. sona --hidden starts without a window, and sona --version prints the version.
sona.exe --remove-sandbox
Section titled “sona.exe --remove-sandbox”Windows
Removes what the playback host’s sandbox left on the computer: its AppContainer profile and the access entries granted to it on Sona’s, GStreamer’s and the Widevine folders. Your settings, library and the downloaded Widevine component stay.
- The installer’s uninstaller runs it for you.
- The portable
.ziphas no uninstaller: quit Sona and run it from the folder before you delete the folder. - It starts nothing and can run again. If a step fails, it exits with status 1 and says why. On other systems it exits with status 1, because there is nothing to remove.
Commands
Section titled “Commands”Options may come anywhere after the command. -- ends them, and a number such as -10 is an argument (sona volume -10). Every command takes -h and --help.
sona play, pause, toggle, next, prev
Section titled “sona play, pause, toggle, next, prev”Resume, pause, play or pause, skip to the next song, go to the previous song (or restart the song in its first seconds, like the previous key).
--json- prints the status after the command.
sona status
Section titled “sona status”Prints the playback state, song, position, volume, shuffle, repeat and private listening.
--follow- keeps printing on every change.--formatstring (optional) - a template for each line (Status bars).--json- prints the status.
sona lyrics
Section titled “sona lyrics”Prints the playing song’s lyrics as plain text.
--lrc- prints an LRC file.--follow- prints the line being sung, a new one each time it changes (Lyrics in a bar or shell).--formatstring (optional) - a template for each line.--translationor--transliteration- prints that version of each line.--json- prints{"track", "state", "position", "provider", "timing", "synced", "lines"}. With--follow, one{"running", "state", "track", …}per line.
sona queue
Section titled “sona queue”Prints the queue in play order and marks the playing song.
--json- prints{"index", "tracks"}.
sona search
Section titled “sona search”Searches the catalogue in Sona’s storefront: sona search <term>….
--typestring (optional) -song,album,artist,playlist,station,music-videoorcurator.--limitnumber (optional) - results of each kind. Default 5, at most 20.--json- prints{"term", "results"}.
sona open
Section titled “sona open”Opens a music.apple.com, music:// or itms:// link in Sona’s window, as clicking it would: sona open <link>.
--json- prints{"kind", "id", "storefront"}.
sona volume
Section titled “sona volume”Shows the volume, or sets it as the player bar’s slider does and keeps it: sona volume [N|+N|-N].
--json- prints{"volume"}.
sona like
Section titled “sona like”Favourites the playing song, which adds it to your library. Needs an Apple Music account signed in to Sona: sona like [on|off|toggle|status]. The default is on.
--json- prints{"track", "liked"}.
sona private
Section titled “sona private”Shows or sets private listening: sona private [on|off|toggle|status]. The default is status. SONA_PRIVATE=1 keeps it on. A development build changes it for the session only.
--json- prints{"on", "source", "saved"}.
sona help
Section titled “sona help”Prints help for a command: sona help [command].
--man- prints the manual page in roff.
sona completion
Section titled “sona completion”Prints the shell completion script: sona completion bash|zsh|fish.
Exit status
Section titled “Exit status”| Status | Meaning |
|---|---|
| 0 | Success |
| 1 | The command failed in Sona (the message says why: nothing is playing, the song has no lyrics, not signed in, Apple refused, …) |
| 2 | The command line is wrong (unknown command, option or argument, or a link Sona can’t open) |
| 3 | Sona isn’t running or can’t be reached (also while it starts or quits). status still prints that it isn’t running |
Messages go to standard error, results to standard output.
With --json a command prints one JSON object on one line. The schemas
(internal/cli/schema.go) only ever gain fields; none is renamed, removed
or changes meaning. Every field is always present. Times are seconds, the
volume a percentage.
The status:
{ "running": true, "state": "playing", "track": { "id": "1441164430", "title": "Come Together", "artist": "The Beatles", "album": "Abbey Road", "duration": 259.95, "explicit": false, "artwork": "https://is1-ssl.mzstatic.com/image/thumb/…/600x600bb.jpg" }, "position": 83.4, "volume": 40, "shuffle": false, "repeat": "off", "private": true, "preview": false, "error": ""}state:idle(nothing loaded),loading,playing,paused,endedorerror(errorthen says what failed).track:nullwhen no song is selected.idis the catalogue ID, or the library ID (i.…) of a song only in your library.artworkis a 600×600 image on Apple’s artwork CDN,""when there is none.position: as of the moment the status was taken.repeat:off,allorone.preview: the song plays as its 30-second preview.- When Sona isn’t running,
status --jsonprints"running": false,"state": "idle"and every other field empty.
queue: {"index": 1, "tracks": [track…]}, each track as above plus
"autoPlay" (the song came from the station or AutoPlay); index is the
playing song’s place, -1 when none. search: {"term": "…", "results": [{"kind", "id", "name", "subtitle", "explicit", "url"}…]}, grouped by kind
in Apple’s order; url is the music.apple.com link, "" when unknown.
like: {"track": track, "liked": true}. private: {"on": true, "source": "setting"|"development"|"environment", "saved": false}. open:
{"kind": "album", "id": "1441164426", "storefront": "gb"}.
lyrics: {"track": track, "state": "playing", "position": 83.4, "provider": "apple", "timing": "word", "synced": true, "lines": [line…]},
and each line {"start": 12.34, "end": 15.8, "text": "…", "background": "", "agent": "v1", "part": "Verse", "translation": "", "transliteration": ""}:
provider: where the lyrics come from:apple,musixmatch,lrclibornetease, as chosen in Settings → Playback.timing:word(each word timed, which the lines below don’t show),lineornone(plain text).syncedis true forwordandline. Plain lyrics have"start": 0, "end": 0on every line.linesare in the order sung; timed lines are in order ofstart.startandendare seconds into the song. A line’sendis at least the end of its last word, so it may run past the next line’sstart.backgroundis the background vocals sung with the line,agentthe voice (v1,v2for a duet’s second voice),partthe song part where the lyrics name them.translationandtransliterationare the line in the translation language (Settings → Playback → Lyrics, else the account’s) and in Latin script;""when the line has none.stateandpositionare the playback’s when Sona answered.
One line of lyrics --follow --json:
{ "running": true, "state": "playing", "track": { "id": "1441164430", "title": "Come Together", "…": "…" }, "position": 12.5, "lyrics": "ready", "provider": "apple", "timing": "word", "synced": true, "index": 1, "line": { "start": 12.34, "end": 15.8, "text": "He come groovin' up slowly", "…": "…" }, "next": { "start": 16.2, "end": 18, "text": "He got joo joo eyeball", "…": "…" }, "text": "He come groovin' up slowly"}lyrics:ready,loading(the song’s lyrics are being fetched) ornone(nothing is playing, the song has no lyrics, or they couldn’t be fetched).index: the place oflinein the lyrics’lines;-1andline: nullwhen no line is sung (before the first, while the voice rests, plain lyrics, no lyrics).nextis the line that begins next,nullafter the last.text: what the text output prints,""when no line is sung. With--translationor--transliterationit is that text where the line has one;linealways has all of them.runningis false only in the last line, when Sona has quit;state,trackandpositionare as in the status (positionis when the line was printed).
Status bars
Section titled “Status bars”sona status --follow prints a line now and another each time the
status changes (the position moving on its own doesn’t count), and ends
when Sona quits, after a last line saying it isn’t running (exit status 0).
When Sona isn’t running at the start it prints that line and exits with 3,
so a bar module should restart it.
--json makes each line the status’s JSON. --format TEMPLATE makes it a
Go text/template over the JSON fields
({{.state}}, {{.track.title}}), with {{json …}} (a JSON value, quoted)
and {{clock …}} (seconds as m:ss); use {{with .track}}…{{end}}, since
track may be null.
Waybar (~/.config/waybar/config):
"custom/sona": { "exec": "sona status --follow --format '{\"text\": {{with .track}}{{json (printf \"%s – %s\" .artist .title)}}{{else}}\"\"{{end}}, \"class\": {{json .state}}, \"alt\": {{json .state}}}'", "return-type": "json", "restart-interval": 5, "on-click": "sona toggle", "on-scroll-up": "sona volume +5", "on-scroll-down": "sona volume -5"}Polybar:
[module/sona]type = custom/scriptexec = sona status --follow --format '{{if eq .state "playing"}}▶{{else}}⏸{{end}} {{with .track}}{{.artist}} – {{.title}}{{end}}'tail = trueclick-left = sona togglescroll-up = sona volume +5scroll-down = sona volume -5Lyrics in a bar or shell
Section titled “Lyrics in a bar or shell”sona lyrics prints the lyrics of the song that is playing, from the
sources chosen in Settings → Playback (the ones the lyrics view uses, with
its cache: asking costs no more requests than the view makes). It needs
Apple Music songs: live radio, music videos and songs only in your library
have no lyrics.
sona lyrics # plain text, one line to a linesona lyrics --translation # each line's translation where it has onesona lyrics --lrc > song.lrc # an LRC file for a lyrics playersona lyrics --json | jq '.lines[] | select(.start > 60) | .text'- Plain text: one line of text per lyric line, a blank line between verses (where the song part changes, or after a pause of 3 seconds or more between lines). Background vocals are left out unless they are all a line has; a line break inside a line becomes a space.
--lrc:[ti:],[ar:]and[al:]tags, then[mm:ss.xx]and the line, one per line in time order (hundredths cut off; minutes go past 99 for a very long song). Word-timed lyrics are written with their line times. Lyrics with no timing can’t be an LRC file: nothing is printed and it exits with status 1 (these lyrics have no timing…), so a redirect doesn’t leave an untimed file looking like LRC; leave--lrcout for the plain text.--translation,--transliterationprint the line’s translation, or its Latin-script sound, instead of the line where it has one, and the line itself where it doesn’t. They apply to the plain text,--lrcand--follow’stext, not to the one-shot--json(which carries every localization: combining them is an error), and not to each other.- Nothing playing, a song with no lyrics (
no_lyrics) and failures end with status 1 and a message, as for the other commands; Sona not running is 3.
Following the line being sung
Section titled “Following the line being sung”sona lyrics --follow prints a line now and another each time the line
sung changes, until Sona quits (then a last empty line, exit status 0; when
Sona isn’t running at the start, an empty line and exit status 3, so a bar
module should restart it, as with status --follow). In the text output a
line is the sung line’s text, "" before the first line, while the voice
rests (3 seconds or more between lines: the line goes half a second after it
ends), after the last line, for a song without lyrics (or with plain ones) and
when nothing plays; a line the same as the one before (a pause, say) isn’t
printed again. --json prints the object above on each change of the line,
the song, the playback state or whether the lyrics are there; --format TEMPLATE is a Go template over those fields, as for status ({{.text}},
{{with .next}}{{.text}}{{end}}, {{.index}}, {{clock .position}}).
The line is the one Sona’s lyrics view lights: it starts a quarter of a
second before it begins (the eye arrives as the voice does) and stays until
the next one begins. It is worked out in the command from the status’s
position, moved on by the clock while the song plays, and it sleeps on one
timer to the next boundary: nothing polls, Sona does no work per line, and
while paused or stopped there is no timer at all. Sona’s status stream says
when to look again: a pause, a resume, a song change, and a seek (a jump of
more than half a second in the position, which the stream publishes though
status --follow leaves it out as only a position change). The song’s
lyrics are fetched once, when the song changes (a fetch that fails other
than for lack of lyrics is told on standard error, and the song shows
nothing until the next one).
Quickshell (a Process reading one JSON object per line; it starts again
if Sona wasn’t running or quits):
import QtQuickimport Quickshellimport Quickshell.Io
Scope { id: root property string line: "" property bool playing: false
Process { id: lyrics running: true command: ["sona", "lyrics", "--follow", "--json"] stdout: SplitParser { onRead: data => { const now = JSON.parse(data) root.line = now.text root.playing = now.state === "playing" } } onExited: retry.start() // 3 when Sona isn't running, 0 when it quit }
Timer { id: retry interval: 5000 onTriggered: lyrics.running = true }
PanelWindow { anchors { top: true; left: true; right: true } implicitHeight: 32 exclusionMode: ExclusionMode.Ignore // don't move windows as lines come and go visible: root.line !== "" Text { anchors.centerIn: parent text: root.line opacity: root.playing ? 1 : 0.5 } }}Waybar (a custom module; Waybar reads markup, so escape is on, and turns
tooltips off in the module’s config, not in each line):
"custom/lyrics": { "exec": "sona lyrics --follow --format '{\"text\": {{json .text}}, \"class\": {{json .state}}}'", "return-type": "json", "escape": true, "tooltip": false, "restart-interval": 5}Polybar:
[module/lyrics]type = custom/scriptexec = sona lyrics --followtail = true--translation and --transliteration work with --follow too, and
sona lyrics --lrc > song.lrc writes the file a lyrics player wants.
Shell completions and the manual page
Section titled “Shell completions and the manual page”The .deb, .rpm and Arch packages install the bash, zsh and fish completions and the sona(1) manual page. Elsewhere, load them by hand:
source <(sona completion bash) # bash, e.g. in ~/.bashrcsona completion zsh > "${fpath[1]}/_sona" # zshsona completion fish > ~/.config/fish/completions/sona.fishsona help --man > ~/.local/share/man/man1/sona.1 # then: man sonaThe AppImage installs neither. Run it with a command: Sona.AppImage status.
How commands reach Sona
Section titled “How commands reach Sona”- Linux: over your D-Bus session bus. The running Sona owns
dev.coredev.Sona. - macOS and Windows: over a socket,
sona.sock, in Sona’s state folder (~/Library/Application Support/Sona/State,%LOCALAPPDATA%\Sona\State). Sona answers only processes of your own user.
The window follows every change a command makes. Help, the manual page, completion descriptions, printed lines and errors use Sona’s Language setting, else your system’s languages. Command and option names, --json output and --format templates are the same in every language.