release / govulncheck (push) Successful in 17s
release / web (push) Failing after 17s
release / go (push) Successful in 1m11s
release / integration (push) Successful in 4m50s
release / android (push) Successful in 4m54s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
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
Ported from Fabled Librarian's System 104. A new lifecycle poller, every ten minutes: - a download the client fails is given up at once; - one nobody shares, or still fetching its file list, past the stall setting (6 h) is asked for again three times, then given up; - giving up removes the download with its files, holds the release back for a week (release_blocks.expires_at), ends the grab and searches the album again, with no limit per album; - a running download the client stops listing for half an hour ends and is searched again, not held back; an empty list is not taken as gone; - an imported download seeds to ratio 2.0 or 14 days, then is removed; - a download the client would not remove is asked again every pass. Every condition and act is one open row per (client, download, condition) in download_interventions. Activity shows what is wrong with a download and how often it was retried, why one ended, its seeding, and a banner for a client that does not answer. A running download can be given up by hand (set aside for good). The seed ratio, seed days and stall hours are on the search settings card. The download client lookup moves to acquire.DownloadClientFor, shared by the importer and the lifecycle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
650 lines
17 KiB
Go
650 lines
17 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: search.sql
|
|
|
|
package dbq
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const blockRelease = `-- name: BlockRelease :exec
|
|
INSERT INTO release_blocks (info_hash, name, reason, detail, want_id, blocked_by, expires_at)
|
|
VALUES ($1, $2, $3, $4,
|
|
$5, $6, $7)
|
|
ON CONFLICT (info_hash) DO UPDATE
|
|
SET reason = EXCLUDED.reason, detail = EXCLUDED.detail, blocked_at = now(),
|
|
expires_at = EXCLUDED.expires_at, blocked_by = EXCLUDED.blocked_by
|
|
WHERE release_blocks.expires_at IS NOT NULL OR EXCLUDED.expires_at IS NULL
|
|
`
|
|
|
|
type BlockReleaseParams struct {
|
|
InfoHash string
|
|
Name string
|
|
Reason string
|
|
Detail string
|
|
WantID pgtype.UUID
|
|
BlockedBy pgtype.UUID
|
|
ExpiresAt pgtype.Timestamptz
|
|
}
|
|
|
|
// A release set aside. expires_at NULL is for good. A block for good is never
|
|
// shortened by a timed one: only a timed block, or another for good, is
|
|
// replaced.
|
|
func (q *Queries) BlockRelease(ctx context.Context, arg BlockReleaseParams) error {
|
|
_, err := q.db.Exec(ctx, blockRelease,
|
|
arg.InfoHash,
|
|
arg.Name,
|
|
arg.Reason,
|
|
arg.Detail,
|
|
arg.WantID,
|
|
arg.BlockedBy,
|
|
arg.ExpiresAt,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const deleteWantCandidates = `-- name: DeleteWantCandidates :exec
|
|
DELETE FROM want_candidates WHERE want_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteWantCandidates(ctx context.Context, wantID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteWantCandidates, wantID)
|
|
return err
|
|
}
|
|
|
|
const editionTrackSpan = `-- name: EditionTrackSpan :one
|
|
SELECT COALESCE(MIN(track_count) FILTER (WHERE status = 'Official'), MIN(track_count), 0)::int AS min_tracks,
|
|
COALESCE(MAX(track_count), 0)::int AS max_tracks
|
|
FROM mb_releases
|
|
WHERE release_group_mbid = $1 AND track_count > 0
|
|
`
|
|
|
|
type EditionTrackSpanRow struct {
|
|
MinTracks int32
|
|
MaxTracks int32
|
|
}
|
|
|
|
// The fewest tracks an official edition of the group has (any edition when
|
|
// none is official), and the most any has. Zero when none is catalogued.
|
|
func (q *Queries) EditionTrackSpan(ctx context.Context, releaseGroupMbid string) (EditionTrackSpanRow, error) {
|
|
row := q.db.QueryRow(ctx, editionTrackSpan, releaseGroupMbid)
|
|
var i EditionTrackSpanRow
|
|
err := row.Scan(&i.MinTracks, &i.MaxTracks)
|
|
return i, err
|
|
}
|
|
|
|
const endGrab = `-- name: EndGrab :exec
|
|
UPDATE grabs
|
|
SET ended_at = now(), end_reason = $1, end_detail = $2
|
|
WHERE id = $3 AND ended_at IS NULL
|
|
`
|
|
|
|
type EndGrabParams struct {
|
|
EndReason string
|
|
EndDetail string
|
|
ID pgtype.UUID
|
|
}
|
|
|
|
func (q *Queries) EndGrab(ctx context.Context, arg EndGrabParams) error {
|
|
_, err := q.db.Exec(ctx, endGrab, arg.EndReason, arg.EndDetail, arg.ID)
|
|
return err
|
|
}
|
|
|
|
const getAcquisitionSettings = `-- name: GetAcquisitionSettings :one
|
|
|
|
SELECT id, auto_grab, search_interval_hours, allowed_qualities, last_pass_at, last_pass, updated_at, import_root, seed_ratio, seed_days, stall_hours FROM acquisition_settings WHERE id = true
|
|
`
|
|
|
|
// Searching for wants and grabbing releases (M502 #5521).
|
|
func (q *Queries) GetAcquisitionSettings(ctx context.Context) (AcquisitionSetting, error) {
|
|
row := q.db.QueryRow(ctx, getAcquisitionSettings)
|
|
var i AcquisitionSetting
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.AutoGrab,
|
|
&i.SearchIntervalHours,
|
|
&i.AllowedQualities,
|
|
&i.LastPassAt,
|
|
&i.LastPass,
|
|
&i.UpdatedAt,
|
|
&i.ImportRoot,
|
|
&i.SeedRatio,
|
|
&i.SeedDays,
|
|
&i.StallHours,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getLiveGrab = `-- name: GetLiveGrab :one
|
|
SELECT id, want_id, info_hash, name, key, indexer, source, client, save_path, quality, origin, forced, grabbed_by, grabbed_at, ended_at, end_reason, end_detail, progress, import_state, import_reason, import_detail, import_forced, import_attempts, import_updated_at, imported_at, imported_files, destination, seeding, ratio, seed_released_at FROM grabs WHERE want_id = $1 AND ended_at IS NULL
|
|
`
|
|
|
|
func (q *Queries) GetLiveGrab(ctx context.Context, wantID pgtype.UUID) (Grab, error) {
|
|
row := q.db.QueryRow(ctx, getLiveGrab, wantID)
|
|
var i Grab
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WantID,
|
|
&i.InfoHash,
|
|
&i.Name,
|
|
&i.Key,
|
|
&i.Indexer,
|
|
&i.Source,
|
|
&i.Client,
|
|
&i.SavePath,
|
|
&i.Quality,
|
|
&i.Origin,
|
|
&i.Forced,
|
|
&i.GrabbedBy,
|
|
&i.GrabbedAt,
|
|
&i.EndedAt,
|
|
&i.EndReason,
|
|
&i.EndDetail,
|
|
&i.Progress,
|
|
&i.ImportState,
|
|
&i.ImportReason,
|
|
&i.ImportDetail,
|
|
&i.ImportForced,
|
|
&i.ImportAttempts,
|
|
&i.ImportUpdatedAt,
|
|
&i.ImportedAt,
|
|
&i.ImportedFiles,
|
|
&i.Destination,
|
|
&i.Seeding,
|
|
&i.Ratio,
|
|
&i.SeedReleasedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getWantCandidate = `-- name: GetWantCandidate :one
|
|
SELECT want_id, key, name, info_hash, indexer, source, size_bytes, seeders, files_count, format, quality, year, verdict, reason, reasons, folded_from, rank, searched_at FROM want_candidates WHERE want_id = $1 AND key = $2
|
|
`
|
|
|
|
type GetWantCandidateParams struct {
|
|
WantID pgtype.UUID
|
|
Key string
|
|
}
|
|
|
|
func (q *Queries) GetWantCandidate(ctx context.Context, arg GetWantCandidateParams) (WantCandidate, error) {
|
|
row := q.db.QueryRow(ctx, getWantCandidate, arg.WantID, arg.Key)
|
|
var i WantCandidate
|
|
err := row.Scan(
|
|
&i.WantID,
|
|
&i.Key,
|
|
&i.Name,
|
|
&i.InfoHash,
|
|
&i.Indexer,
|
|
&i.Source,
|
|
&i.SizeBytes,
|
|
&i.Seeders,
|
|
&i.FilesCount,
|
|
&i.Format,
|
|
&i.Quality,
|
|
&i.Year,
|
|
&i.Verdict,
|
|
&i.Reason,
|
|
&i.Reasons,
|
|
&i.FoldedFrom,
|
|
&i.Rank,
|
|
&i.SearchedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getWantForSearch = `-- name: GetWantForSearch :one
|
|
SELECT w.id, w.release_group_mbid, w.artist_mbid, w.artist_name, w.title, w.reason, w.fulfilled_at,
|
|
COALESCE(NULLIF(w.primary_type, ''), g.primary_type, '')::text AS primary_type,
|
|
COALESCE(g.secondary_types, '{}')::text[] AS secondary_types,
|
|
COALESCE(NULLIF(w.first_release_date, ''), g.first_release_date, '')::text AS first_release_date
|
|
FROM wants w
|
|
LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid
|
|
WHERE w.id = $1
|
|
`
|
|
|
|
type GetWantForSearchRow struct {
|
|
ID pgtype.UUID
|
|
ReleaseGroupMbid string
|
|
ArtistMbid string
|
|
ArtistName string
|
|
Title string
|
|
Reason string
|
|
FulfilledAt pgtype.Timestamptz
|
|
PrimaryType string
|
|
SecondaryTypes []string
|
|
FirstReleaseDate string
|
|
}
|
|
|
|
func (q *Queries) GetWantForSearch(ctx context.Context, id pgtype.UUID) (GetWantForSearchRow, error) {
|
|
row := q.db.QueryRow(ctx, getWantForSearch, id)
|
|
var i GetWantForSearchRow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.ReleaseGroupMbid,
|
|
&i.ArtistMbid,
|
|
&i.ArtistName,
|
|
&i.Title,
|
|
&i.Reason,
|
|
&i.FulfilledAt,
|
|
&i.PrimaryType,
|
|
&i.SecondaryTypes,
|
|
&i.FirstReleaseDate,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const insertGrab = `-- name: InsertGrab :one
|
|
INSERT INTO grabs (want_id, info_hash, name, key, indexer, source, client, save_path, quality,
|
|
origin, forced, grabbed_by)
|
|
VALUES ($1, $2, $3, $4, $5,
|
|
$6, $7, $8, $9,
|
|
$10, $11, $12)
|
|
RETURNING id, want_id, info_hash, name, key, indexer, source, client, save_path, quality, origin, forced, grabbed_by, grabbed_at, ended_at, end_reason, end_detail, progress, import_state, import_reason, import_detail, import_forced, import_attempts, import_updated_at, imported_at, imported_files, destination, seeding, ratio, seed_released_at
|
|
`
|
|
|
|
type InsertGrabParams struct {
|
|
WantID pgtype.UUID
|
|
InfoHash string
|
|
Name string
|
|
Key string
|
|
Indexer string
|
|
Source string
|
|
Client string
|
|
SavePath string
|
|
Quality string
|
|
Origin string
|
|
Forced bool
|
|
GrabbedBy pgtype.UUID
|
|
}
|
|
|
|
func (q *Queries) InsertGrab(ctx context.Context, arg InsertGrabParams) (Grab, error) {
|
|
row := q.db.QueryRow(ctx, insertGrab,
|
|
arg.WantID,
|
|
arg.InfoHash,
|
|
arg.Name,
|
|
arg.Key,
|
|
arg.Indexer,
|
|
arg.Source,
|
|
arg.Client,
|
|
arg.SavePath,
|
|
arg.Quality,
|
|
arg.Origin,
|
|
arg.Forced,
|
|
arg.GrabbedBy,
|
|
)
|
|
var i Grab
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.WantID,
|
|
&i.InfoHash,
|
|
&i.Name,
|
|
&i.Key,
|
|
&i.Indexer,
|
|
&i.Source,
|
|
&i.Client,
|
|
&i.SavePath,
|
|
&i.Quality,
|
|
&i.Origin,
|
|
&i.Forced,
|
|
&i.GrabbedBy,
|
|
&i.GrabbedAt,
|
|
&i.EndedAt,
|
|
&i.EndReason,
|
|
&i.EndDetail,
|
|
&i.Progress,
|
|
&i.ImportState,
|
|
&i.ImportReason,
|
|
&i.ImportDetail,
|
|
&i.ImportForced,
|
|
&i.ImportAttempts,
|
|
&i.ImportUpdatedAt,
|
|
&i.ImportedAt,
|
|
&i.ImportedFiles,
|
|
&i.Destination,
|
|
&i.Seeding,
|
|
&i.Ratio,
|
|
&i.SeedReleasedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const insertWantCandidate = `-- name: InsertWantCandidate :exec
|
|
INSERT INTO want_candidates (want_id, key, name, info_hash, indexer, source, size_bytes, seeders,
|
|
files_count, format, quality, year, verdict, reason, reasons, folded_from, rank)
|
|
VALUES ($1, $2, $3, $4, $5,
|
|
$6, $7, $8, $9, $10,
|
|
$11, $12, $13, $14, $15,
|
|
$16, $17)
|
|
ON CONFLICT (want_id, key) DO NOTHING
|
|
`
|
|
|
|
type InsertWantCandidateParams struct {
|
|
WantID pgtype.UUID
|
|
Key string
|
|
Name string
|
|
InfoHash string
|
|
Indexer string
|
|
Source string
|
|
SizeBytes int64
|
|
Seeders int32
|
|
FilesCount int32
|
|
Format string
|
|
Quality string
|
|
Year int32
|
|
Verdict string
|
|
Reason string
|
|
Reasons []byte
|
|
FoldedFrom []string
|
|
Rank int32
|
|
}
|
|
|
|
func (q *Queries) InsertWantCandidate(ctx context.Context, arg InsertWantCandidateParams) error {
|
|
_, err := q.db.Exec(ctx, insertWantCandidate,
|
|
arg.WantID,
|
|
arg.Key,
|
|
arg.Name,
|
|
arg.InfoHash,
|
|
arg.Indexer,
|
|
arg.Source,
|
|
arg.SizeBytes,
|
|
arg.Seeders,
|
|
arg.FilesCount,
|
|
arg.Format,
|
|
arg.Quality,
|
|
arg.Year,
|
|
arg.Verdict,
|
|
arg.Reason,
|
|
arg.Reasons,
|
|
arg.FoldedFrom,
|
|
arg.Rank,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const listReleaseBlocks = `-- name: ListReleaseBlocks :many
|
|
SELECT info_hash, name, reason, detail, want_id, blocked_by, blocked_at, expires_at FROM release_blocks
|
|
WHERE expires_at IS NULL OR expires_at > now()
|
|
ORDER BY blocked_at DESC
|
|
`
|
|
|
|
// Every release set aside and still held back: a stalled one lifts by itself
|
|
// at expires_at (#5523).
|
|
func (q *Queries) ListReleaseBlocks(ctx context.Context) ([]ReleaseBlock, error) {
|
|
rows, err := q.db.Query(ctx, listReleaseBlocks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ReleaseBlock
|
|
for rows.Next() {
|
|
var i ReleaseBlock
|
|
if err := rows.Scan(
|
|
&i.InfoHash,
|
|
&i.Name,
|
|
&i.Reason,
|
|
&i.Detail,
|
|
&i.WantID,
|
|
&i.BlockedBy,
|
|
&i.BlockedAt,
|
|
&i.ExpiresAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listWantCandidates = `-- name: ListWantCandidates :many
|
|
SELECT want_id, key, name, info_hash, indexer, source, size_bytes, seeders, files_count, format, quality, year, verdict, reason, reasons, folded_from, rank, searched_at FROM want_candidates WHERE want_id = $1 ORDER BY rank, key
|
|
`
|
|
|
|
func (q *Queries) ListWantCandidates(ctx context.Context, wantID pgtype.UUID) ([]WantCandidate, error) {
|
|
rows, err := q.db.Query(ctx, listWantCandidates, wantID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []WantCandidate
|
|
for rows.Next() {
|
|
var i WantCandidate
|
|
if err := rows.Scan(
|
|
&i.WantID,
|
|
&i.Key,
|
|
&i.Name,
|
|
&i.InfoHash,
|
|
&i.Indexer,
|
|
&i.Source,
|
|
&i.SizeBytes,
|
|
&i.Seeders,
|
|
&i.FilesCount,
|
|
&i.Format,
|
|
&i.Quality,
|
|
&i.Year,
|
|
&i.Verdict,
|
|
&i.Reason,
|
|
&i.Reasons,
|
|
&i.FoldedFrom,
|
|
&i.Rank,
|
|
&i.SearchedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listWantsDueForSearch = `-- name: ListWantsDueForSearch :many
|
|
SELECT w.id, w.release_group_mbid, w.artist_name, w.title, w.reason,
|
|
COALESCE(NULLIF(w.primary_type, ''), g.primary_type, '')::text AS primary_type,
|
|
COALESCE(g.secondary_types, '{}')::text[] AS secondary_types,
|
|
COALESCE(NULLIF(w.first_release_date, ''), g.first_release_date, '')::text AS first_release_date
|
|
FROM wants w
|
|
LEFT JOIN mb_release_groups g ON g.mbid = w.release_group_mbid
|
|
WHERE w.fulfilled_at IS NULL
|
|
AND NOT EXISTS (SELECT 1 FROM grabs gr WHERE gr.want_id = w.id AND gr.ended_at IS NULL)
|
|
AND (w.searched_at IS NULL OR w.searched_at < now() - make_interval(hours => $1::int))
|
|
ORDER BY w.searched_at IS NOT NULL,
|
|
CASE w.reason WHEN 'request' THEN 0 WHEN 'missing' THEN 1 ELSE 2 END,
|
|
w.searched_at NULLS FIRST, w.wanted_at, w.id
|
|
LIMIT $2
|
|
`
|
|
|
|
type ListWantsDueForSearchParams struct {
|
|
Hours int32
|
|
MaxRows int32
|
|
}
|
|
|
|
type ListWantsDueForSearchRow struct {
|
|
ID pgtype.UUID
|
|
ReleaseGroupMbid string
|
|
ArtistName string
|
|
Title string
|
|
Reason string
|
|
PrimaryType string
|
|
SecondaryTypes []string
|
|
FirstReleaseDate string
|
|
}
|
|
|
|
// Open wants with no download running that were never searched or not since
|
|
// @hours ago: never-searched first, then requests, then missing files, then
|
|
// followed artists' releases.
|
|
func (q *Queries) ListWantsDueForSearch(ctx context.Context, arg ListWantsDueForSearchParams) ([]ListWantsDueForSearchRow, error) {
|
|
rows, err := q.db.Query(ctx, listWantsDueForSearch, arg.Hours, arg.MaxRows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListWantsDueForSearchRow
|
|
for rows.Next() {
|
|
var i ListWantsDueForSearchRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.ReleaseGroupMbid,
|
|
&i.ArtistName,
|
|
&i.Title,
|
|
&i.Reason,
|
|
&i.PrimaryType,
|
|
&i.SecondaryTypes,
|
|
&i.FirstReleaseDate,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const markCandidatesBlocked = `-- name: MarkCandidatesBlocked :exec
|
|
UPDATE want_candidates
|
|
SET verdict = 'blocked', reason = $1,
|
|
reasons = jsonb_build_array(jsonb_build_object('kind', 'hard', 'code', 'blocked', 'text', $1::text))
|
|
WHERE info_hash = $2
|
|
`
|
|
|
|
type MarkCandidatesBlockedParams struct {
|
|
Reason string
|
|
InfoHash string
|
|
}
|
|
|
|
func (q *Queries) MarkCandidatesBlocked(ctx context.Context, arg MarkCandidatesBlockedParams) error {
|
|
_, err := q.db.Exec(ctx, markCandidatesBlocked, arg.Reason, arg.InfoHash)
|
|
return err
|
|
}
|
|
|
|
const markCandidatesUnblocked = `-- name: MarkCandidatesUnblocked :exec
|
|
UPDATE want_candidates
|
|
SET verdict = 'review', reason = $1,
|
|
reasons = jsonb_build_array(jsonb_build_object('kind', 'soft', 'code', 'unblocked', 'text', $1::text))
|
|
WHERE info_hash = $2 AND verdict = 'blocked'
|
|
`
|
|
|
|
type MarkCandidatesUnblockedParams struct {
|
|
Reason string
|
|
InfoHash string
|
|
}
|
|
|
|
func (q *Queries) MarkCandidatesUnblocked(ctx context.Context, arg MarkCandidatesUnblockedParams) error {
|
|
_, err := q.db.Exec(ctx, markCandidatesUnblocked, arg.Reason, arg.InfoHash)
|
|
return err
|
|
}
|
|
|
|
const recordSearchPass = `-- name: RecordSearchPass :exec
|
|
UPDATE acquisition_settings SET last_pass_at = now(), last_pass = $1 WHERE id = true
|
|
`
|
|
|
|
func (q *Queries) RecordSearchPass(ctx context.Context, report []byte) error {
|
|
_, err := q.db.Exec(ctx, recordSearchPass, report)
|
|
return err
|
|
}
|
|
|
|
const recordWantSearch = `-- name: RecordWantSearch :exec
|
|
UPDATE wants
|
|
SET searched_at = now(),
|
|
search_outcome = $1,
|
|
search_considered = $2,
|
|
best_release = $3,
|
|
best_verdict = $4,
|
|
search_error = $5,
|
|
updated_at = now()
|
|
WHERE id = $6
|
|
`
|
|
|
|
type RecordWantSearchParams struct {
|
|
Outcome string
|
|
Considered int32
|
|
BestRelease string
|
|
BestVerdict string
|
|
SearchError string
|
|
ID pgtype.UUID
|
|
}
|
|
|
|
func (q *Queries) RecordWantSearch(ctx context.Context, arg RecordWantSearchParams) error {
|
|
_, err := q.db.Exec(ctx, recordWantSearch,
|
|
arg.Outcome,
|
|
arg.Considered,
|
|
arg.BestRelease,
|
|
arg.BestVerdict,
|
|
arg.SearchError,
|
|
arg.ID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const unblockRelease = `-- name: UnblockRelease :execrows
|
|
DELETE FROM release_blocks WHERE info_hash = $1
|
|
`
|
|
|
|
func (q *Queries) UnblockRelease(ctx context.Context, infoHash string) (int64, error) {
|
|
result, err := q.db.Exec(ctx, unblockRelease, infoHash)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected(), nil
|
|
}
|
|
|
|
const updateAcquisitionSettings = `-- name: UpdateAcquisitionSettings :one
|
|
UPDATE acquisition_settings
|
|
SET auto_grab = $1,
|
|
search_interval_hours = $2,
|
|
allowed_qualities = $3,
|
|
import_root = $4,
|
|
seed_ratio = $5,
|
|
seed_days = $6,
|
|
stall_hours = $7,
|
|
updated_at = now()
|
|
WHERE id = true
|
|
RETURNING id, auto_grab, search_interval_hours, allowed_qualities, last_pass_at, last_pass, updated_at, import_root, seed_ratio, seed_days, stall_hours
|
|
`
|
|
|
|
type UpdateAcquisitionSettingsParams struct {
|
|
AutoGrab bool
|
|
SearchIntervalHours int32
|
|
AllowedQualities []string
|
|
ImportRoot string
|
|
SeedRatio float32
|
|
SeedDays int32
|
|
StallHours int32
|
|
}
|
|
|
|
func (q *Queries) UpdateAcquisitionSettings(ctx context.Context, arg UpdateAcquisitionSettingsParams) (AcquisitionSetting, error) {
|
|
row := q.db.QueryRow(ctx, updateAcquisitionSettings,
|
|
arg.AutoGrab,
|
|
arg.SearchIntervalHours,
|
|
arg.AllowedQualities,
|
|
arg.ImportRoot,
|
|
arg.SeedRatio,
|
|
arg.SeedDays,
|
|
arg.StallHours,
|
|
)
|
|
var i AcquisitionSetting
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.AutoGrab,
|
|
&i.SearchIntervalHours,
|
|
&i.AllowedQualities,
|
|
&i.LastPassAt,
|
|
&i.LastPass,
|
|
&i.UpdatedAt,
|
|
&i.ImportRoot,
|
|
&i.SeedRatio,
|
|
&i.SeedDays,
|
|
&i.StallHours,
|
|
)
|
|
return i, err
|
|
}
|