Stellody v0.3.0
Release notes
Since the last release.
Album covers in the library
Each album now shows its cover. Stellody looks first for a file next to the
music, choosing by the names a ripper is likeliest to have written, then for a
picture inside the audio itself. Measured over a real library, four folders in
five carry a file beside the music while another fifth carry only an embedded
picture, so both are main paths rather than one being a fallback.
Reading a cover means going to disk and decoding an image, so it happens on a
thread of its own and only for albums a row has actually asked to draw. A
library of several hundred albums therefore costs a dozen reads to show a
dozen rows rather than several hundred to show any. Until an answer arrives an
album draws a plain square; an album carrying no picture anywhere keeps
that square rather than leaving a gap where every other row has a sleeve.
What is read is kept, scaled down, against the album's identity rather than
its path, so renaming a folder reuses the picture instead of reading it again.
What it was read from is recorded beside it and checked against that file's
size and modification time, so a cover replaced on disk is read afresh while a
rescan that changed nothing reuses what is already there.
Nothing about this reaches the network and nothing is written into the music
folder. The picture is read out of the file and Stellody's own copy is kept
where Stellody's own state lives.
A grid of covers, with the album opened underneath
The library can now be shown as a wall of sleeves rather than a list, with a
toggle at the left of the bottom strip between the two. That toggle was drawn
and disabled from the start; it now works, naming the view it would move
to rather than the one on show, since a button naming the current state reads
as a label and gets pressed to confirm it. Which view was last used is
remembered between sessions, as the appearance and the sort order already were.
Both views are the same library rather than two copies of it, so neither can
disagree with the other about what is there or the order it is in. Switching
keeps the order because there is only one of it; one cover serves both:
kept at the size the grid draws it and scaled down for a row, so moving between
the views reads nothing from disk a second time.
Picking a sleeve opens that album in a pane beneath the grid rather than
replacing the grid, so the sleeves stay where they were. The pane carries the
cover, the album's title and artist, a control that plays it from the first
track and one that shuts the pane again, with the album's tracks listed under
it. Those tracks are the same library rooted at that album, so their durations
and both ways of starting a track are the ones the list already had.
The sleeves are drawn as tiles
A grid of covers is not a list with pictures in it, so a tile is drawn rather
than left to the item view. Every tile is the same size whatever the length of
the names on it, the sleeve is centred rather than pushed against an edge, the
title sits over the artist and a name too long for its tile is cut with an
ellipsis rather than running into its neighbour.
The album whose pane is open wears the accent ring the rest of the application
uses to say where attention is, so the wall says which sleeve was picked
without a second device having to be invented for it. The pane itself is now a
panel of its own rather than more window; its heading carries the year.
The open album runs down two columns
An album opened under the sleeves lists its tracks in two columns rather than
one, the way the back of a sleeve does, so an album of a dozen tracks is read
without the pane growing to the height of a dozen rows.
Both columns are the one library rooted at the one album. Each hides the rows
belonging to the other rather than holding a copy of them, so the two cannot
disagree about the order or about what is on the album; no track can go
missing between the foot of one column and the head of the next. Nothing is
built out of widgets by hand, so the arrows still walk a column and the ring
still lands on real rows. An odd number of tracks leaves the longer run on the
left, where a reader starts. An album with a single track draws one column
rather than an empty panel beside a full one.
Opening an album leaves a track ready to play
Picking a sleeve now highlights that album's first track, so the play button at
the top has something to start. On a multi-disc album the highlight goes to the
first track on the first disc rather than to the disc itself.
The play button reads the view that is ON SHOW rather than always reading the
list. While the sleeves are up it starts what is highlighted in the open album,
which is what somebody looking at the sleeves is pointing at. One highlight is
shared between the two columns, so moving it into the second column takes it
out of the first.
The transport menu belongs to the sleeves too
Right clicking a sleeve offers the same Play, Pause, Stop, Previous and Next
the list has always carried, as does right clicking a track in the open album.
Play over anything naming an album means that album from its first track,
whether it is a sleeve in the grid or an album row in the list. It used to do
nothing at all on an album row, on the reading that such a row carries no
track of its own; a sleeve carries none either and pressing Play on one plainly
means play this. Over the album already loaded it means carry on, exactly as it
does over the track already loaded: starting a long piece over is what next and
previous are for.
The list gives a track row the height of a track row
A cover is drawn in the list at the size a row can carry rather than at the
size the grid keeps it. One pixmap serves both views; the list was taking the
grid's, which made every row as tall as a sleeve. Asking the view for a smaller
icon does not fix that, since the size is read off the pixmap and the view is
never consulted for one, so the size is now stated where it is read.
Rows are no longer held to a single height either, because only an album row
carries a picture. Measured on one album with its tracks showing: an album row
went from 166 pixels to 46 and a track row from 166 to 16.
The play button starts what is picked
Picking a second album and pressing play started the FIRST one again. Anything
loaded turned the press into a resume, whatever had been chosen since. Play now
means the highlighted track wherever that is not the track already loaded,
which is the rule the right click menu has always followed.
While something is playing the button is a pause button, so it still pauses
with another album picked: a press there is asking to stop rather than to go
somewhere else. The press after it starts what was picked.
Three sizes of sleeve in the grid
The grid draws its sleeves at one of three sizes, medium, large or extra large,
stepped through by a button in the bottom strip beside the view toggle. It
names the size it would move to rather than the one on show, as that toggle
does; it is dead over the list, where the size means nothing. The choice
outlasts the session, as the view and the sort order already did.
The tiles and the grid grow together, since a view keeps the spacing it was
given and would otherwise overlap them. Measured across the three: a 160 pixel
sleeve in a 192 pixel cell, then 240 in 272, then 320 in 352. The names under a
sleeve get the same room at every size, because a title is the same title
however large the picture above it.
Changing the size reads the covers again rather than stretching what is
already held. Reading comes out of Stellody's own store, which keeps a cover at
512 pixels, so none of the three asks for more than was kept and nothing
touches the music folder or the network. Holding one size at a time is also
what keeps the memory to the size chosen rather than to the largest on offer.
Repair moves up beside rescan
The repair control, which is still not built, sat on the bottom strip beside
the view toggle: among the settings that outlast a track rather than beside the
control it follows from. It now sits under the menus to the right of rescan,
since repair is the answer to what a rescan finds.
Its wording has one home, which moved with it, so the button and the one in the
library health report cannot come to say different things about the same
unbuilt feature. It stays disabled and stays named in the focus ring, so the
ring picks it up on the day it works without the order being revisited.
A bonus disc joins the album it belongs to
A folder such as "Ether Song (Bonus Disc)" sitting beside "Ether Song" showed
as a second album of the same name and artist, one above the other in the
library. The folder marker the grouping recognised needed a digit and this one
has none, so nothing joined them.
A bonus disc is now a disc even where its folder names no number. Which disc it
is comes from the tags where they say so; where they say nothing, the tracks go
on the disc after everything else the album holds, since a bonus disc is never
the first one and leaving it there would collide with the album proper track
for track.
The word CD, Disc or Disk is still required, because a bonus EDITION is not a
bonus disc. Measured across the reference library of 984 folders: three pairs
fold, "Ether Song", "Come Away With Me" and "The Ecleftic", each becoming one
album of two discs with no new issues reported. The folders naming an edition,
"[Bonus Track]", "(Bonus Track Version)", "[Bonus DVD]" and "[UK Bonus
Edition]", stay their own albums as before.
One older fault went with it. A folder named "Ether Song (Bonus Disc 2)" used
to be read as an album called "Ether Song (Bonus", the opening bracket left
behind; it now reads as disc 2 of "Ether Song".
Pressing a sleeve again rolls the pane back up
The gesture that opens the album pane now closes it. The pane always had a
close button of its own, at the size the tray draws its buttons and wearing the
mark the mute switch uses, which is not a way down anybody found.
The press itself is read rather than the click that follows it, because Qt
moves the current sleeve during the press: by the time a click arrives, a first
press on a fresh sleeve and a second press on the open one look alike. Pressing
another sleeve still switches to it rather than closing anything; pressing past
the last sleeve says nothing about the pane at all.
A sleeve whose pane had been closed used to go dead. It was still the current
one, so pressing it changed no selection and nothing reopened; only picking a
different album and coming back would do it. Reading the press fixes that too.
The window opens larger
Stellody opens at 1188 by 864 rather than 1080 by 720: a tenth wider and a
fifth taller, which is a row of sleeves more library to look at before anything
has been scrolled. That is the size a first run opens at; what a later run
opens at is the next section.
The window opens at the size it was left
Drag Stellody to the size you want it and it comes back that size, as the
appearance, the view, the sort order and the volume already did.
Two values are kept rather than one. A window left maximised reports the screen
as its size, so keeping that alone would come back as a window the size of the
screen that is not actually maximised: the same shape without the behaviour;
no way back to the size it had before either. What is kept is the size it would
return to, with the maximised state beside it, so a maximised window reopens
maximised and unmaximises to where it was.
What comes back is checked rather than trusted. A size is clamped to the screen
now attached, since a window sized for a monitor that is no longer there opens
with its controls past the edge; it is floored at what the window says it
needs, since anything smaller cannot be used; and a stored value that is not a
number falls back to the size a first run opens at. The screen asked is the one
the window is on rather than the primary one, because a second monitor is often
the larger of the two.
The size is written down on every way out, since the cross can leave Stellody
in the notification area and the tray's Quit then closes a window that is
already hidden.
Cover art can be looked up, once there is something to ask with
The half of the cover chooser that does the looking is built: what a candidate
is, the port that offers and fetches one, the service that puts them in order
then keeps the one chosen, plus the client that reads MusicBrainz for an
album's releases and the Cover Art Archive for their pictures. The chooser a listener
sees is not built yet, so nothing reaches outward.
That last sentence is a structural test rather than a promise. Exactly one
module may import anything able to open a socket; the guard was proved to bite
by planting an import elsewhere and watching the suite fail. Everything else
holds a port, so nothing can come to depend on the archive being MusicBrainz
and no test can come to depend on a connection.
The terms those services ask for are honoured rather than hoped for. Every
request names Stellody and a way to reach its author; no more than one goes out
a second: measured on 2026-08-30, two searches sent back to back were
refused with a 503. A release nobody has photographed answers 404, which is an
ordinary answer meaning try the next release rather than a failure.
A cover somebody chooses is kept against the album's identity exactly as a
local one is, though marked as chosen, so it is not checked against any file
and outlives a rescan. Nothing is ever written into the music folder.
The archive names the thumbnail sizes it will serve, 250, 500 and 1200; it
never names the pixel size of the original. A candidate is therefore labelled
with the largest size on offer rather than with true dimensions, which still
tells a scan from a proper cover.