feat: a held album below the quality you settle for, or holding a video rip, stays wanted for a better copy, and the import replaces the old tracks with their likes and plays carried over (M502 #5524)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m23s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 5m20s
release / android (push) Successful in 5m28s
release / Build signed APK (releases and dev) (push) Successful in 5m30s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 27s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m23s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 5m20s
release / android (push) Successful in 5m28s
release / Build signed APK (releases and dev) (push) Successful in 5m30s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 27s
release / Verify release artifacts (tag releases only) (push) Skipped
- acquisition_settings.upgrade_until (default High quality lossy, Lidarr's cutoff, note #5527; "" is off), an "Upgrade until" row under Searching. - The wanted worker judges held albums hourly: tier per format from size per second (the scanner records no bitrate), the album's worst. Below the cutoff it is wanted for quality; a video rip among its tracks always. - The schedule searches upgrades weekly, after open wants; a release no better than the copy held is refused ("not_better"). - The import matches each file to the track it would replace (recording, then disc/track) and replaces it when it is a rip or the file is a better tier: over the same path in one rename, or filed beside it and the old track folded in (library.ReplaceTrack: file first, then foldTrackInto). Nothing better: the release is set aside. - Collection › Upgrades (Lidarr's Cutoff Unmet); Suspect sources says when a clean copy was looked for instead of Lidarr's search. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,38 @@ func (q *Queries) ClaimGrabImport(ctx context.Context, id pgtype.UUID) (Grab, er
|
||||
return i, err
|
||||
}
|
||||
|
||||
const clearTrackSourceVerdict = `-- name: ClearTrackSourceVerdict :exec
|
||||
UPDATE tracks SET source_verdict = NULL, source_verdict_at = NULL
|
||||
WHERE id = $1 AND source_verdict = 'suspect'
|
||||
`
|
||||
|
||||
// A track whose file was replaced in place is no longer the rip it was.
|
||||
func (q *Queries) ClearTrackSourceVerdict(ctx context.Context, id pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, clearTrackSourceVerdict, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const finishUpgrade = `-- name: FinishUpgrade :exec
|
||||
UPDATE wants
|
||||
SET album_id = COALESCE($1, album_id),
|
||||
upgrade = '',
|
||||
upgrade_checked_at = NULL,
|
||||
updated_at = now()
|
||||
WHERE id = $2
|
||||
`
|
||||
|
||||
type FinishUpgradeParams struct {
|
||||
AlbumID pgtype.UUID
|
||||
ID pgtype.UUID
|
||||
}
|
||||
|
||||
// An upgrade was imported: the want holds the album the new tracks are in,
|
||||
// and is judged again by the next upgrade check.
|
||||
func (q *Queries) FinishUpgrade(ctx context.Context, arg FinishUpgradeParams) error {
|
||||
_, err := q.db.Exec(ctx, finishUpgrade, arg.AlbumID, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
const forceGrabImport = `-- name: ForceGrabImport :one
|
||||
UPDATE grabs
|
||||
SET import_state = '', import_forced = true, import_reason = '', import_updated_at = now()
|
||||
@@ -479,6 +511,57 @@ func (q *Queries) ListReleaseBlocksPage(ctx context.Context, arg ListReleaseBloc
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUpgradeTracks = `-- name: ListUpgradeTracks :many
|
||||
SELECT id, file_path, mbid, COALESCE(disc_number, 1)::int AS disc, track_number,
|
||||
file_format, file_size, duration_ms, source_verdict
|
||||
FROM tracks
|
||||
WHERE album_id = $1 AND missing_since IS NULL
|
||||
`
|
||||
|
||||
type ListUpgradeTracksRow struct {
|
||||
ID pgtype.UUID
|
||||
FilePath string
|
||||
Mbid *string
|
||||
Disc int32
|
||||
TrackNumber *int32
|
||||
FileFormat string
|
||||
FileSize int64
|
||||
DurationMs int32
|
||||
SourceVerdict *string
|
||||
}
|
||||
|
||||
// The tracks an upgrade may replace (#5524): the present tracks of the album
|
||||
// the want holds.
|
||||
func (q *Queries) ListUpgradeTracks(ctx context.Context, albumID pgtype.UUID) ([]ListUpgradeTracksRow, error) {
|
||||
rows, err := q.db.Query(ctx, listUpgradeTracks, albumID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListUpgradeTracksRow
|
||||
for rows.Next() {
|
||||
var i ListUpgradeTracksRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.FilePath,
|
||||
&i.Mbid,
|
||||
&i.Disc,
|
||||
&i.TrackNumber,
|
||||
&i.FileFormat,
|
||||
&i.FileSize,
|
||||
&i.DurationMs,
|
||||
&i.SourceVerdict,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const markWantSearched = `-- name: MarkWantSearched :exec
|
||||
UPDATE wants SET searched_at = now() WHERE id = $1
|
||||
`
|
||||
@@ -490,7 +573,7 @@ func (q *Queries) MarkWantSearched(ctx context.Context, id pgtype.UUID) error {
|
||||
}
|
||||
|
||||
const openWantsForGroups = `-- name: OpenWantsForGroups :many
|
||||
SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.primary_type, w.first_release_date, w.reason, w.album_id, w.created_by, w.wanted_at, w.fulfilled_at, w.created_at, w.updated_at, w.searched_at, w.search_outcome, w.search_considered, w.best_release, w.best_verdict, w.search_error FROM wants w
|
||||
SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.primary_type, w.first_release_date, w.reason, w.album_id, w.created_by, w.wanted_at, w.fulfilled_at, w.created_at, w.updated_at, w.searched_at, w.search_outcome, w.search_considered, w.best_release, w.best_verdict, w.search_error, w.upgrade, w.held_tier, w.held_quality, w.upgrade_checked_at FROM wants w
|
||||
WHERE w.fulfilled_at IS NULL AND w.release_group_mbid = ANY($1::text[])
|
||||
AND NOT EXISTS (SELECT 1 FROM grabs g WHERE g.want_id = w.id AND g.ended_at IS NULL)
|
||||
`
|
||||
@@ -526,6 +609,10 @@ func (q *Queries) OpenWantsForGroups(ctx context.Context, groups []string) ([]Wa
|
||||
&i.BestRelease,
|
||||
&i.BestVerdict,
|
||||
&i.SearchError,
|
||||
&i.Upgrade,
|
||||
&i.HeldTier,
|
||||
&i.HeldQuality,
|
||||
&i.UpgradeCheckedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user