// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

/**
 * AutoDownloadPrefs gates and scores what AutoPickable may choose
 * without asking.  Zero values are permissive: no bitrate window, no
 * size ceiling and no format restriction.
 * 
 * **The window is a rate, not a size.**  It used to be three numbers in
 * megabytes, which cannot mean anything on their own: 300 MB is a
 * generous FLAC single and a suspiciously small boxset, and the user
 * setting the number has no idea which release the pipeline will
 * eventually apply it to.  A bitrate is the same statement normalised
 * by how long the music is, so one number holds across a 9-minute EP
 * and a 3-hour opera — and it is the unit the thing being described is
 * actually measured in.  The runtime is known for every request
 * auto-pick can act on (`Download.Expected` carries per-track lengths,
 * and an anchored request is the only kind that reaches here), so this
 * costs no extra lookup.
 */
export interface AutoDownloadPrefs {
    /**
     * MinKbps and MaxKbps bound the average bitrate auto-pick will
     * grab.  Zero means no bound on that side.  A candidate outside the
     * window is filtered out of auto-pick entirely, not merely scored
     * down — a 96 kbps rip of the right album is not a worse copy the
     * user might accept, it is one they said not to take unattended.
     * 
     * For reference: 320 is the top of MP3, ~500–1000 is FLAC depending
     * on the material, and anything under ~128 is a transcode.
     */
    "minKbps": number;
    "maxKbps": number;

    /**
     * PreferredKbps nudges the score toward a target rate within the
     * window, and breaks the tie when several candidates are equally
     * good matches.  Zero disables the nudge; bitrateFit then returns a
     * neutral value that does not affect ranking.
     */
    "preferredKbps": number;

    /**
     * MaxSizeMB is a hard ceiling on the whole candidate, and it is
     * deliberately still a size.  It answers a different question from
     * the window above — not "is this the quality I want" but "is this
     * going to fill the disk" — and it has to hold even for a candidate
     * whose bitrate cannot be worked out, which is exactly the shape a
     * mislabelled boxset arrives in.  Zero means no ceiling.
     */
    "maxSizeMb": number;

    /**
     * AllowedFormats restricts auto-pick to candidates whose audio
     * files are all in one of these formats.  Empty means no
     * restriction.
     */
    "allowedFormats": Format[] | null;
}

/**
 * Candidate is one acquirable thing a provider found: a Soulseek user's
 * folder, a torrent, a YouTube playlist.  Providers fill the descriptive
 * fields; the ranker fills Match, Quality and Score.
 */
export interface Candidate {
    /**
     * ID is unique within the provider that produced it, and is what
     * gets handed back to Grab.
     */
    "id": string;
    "providerId": number;
    "kind": Kind;

    /**
     * Protocol determines which transport can fetch this.
     */
    "protocol": Protocol;

    /**
     * Descriptive.
     */
    "title": string;
    "artist"?: string;

    /**
     * peer username, indexer name, channel
     */
    "origin"?: string;
    "files": CandidateFile[] | null;
    "totalSize": number;

    /**
     * Health is the provider's own availability signal, normalized to
     * 0..1: seeder count for torrents, free upload slots and queue
     * length for Soulseek.  0.5 when the provider has no signal.
     */
    "health": number;

    /**
     * Scores, filled by the ranker.
     */
    "match": MatchScore;
    "quality": QualityScore;
    "score": number;
}

/**
 * CandidateFile is one file inside a candidate.  Soulseek and torrent
 * results give paths and sizes but no tags, so Format and duration are
 * inferred from the path and size where possible.
 */
export interface CandidateFile {
    "path": string;
    "size": number;
    "format": Format;

    /**
     * kbps, 0 when unknown
     */
    "bitrate"?: number;
    "isAudio": boolean;

    /**
     * expected track position
     */
    "matchedTo"?: number;
}

/**
 * Caps declares which roles a provider fills and which optional
 * behaviours it supports.  The frontend renders controls from this
 * rather than switching on Kind, so a provider that gains resume
 * support later needs no frontend change.
 */
export interface Caps {
    /**
     * Roles.
     */
    "canSearch": boolean;
    "canTransport": boolean;
    "canDelegate": boolean;

    /**
     * CanList marks a provider that keeps a persistent wanted list of
     * its own, which the reconciler mirrors this app's list into.
     */
    "canList": boolean;

    /**
     * Optional behaviours.
     */
    "canResume": boolean;
    "canCancel": boolean;
    "reportsSize": boolean;

    /**
     * Protocols this provider can transport.  Empty for providers that
     * only fetch their own search results.
     */
    "transports": Protocol[] | null;
}

/**
 * Config is a provider's stored settings.  Secret values are not held
 * here — they live in the secrets store keyed by provider ID, so a
 * config blob can be logged or shown in the UI without redaction.
 */
export interface Config {
    "id": number;
    "kind": Kind;
    "name": string;
    "enabled": boolean;
    "priority": number;
    "settings": { [_ in string]?: string } | null;

    /**
     * SetSecrets names which of the descriptor's secret fields already
     * have a stored value, without exposing it.  Populated only when a
     * Config is built for the frontend (see Service.withSecretFlags);
     * empty when read from or written to the store.
     */
    "setSecrets"?: { [_ in string]?: boolean } | null;
}

/**
 * Descriptor is the static, instance-independent description of a
 * provider kind: what it is called, what it can do, and which settings
 * it needs.  The settings page renders its form from this, so a new
 * provider gets a config UI without any frontend work.
 */
export interface Descriptor {
    "kind": Kind;
    "name": string;

    /**
     * Summary is one line explaining what connecting this gets you.
     */
    "summary": string;

    /**
     * Caps are the kind's inherent capabilities, before configuration.
     */
    "caps": Caps;

    /**
     * Fields are the settings the user must supply.
     */
    "fields": Field[] | null;

    /**
     * RequiresExternal names the software the user must run themselves
     * (a slskd daemon, a Lidarr instance), or is empty for providers
     * that need nothing but a binary on PATH.
     */
    "requiresExternal"?: string;
}

/**
 * DownloadItem is one grab attempt, as stored.
 * 
 * deliberate: distinguishes it from download.Download (the attempt) and
 * download.Request (the durable record) at every call site, which a bare
 * "Item" would not.
 */
export interface DownloadItem {
    "id": string;
    "downloadId": string;
    "providerId": number;
    "transportId"?: number;
    "externalId"?: string;
    "candidate": Candidate;
    "state": State;
    "bytesDone": number;
    "bytesTotal": number;
    "error"?: string;
    "createdAt": string;
    "updatedAt": string;
}

/**
 * DownloadView is one row of the downloads list.
 * 
 * would stop reading as "one row of the Downloads list" the moment this
 * package also has a Requests list — see RequestInput/Request nearby.
 */
export interface DownloadView {
    "id": string;

    /**
     * Anchors.  Any may be empty; all empty means free-text.
     */
    "releaseMbid"?: string;
    "releaseGroupMbid"?: string;

    /**
     * RecordingMBID anchors a single-track download.  Its Expected holds
     * exactly that one track, which is what lets a track download be
     * scored — and therefore auto-picked — on the same footing as an
     * album.
     */
    "recordingMbid"?: string;

    /**
     * RequestID links back to the durable Request row this download was
     * raised for or attached to, or 0 for a free-text download with
     * nothing stable to attach to.  The reconciler and manual anchored
     * downloads both write the outcome back through it.
     */
    "requestId"?: number;

    /**
     * Source records where the download came from, for the downloads
     * list.  Empty means "manual".
     */
    "source"?: string;

    /**
     * Display and query text.  Artist/Album are what searches are built
     * from; Query overrides them when the user typed something raw.
     */
    "artist": string;
    "album": string;
    "query"?: string;

    /**
     * Expected is the tracklist the anchor resolves to, used for
     * completeness scoring and for the autotag match at import.  Empty
     * for free-text downloads.
     */
    "expected"?: ExpectedTrack[] | null;

    /**
     * LibraryID is the library imported files belong to.
     */
    "libraryId": number;
    "createdAt": string;
    "state": State;
    "error"?: string;
    "items": DownloadItem[] | null;
}

/**
 * Entity says what a request's MBID names, and is the only type
 * distinction the durable request list makes.
 */
export enum Entity {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Request entity types.
     *
     * EntityArtist is a subscription rather than a thing to fetch: it
     * is never satisfied, and each reconcile expands the artist's
     * discography into child requests.
     */
    EntityArtist = "artist",

    /**
     * EntityReleaseGroup is an album in the abstract — any release of
     * it satisfies the request, which is what a user means by "I want
     * this album".
     */
    EntityReleaseGroup = "release-group",

    /**
     * EntityRelease is one specific edition, used when the user picked
     * a particular pressing.
     */
    EntityRelease = "release",

    /**
     * EntityRecording is a single track.
     */
    EntityRecording = "recording",
};

/**
 * ExpectedTrack is one track of the release the user asked for.
 */
export interface ExpectedTrack {
    "position": number;
    "discNumber": number;
    "title": string;
    "artist": string;
    "lengthMillis": number;
}

/**
 * Field describes one provider setting for the settings form.
 */
export interface Field {
    "key": string;
    "label": string;
    "placeholder"?: string;
    "help"?: string;

    /**
     * Secret marks a value stored in the secrets store rather than the
     * provider config row, and rendered as a password input.
     */
    "secret": boolean;

    /**
     * Path marks a value that names a local filesystem directory, so
     * the settings form can offer a native folder picker beside the
     * text input rather than making the user type or paste it.
     */
    "path": boolean;
    "required": boolean;
    "default"?: string;
}

/**
 * Format is a normalized audio container/codec name.
 */
export enum Format {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Audio formats, ordered by the quality ranking in formatRank.
     */
    FormatUnknown = "",
    FormatFLAC = "flac",
    FormatALAC = "alac",
    FormatWAV = "wav",
    FormatMP3 = "mp3",
    FormatAAC = "aac",
    FormatOGG = "ogg",
    FormatOpus = "opus",
    FormatWMA = "wma",
};

/**
 * Kind identifies a provider implementation.  It is stored in the
 * database and used to look up the constructor in the registry, so
 * values are stable strings and never renamed.
 */
export enum Kind {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Provider kinds.
     */
    KindSlskd = "slskd",
    KindYtDlp = "yt-dlp",
    KindLidarr = "lidarr",
    KindProwlarr = "prowlarr",
    KindQBittorrent = "qbittorrent",
    KindSABnzbd = "sabnzbd",

    /**
     * KindFake is an in-memory provider used by tests.  It is never
     * offered in the UI.
     */
    KindFake = "fake",
};

/**
 * MatchScore answers "is this the release the user asked for?"  It is
 * deliberately separate from QualityScore: a perfect match at 128kbps
 * and a mediocre match in FLAC are different failures, and collapsing
 * them into one number makes the ranking impossible to explain.
 */
export interface MatchScore {
    /**
     * Overall is 0..1.
     */
    "overall": number;

    /**
     * filenames vs expected titles
     */
    "titleFit": number;

    /**
     * path/origin vs expected artist
     */
    "artistFit": number;

    /**
     * folder name vs album title
     */
    "albumFit": number;

    /**
     * audio files vs expected count
     */
    "completeness": number;

    /**
     * Anchored records whether an MBID drove this score.  Unanchored
     * matches are capped, because there is nothing to be right about.
     */
    "anchored": boolean;
}

/**
 * Protocol is how a candidate's bytes are moved.  Search-only providers
 * report it so the pipeline can pick a compatible transport; providers
 * that transport their own results use ProtocolDirect.
 */
export enum Protocol {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Transport protocols.
     *
     * ProtocolDirect means the finding provider also does the fetch.
     */
    ProtocolDirect = "direct",
    ProtocolTorrent = "torrent",
    ProtocolUsenet = "usenet",
};

/**
 * QualityScore answers "is this a good copy?".
 */
export interface QualityScore {
    /**
     * Overall is 0..1.
     */
    "overall": number;

    /**
     * FLAC > V0 > 320 > lower
     */
    "formatRank": number;
    "bitrate": number;

    /**
     * seeders, free slots
     */
    "health": number;

    /**
     * user's per-provider preference
     */
    "priority": number;

    /**
     * BitrateFit is closeness to the preferred *rate*, which is what
     * the auto-download window is expressed in.  It replaced a
     * `SizeFit` measured in megabytes: a size means nothing without
     * knowing how long the music is, so the same number described a
     * generous single and a suspiciously small boxset.
     */
    "bitrateFit": number;

    /**
     * Mixed marks a candidate whose files are not all the same format,
     * which usually means a hand-assembled folder rather than a rip.
     */
    "mixed": boolean;
}

/**
 * Request is one row of the durable request list.
 */
export interface Request {
    "id": number;
    "mbid": string;
    "entity": Entity;
    "libraryId": number;

    /**
     * Artist and Title are display cache only.  Matching always uses
     * the MBID.
     */
    "artist": string;
    "title": string;
    "scope": RequestScope;

    /**
     * Secondary includes compilations, live albums and remixes in an
     * artist request's expansion.
     */
    "secondary": boolean;
    "state": RequestState;

    /**
     * ParentID is set on requests the reconciler derived from an artist
     * subscription.  A request the user pinned directly has none, so
     * removing the artist leaves it alone.
     */
    "parentId"?: number;
    "attempts": number;
    "lastError"?: string;
    "lastTriedAt"?: string;
    "nextTryAt"?: string;

    /**
     * ExternalIDs maps provider row ID (as a string, because JSON
     * object keys are strings) to that provider's own identifier for
     * this request.  Only set for providers that keep a persistent
     * list of their own.
     */
    "externalIds"?: { [_ in string]?: string } | null;
    "createdAt": string;
    "updatedAt": string;
}

/**
 * RequestInput is what the frontend submits to request something.  It
 * is one MBID and the type of thing it names, because that is
 * genuinely all a durable request is.
 */
export interface RequestInput {
    "mbid": string;
    "entity": string;
    "libraryId": number;

    /**
     * Artist and Title are display text only, and optional: the
     * reconciler fills them in from the catalog when the caller has
     * nothing but an MBID.
     */
    "artist": string;
    "title": string;

    /**
     * Scope and Secondary apply to artist requests.
     */
    "scope": string;
    "secondary": boolean;
}

/**
 * RequestScope applies to artist requests only.
 */
export enum RequestScope {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Artist request scopes.
     *
     * ScopeFuture takes only releases first published after the artist
     * was added.  Default, because subscribing to an artist should not
     * silently queue their entire back catalogue.
     */
    ScopeFuture = "future",

    /**
     * ScopeAll backfills the whole discography as well.
     */
    ScopeAll = "all",
};

/**
 * RequestState is where a request sits.  There is deliberately no
 * "failed": an attempt can fail, a request cannot.  A request that has
 * tried and not found anything is still wanted, with attempts and
 * last_error recording why it is taking a while.
 */
export enum RequestState {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Request states.
     *
     * RequestStateWanted is the active state: due for another attempt
     * when its backoff elapses.
     */
    RequestStateWanted = "wanted",

    /**
     * RequestStateSatisfied means the library owns it.  How it got
     * there — downloaded here, ripped, bought elsewhere — does not
     * matter.
     */
    RequestStateSatisfied = "satisfied",

    /**
     * RequestStatePaused is the user saying "keep this on the list but
     * stop trying".
     */
    RequestStatePaused = "paused",
};

/**
 * SearchRequest is what the frontend submits to start a download.
 */
export interface SearchRequest {
    "libraryId": number;
    "releaseMbid": string;
    "releaseGroupMbid": string;
    "artist": string;
    "album": string;
    "query": string;
    "expected": ExpectedTrack[] | null;
}

/**
 * StartResult is what the picker needs after a search.
 */
export interface StartResult {
    "downloadId": string;
    "candidates": Candidate[] | null;

    /**
     * AutoPicked reports that the pipeline already chose and is
     * downloading, so the picker should show progress rather than a
     * list of choices.
     */
    "autoPicked": boolean;
}

/**
 * State is the lifecycle position of a download item.
 */
export enum State {
    /**
     * The Go zero value for the underlying type of the enum.
     */
    $zero = "",

    /**
     * Download item states.  Searching through Importing are live;
     * Complete, Cancelled and Failed are terminal.
     */
    StateSearching = "searching",
    StateFound = "found",
    StateQueued = "queued",
    StateGrabbing = "grabbing",
    StateVerifying = "verifying",
    StateTagging = "tagging",
    StateImporting = "importing",
    StateComplete = "complete",
    StateCancelled = "cancelled",
    StateFailed = "failed",
};

/**
 * Summary reports what a pass did, for logging and for the UI.
 */
export interface Summary {
    /**
     * Expanded is how many child requests artist subscriptions produced.
     */
    "expanded": number;

    /**
     * Satisfied is how many requests the library turned out to own.
     */
    "satisfied": number;

    /**
     * Attempted is how many requests were searched for.
     */
    "attempted": number;

    /**
     * Started is how many of those found a clear enough winner to
     * download unattended.
     */
    "started": number;

    /**
     * Synced is how many requests were pushed to an external list.
     */
    "synced": number;

    /**
     * Waiting is how many requests are on the list and still being
     * looked for.  A pass that did nothing is the normal case, and the
     * UI can only say so honestly if it knows the list was not empty.
     */
    "waiting": number;

    /**
     * NoProviders reports that nothing could be searched because no
     * download client is enabled — the one "nothing happened" the user
     * can actually fix.
     */
    "noProviders": boolean;
}
