-- Import with verification (M502 #5522). -- name: ListLiveGrabs :many -- Every download still running or waiting on its import, oldest first. SELECT g.*, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title AS want_title, w.reason AS want_reason, w.album_id AS want_album_id FROM grabs g LEFT JOIN wants w ON w.id = g.want_id WHERE g.ended_at IS NULL ORDER BY g.grabbed_at, g.id; -- name: GetGrab :one SELECT * FROM grabs WHERE id = $1; -- name: SetGrabProgress :exec -- What the download client says of a download not yet finished, or finished -- and waiting for what the import needs. Leaves a claimed, decided or failed -- import alone. UPDATE grabs SET progress = sqlc.arg(progress), import_state = sqlc.arg(import_state), import_reason = sqlc.arg(import_reason), import_updated_at = now() WHERE id = sqlc.arg(id) AND ended_at IS NULL AND import_state IN ('', 'downloading', 'waiting'); -- name: ClaimGrabImport :one -- Takes a finished download for import. The update is the lock: a second -- pass finds nothing to claim. UPDATE grabs SET import_state = 'importing', import_attempts = import_attempts + 1, import_updated_at = now(), progress = 1 WHERE id = $1 AND ended_at IS NULL AND import_state IN ('', 'downloading', 'waiting') RETURNING *; -- name: ReclaimStaleImports :execrows -- An import cut short (a restart mid-copy) is tried again. UPDATE grabs SET import_state = 'waiting', import_reason = 'The last import was cut short, so it is being tried again.' WHERE ended_at IS NULL AND import_state = 'importing' AND import_updated_at < now() - make_interval(mins => sqlc.arg(minutes)::int); -- name: RecordImport :one -- The import's outcome. An end reason ends the grab: imported, refused or -- held. Without one the grab stays live: review and failed wait for a person. UPDATE grabs SET import_state = sqlc.arg(import_state), import_reason = sqlc.arg(import_reason), import_detail = sqlc.arg(import_detail), import_updated_at = now(), import_forced = false, imported_at = CASE WHEN sqlc.arg(import_state)::text = 'imported' THEN now() ELSE imported_at END, imported_files = sqlc.arg(imported_files), destination = sqlc.arg(destination), ended_at = CASE WHEN sqlc.arg(end_reason)::text <> '' THEN now() ELSE ended_at END, end_reason = sqlc.arg(end_reason), end_detail = CASE WHEN sqlc.arg(end_reason)::text <> '' THEN sqlc.arg(import_reason)::text ELSE end_detail END WHERE id = sqlc.arg(id) RETURNING *; -- name: ForceGrabImport :one -- "Import anyway": the next pass imports the download whatever the check said. UPDATE grabs SET import_state = '', import_forced = true, import_reason = '', import_updated_at = now() WHERE id = $1 AND ended_at IS NULL AND import_state IN ('review', 'failed') RETURNING *; -- name: RetryGrabImport :one UPDATE grabs SET import_state = '', import_reason = '', import_updated_at = now() WHERE id = $1 AND ended_at IS NULL AND import_state = 'failed' RETURNING *; -- name: RehomeGrab :one -- A download that turned out to be another wanted album is that want's grab, -- when the want has none running. UPDATE grabs g SET want_id = sqlc.arg(want_id) WHERE g.id = sqlc.arg(id) AND g.ended_at IS NULL AND NOT EXISTS (SELECT 1 FROM grabs o WHERE o.want_id = sqlc.arg(want_id) AND o.ended_at IS NULL) RETURNING *; -- name: OpenWantsForGroups :many -- Open wants for these release groups with no download running. SELECT w.* FROM wants w WHERE w.fulfilled_at IS NULL AND w.release_group_mbid = ANY(sqlc.arg(groups)::text[]) AND NOT EXISTS (SELECT 1 FROM grabs g WHERE g.want_id = w.id AND g.ended_at IS NULL); -- name: MarkWantSearched :exec -- Imported: nothing to search for until the wanted pass settles the want. UPDATE wants SET searched_at = now() WHERE id = $1; -- name: SearchWantAgain :exec -- Refused: search again on the next pass. UPDATE wants SET searched_at = NULL, search_outcome = '' WHERE id = $1; -- name: HeldRecordings :many -- Which of these recordings the library holds a file for. SELECT DISTINCT mbid::text AS mbid FROM tracks WHERE mbid = ANY(sqlc.arg(recordings)::text[]) AND missing_since IS NULL; -- name: HeldPositions :many -- The disc and track positions the library holds for an album of this group. SELECT DISTINCT COALESCE(t.disc_number, 1)::int AS disc, t.track_number::int AS track FROM tracks t JOIN albums a ON a.id = t.album_id WHERE a.release_group_mbid = sqlc.arg(release_group_mbid) AND t.missing_since IS NULL AND t.track_number IS NOT NULL; -- name: ListGrabs :many -- The Wanted view's Activity tab: downloads waiting on a person first, then -- the rest still running, then the ended ones newest first. SELECT g.id, g.want_id, g.name, g.indexer, g.client, g.quality, g.origin, g.forced, g.grabbed_at, g.ended_at, g.end_reason, g.end_detail, g.progress, g.import_state, g.import_reason, g.import_detail, g.import_updated_at, g.imported_at, g.imported_files, g.destination, w.title AS want_title, w.artist_name AS want_artist FROM grabs g LEFT JOIN wants w ON w.id = g.want_id ORDER BY (g.ended_at IS NULL AND g.import_state IN ('review', 'failed')) DESC, g.ended_at IS NULL DESC, g.grabbed_at DESC, g.id LIMIT sqlc.arg(max_rows) OFFSET sqlc.arg(skip); -- name: ListReleaseBlocksPage :many SELECT b.info_hash, b.name, b.reason, b.detail, b.blocked_at, w.title AS want_title, w.artist_name AS want_artist FROM release_blocks b LEFT JOIN wants w ON w.id = b.want_id ORDER BY b.blocked_at DESC, b.info_hash LIMIT sqlc.arg(max_rows) OFFSET sqlc.arg(skip);