Skip to content

Stellody v0.1.0

Choose a tag to compare

@oernster oernster released this 30 Aug 05:40
· 90 commits to main since this release

Release notes

The first release. Stellody reads a FLAC library, shows it, plays it and never
writes to it.

Reading a library without touching it

The read-only guarantee is the reason the project exists, so it is enforced
rather than intended: one structural test proves the mutagen write surface is
unreachable from every module that can read tags; another proves that only
the modules owning Stellody's own state write to disk at all. Nothing in the
scanning or probing path writes anything.

A scan walks a folder you choose and caches each folder's result. A rescan
compares every file's size and modification time against that cache, so a
folder whose files are all unchanged is reused without opening one. On a
library of 510 folders and 4,870 files a cold scan takes about two and a half
seconds and a rescan about a third of a second.

What the walker skips is a named list of system directories and macOS stubs,
never a guess. An earlier version treated a leading dot as "hidden" and
silently swallowed two real albums.

Making sense of real, damaged libraries

A folder is one album. Sibling folders differing only by a disc marker merge
into one multi-disc set. Tags then supply the title, artist, date and genre,
each taken as the most common value the tracks carry. Grouping by tags was
tried first and measured: it fragmented one Mozart folder into five albums.

Where tags contradict something physical, the physical thing wins; every
fallback is recorded rather than hidden. A read-only health view lists exactly
what to repair, in a tagger of your own choosing. Stellody describes a damaged
tag; it never repairs one.

A track is a slice of a file rather than a file, so an album ripped as one FLAC
with a cue sheet behaves exactly like an album ripped as separate tracks. On
the reference library that is 163 albums out of 485, which makes it a main path
rather than an edge case.

Playing

The transport sits centred in the tray: previous, play toggling to pause, stop
and next. A track starts on a double click, on Return or from the right click
menu; the album plays on from there. The library highlight follows whatever
is playing, however it came to be playing. It moves only when the
track changes, so browsing while the music continues is not interrupted.

Along the bottom are volume with a slider, mute, shuffle and repeat. Shuffle
takes a permutation of the album and keeps playing whatever is already playing,
leading the scattered run with that track so the whole of the rest of the album
is still ahead of it. Repeat carries the end of the album round to its start
and keeps it there until it is turned off; it never settles on one track.
Shuffled, the album is scattered afresh each time round rather than replaying
the order it took last time; the new run never opens on the track that just
ended.
Shuffle and repeat light up while they are on rather than being struck through
while they are off, so the slash means one thing across the application: that
what the picture depicts is not happening. Each of the four is remembered
between sessions.

A new install and a reinstall both start with shuffle and repeat off. Stellody's
own directory outlives an uninstall unless it is asked to go, so without this a
reinstall came back wearing switches set months earlier. An update and a
downgrade are the same install carrying on, so they leave every choice alone;
a repair changes nothing at all.

Back returns to the beginning of the track in hand and waits there rather than
playing on, so the moment to carry on is the listener's. Pressing it again from
there goes to the track before, waiting at its beginning too, so repeated
presses walk back through the album at whatever pace suits. What decides between
the two is where the transport already is rather than how fast the button was
pressed: nothing here is timed. Under shuffle back always returns to the
beginning of the track in hand, because a scattered run is not the order the
tracks were heard in.

The stream is opened on the WASAPI device rather than on the multimedia default,
which is what actually produces sound on a modern Windows machine.

Coming and going

Only one Stellody runs at a time. Closing the window leaves it in the
notification area; a hidden window has no button on the taskbar, so opening
Stellody again from a shortcut used to start a second copy over the same
library. A second launch now asks the copy already running to come forward and
leaves, which is what opening it again meant. Ownership is a system
semaphore holding a shared memory claim; the ask crosses a local socket. All
three are the same objects on Windows, Linux and macOS; none of them is a
file left in a directory.

That ask is a word on the channel rather than the act of opening it. Anything
on the machine may open a named pipe; several kinds of Windows software
enumerate them as a matter of course, so a connection alone used to bring the
window up out of the tray with nobody having asked for it. The word is read now
and has to be the right one before the window moves. The copy that asks holds
its end of the channel until the word has been taken, since letting go the
moment it had written discarded the word along with it.

The window's close button asks what it should mean the first time it is
pressed, offering the notification area or a full quit; the tray is the
default and the answer can be remembered so it stops asking. That answer can
be taken back: "Ask again when I close" sits on the File menu and on the
notification area's own menu, because the window is hidden exactly when
somebody wants the question again. It is greyed out while there is nothing to
forget. A fresh install or a reinstall forgets it as well, since Stellody's
directory outlives an uninstall and an answer given to one install should not
quietly govern the next.

Quit means quit, from the tray's menu and from that prompt alike. Stellody does
not end when its last window closes, which is exactly what lets the cross leave
it running, so ending the application is said out loud rather than left to Qt.
Without that, Quit closed a window nobody could see and left the process
running, holding the tray icon and the claim to being the copy that runs. Where
there is no notification area at all, the cross ends Stellody rather than
leaving a process with nothing on screen.

Whether there is a notification area to wait in is decided by asking the
platform rather than by asking an icon whether it has appeared yet. An icon
shown a moment earlier has not necessarily been taken up by the shell; a launch
asked to start quietly would then open a window instead.

Getting about

Everything is reachable from the keyboard, in one explicit ring that follows the
order the window is drawn rather than the order Qt happened to build it. A
disabled control is never a stop. A ring belongs to a control, never to the pane
holding it; an item view shows its current row instead of wearing a
rectangle round everything.

Light and dark appearances, with the sort order, the chosen folder and the
switches all remembered.

Chrome that behaves like chrome

A read-only page is something to read, not something to act on, so clicking
anywhere in About, a licence or the health report no longer focuses the page
and draws a ring round it. The ring appears only when somebody tabs there,
which is the one time it says anything.

A page that fits its window is not a stop at all, since it scrolls nowhere. A
page that overflows keeps its place in the keyboard order, because a long text
with no controls of its own could not be read otherwise. Which of the two it is
gets decided again whenever the window is resized.

Installing

The About box states the copyright; the exe's own file properties are stamped
from the same constant, so the two cannot drift apart.

A per-user setup program, so Windows never asks for administrator rights. It
covers install, repair and removal, asks before replacing the files of a running
copy; it hands the foreground to the application before closing itself rather
than leaving a spent installer on screen. It offers to start Stellody when you
sign in, which brings it up in the tray rather than over whatever Windows has
just finished drawing.

Setup stays out of the library database entirely. Clearing the switches on a
fresh install leaves a note for the application to act on rather than opening
the store itself, so a setup program can never be what damages a library index.
A database that will not open is set aside whole and a fresh one opened in its
place, so Stellody comes up and rescans instead of refusing to start.

A launch that produces no window says why. Startup writes
%TEMP%\stellody-startup.log as it goes, so a copy that dies before it can
draw anything leaves a trail rather than nothing at all.

Saying thank you

A button at the far left of the bottom strip opens a donation page in your
browser. It is the only address Stellody knows; it is handed to the
desktop rather than fetched, so the local-first guarantee is untouched: the
browser does the asking and the application still opens no connection of its
own.

Not in this release

Nothing shows where a track has reached, so there is no elapsed time, no
progress bar and no way to seek within a track. Cover art, a grid view, search,
ratings, play counts, an equalizer and gapless transitions are not built.
Windows is the only platform.

Two controls are on screen for work that is not done: the view toggle and the
repair button on the health report, which also appears on the bottom strip.
Both are disabled and each says so in its tooltip, so nothing offers to do
something it cannot. The repair one is the nearer of the two: what every issue
should become is already worked out on each load, since the store keeps raw tag
values rather than resolved ones; what is missing is somewhere to keep a
correction once it has been accepted.

Stellody keeps a plain-text account of its own comings and goings at
%TEMP%\stellody-diary.log: when a window was shown and what asked for it,
which of the three doors into the notification area opened, then how a
shutdown went. It is there because a window arriving unbidden cannot be traced after the
event; it found two faults that reading the source had not. It holds no
music, no library contents and nothing personal, it is never sent anywhere and
it can be deleted at any time.

PLAN.md holds what comes next and what is deliberately excluded.