release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m32s
release / integration (push) Successful in 5m1s
release / android (push) Successful in 5m7s
release / Build signed APK (releases and dev) (push) Successful in 5m17s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
The release id was only ever used to find the group. 238 albums matched to a group carried none, so their losses, five of the resolver's wrong-slot removals among them, were never fetched again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
94 lines
4.5 KiB
SQL
94 lines
4.5 KiB
SQL
-- Re-acquisition of missing files (milestone #290, reworked for M502 #5520).
|
|
-- The unit is the album: an album whose files went missing becomes a want for
|
|
-- its release group, and the search schedule (#5521) looks for it.
|
|
|
|
-- name: GetReacquisitionSettings :one
|
|
SELECT * FROM reacquisition_settings WHERE id = true;
|
|
|
|
-- name: UpdateReacquisitionSettings :one
|
|
-- Whole-row write from the admin card; the CHECKs in migration 0056 are the
|
|
-- validation, so a bad value fails loudly rather than being clamped silently.
|
|
UPDATE reacquisition_settings
|
|
SET enabled = sqlc.arg(enabled),
|
|
grace_hours = sqlc.arg(grace_hours),
|
|
max_per_pass = sqlc.arg(max_per_pass)
|
|
WHERE id = true
|
|
RETURNING *;
|
|
|
|
-- name: ListAlbumsDueReacquisition :many
|
|
-- The sweeper's selection. An album qualifies when:
|
|
--
|
|
-- * it still has at least one track whose file has been missing longer than
|
|
-- the grace window. Measured on missing_since, which reconcile never
|
|
-- re-stamps (#2523), so it is a genuine "gone since" clock;
|
|
-- * MusicBrainz can name it: the artist has an MBID, and the album a
|
|
-- release MBID or a release group. The release MBID is only ever used to
|
|
-- find the group, and 238 albums matched to a group carried no release
|
|
-- id, so their losses were never wanted back (#6167). Albums failing this
|
|
-- are counted separately (CountAlbumsMissingWithoutMbid);
|
|
-- * it is on the wanted list (#5567): an album taken off the list, or
|
|
-- dropped into the library by hand, is not fetched back;
|
|
-- * no want already covers it: none open, and none held since its files
|
|
-- went missing. A want held after the loss means the library has a full
|
|
-- copy despite the missing rows (#5245), so asking again would loop.
|
|
SELECT albums.id AS album_id,
|
|
albums.title AS album_title,
|
|
albums.mbid AS album_mbid,
|
|
albums.release_group_mbid AS album_release_group_mbid,
|
|
artists.name AS artist_name,
|
|
artists.mbid AS artist_mbid,
|
|
COUNT(tracks.id)::bigint AS missing_track_count,
|
|
MAX(tracks.missing_since)::timestamptz AS last_missing_since
|
|
FROM albums
|
|
JOIN artists ON artists.id = albums.artist_id
|
|
JOIN tracks ON tracks.album_id = albums.id
|
|
WHERE tracks.missing_since IS NOT NULL
|
|
AND tracks.missing_since <= now() - make_interval(hours => sqlc.arg(grace_hours)::int)
|
|
AND (albums.mbid IS NOT NULL OR albums.release_group_mbid IS NOT NULL)
|
|
AND artists.mbid IS NOT NULL
|
|
GROUP BY albums.id, albums.title, albums.mbid, albums.release_group_mbid,
|
|
artists.name, artists.mbid
|
|
HAVING EXISTS (
|
|
SELECT 1 FROM wants w
|
|
WHERE w.album_id = albums.id OR w.release_group_mbid = albums.release_group_mbid)
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM wants w
|
|
WHERE (w.album_id = albums.id OR w.release_group_mbid = albums.release_group_mbid)
|
|
AND (w.fulfilled_at IS NULL OR w.fulfilled_at > MAX(tracks.missing_since)))
|
|
ORDER BY MIN(tracks.missing_since), albums.sort_title
|
|
LIMIT sqlc.arg(page_limit);
|
|
|
|
-- name: CountAlbumsMissingWithoutMbid :one
|
|
-- Albums with missing files that can never be wanted automatically because
|
|
-- nothing identifies them to MusicBrainz. Surfaced on the admin card so the
|
|
-- gap is visible: silently doing nothing for these would read as broken.
|
|
SELECT COUNT(DISTINCT albums.id)::bigint
|
|
FROM albums
|
|
JOIN artists ON artists.id = albums.artist_id
|
|
JOIN tracks ON tracks.album_id = albums.id
|
|
WHERE tracks.missing_since IS NOT NULL
|
|
AND ((albums.mbid IS NULL AND albums.release_group_mbid IS NULL) OR artists.mbid IS NULL);
|
|
|
|
-- name: WantMissingAlbum :one
|
|
-- Records an album with missing files as wanted. A held want for the same
|
|
-- group is reopened; an open one is left as it is, and no row comes back.
|
|
INSERT INTO wants (release_group_mbid, artist_mbid, artist_name, title, reason, album_id)
|
|
VALUES (sqlc.arg(release_group_mbid), sqlc.arg(artist_mbid), sqlc.arg(artist_name),
|
|
sqlc.arg(title), 'missing', sqlc.arg(album_id))
|
|
ON CONFLICT (release_group_mbid) DO UPDATE
|
|
SET reason = 'missing',
|
|
album_id = EXCLUDED.album_id,
|
|
wanted_at = now(),
|
|
fulfilled_at = NULL,
|
|
updated_at = now()
|
|
WHERE wants.fulfilled_at IS NOT NULL
|
|
RETURNING *;
|
|
|
|
-- name: GetWantsForAlbums :many
|
|
-- What the wanted list says about each album on the missing-files page.
|
|
SELECT a.id AS album_id, w.id AS want_id, w.wanted_at, w.fulfilled_at
|
|
FROM albums a
|
|
JOIN wants w ON w.album_id = a.id OR w.release_group_mbid = a.release_group_mbid
|
|
WHERE a.id = ANY(sqlc.arg(album_ids)::uuid[])
|
|
ORDER BY w.wanted_at DESC;
|