Six rules over the scrobble history and the library index, written as extended
M3U into <mirror>/_playlists/ and rebuilt every pass.
Playlist
Rule
heavy-rotation
Most played over the last twelve months
all-time
Most played ever
neglected
Played heavily once, silent for twelve months
deep-cuts
Never played, from albums whose other tracks you play constantly
unheard-favourites
Never played, by the artists you play most
unheard
Never played, anywhere in the library
Three look at what gets played and three at what does not, because four fifths
of the library has never been played and a best-of alone would ignore 41,000
tracks.
Two decisions worth flagging
Twelve months, not ninety days. Ninety days is the obvious window and is the
wrong one: on the real history it holds a few hundred plays spread across a
twenty-thousand track rotation, so nothing ranks. The report's own top track 90d list -- one track at 35 plays, then a cliff to 3 -- is what that
looks like.
Rotation is weekly, not per pass. A pass runs every few hours. A playlist
that reorders itself each time is one that has to be re-imported each time,
because the Music app imports a snapshot of a file rather than tracking it.
Paths, and the part I could not test
Lidarr knows where the FLAC is; the playlist has to point at the MP3
music-mirror made from it. --library-root is stripped from Lidarr's paths and
they are re-rooted under --mirror with the suffix changed.
The root is derived from the common parent of the indexed artist folders, so it
agrees with Lidarr by construction rather than by being kept in step by hand.
Override it if the guess is wrong.
Entries are written relative to the playlist file, so one playlist works from
the NAS, from a Mac over SMB, and from Linux.
A track is listed only once its mirror file is confirmed to exist. Lidarr
holding the FLAC says nothing about whether the MP3 has been encoded. When many
are missing the run says so loudly — that is exactly what a wrong root looks
like, every path mapping to nothing, and silence would present an empty playlist
as a correct one. This is the piece I cannot verify from here; the first real
run is the test.
_playlists/ survives music-mirror's prune, which only deletes *.mp3 and
skips directories that are not empty. Checked in its source, not assumed.
Testing
80 tests, green locally and in docker build --target test. The playlist ones
build a real library on disk with mirror MP3s beside the source paths, and
cover the mapping, relative paths resolving to real files, the limit, weekly
rotation stability, group-readability, and a missing mirror file being left out.
Next
Genre and mood playlists — 80s synths, high energy rock, screamo — follow
immediately in a separate PR. They need Last.fm's crowd tags rather than
MusicBrainz genres, which are too sparse to be useful, so that is a new ingest
and a new table rather than an extra query here.
## Playlists
Six rules over the scrobble history and the library index, written as extended
M3U into `<mirror>/_playlists/` and rebuilt every pass.
| Playlist | Rule |
| -------------------- | --------------------------------------------------------- |
| `heavy-rotation` | Most played over the last twelve months |
| `all-time` | Most played ever |
| `neglected` | Played heavily once, silent for twelve months |
| `deep-cuts` | Never played, from albums whose other tracks you play constantly |
| `unheard-favourites` | Never played, by the artists you play most |
| `unheard` | Never played, anywhere in the library |
Three look at what gets played and three at what does not, because four fifths
of the library has never been played and a best-of alone would ignore 41,000
tracks.
## Two decisions worth flagging
**Twelve months, not ninety days.** Ninety days is the obvious window and is the
wrong one: on the real history it holds a few hundred plays spread across a
twenty-thousand track rotation, so nothing ranks. The report's own
`top track 90d` list -- one track at 35 plays, then a cliff to 3 -- is what that
looks like.
**Rotation is weekly, not per pass.** A pass runs every few hours. A playlist
that reorders itself each time is one that has to be re-imported each time,
because the Music app imports a snapshot of a file rather than tracking it.
## Paths, and the part I could not test
Lidarr knows where the FLAC is; the playlist has to point at the MP3
music-mirror made from it. `--library-root` is stripped from Lidarr's paths and
they are re-rooted under `--mirror` with the suffix changed.
The root is derived from the common parent of the indexed artist folders, so it
agrees with Lidarr by construction rather than by being kept in step by hand.
Override it if the guess is wrong.
Entries are written relative to the playlist file, so one playlist works from
the NAS, from a Mac over SMB, and from Linux.
**A track is listed only once its mirror file is confirmed to exist.** Lidarr
holding the FLAC says nothing about whether the MP3 has been encoded. When many
are missing the run says so loudly — that is exactly what a wrong root looks
like, every path mapping to nothing, and silence would present an empty playlist
as a correct one. This is the piece I cannot verify from here; the first real
run is the test.
`_playlists/` survives music-mirror's prune, which only deletes `*.mp3` and
skips directories that are not empty. Checked in its source, not assumed.
## Testing
80 tests, green locally and in `docker build --target test`. The playlist ones
build a real library on disk with mirror MP3s beside the source paths, and
cover the mapping, relative paths resolving to real files, the limit, weekly
rotation stability, group-readability, and a missing mirror file being left out.
## Next
Genre and mood playlists — 80s synths, high energy rock, screamo — follow
immediately in a separate PR. They need Last.fm's crowd tags rather than
MusicBrainz genres, which are too sparse to be useful, so that is a new ingest
and a new table rather than an extra query here.
Six rules over the scrobble history and the library index, written as extended
M3U into <mirror>/_playlists/ and rebuilt every pass. Three look at what gets
played -- heavy rotation, all-time, and things played heavily once and silent
for a year. Three look at what does not: album tracks skipped on records
otherwise played constantly, unplayed tracks by the artists played most, and
unplayed tracks from anywhere. Four fifths of the library has never been played,
so both halves are needed.
Ninety days was the obvious window for "recent" and is the wrong one. On a real
history it holds a few hundred plays spread across a twenty-thousand track
rotation, and nothing ranks meaningfully. Twelve months does.
The two rotating playlists are shuffled by week rather than by pass. A pass runs
every few hours; a playlist that reorders itself each time is one that has to be
re-imported each time, because the Music app imports a snapshot of a file rather
than tracking it.
Lidarr knows where the lossless source is, and the playlists have to point at
the MP3s music-mirror produced from it. The library root is derived from the
common parent of the indexed artist folders, so it agrees with Lidarr by
construction instead of being kept in step by hand, and can be overridden.
Entries are relative to the playlist file, so one file works from the NAS, from
a Mac over SMB and from Linux.
A track is listed only once its mirror file has been confirmed to exist: Lidarr
holding the FLAC says nothing about whether the MP3 has been encoded. When many
are missing the run says so, because that is what a misconfigured root looks
like -- every path mapping to nothing -- and silence there would present an
empty playlist as a correct one.
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.
Playlists
Six rules over the scrobble history and the library index, written as extended
M3U into
<mirror>/_playlists/and rebuilt every pass.heavy-rotationall-timeneglecteddeep-cutsunheard-favouritesunheardThree look at what gets played and three at what does not, because four fifths
of the library has never been played and a best-of alone would ignore 41,000
tracks.
Two decisions worth flagging
Twelve months, not ninety days. Ninety days is the obvious window and is the
wrong one: on the real history it holds a few hundred plays spread across a
twenty-thousand track rotation, so nothing ranks. The report's own
top track 90dlist -- one track at 35 plays, then a cliff to 3 -- is what thatlooks like.
Rotation is weekly, not per pass. A pass runs every few hours. A playlist
that reorders itself each time is one that has to be re-imported each time,
because the Music app imports a snapshot of a file rather than tracking it.
Paths, and the part I could not test
Lidarr knows where the FLAC is; the playlist has to point at the MP3
music-mirror made from it.
--library-rootis stripped from Lidarr's paths andthey are re-rooted under
--mirrorwith the suffix changed.The root is derived from the common parent of the indexed artist folders, so it
agrees with Lidarr by construction rather than by being kept in step by hand.
Override it if the guess is wrong.
Entries are written relative to the playlist file, so one playlist works from
the NAS, from a Mac over SMB, and from Linux.
A track is listed only once its mirror file is confirmed to exist. Lidarr
holding the FLAC says nothing about whether the MP3 has been encoded. When many
are missing the run says so loudly — that is exactly what a wrong root looks
like, every path mapping to nothing, and silence would present an empty playlist
as a correct one. This is the piece I cannot verify from here; the first real
run is the test.
_playlists/survives music-mirror's prune, which only deletes*.mp3andskips directories that are not empty. Checked in its source, not assumed.
Testing
80 tests, green locally and in
docker build --target test. The playlist onesbuild a real library on disk with mirror MP3s beside the source paths, and
cover the mapping, relative paths resolving to real files, the limit, weekly
rotation stability, group-readability, and a missing mirror file being left out.
Next
Genre and mood playlists — 80s synths, high energy rock, screamo — follow
immediately in a separate PR. They need Last.fm's crowd tags rather than
MusicBrainz genres, which are too sparse to be useful, so that is a new ingest
and a new table rather than an extra query here.