An album is cold when it has files, not one of its tracks has ever been
scrobbled across the whole nine-year history, and its newest file landed over a
year ago.
The age floor is measured from the file, not the release date. What matters is
how long a record has been available to play, not how old it is. --cold-after
sets it.
Album-level, not track-level. A record with two played tracks is a record
that gets played; picking the other ten off it leaves gaps rather than
reclaiming anything worth having.
Artists whose every album is cold are counted separately — a different
proposition from one cold record by somebody otherwise played, and Lidarr can
only tag at artist level anyway.
Ranked by disk occupied, which is the point. That needed file sizes in the
index, and therefore a column on a table that already exists, so the store
gained an in-place column migration. A rebuild would mean re-downloading 62,117
scrobbles.
What stops it
The report produces nothing at all when:
the scrobble backfill is unfinished
any artist failed to index, or any artist has no albums indexed
the library is unindexed, or there is no history to judge against
Each makes played music look unplayed, which is the one failure that costs a
library. Checked rather than trusted, because the report they gate is the one
that ends in deletion.
Nothing is written
Every Lidarr call remains a GET. Unmonitoring comes in the next PR, once you
have looked at the list — no flag protects against a list that is wrong, and on
current numbers this will propose something like four fifths of the library.
Also: playlist pruning
#12 renamed moods, which orphaned high-energy-rock.m3u with nothing to remove
it. Playlists no longer produced are now deleted — driven by a record of what
was written last time, not by deleting every M3U that is not currently ours, so
a playlist you put there by hand is left alone.
Testing
116 tests, green locally and in docker build --target test. New ones cover an
unplayed album being cold, a partly-played one not being, a recent arrival being
too young to judge, both refusal conditions, the report writing nothing, a
renamed mood's playlist being removed, and a hand-made one surviving.
.m3u is the only extension it treats as non-UTF-8 — everything else is
UTF-8 by default, and .m3u gets decoded through the user's configured
codepage instead. So the one extension being written was the one that mangles
accented filenames, and this library holds Mötley Crüe, Beyoncé and Sigur Rós.
No BOM is written. It would promote a .m3u file too, but it is unnecessary at
this extension and upsets players that do not expect one.
This is why it belongs here rather than in its own PR: without the pruning
in this branch, the rename would leave seventeen dead .m3u files on the
device for ever, each still full of paths that resolve.
119 tests, green locally and in docker build --target test.
## Stage four, read-only
An album is **cold** when it has files, not one of its tracks has ever been
scrobbled across the whole nine-year history, and its newest file landed over a
year ago.
The age floor is measured from the *file*, not the release date. What matters is
how long a record has been available to play, not how old it is. `--cold-after`
sets it.
**Album-level, not track-level.** A record with two played tracks is a record
that gets played; picking the other ten off it leaves gaps rather than
reclaiming anything worth having.
Artists whose every album is cold are counted separately — a different
proposition from one cold record by somebody otherwise played, and Lidarr can
only tag at artist level anyway.
Ranked by disk occupied, which is the point. That needed file sizes in the
index, and therefore a column on a table that already exists, so the store
gained an in-place column migration. A rebuild would mean re-downloading 62,117
scrobbles.
## What stops it
The report produces nothing at all when:
- the scrobble backfill is unfinished
- any artist failed to index, or any artist has no albums indexed
- the library is unindexed, or there is no history to judge against
Each makes played music look unplayed, which is the one failure that costs a
library. Checked rather than trusted, because the report they gate is the one
that ends in deletion.
## Nothing is written
Every Lidarr call remains a `GET`. Unmonitoring comes in the next PR, once you
have looked at the list — no flag protects against a list that is wrong, and on
current numbers this will propose something like four fifths of the library.
## Also: playlist pruning
#12 renamed moods, which orphaned `high-energy-rock.m3u` with nothing to remove
it. Playlists no longer produced are now deleted — driven by a record of what
was written last time, not by deleting every M3U that is not currently ours, so
a playlist you put there by hand is left alone.
## Testing
116 tests, green locally and in `docker build --target test`. New ones cover an
unplayed album being cold, a partly-played one not being, a recent arrival being
too young to judge, both refusal conditions, the report writing nothing, a
renamed mood's playlist being removed, and a hand-made one surviving.
---
## Also folded in: playlists as `.m3u8`
Rockbox's `is_m3u8_name()`:
/* Default to M3U8 unless explicitly told otherwise. */
return (!dot || strcasecmp(dot, ".m3u") != 0);
`.m3u` is the *only* extension it treats as non-UTF-8 — everything else is
UTF-8 by default, and `.m3u` gets decoded through the user's configured
codepage instead. So the one extension being written was the one that mangles
accented filenames, and this library holds Mötley Crüe, Beyoncé and Sigur Rós.
No BOM is written. It would promote a `.m3u` file too, but it is unnecessary at
this extension and upsets players that do not expect one.
**This is why it belongs here** rather than in its own PR: without the pruning
in this branch, the rename would leave seventeen dead `.m3u` files on the
device for ever, each still full of paths that resolve.
119 tests, green locally and in `docker build --target test`.
Stage four, read-only. An album is cold when it has files, not one of its tracks
has ever been scrobbled across the whole nine-year history, and its newest file
landed over a year ago. The age floor is measured from the file rather than the
release date: what matters is how long a record has been available to play, not
how old it is.
Album-level rather than track-level. A record with two played tracks is a record
that gets played, and picking the other ten off it leaves gaps in an album
rather than reclaiming anything worth having.
Track file sizes are now indexed so the report can rank by the disk actually
recoverable, which is the point of the exercise. That needed a column on a table
that already exists, so the store gained an in-place column migration; a full
rebuild would mean re-downloading sixty thousand scrobbles.
The report refuses to produce anything when the backfill is unfinished, when any
artist failed to index, when any artist has no albums, or when there is no
history to judge against. Each of those makes played music look unplayed, which
is the one failure that costs a library, and they are checked rather than
trusted because the report they gate is the one that ends in deletion.
Nothing is written to Lidarr. Every call there remains a GET, and unmonitoring
waits until the list this produces has been looked at -- no flag protects
against a list that is wrong.
Also prunes playlists no longer produced, which #12 made necessary by renaming
moods: high-energy-rock would otherwise have stayed on the device for ever. It
is driven by a record of what was written last time rather than by deleting
every M3U that is not currently ours, so a playlist put in that directory by
hand is left alone.
Rockbox's is_m3u8_name() treats every playlist extension as UTF-8 except an
explicit ".m3u", which it instead decodes through the user's configured
codepage:
/* Default to M3U8 unless explicitly told otherwise. */
return (!dot || strcasecmp(dot, ".m3u") != 0);
The one extension being used was therefore the only one that mangles accented
filenames, and this library holds Motley Crue, Beyonce and Sigur Ros. Renaming
the output is the whole fix.
No byte order mark is written. One would promote a .m3u file to UTF-8 as well,
but it is unnecessary at this extension and upsets players that do not expect
to find one.
Kept with the pruning change rather than raised separately, because the rename
depends on it: without pruning, seventeen dead .m3u files would sit on the
device for ever, and every one of them full of paths that still resolve.
lyrathorpe
changed title from feat: report which albums have never been played to feat: cold report, playlist pruning, and .m3u8 playlists2026-08-25 10:48:07 +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.
Stage four, read-only
An album is cold when it has files, not one of its tracks has ever been
scrobbled across the whole nine-year history, and its newest file landed over a
year ago.
The age floor is measured from the file, not the release date. What matters is
how long a record has been available to play, not how old it is.
--cold-aftersets it.
Album-level, not track-level. A record with two played tracks is a record
that gets played; picking the other ten off it leaves gaps rather than
reclaiming anything worth having.
Artists whose every album is cold are counted separately — a different
proposition from one cold record by somebody otherwise played, and Lidarr can
only tag at artist level anyway.
Ranked by disk occupied, which is the point. That needed file sizes in the
index, and therefore a column on a table that already exists, so the store
gained an in-place column migration. A rebuild would mean re-downloading 62,117
scrobbles.
What stops it
The report produces nothing at all when:
Each makes played music look unplayed, which is the one failure that costs a
library. Checked rather than trusted, because the report they gate is the one
that ends in deletion.
Nothing is written
Every Lidarr call remains a
GET. Unmonitoring comes in the next PR, once youhave looked at the list — no flag protects against a list that is wrong, and on
current numbers this will propose something like four fifths of the library.
Also: playlist pruning
#12 renamed moods, which orphaned
high-energy-rock.m3uwith nothing to removeit. Playlists no longer produced are now deleted — driven by a record of what
was written last time, not by deleting every M3U that is not currently ours, so
a playlist you put there by hand is left alone.
Testing
116 tests, green locally and in
docker build --target test. New ones cover anunplayed album being cold, a partly-played one not being, a recent arrival being
too young to judge, both refusal conditions, the report writing nothing, a
renamed mood's playlist being removed, and a hand-made one surviving.
Also folded in: playlists as
.m3u8Rockbox's
is_m3u8_name():.m3uis the only extension it treats as non-UTF-8 — everything else isUTF-8 by default, and
.m3ugets decoded through the user's configuredcodepage instead. So the one extension being written was the one that mangles
accented filenames, and this library holds Mötley Crüe, Beyoncé and Sigur Rós.
No BOM is written. It would promote a
.m3ufile too, but it is unnecessary atthis extension and upsets players that do not expect one.
This is why it belongs here rather than in its own PR: without the pruning
in this branch, the rename would leave seventeen dead
.m3ufiles on thedevice for ever, each still full of paths that resolve.
119 tests, green locally and in
docker build --target test.Rockbox's is_m3u8_name() treats every playlist extension as UTF-8 except an explicit ".m3u", which it instead decodes through the user's configured codepage: /* Default to M3U8 unless explicitly told otherwise. */ return (!dot || strcasecmp(dot, ".m3u") != 0); The one extension being used was therefore the only one that mangles accented filenames, and this library holds Motley Crue, Beyonce and Sigur Ros. Renaming the output is the whole fix. No byte order mark is written. One would promote a .m3u file to UTF-8 as well, but it is unnecessary at this extension and upsets players that do not expect to find one. Kept with the pruning change rather than raised separately, because the rename depends on it: without pruning, seventeen dead .m3u files would sit on the device for ever, and every one of them full of paths that still resolve.feat: report which albums have never been playedto feat: cold report, playlist pruning, and .m3u8 playlists