The first set of moods was guessed at. A tag census of the real library shows
how badly.
Dead weight I shipped.edm, big room, hardstyle and electronic dance music carry nothing at all — they do not appear in the top 150 tags. Meanwhile techno (1,828), electro (1,891), big beat (1,379), rave (1,334) and progressive house (1,207) carry real weight and were all absent from my list.
Spellings missed. The drum and bass mood had four of the eight spellings the
taggers actually use, and missed techstep, darkstep, drumstep and hospital records entirely.
The eighties mood was the worst of it. It leaned on the bare 80s tag —
eleventh most-played here at 8,188 plays — which in this library sits on Def
Leppard, Bon Jovi and AC/DC, not on synthesisers. Dropping it and adding hair-metal (glam rock, hair metal, glam metal, arena rock, AOR, windowed
1975-1994) puts ~8,500 plays somewhere sensible and stops the synth playlist
being a stadium rock playlist.
Whole clusters had no mood. Metal is ~25,000 plays across heavy, thrash,
speed, power, death and NWOBHM. Pop punk and emo is similar. Neither existed.
The set now
Mood
Selected on
drum-and-bass
all six spellings, liquid funk, neurofunk, jungle, techstep, hospital records
heavy metal, thrash, speed, power, death, prog, NWOBHM
hair-metal
hair metal, glam metal, glam rock, arena rock, AOR — 1975-1994
nu-metal
nu metal, alternative metal, rapcore, industrial
classic-rock
classic rock, prog, psychedelic, blues rock, 70s, 60s
80s-synths
synthpop, electropop, new wave, post-punk — 1975-1992
indie
indie, indie rock, indie pop, britpop, singer-songwriter
Three tags never used, with a test enforcing it
Each produces a playlist that looks reasonable and is not.
Nationality.american spans 241 artists, british 202. A passport is
not a sound.
rock and electronic. 340 and 275 artists — most of the library. A
mood that matches everything is not a mood.
Artist names. Last.fm's most popular tag for an artist is frequently the
artist's own name: green day at 1,711 plays, paramore at 711, queen at
523. Selecting on those yields a single-artist playlist wearing a genre's
clothes.
Testing
101 tests, green locally and in docker build --target test. Three new ones
pin the exclusions, the uniqueness of mood names, and that 80s-synths does
not lean on the bare decade tag.
Also folded in: playlist ownership
Playlists were being written owned by root. The image runs as root by
default, deliberately, so a bind-mounted dataset of any ownership stays
writable -- but everything it writes then comes out root-owned, and a root-owned
playlist inside a mirror owned by the apps account is unreadable to whatever
serves it. The group-read bit does not help when the group is also root.
Each playlist now takes the owner and group of the mirror it is written
into. No configuration, cannot drift from what the mirror actually is, and a
no-op when the two already agree -- which is the case whenever the container is
run with an explicit user:.
Applied to the temporary file before the rename, so a playlist is never briefly
visible owned by the wrong account, and to _playlists/ on the run that creates
it. A refused chown is ignored rather than fatal: that only happens when not
running as root, which is exactly when the ownership was already correct.
Kept in this PR rather than raised separately, to save a container rebuild.
Testing
107 tests, green locally and in docker build --target test.
## Measured, then written
The first set of moods was guessed at. A tag census of the real library shows
how badly.
**Dead weight I shipped.** `edm`, `big room`, `hardstyle` and `electronic dance
music` carry *nothing at all* — they do not appear in the top 150 tags. Meanwhile
`techno` (1,828), `electro` (1,891), `big beat` (1,379), `rave` (1,334) and
`progressive house` (1,207) carry real weight and were all absent from my list.
**Spellings missed.** The drum and bass mood had four of the eight spellings the
taggers actually use, and missed `techstep`, `darkstep`, `drumstep` and
`hospital records` entirely.
**The eighties mood was the worst of it.** It leaned on the bare `80s` tag —
eleventh most-played here at 8,188 plays — which in this library sits on Def
Leppard, Bon Jovi and AC/DC, not on synthesisers. Dropping it and adding
`hair-metal` (glam rock, hair metal, glam metal, arena rock, AOR, windowed
1975-1994) puts ~8,500 plays somewhere sensible and stops the synth playlist
being a stadium rock playlist.
**Whole clusters had no mood.** Metal is ~25,000 plays across heavy, thrash,
speed, power, death and NWOBHM. Pop punk and emo is similar. Neither existed.
## The set now
| Mood | Selected on |
| --------------- | ------------------------------------------------------- |
| `drum-and-bass` | all six spellings, liquid funk, neurofunk, jungle, techstep, hospital records |
| `bass` | dubstep, brostep, grime, trip-hop, big beat |
| `dance` | house variants, trance, techno, electro, rave |
| `pop-punk` | pop punk, punk, emo, emocore, easycore, power pop |
| `screamo` | screamo, post-hardcore, metalcore, melodic hardcore, trancecore |
| `heavy-metal` | heavy metal, thrash, speed, power, death, prog, NWOBHM |
| `hair-metal` | hair metal, glam metal, glam rock, arena rock, AOR — 1975-1994 |
| `nu-metal` | nu metal, alternative metal, rapcore, industrial |
| `classic-rock` | classic rock, prog, psychedelic, blues rock, 70s, 60s |
| `80s-synths` | synthpop, electropop, new wave, post-punk — 1975-1992 |
| `indie` | indie, indie rock, indie pop, britpop, singer-songwriter |
## Three tags never used, with a test enforcing it
Each produces a playlist that looks reasonable and is not.
- **Nationality.** `american` spans 241 artists, `british` 202. A passport is
not a sound.
- **`rock` and `electronic`.** 340 and 275 artists — most of the library. A
mood that matches everything is not a mood.
- **Artist names.** Last.fm's most popular tag for an artist is frequently the
artist's own name: `green day` at 1,711 plays, `paramore` at 711, `queen` at
523. Selecting on those yields a single-artist playlist wearing a genre's
clothes.
## Testing
101 tests, green locally and in `docker build --target test`. Three new ones
pin the exclusions, the uniqueness of mood names, and that `80s-synths` does
not lean on the bare decade tag.
---
## Also folded in: playlist ownership
Playlists were being written **owned by root**. The image runs as root by
default, deliberately, so a bind-mounted dataset of any ownership stays
writable -- but everything it writes then comes out root-owned, and a root-owned
playlist inside a mirror owned by the apps account is unreadable to whatever
serves it. The group-read bit does not help when the group is also root.
Each playlist now takes the **owner and group of the mirror it is written
into**. No configuration, cannot drift from what the mirror actually is, and a
no-op when the two already agree -- which is the case whenever the container is
run with an explicit `user:`.
Applied to the temporary file before the rename, so a playlist is never briefly
visible owned by the wrong account, and to `_playlists/` on the run that creates
it. A refused chown is ignored rather than fatal: that only happens when not
running as root, which is exactly when the ownership was already correct.
Kept in this PR rather than raised separately, to save a container rebuild.
## Testing
107 tests, green locally and in `docker build --target test`.
The first set of moods was guessed at, and a tag census of the real library
shows how badly. Four tags in the dance mood -- edm, big room, hardstyle,
electronic dance music -- carry nothing whatsoever, while techno, electro, big
beat, rave and progressive house together carry over seven thousand plays and
were all absent. The drum and bass mood missed four of the six spellings the
taggers actually use, plus techstep, darkstep and hospital records.
The eighties mood was the worst of it. It leaned on the bare `80s` tag, which is
the eleventh most-played tag here and sits on Def Leppard, Bon Jovi and AC/DC
rather than on anything with a synthesiser in it. Removing it and adding a
hair-metal mood -- glam rock, hair metal, glam metal, arena rock, AOR, windowed
to 1975-1994 -- puts roughly eight thousand plays somewhere sensible and stops
the synth playlist being a stadium rock playlist.
Whole clusters had no mood at all: metal at around twenty-five thousand plays
across heavy, thrash, speed, power, death and NWOBHM, and pop punk and emo at a
similar figure. Both now exist, along with bass, nu-metal and indie.
Three kinds of tag are excluded on principle, with a test enforcing it, because
each produces a playlist that looks reasonable and is not. Nationality describes
a passport rather than a sound, and `american` alone spans 241 artists. `rock`
and `electronic` span 340 and 275, which is most of the collection. And
Last.fm's most popular tag for an artist is frequently the artist's own name, so
selecting on `green day` yields a Green Day playlist wearing a genre's clothes.
The eighties mood selected on synth-specific tags only, on the grounds that the
bare `80s` tag drags in Def Leppard and Bon Jovi. Checking the canon against
live Last.fm pages shows what that costs. Eurythmics is tagged 80s, new wave,
pop, female vocalists, synth pop -- four of those five are tags no mood may use.
Frankie Goes to Hollywood is tagged 80s, new wave, pop, british, dance, and
survives only on new wave. An act tagged purely 80s, pop and dance, which is a
great deal of eighties pop, was missed outright.
Two spellings also matter more than the census suggested. Of Depeche Mode, Duran
Duran, Eurythmics and Frankie Goes to Hollywood, three carry "synth pop" with a
space and only one carries "synthpop" without. The census could not show this
because it only sees artists already in the library; the spelling that was kept
was the rarer one.
Add an `exclude` list to a mood. An excluded tag drops the artist outright
rather than docking their score, which is the only construction that expresses
"the eighties, but not the stadium rock" -- weighting cannot do it, because the
tag it would weight is the one both share. The synth acts do not carry hard rock
or hair metal, and that is the whole of the difference.
A mood may not both select on and exclude the same tag; that is rejected when
the definitions are read rather than silently producing nothing.
Playlists were being written owned by root. The image runs as root by default,
deliberately, so that a bind-mounted dataset of any ownership stays writable --
but everything it writes then comes out root-owned, and a root-owned playlist
inside a mirror owned by the apps account is unreadable to whatever serves it.
The group-read bit does not help when the group is also root.
Copy the ownership of the mirror the playlist is being written into. That needs
no configuration, cannot drift from whatever the mirror actually is, and does
nothing at all when the two already agree -- which is the case whenever the
container is run with an explicit user.
Applied to the temporary file before the rename, so a playlist is never briefly
visible owned by the wrong account, and to the _playlists directory when this is
the run that creates it. A chown that is refused is ignored rather than fatal:
that only happens when not running as root, which is precisely the case where
the ownership was already right.
lyrathorpe
changed title from feat: rebuild the moods from the library's measured tag distribution to feat: rebuild the moods from real tags, add exclusions, fix playlist ownership2026-08-24 18:46:06 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Measured, then written
The first set of moods was guessed at. A tag census of the real library shows
how badly.
Dead weight I shipped.
edm,big room,hardstyleandelectronic dance musiccarry nothing at all — they do not appear in the top 150 tags. Meanwhiletechno(1,828),electro(1,891),big beat(1,379),rave(1,334) andprogressive house(1,207) carry real weight and were all absent from my list.Spellings missed. The drum and bass mood had four of the eight spellings the
taggers actually use, and missed
techstep,darkstep,drumstepandhospital recordsentirely.The eighties mood was the worst of it. It leaned on the bare
80stag —eleventh most-played here at 8,188 plays — which in this library sits on Def
Leppard, Bon Jovi and AC/DC, not on synthesisers. Dropping it and adding
hair-metal(glam rock, hair metal, glam metal, arena rock, AOR, windowed1975-1994) puts ~8,500 plays somewhere sensible and stops the synth playlist
being a stadium rock playlist.
Whole clusters had no mood. Metal is ~25,000 plays across heavy, thrash,
speed, power, death and NWOBHM. Pop punk and emo is similar. Neither existed.
The set now
drum-and-bassbassdancepop-punkscreamoheavy-metalhair-metalnu-metalclassic-rock80s-synthsindieThree tags never used, with a test enforcing it
Each produces a playlist that looks reasonable and is not.
americanspans 241 artists,british202. A passport isnot a sound.
rockandelectronic. 340 and 275 artists — most of the library. Amood that matches everything is not a mood.
artist's own name:
green dayat 1,711 plays,paramoreat 711,queenat523. Selecting on those yields a single-artist playlist wearing a genre's
clothes.
Testing
101 tests, green locally and in
docker build --target test. Three new onespin the exclusions, the uniqueness of mood names, and that
80s-synthsdoesnot lean on the bare decade tag.
Also folded in: playlist ownership
Playlists were being written owned by root. The image runs as root by
default, deliberately, so a bind-mounted dataset of any ownership stays
writable -- but everything it writes then comes out root-owned, and a root-owned
playlist inside a mirror owned by the apps account is unreadable to whatever
serves it. The group-read bit does not help when the group is also root.
Each playlist now takes the owner and group of the mirror it is written
into. No configuration, cannot drift from what the mirror actually is, and a
no-op when the two already agree -- which is the case whenever the container is
run with an explicit
user:.Applied to the temporary file before the rename, so a playlist is never briefly
visible owned by the wrong account, and to
_playlists/on the run that createsit. A refused chown is ignored rather than fatal: that only happens when not
running as root, which is exactly when the ownership was already correct.
Kept in this PR rather than raised separately, to save a container rebuild.
Testing
107 tests, green locally and in
docker build --target test.feat: rebuild the moods from the library's measured tag distributionto feat: rebuild the moods from real tags, add exclusions, fix playlist ownership