feat: search and grab — music release names, a quality ladder, a paced search schedule and one live grab per want (M502 #5521)
release / govulncheck (push) Successful in 21s
release / go (push) Failing after 33s
release / web (push) Successful in 56s
release / integration (push) Failing after 4m48s
release / android (push) Successful in 5m6s
release / Build signed APK (releases and dev) (push) Successful in 5m16s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 21s
release / go (push) Failing after 33s
release / web (push) Successful in 56s
release / integration (push) Failing after 4m48s
release / android (push) Successful in 5m6s
release / Build signed APK (releases and dev) (push) Successful in 5m16s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
- internal/release: reads a release name (format, bitrate, bit depth and sample rate, source, year, video, discography) and judges it against the album wanted: the artist and title must be in it; video rips, discographies, other versions (drumless, instrumental, karaoke, remix, live unless the album is live…) and singles or EPs for an album are refused. Quality tiers on Lidarr's ladder; a .torrent's file list is read for format, video files and a track count short of the album. - internal/acquire: fan-out across every search source with a narrowed search kept, a process-wide pacer per source, every candidate judged and kept with its reasons, and the grab: one live grab per want, tie-broken (a person's grab beats the schedule's; a better release replaces a worse one unless it is nearly done). Each download lands in its own folder under the client's downloads folder. - internal/wanted: the search schedule, every ten minutes, never-searched first, then requests, missing files and followed artists, taking the best release when auto-grab is on (the default). - Migration 0082: acquisition_settings (auto-grab, interval, allowed qualities seeded from Lidarr's "Any"), want search columns, want_candidates, grabs, release_blocks. - Web: the Wanted page shows each want's last search, a Search button and every release found with its verdict (Grab, Grab anyway, Never this one, Allow again). Integrations gains "Searching and grabbing". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -206,7 +206,7 @@ func (q *Queries) GetReleaseTypeProfile(ctx context.Context, id pgtype.UUID) (Re
|
||||
}
|
||||
|
||||
const getWantByReleaseGroup = `-- name: GetWantByReleaseGroup :one
|
||||
SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at FROM wants WHERE release_group_mbid = $1
|
||||
SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error FROM wants WHERE release_group_mbid = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetWantByReleaseGroup(ctx context.Context, releaseGroupMbid string) (Want, error) {
|
||||
@@ -227,6 +227,12 @@ func (q *Queries) GetWantByReleaseGroup(ctx context.Context, releaseGroupMbid st
|
||||
&i.FulfilledAt,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.SearchedAt,
|
||||
&i.SearchOutcome,
|
||||
&i.SearchConsidered,
|
||||
&i.BestRelease,
|
||||
&i.BestVerdict,
|
||||
&i.SearchError,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -406,7 +412,7 @@ func (q *Queries) ListFollowsDue(ctx context.Context, arg ListFollowsDueParams)
|
||||
}
|
||||
|
||||
const listOpenWants = `-- name: ListOpenWants :many
|
||||
SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at FROM wants
|
||||
SELECT id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error FROM wants
|
||||
WHERE fulfilled_at IS NULL
|
||||
ORDER BY wanted_at, id
|
||||
LIMIT $1
|
||||
@@ -436,6 +442,12 @@ func (q *Queries) ListOpenWants(ctx context.Context, limit int32) ([]Want, error
|
||||
&i.FulfilledAt,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.SearchedAt,
|
||||
&i.SearchOutcome,
|
||||
&i.SearchConsidered,
|
||||
&i.BestRelease,
|
||||
&i.BestVerdict,
|
||||
&i.SearchError,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -505,10 +517,14 @@ SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.reas
|
||||
COALESCE(g.secondary_types, '{}')::text[] AS secondary_types,
|
||||
COALESCE(NULLIF(w.first_release_date, ''), g.first_release_date, '')::text AS first_release_date,
|
||||
u.username AS requested_by,
|
||||
(SELECT ar.id FROM artists ar WHERE ar.mbid = w.artist_mbid) AS library_artist_id
|
||||
(SELECT ar.id FROM artists ar WHERE ar.mbid = w.artist_mbid) AS library_artist_id,
|
||||
-- The search schedule's last look (#5521), and the download running.
|
||||
w.searched_at, w.search_outcome, w.search_considered, w.best_release, w.best_verdict, w.search_error,
|
||||
gr.name AS grab_name, gr.grabbed_at, gr.origin AS grab_origin, gr.quality AS grab_quality
|
||||
FROM wants w
|
||||
LEFT JOIN users u ON u.id = w.created_by
|
||||
LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid
|
||||
LEFT JOIN grabs gr ON gr.want_id = w.id AND gr.ended_at IS NULL
|
||||
WHERE CASE $1::text
|
||||
WHEN 'held' THEN w.fulfilled_at IS NOT NULL
|
||||
WHEN 'missing' THEN w.fulfilled_at IS NULL AND w.reason = 'missing'
|
||||
@@ -539,6 +555,16 @@ type ListWantsRow struct {
|
||||
FirstReleaseDate string
|
||||
RequestedBy *string
|
||||
LibraryArtistID pgtype.UUID
|
||||
SearchedAt pgtype.Timestamptz
|
||||
SearchOutcome string
|
||||
SearchConsidered int32
|
||||
BestRelease string
|
||||
BestVerdict string
|
||||
SearchError string
|
||||
GrabName *string
|
||||
GrabbedAt pgtype.Timestamptz
|
||||
GrabOrigin *string
|
||||
GrabQuality *string
|
||||
}
|
||||
|
||||
// The Wanted page: open wants (all but missing ones, or only missing ones),
|
||||
@@ -567,6 +593,16 @@ func (q *Queries) ListWants(ctx context.Context, arg ListWantsParams) ([]ListWan
|
||||
&i.FirstReleaseDate,
|
||||
&i.RequestedBy,
|
||||
&i.LibraryArtistID,
|
||||
&i.SearchedAt,
|
||||
&i.SearchOutcome,
|
||||
&i.SearchConsidered,
|
||||
&i.BestRelease,
|
||||
&i.BestVerdict,
|
||||
&i.SearchError,
|
||||
&i.GrabName,
|
||||
&i.GrabbedAt,
|
||||
&i.GrabOrigin,
|
||||
&i.GrabQuality,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -791,7 +827,7 @@ INSERT INTO wants (release_group_mbid, artist_mbid, artist_name, title, primary_
|
||||
VALUES ($1, $2, $3, $4,
|
||||
$5, $6, $7, $8)
|
||||
ON CONFLICT (release_group_mbid) DO UPDATE SET updated_at = wants.updated_at
|
||||
RETURNING id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at
|
||||
RETURNING id, release_group_mbid, artist_mbid, artist_name, title, primary_type, first_release_date, reason, album_id, created_by, wanted_at, fulfilled_at, created_at, updated_at, searched_at, search_outcome, search_considered, best_release, best_verdict, search_error
|
||||
`
|
||||
|
||||
type WantReleaseGroupParams struct {
|
||||
@@ -834,6 +870,12 @@ func (q *Queries) WantReleaseGroup(ctx context.Context, arg WantReleaseGroupPara
|
||||
&i.FulfilledAt,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.SearchedAt,
|
||||
&i.SearchOutcome,
|
||||
&i.SearchConsidered,
|
||||
&i.BestRelease,
|
||||
&i.BestVerdict,
|
||||
&i.SearchError,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user