feat: Lidarr searches for a better copy of a rip that has none (M498 #5447)
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m26s
release / go (push) Successful in 1m45s
release / integration (push) Successful in 5m6s
release / android (push) Successful in 5m58s
release / Build signed APK (releases and dev) (push) Successful in 6m17s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m26s
release / go (push) Successful in 1m45s
release / integration (push) Successful in 5m6s
release / android (push) Successful in 5m58s
release / Build signed APK (releases and dev) (push) Successful in 6m17s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
The operator chose option 2: an album holding a video rip that is the only copy of its song is searched in Lidarr (AlbumSearch), at most once a week and ten albums a pass. Lidarr grabs only when the quality profile allows an upgrade, so nothing is removed and the rip stays held back either way. - lidarr.Client.SearchAlbums posts the AlbumSearch command. - ListAlbumsWithSoleCopyRips finds the albums: a held-back rip with no present clean copy sharing its song or its pending group, and not searched in the last week (audit action lidarr_rip_search). - Suspect sources shows when Lidarr last searched the track's album. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -405,6 +405,78 @@ func (q *Queries) GetTracksByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listAlbumsWithSoleCopyRips = `-- name: ListAlbumsWithSoleCopyRips :many
|
||||
SELECT a.id AS album_id,
|
||||
a.release_group_mbid::text AS release_group_mbid,
|
||||
a.title AS album_title,
|
||||
ar.name AS artist_name,
|
||||
count(*)::bigint AS rips
|
||||
FROM tracks t
|
||||
JOIN albums a ON a.id = t.album_id
|
||||
JOIN artists ar ON ar.id = a.artist_id
|
||||
WHERE t.source_verdict = 'suspect'
|
||||
AND t.missing_since IS NULL
|
||||
AND a.release_group_mbid IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM tracks c
|
||||
WHERE c.song_key = t.song_key AND c.id <> t.id
|
||||
AND c.missing_since IS NULL AND c.source_verdict IS DISTINCT FROM 'suspect')
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM duplicate_group_members m
|
||||
JOIN duplicate_groups g ON g.id = m.group_id AND g.status = 'pending'
|
||||
JOIN duplicate_group_members m2 ON m2.group_id = g.id AND m2.track_id <> t.id
|
||||
JOIN tracks c ON c.id = m2.track_id
|
||||
WHERE m.track_id = t.id
|
||||
AND c.missing_since IS NULL AND c.source_verdict IS DISTINCT FROM 'suspect')
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM audit_log l
|
||||
WHERE l.action = 'lidarr_rip_search'
|
||||
AND l.metadata->>'album_id' = a.id::text
|
||||
AND l.created_at > now() - interval '7 days')
|
||||
GROUP BY a.id, a.release_group_mbid, a.title, ar.name
|
||||
ORDER BY count(*) DESC, a.id
|
||||
LIMIT $1
|
||||
`
|
||||
|
||||
type ListAlbumsWithSoleCopyRipsRow struct {
|
||||
AlbumID pgtype.UUID
|
||||
ReleaseGroupMbid string
|
||||
AlbumTitle string
|
||||
ArtistName string
|
||||
Rips int64
|
||||
}
|
||||
|
||||
// Albums holding a held-back video rip that is the only copy of its song
|
||||
// (#5447): no present copy that is not a rip shares its song, and no pending
|
||||
// duplicate group pairs it with one. Lidarr counts such a track fulfilled, so
|
||||
// the resolver asks it to search the album for a better release. Albums
|
||||
// searched within the last week are left out, most rips first.
|
||||
func (q *Queries) ListAlbumsWithSoleCopyRips(ctx context.Context, pageLimit int32) ([]ListAlbumsWithSoleCopyRipsRow, error) {
|
||||
rows, err := q.db.Query(ctx, listAlbumsWithSoleCopyRips, pageLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListAlbumsWithSoleCopyRipsRow
|
||||
for rows.Next() {
|
||||
var i ListAlbumsWithSoleCopyRipsRow
|
||||
if err := rows.Scan(
|
||||
&i.AlbumID,
|
||||
&i.ReleaseGroupMbid,
|
||||
&i.AlbumTitle,
|
||||
&i.ArtistName,
|
||||
&i.Rips,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listArtistTracksForUser = `-- name: ListArtistTracksForUser :many
|
||||
SELECT t.id, t.title, t.album_id, t.artist_id, t.track_number, t.disc_number, t.duration_ms, t.file_path, t.file_size, t.file_format, t.bitrate, t.mbid, t.genre, t.added_at, t.updated_at, t.tag_source, t.tag_sources_version, t.tag_read_version, t.missing_since, t.mbid_source, t.song_id, t.song_key, t.source_verdict, t.source_verdict_at,
|
||||
albums.title AS album_title,
|
||||
@@ -659,10 +731,17 @@ SELECT t.id,
|
||||
artists.id AS artist_id,
|
||||
artists.name AS artist_name,
|
||||
t.source_verdict,
|
||||
t.source_verdict_at
|
||||
t.source_verdict_at,
|
||||
searched.at AS searched_at
|
||||
FROM tracks t
|
||||
JOIN albums ON albums.id = t.album_id
|
||||
JOIN artists ON artists.id = t.artist_id
|
||||
-- When the resolver last asked Lidarr to search the album for a better copy
|
||||
-- (#5447).
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT max(l.created_at)::timestamptz AS at FROM audit_log l
|
||||
WHERE l.action = 'lidarr_rip_search' AND l.metadata->>'album_id' = albums.id::text
|
||||
) searched ON true
|
||||
WHERE t.missing_since IS NULL
|
||||
AND regexp_replace(t.file_path, '^.*/', '') ~* $1::text
|
||||
ORDER BY directory, t.disc_number NULLS FIRST, t.track_number NULLS FIRST, t.title
|
||||
@@ -689,6 +768,7 @@ type ListSuspectSourceTracksRow struct {
|
||||
ArtistName string
|
||||
SourceVerdict *string
|
||||
SourceVerdictAt pgtype.Timestamptz
|
||||
SearchedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
// The admin report of present tracks whose filename looks like a video rip
|
||||
@@ -724,6 +804,7 @@ func (q *Queries) ListSuspectSourceTracks(ctx context.Context, arg ListSuspectSo
|
||||
&i.ArtistName,
|
||||
&i.SourceVerdict,
|
||||
&i.SourceVerdictAt,
|
||||
&i.SearchedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user