Skip to content

Releases: skerdudou/ritornello

v0.2.0-beta.8

v0.2.0-beta.8 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 10 Oct 21:48
30dfb6d

Nothing to do — replace the binaries.

No systemd unit, polkit rule, privileged updater or mount helper changed
since beta.7, so the page updates everything by itself. This assumes the
device already went through ritornello-install 0.3.0 or later once, as
beta.7 asked.

This is not a wire break: three contracts gained compatible additions
(source 1.2, display 1.1, metadata 1.1) and the bootstrap
PROTOCOL_VERSION did not move. Any mix of old and new components still
talks: an older core ignores what it does not know.

Behaviour changes

Stop keeps the track on screen, and Next and Previous move it. While
nothing plays, the source keeps one track armed: the one Play starts.

  • The screen (web page and physical display) keeps its title, artist and
    cover.
  • Next and Previous move the armed track without any sound, and Play
    starts it from its beginning.
  • Files: Stop arms the track that was playing. Next and Previous
    follow the current order, shuffled or not, and wrap around. At the end
    of the list (repeat off), the first track of the next pass is armed.
  • CD: a disc that is inserted and not played shows its armed track at
    once, and MusicBrainz is asked for its titles then. Next and Previous
    stop at both ends of the disc. Eject forgets the track. Play after Stop
    restarts the track that is armed, whatever the "on insertion" setting
    says: that setting governs arrival and insertion only.
  • Radio: Stop keeps the station's number and name, but not the song
    that was on air. Next and Previous change station without tuning in.
  • A third-party source keeps today's behaviour until it learns to arm a
    track: Stop empties the screen.

The display shows whether it plays. The first line of the console
display now starts with ▶ (playing), ║ (paused) or ■ (stopped).

Choosing a source wakes the device. In standby, a source key — on the
page, the remote or from an MPD client — wakes the device on that source.
The active source wakes where it was, and another one is switched to.
Everything else still waits for Power.

Source icons in the player card. The home page chooses the source with
one icon key per source in the player card's header, the active one
pressed. When they do not fit, the single Source key cycles through them
as before. A source without an icon shows its initial. The bar of named
source keys above the cards is gone.

The presets card in standby, and its pages. In standby, the presets
grid keeps showing the active source's stations. With several pages, the
pagination sits in the card header ("11–20 of 23"), and the lone count
under the title is gone.

Choose the name of an archived cover. The files plugin's Sources tab
picks, once for every source, the name a found cover is saved under next
to the music: cover (the default, as before), folder, front,
albumart or album. A folder that already holds an image under any of
those names, in any case, is never written to.

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one. When the bootstrap PROTOCOL_VERSION or the product's major changed, every
component moved; when a wire contract's major changed, the core and every
plugin that speaks it moved (the release script refuses a break that left one
of them on its old number). A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater) compatibly, nothing was
republished for it: devices install on version inequality alone, so a
component only reaches them under a new number. If the fix must reach a
plugin, that plugin's version must have been bumped by hand in the same
commit.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

v0.2.0-beta.7

v0.2.0-beta.7 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 10 Oct 14:40
47ea58c

Action required — install this release with ritornello-install 0.3.0
or later
, once, from a workstation (an older one fails on this release's
inventory, saying it does not parse).
Two reasons, and the page can handle neither:

  • The core's systemd unit changed (ritornello.service). An update from
    the web UI replaces binaries and never writes a unit, by design. The one
    change is ReadWritePaths=/etc/ritornello -/mnt/ritornello: without it, a
    network share already mounted when the service starts — after every boot —
    is seen read-only by the core and its plugins, so archiving a cover onto the
    NAS fails with "Read-only file system".
  • From this release on, the core refuses to update itself from the page
    while a root file of its archive moved
    (a unit, a polkit rule, the
    updater): see Behaviour changes. It judges by what ritornello-install
    recorded placing, and no installer recorded it before 0.3.0. That one run
    records it; until then, the page refuses every later update of the core and
    says to use ritornello-install.

Before installing, set Automatic checks to Off or Check only
(Settings → Updates): the core you are running now predates this rule, and
left on Check and install it would install this core's binary alone during
the night, without the unit.

This is not a wire break: no contract version moved. The privileged updater
did not change in behaviour; it now carries a number of its own, 1.0.0,
which is what the core compares. The mount helper did not change.

Behaviour changes

The core no longer updates itself past its root files. Its archive
carries systemd units, polkit rules and the updater, which the page never
places. The core's update is now offered from the page only while each of
them is the one ritornello-install recorded placing; otherwise the update
dialog names the files that changed and says to update with
ritornello-install, before anything is pressed, and the night-time update
leaves it alone. The card no longer says, after the fact, that "N files were
not installed".

One key per source on a wide screen. From a desktop width up, the home
page shows a bar with one key per source, the active one pressed: changing
source is one click. Pages now use up to 1280 px, and every plugin page is a
card with a title. Narrow screens and the remote are unchanged.

A progress bar on Oüi FM. The Oüi FM plugin now gives the position in the
track on air, as Radio France stations already did. The first track after
switching to a station shows its duration but no bar: its start time is
unknown. The bar may run a few seconds ahead of the speakers.

A cut in a stream leaves a trace. When a station stops sending data,
the journal (and the System tab's log card) now says when playback stalled
and, once it resumes, for how long — naming the stream. Until now such a cut
left no line at all, and a station's silence could not be told from a fault
of the device.

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one. When the bootstrap PROTOCOL_VERSION or the product's major changed, every
component moved; when a wire contract's major changed, the core and every
plugin that speaks it moved (the release script refuses a break that left one
of them on its old number). A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater) compatibly, nothing was
republished for it: devices install on version inequality alone, so a
component only reaches them under a new number. If the fix must reach a
plugin, that plugin's version must have been bumped by hand in the same
commit.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

v0.2.0-beta.6

v0.2.0-beta.6 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 10 Oct 10:43
a8f4629

Action required — wire break: install the core and every plugin
together. The bootstrap PROTOCOL_VERSION moved from 1 to 2, so every
component of this release carries a new number and none of the previous
ones can talk to the new core (nor the new plugins to an old core).

  • Before installing, set Automatic checks to Off or
    Check only (Settings → Updates). The core you are running now
    predates grouped updates: left on Check and install, it would install
    this release one component at a time during the night, and a failed
    start of the new core would be rolled back alone — leaving every new
    plugin refused by the old core, and the device silent.
  • Then install everything in one go, while you watch: the update dialog
    with every component checked, or ritornello-install from a
    workstation. From this release on, the core installs a break as one
    group and rolls it back as one.
  • A rollback of the core leaves every plugin refused until the core is
    reinstalled.

The privileged updater's crate changed only in its tests: nothing to
reinstall for it. No unit, polkit rule or mount helper changed.

Behaviour changes

Where is this playing from? The (?) next to the track on the player
page now opens with a Source row: the stream URL of the station, or the
address of the file — smb://host/share/… for a file on the NAS (never the
user name), its path on the device otherwise. The CD shows none. The (?)
now appears even when nothing else is known about what plays, such as a
station that announces no title.

A disc can start playing when it is inserted. The CD plugin's page has a
new setting, When a disc is inserted: nothing (the default), play if the CD is
the source being listened to, switch to the CD and play, or also leave
standby to do so.

Faster tracks from a folder with a cover. mpv no longer opens the
cover.jpg beside every track itself (4.5 s to start a track in such a
folder on the Pi, against 1.8 s elsewhere). A cover archived onto the NAS is
now credited to the folder for the rest of the album, and archiving a large
cover no longer marks a healthy share as unresponsive.

Each wire contract has its own version. A plugin now announces one
version per contract it speaks (source, display, input, metadata, admin).
The System page shows a plugin whose contract major differs from the core's
as incompatible, naming the contract, and one whose minor is newer as
limited: it runs, with some features inactive. A future break of one
contract will only require the plugins that speak it to move.

A breaking core is installed with its dependents. When an update changes
a contract's major, the core and the plugins that depend on it are installed
in one step and rolled back together if the new core does not start. The
night-time update never installs a break; it waits for you. This applies to
updates installed by this core — hence the action above for this one.

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one. When the bootstrap PROTOCOL_VERSION or the product's major changed, every
component moved; when a wire contract's major changed, the core and every
plugin that speaks it moved (the release script refuses a break that left one
of them on its old number). A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater) compatibly, nothing was
republished for it: devices install on version inequality alone, so a
component only reaches them under a new number. If the fix must reach a
plugin, that plugin's version must have been bumped by hand in the same
commit.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

ritornello-install 0.3.1

Choose a tag to compare

@github-actions github-actions released this 10 Oct 15:03
cca597e

ritornello-install 0.3.1

Take the file for your system, extract it, and run it:

./ritornello-install --host account@device

The newest installer is always at
https://github.com/skerdudou/ritornello/releases/download/installer/<file>;
this release is the numbered, permanent copy of version 0.3.1. The
installer installs the newest Ritornello release by itself and tells you when
a newer installer than this one exists. It never updates itself.

SHA256SUMS lists the archives of this release, if you want to check a
download.

What changed in this installer:

  • Right after looking at the device, it says which version of Ritornello
    the device runs, asked of the running core itself.
  • The device address question explains what it expects, with examples
    (192.168.1.20, dietpi.local, account@address).
  • Every yes-or-no question waits for y or n: Enter alone no longer
    answers "no" and ends the run.

ritornello-install 0.3.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 14:42
47ea58c

ritornello-install 0.3.0

Take the file for your system, extract it, and run it:

./ritornello-install --host account@device

The newest installer is always at
https://github.com/skerdudou/ritornello/releases/download/installer/<file>;
this release is the numbered, permanent copy of version 0.3.0. The
installer installs the newest Ritornello release by itself and tells you when
a newer installer than this one exists. It never updates itself.

SHA256SUMS lists the archives of this release, if you want to check a
download.

What changed in this installer:

  • It reads the release inventory of Ritornello v0.2.0-beta.7 and later
    (format 2). Installer 0.2.0 cannot read it; use this one.
  • It records which content each root-owned file it places is (systemd
    units, polkit rules, the updater). The device's core compares that before
    updating itself from the web page, and refuses — naming the files — when a
    release changes one of them, so they are never left behind.
  • Its first run on a device already installed places the core's root files
    again, once, to record them. Until that run, the web page refuses updates
    of the core and says to use ritornello-install.

ritornello-install — latest (0.3.1)

Choose a tag to compare

@github-actions github-actions released this 06 Oct 20:50
cca597e

The newest installer, always at this address: version 0.3.1. Every numbered installer is a release of its own, tagged installer-vX.Y.Z; the notes of installer-v0.3.1 say what changed.

v0.2.0-beta.5

v0.2.0-beta.5 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Oct 12:32
44f3dab

Nothing to do — replace the binaries.

Behaviour changes

The update dialog says what it really shows: only the components that need
updating are listed, and you choose which to install. It used to say that
what is already up to date is left unchecked, but such rows never appear.

Fewer downloads between betas: a beta now carries only what moved since the
previous beta, not since the last finished release. This one carries the
core and the four language packs. A device that offers prereleases finds
every other component in the release that last carried it, and
ritornello-install does the same. A finished release still carries
everything that changed since the previous finished one.

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one. When PROTOCOL_VERSION or the product's major changed, every
component moved (the release script refuses a wire break that left a core or
plugin on its old number). A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater) compatibly, nothing was
republished for it: devices install on version inequality alone, so a
component only reaches them under a new number. If the fix must reach a
plugin, that plugin's version must have been bumped by hand in the same
commit.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

v0.2.0-beta.4

v0.2.0-beta.4 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Oct 21:54
1d770a7

Action required — the root mount helper for network shares,
files-mount, changed (it now remounts a share whose "writable" setting
changed). Only ritornello-install may place it, so the update page refuses
to update the files plugin with "update with ritornello-install" until it
is run. The core and the other plugins update from the page as usual.

files-mount now carries its own number, independent of the product's:
it moves from 0.2.0-beta.3 to 1.0.1, and from now on it only moves when
the helper itself changes — so this installer run is not one you will be
asked for at every release.

Take the installer for your computer from its permanent link (the README's
Download table, or releases/download/installer/<file>), then:

./ritornello-install --host account@device --keep

This installer leaves alone what is already up to date. Its first run on a
device installed by an older installer places every plugin and pack once
more — the older one did not record them — and later runs only what changed.

Behaviour changes

New: a "Full journal" on the System page. The core now relays every
plugin's own output into its log, prefixed with the plugin's name, and keeps
the latest lines (errors apart) for the page to show. A stream URL is never
written there by the musicbrainz plugin.

The generic-input plugin reopens a remote receiver that is unplugged and
plugged back in, without a restart, and warns once per device node rather
than on every retry.

The files-mount helper remounts a network share whose "writable" setting
changed, instead of keeping it in the old mode until the next reboot.

Fewer downloads: a component whose own code did not change now keeps its
number, so a device only fetches what really moved — here the core, files,
generic-input, musicbrainz and the language packs. The installer is now
published on its own channel (see Action required above).

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one. When PROTOCOL_VERSION or the product's major changed, every
component moved (the release script refuses a wire break that left a core or
plugin on its old number). A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater) compatibly, nothing was
republished for it: devices install on version inequality alone, so a
component only reaches them under a new number. If the fix must reach a
plugin, that plugin's version must have been bumped by hand in the same
commit.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

v0.2.0-beta.3

v0.2.0-beta.3 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Oct 16:30
c45c19d

Action required for this beta (0.2.0-beta.3) — the repeat key was renamed. If /var/lib/ritornello/plugins/generic-input/input-bindings.toml binds cmd = "ToggleRepeatAll", replace it with cmd = "CycleRepeat" just before updating. generic-input reads that file only when it starts and parses it as a whole: the new plugin would start with no keys at all on the old name, and the old one with none on the new name. Between the edit and the update, do not save from the keys page, which rewrites the file from its in-memory table. The shipped presets bind no mode key.

sudo sed -i 's/^cmd = "ToggleRepeatAll"$/cmd = "CycleRepeat"/' /var/lib/ritornello/plugins/generic-input/input-bindings.toml

Behaviour change: repeat is now off / all / one. One repeat button on the web remote cycles off → all → one, and shows a "1" badge for repeat-one. The physical key "Repeat" cycles the same way. Under repeat-one, Next and Previous still change track, and the new track repeats in turn. Files loop seamlessly. The CD seeks back to the start of the track, and an instant of the next track may be heard; this has never been measured. MPD clients can now use single: repeat-one is reported as repeat 1 + single 1.

The repeat setting is reset once. The saved state named it repeat_all; it is now repeat. The old value is ignored, repeat starts off, and every other setting is kept.


Action required — this is the first release, so it carries every
privileged file at once: the updater's binary, two new systemd units, a new
polkit rule, and a ritornello.service that gained the start limit and the
OnFailure= line arming the rollback. An update can write none of those, by
design, so they are placed by hand or by ritornello-install.

On a device installed with ritornello-install, nothing to do: it
places all four and reloads systemd.

On a device installed from these archives, after extracting the core's:

sudo systemctl daemon-reload
sudo systemctl restart ritornello

The four files are inside ritornello-core-<version>-<arch>.tar.gz at the
paths they occupy on the device, so the ordinary tar -C / of the Install
section below already put them there. What does not happen on its own is the
daemon-reload: without it systemd keeps the old ritornello.service, the
rollback stays unarmed, and every install attempt is refused by polkit with
Access denied — a message that names no file.

Until this release is installed, the update card checks and reports
correctly and every install fails. That is expected: the feature installs
its own privileged half exactly once, and this is that once.

Behaviour changes

Behaviour change: the source key's cycle now follows the order of
/etc/ritornello/plugins.toml instead of being sorted alphabetically. On a
device in service the cycle order therefore changes at the first start after
this update. The configuration page reorders it, and the same order now also
sets metadata priority.

Behaviour change: updating a plugin now refuses when its plugins.toml
entry declares an exec outside
/usr/local/lib/ritornello/plugins/. Before this release that case was a
silent half-success — the archive's binary landing where the entry is never
read from, and the row then claiming a version that is not the one actually
running. If an existing device meets this refusal on its next update, the
fix is to move the binary under the plugins directory, or to point exec
there.

New setting, and no behaviour change unless it is ticked: "Offer
prereleases", in the automatic-checks card. Off by default, so a device that
is not told otherwise is offered finished releases only, exactly as before.
Ticked, betas and release candidates are offered too — on every check, for
the core, the plugins and any third-party plugin. A device on prereleases
moves to a finished release as soon as one is published, since the two carry
different version numbers.

Install

Common case — the core and every plugin:

sha256sum -c SHA256SUMS --ignore-missing
sudo tar --no-same-owner -C / -xzf ritornello-core-<version>-<arch>.tar.gz
sudo tar --no-same-owner -C / -xzf ritornello-plugins-<version>-<arch>.tar.gz
sudo chown -R ritornello: /etc/ritornello
sudo systemctl daemon-reload && sudo systemctl restart ritornello

--no-same-owner is belt and braces, not a workaround: the archives are
built with every entry owned by root, and the packaging script refuses to
produce one that is not. But extracting as root restores whatever ownership
an archive carries, so the flag makes the recipe safe even for an archive
built before that rule existed — a polkit rules file (JavaScript polkitd
runs as root) owned by a non-root uid is a local privilege escalation.

Each archive holds the tree as it will exist on the device, and holds no
configuration you may have edited: stations.toml, input-bindings.toml and
plugins.toml are never in it. Example files and the plugins.toml block of
each plugin travel beside the tree, to be copied by hand.

Replacing a single plugin is the same two commands with that plugin's archive.

The files plugin needs its companion, ritornello-files-mount, which
carries the root mount helper, its unit and its polkit rule: the plugin's own
archive does not. After installing ritornello-plugin-files together with
ritornello-files-mount (or the bundle, which carries both) for the first
time:

sudo systemctl enable ritornello-media-mount.service

Enabled, not started: what it is enabled for is machine boot, where it
reconciles the declared network shares. Skip it and declared shares silently
stop being mounted after a reboot.

A language pack (ritornello-lang-<language>-<version>.tar.gz) is not part
of the recipe above, and not part of any component's archive either. It is
flat — pack.toml plus one file per plugin it covers, no leading
path — so the tar -C / above must never be run against it: doing so drops
those files straight into /. Install one from the config page, where the
core fetches, verifies and writes it itself with no privileged step at all;
or, by hand, extract it into its own directory:

sudo mkdir -p /etc/ritornello/language-packs/ritornello-lang-<language>
sudo tar --no-same-owner -C /etc/ritornello/language-packs/ritornello-lang-<language> \
  -xzf ritornello-lang-<language>-<version>.tar.gz
sudo chown -R ritornello: /etc/ritornello/language-packs/ritornello-lang-<language>

What this release carries

This release carries the components whose own version moved since the
previous one — plus, when a shared crate changed, every component, since all
eleven binaries were rebuilt. A component missing from the assets below is
unchanged, not removed — do not read its absence as a regression.

If a shared crate changed (ritornello-proto, ritornello-i18n,
ritornello-plugin-sdk, ritornello-updater), check that every
component's version was bumped in the same commit. Devices install on version
inequality alone: an archive republished under its old number is never
fetched, so the release ships everything and delivers nothing.

The version in an attached file's name is that component's own version,
not this release's tag: ritornello-plugin-radio-0.2.1-<arch>.tar.gz says
nothing about the tag it ships under. Only ritornello-plugins-<version>,
the bundle of every plugin, is named after this release's own tag.

Never delete a published release or its attached files. The appliance
goes back to fetch, from there, the components that have not changed since.

Architectures

  • armv7 — Raspberry Pi 2 and similar, the reference hardware.
  • x86_64 — PC/server; the target this project's tests and end-to-end
    journeys run on.
  • arm64 — Pi 3/4/5 class. Cross-compiled but never started on hardware,
    for lack of a device to try it on.

ritornello-install 0.2.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 20:50
1a60c91

ritornello-install 0.2.0

Take the file for your system, extract it, and run it:

./ritornello-install --host account@device

The newest installer is always at
https://github.com/skerdudou/ritornello/releases/download/installer/<file>;
this release is the numbered, permanent copy of version 0.2.0. The
installer installs the newest Ritornello release by itself and tells you when
a newer installer than this one exists. It never updates itself.

SHA256SUMS lists the archives of this release, if you want to check a
download.

What changed in this installer. This is the first installer published on its own channel and under its own number, independent of Ritornello's release numbers. Compared with the copies attached to v0.2.0-beta.1 to beta.3:

  • It installs only what changed. A run against an up-to-date device answers "already up to date". It asks for no sudo password, downloads no archive, and does not stop the radio. When one component moved, only that component is downloaded and placed.
  • --reinstall, or "Repair (reinstall everything)" on the first screen, reinstalls everything as before. Use it for a hand-damaged unit or rule, or for a downgrade the device's registry does not see.
  • It decides what to skip from its own root-owned registry only. That registry now records every component placed, language packs included. A registry not owned by root, or writable by others, is ignored, and everything is placed again.
  • The first run on a device installed by an older installer places every plugin and pack once more, because the old registry did not record them. Every run after that is a no-op when nothing changed.
  • It shows its own number on its first line and in --help, and tells you when a newer installer exists.
  • It fetches each release's SHA256SUMS once per run, no longer once per archive.