feat(wails): move the frontend onto v3's generated bindings
frontend/wailsjs/ is deleted and frontend/bindings/ takes its place — a real TypeScript module tree nested by Go import path, generated by wails3's static analyser rather than by building the app and running it. The @go alias absorbs the constant prefix, so a call site imports '@go/library/library.js' and the codemod over all 93 sites was a specifier rewrite plus splitting @go/models' namespaces into one import per package. The 12 SetContext bindings and the fake `context` model are gone, as Phase 2's ServiceStartup port promised: 272 methods across 12 services, none of them plumbing. @runtime/runtime is now a local shim (src/wails/runtime.ts) over @wailsio/runtime, so the 22 EventsOn imports are untouched. It unwraps v3's WailsEvent into v2's callback shape, which is exact here: nothing in backend/events passes more than one data argument, and v3 only packs arguments into a slice when there is more than one. v3 tells the truth about two things v2 lied about, and that is most of the diff. A Go nil slice really does arrive as JSON null, and a Go named string type really is an enum; v2 typed them as T[] and string. utils/binding.ts states the app's actual contract — an absent list is an empty list — once, at the boundary where it is true, and also drops the CancellablePromise the app never cancels. Four test fixtures widen an enum field back to its value union. Not done, and Phase 5's to fix: frontend/test/support/wails-fake.ts still fakes window.go, which v3 does not have, so `make ui-test` is broken and harness.test.ts fails to compile on EventsEmit. That test also asserts v2 ordering that no longer holds — v3's Events.Emit calls the backend and does not notify in-page listeners at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as Service from "./service.js";
|
||||
export {
|
||||
Service
|
||||
};
|
||||
|
||||
export {
|
||||
ShelfKind
|
||||
} from "./models.js";
|
||||
|
||||
export type {
|
||||
AlbumCompleteFunc,
|
||||
IndexStatus,
|
||||
LBSimilarArtist,
|
||||
LBTopRecording,
|
||||
LBTopReleaseGroup,
|
||||
LyricsResult,
|
||||
MBArtist,
|
||||
MBRecording,
|
||||
MBRelease,
|
||||
MBReleaseGroup,
|
||||
MBSearchResult,
|
||||
MBTrack,
|
||||
MusicBrainzClient,
|
||||
RateLimiter,
|
||||
Shelf,
|
||||
ShelfPage,
|
||||
ThumbnailRequest,
|
||||
TierStatus,
|
||||
TopResult,
|
||||
TrackLyrics,
|
||||
TrackThumbnailRequest
|
||||
} from "./models.js";
|
||||
@@ -0,0 +1,469 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* AlbumCompleteFunc answers "is the local album with this id complete",
|
||||
* i.e. do its files declare a track total the library actually has.
|
||||
*/
|
||||
export type AlbumCompleteFunc = any;
|
||||
|
||||
/**
|
||||
* IndexStatus is the full index build status, exposed to the frontend.
|
||||
*/
|
||||
export interface IndexStatus {
|
||||
"building": boolean;
|
||||
"ready": boolean;
|
||||
|
||||
/**
|
||||
* RFC3339 timestamp of last complete build
|
||||
*/
|
||||
"lastBuilt"?: string;
|
||||
"tiers": TierStatus[] | null;
|
||||
"artists": number;
|
||||
"recordings": number;
|
||||
"releaseGroups": number;
|
||||
"totalRows": number;
|
||||
}
|
||||
|
||||
/**
|
||||
* LBSimilarArtist represents a similar artist from the
|
||||
* ListenBrainz labs API.
|
||||
*/
|
||||
export interface LBSimilarArtist {
|
||||
"artistMbid": string;
|
||||
"name": string;
|
||||
"score": number;
|
||||
}
|
||||
|
||||
/**
|
||||
* LBTopRecording represents a popular recording from the
|
||||
* ListenBrainz popularity API.
|
||||
*
|
||||
* JSON tags use camelCase for Wails→frontend serialization.
|
||||
* The API response uses snake_case, so we unmarshal into
|
||||
* lbTopRecordingWire first, then convert.
|
||||
*/
|
||||
export interface LBTopRecording {
|
||||
"recordingMbid": string;
|
||||
"artistName": string;
|
||||
"trackName": string;
|
||||
"totalListenCount": number;
|
||||
"caaReleaseMbid": string;
|
||||
|
||||
/**
|
||||
* ReleaseGroupMBID is resolved from CAAReleaseMBID so a top-track
|
||||
* row can link to its album page with the track highlighted.
|
||||
*/
|
||||
"releaseGroupMbid"?: string;
|
||||
"releaseName": string;
|
||||
|
||||
/**
|
||||
* milliseconds (from LB API)
|
||||
*/
|
||||
"length": number;
|
||||
"inLibrary": boolean;
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* LBTopReleaseGroup represents a popular release group from the
|
||||
* ListenBrainz popularity API.
|
||||
*/
|
||||
export interface LBTopReleaseGroup {
|
||||
"releaseGroupMbid": string;
|
||||
"title": string;
|
||||
"artistName": string;
|
||||
"type": string;
|
||||
"date": string;
|
||||
"totalListenCount": number;
|
||||
"caaReleaseMbid": string;
|
||||
"inLibrary": boolean;
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* LyricsResult is a single lyric-search hit, mapped from the DB layer
|
||||
* into the camelCase shape the frontend consumes.
|
||||
*/
|
||||
export interface LyricsResult {
|
||||
"recordingId": number;
|
||||
"filePath": string;
|
||||
"lengthMs": number;
|
||||
"title": string;
|
||||
"artist": string;
|
||||
"album": string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBArtist is a Wails-friendly projection of a MusicBrainz artist.
|
||||
*/
|
||||
export interface MBArtist {
|
||||
"mbid": string;
|
||||
"name": string;
|
||||
"sortName": string;
|
||||
"englishName"?: string;
|
||||
"type": string;
|
||||
"country": string;
|
||||
"disambiguation": string;
|
||||
"score": number;
|
||||
|
||||
/**
|
||||
* raw LB listen count (0 if unknown)
|
||||
*/
|
||||
"popularity": number;
|
||||
"listenerCount": number;
|
||||
|
||||
/**
|
||||
* true if the user owns music by this artist
|
||||
*/
|
||||
"inLibrary": boolean;
|
||||
|
||||
/**
|
||||
* local artist row ID for navigation
|
||||
*/
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBRecording is a Wails-friendly projection of a MusicBrainz
|
||||
* recording.
|
||||
*/
|
||||
export interface MBRecording {
|
||||
"mbid": string;
|
||||
"title": string;
|
||||
"length": number;
|
||||
"artistCredit": string;
|
||||
|
||||
/**
|
||||
* for linking the artist to its detail page
|
||||
*/
|
||||
"artistMbid"?: string;
|
||||
"score": number;
|
||||
|
||||
/**
|
||||
* raw LB listen count (0 if unknown)
|
||||
*/
|
||||
"popularity": number;
|
||||
"listenerCount": number;
|
||||
|
||||
/**
|
||||
* parent release, for album navigation
|
||||
*/
|
||||
"caaReleaseMbid"?: string;
|
||||
|
||||
/**
|
||||
* ReleaseGroupMBID is resolved from CAAReleaseMBID so a track can
|
||||
* link to its album page with the track highlighted, matching how
|
||||
* tracks behave everywhere else.
|
||||
*/
|
||||
"releaseGroupMbid"?: string;
|
||||
|
||||
/**
|
||||
* album title
|
||||
*/
|
||||
"releaseName"?: string;
|
||||
|
||||
/**
|
||||
* true if the user owns this recording
|
||||
*/
|
||||
"inLibrary": boolean;
|
||||
|
||||
/**
|
||||
* local recording row ID
|
||||
*/
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBRelease is a Wails-friendly projection of a MusicBrainz release.
|
||||
*/
|
||||
export interface MBRelease {
|
||||
"mbid": string;
|
||||
"title": string;
|
||||
"date": string;
|
||||
"country": string;
|
||||
"status": string;
|
||||
"artistCredit"?: string;
|
||||
"tracks"?: MBTrack[] | null;
|
||||
|
||||
/**
|
||||
* ReleaseGroupMBID is the parent release group's MBID. Empty unless
|
||||
* the lookup requested the "release-groups" include (LookupRelease
|
||||
* does); used to resolve a release-level MBID (what many taggers
|
||||
* write) back to the release-group MBID everything else on the
|
||||
* album page is keyed by.
|
||||
*/
|
||||
"releaseGroupMbid"?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBReleaseGroup is a Wails-friendly projection of a MusicBrainz
|
||||
* release group.
|
||||
*/
|
||||
export interface MBReleaseGroup {
|
||||
"mbid": string;
|
||||
"title": string;
|
||||
"primaryType": string;
|
||||
"secondaryTypes"?: string[] | null;
|
||||
"firstReleaseDate": string;
|
||||
"artistCredit": string;
|
||||
|
||||
/**
|
||||
* for linking the artist to its detail page
|
||||
*/
|
||||
"artistMbid"?: string;
|
||||
|
||||
/**
|
||||
* raw LB listen count (0 if unknown)
|
||||
*/
|
||||
"popularity": number;
|
||||
"listenerCount": number;
|
||||
|
||||
/**
|
||||
* true if the user owns this album
|
||||
*/
|
||||
"inLibrary": boolean;
|
||||
|
||||
/**
|
||||
* local release_group row ID
|
||||
*/
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBSearchResult aggregates the three searchable entity types
|
||||
* returned by the MusicBrainz search API.
|
||||
*/
|
||||
export interface MBSearchResult {
|
||||
"artists"?: MBArtist[] | null;
|
||||
"releaseGroups"?: MBReleaseGroup[] | null;
|
||||
"recordings"?: MBRecording[] | null;
|
||||
"topResults"?: TopResult[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* MBTrack is a Wails-friendly projection of a MusicBrainz track.
|
||||
*/
|
||||
export interface MBTrack {
|
||||
"position": number;
|
||||
"discNumber": number;
|
||||
"title": string;
|
||||
"length": number;
|
||||
"mbid": string;
|
||||
"inLibrary": boolean;
|
||||
"localId"?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* MusicBrainzClient wraps the musicbrainzws2 library with a local
|
||||
* response cache. Every API call checks the cache first and stores
|
||||
* successful responses for future hits.
|
||||
*
|
||||
* A proactive rate limiter gates all outgoing requests at 1 req/sec
|
||||
* to avoid triggering MusicBrainz 429 responses. The underlying
|
||||
* musicbrainzws2.Client still retries on 429 as a safety net, but
|
||||
* the limiter should prevent most rate-limit hits.
|
||||
*/
|
||||
export interface MusicBrainzClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* RateLimiter enforces a maximum request rate using a token bucket.
|
||||
* MusicBrainz requires ≤1 request per second and rejects ALL
|
||||
* requests (not just excess) when the rate is exceeded, so callers
|
||||
* block proactively via Wait rather than retrying reactively.
|
||||
*
|
||||
* A limiter may carry a second, slower **background lane** (see
|
||||
* WithBackgroundLane). A caller marked by WithBackgroundPriority is
|
||||
* paced by that lane *and* yields to interactive callers: while any
|
||||
* interactive Wait is outstanding, background waits do not take a
|
||||
* token at all. This is what keeps a multi-thousand-request backfill
|
||||
* from putting the album page the user is looking at right now behind
|
||||
* hours of queued work.
|
||||
*
|
||||
* RateLimiter is safe for concurrent use.
|
||||
*/
|
||||
export interface RateLimiter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shelf is one horizontal row on the Explore page.
|
||||
*
|
||||
* A shelf carries albums or artists, never both: they route to
|
||||
* different pages and render as different cards, and a row that is
|
||||
* sometimes one and sometimes the other is two components pretending to
|
||||
* be one.
|
||||
*/
|
||||
export interface Shelf {
|
||||
"id": string;
|
||||
"kind": ShelfKind;
|
||||
|
||||
/**
|
||||
* Title is the row heading.
|
||||
*/
|
||||
"title": string;
|
||||
|
||||
/**
|
||||
* Subtitle says why these are here. As on Home it is not
|
||||
* decoration: without it a shelf is indistinguishable from a
|
||||
* random grid.
|
||||
*/
|
||||
"subtitle": string;
|
||||
"albums"?: MBReleaseGroup[] | null;
|
||||
"artists"?: MBArtist[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ShelfKind identifies what a shelf is built from, so the frontend can
|
||||
* pick an icon and a spec can assert on a shelf without matching
|
||||
* display copy.
|
||||
*/
|
||||
export enum ShelfKind {
|
||||
/**
|
||||
* The Go zero value for the underlying type of the enum.
|
||||
*/
|
||||
$zero = "",
|
||||
|
||||
/**
|
||||
* Shelf kinds.
|
||||
*/
|
||||
ShelfPopularAlbums = "popular-albums",
|
||||
ShelfPopularArtists = "popular-artists",
|
||||
ShelfMoreFromOwned = "more-from-owned",
|
||||
};
|
||||
|
||||
/**
|
||||
* ShelfPage is what Explore renders before a query.
|
||||
*
|
||||
* State exists because "no shelves" has three different causes here and
|
||||
* the page must not present them identically — a blank panel is the bug
|
||||
* this whole feature is fixing, and a blank panel that says nothing
|
||||
* about why is the same bug with more code behind it.
|
||||
*/
|
||||
export interface ShelfPage {
|
||||
"shelves": Shelf[] | null;
|
||||
|
||||
/**
|
||||
* State is one of:
|
||||
*
|
||||
* "ready" — the catalog is here and the shelves are below.
|
||||
* "building" — it is being fetched or built right now.
|
||||
* "no-index" — there is no catalog. Search still works over
|
||||
* whatever is in the index, which may be nothing;
|
||||
* the page says so and points at Settings.
|
||||
*/
|
||||
"state": string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ThumbnailRequest is a single item in a batch thumbnail request.
|
||||
*/
|
||||
export interface ThumbnailRequest {
|
||||
"mbid": string;
|
||||
"albumName": string;
|
||||
"artistName": string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TierStatus represents the state of a single index tier.
|
||||
*/
|
||||
export interface TierStatus {
|
||||
"name": string;
|
||||
|
||||
/**
|
||||
* "pending", "running", "complete", "error", "skipped"
|
||||
*/
|
||||
"state": string;
|
||||
"total": number;
|
||||
"completed": number;
|
||||
"error"?: string;
|
||||
|
||||
/**
|
||||
* Detail is a human-readable progress line for stages whose raw
|
||||
* completed/total numbers say little on their own — the listens
|
||||
* stream reports "42.3 / 205.1 GB · 18 MB/s · ~3h20m left" here.
|
||||
*/
|
||||
"detail"?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TopResult represents a single top-result card shown above the
|
||||
* categorized search lists. Computed by intent scoring after all
|
||||
* reranking is complete.
|
||||
*/
|
||||
export interface TopResult {
|
||||
/**
|
||||
* "artist", "release_group", "recording"
|
||||
*/
|
||||
"entityType": string;
|
||||
"mbid": string;
|
||||
"name": string;
|
||||
|
||||
/**
|
||||
* for tracks/albums
|
||||
*/
|
||||
"artistCredit"?: string;
|
||||
|
||||
/**
|
||||
* for linking the artist subtitle
|
||||
*/
|
||||
"artistMbid"?: string;
|
||||
"intentScore": number;
|
||||
|
||||
/**
|
||||
* Artist-specific
|
||||
* "Group", "Person"
|
||||
*/
|
||||
"artistType"?: string;
|
||||
"country"?: string;
|
||||
|
||||
/**
|
||||
* Album-specific
|
||||
*/
|
||||
"primaryType"?: string;
|
||||
"year"?: string;
|
||||
|
||||
/**
|
||||
* Track-specific. ReleaseGroupMBID is resolved (from CAAReleaseMBID)
|
||||
* so a track click can open its album page with the track highlighted,
|
||||
* matching how tracks behave everywhere else. ReleaseName is the album
|
||||
* title used for the album page header.
|
||||
*/
|
||||
"length"?: number;
|
||||
"caaReleaseMbid"?: string;
|
||||
"releaseGroupMbid"?: string;
|
||||
"releaseName"?: string;
|
||||
|
||||
/**
|
||||
* Library status — populated from index cross-reference columns.
|
||||
*/
|
||||
"inLibrary": boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* TrackLyrics is the stored or freshly-fetched lyrics for one track.
|
||||
* Source is "embedded" (from the file's tags / library DB), "lrclib"
|
||||
* (fetched on demand), or "" when none are available.
|
||||
*/
|
||||
export interface TrackLyrics {
|
||||
"plain": string;
|
||||
"synced": string;
|
||||
"instrumental": boolean;
|
||||
"source": string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TrackThumbnailRequest is a single item in a batch track thumbnail
|
||||
* request. Either ReleaseMBID or ReleaseGroupMBID may be empty;
|
||||
* the proxy tries whichever is present.
|
||||
*/
|
||||
export interface TrackThumbnailRequest {
|
||||
/**
|
||||
* stable key used in the returned map
|
||||
*/
|
||||
"key": string;
|
||||
"releaseMbid": string;
|
||||
"releaseGroupMbid": string;
|
||||
"albumName": string;
|
||||
"artistName": string;
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* Service is the Wails-bound service for the explore feature.
|
||||
* It owns the lifecycle of all explore-related components: the
|
||||
* MusicBrainz client, ListenBrainz client, rate limiter, and
|
||||
* response cache. Its exported methods form the binding surface
|
||||
* that the frontend calls via generated TypeScript stubs.
|
||||
* @module
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import { Call as $Call, CancellablePromise as $CancellablePromise } from "@wailsio/runtime";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as time$0 from "../../../time/models.js";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as jobs$0 from "../jobs/models.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* AdoptPausedIndexBuild re-registers a build paused in a previous
|
||||
* session so it appears in the jobs panel, still paused.
|
||||
*/
|
||||
export function AdoptPausedIndexBuild(): $CancellablePromise<void> {
|
||||
return $Call.ByID(3754928399);
|
||||
}
|
||||
|
||||
/**
|
||||
* BackfillLibraryDiscographies enriches owned artists that have not had
|
||||
* their discography fetched yet, in the background. Idempotent and
|
||||
* bounded — the query only returns unenriched artists and each is marked
|
||||
* discog_fetched on success, so this is cheap (an empty query) once every
|
||||
* owned artist is covered and safe to call on every scan and launch.
|
||||
*/
|
||||
export function BackfillLibraryDiscographies(): $CancellablePromise<void> {
|
||||
return $Call.ByID(3678857155);
|
||||
}
|
||||
|
||||
/**
|
||||
* BackfillLibraryLyrics fetches lyrics from LRCLIB for library tracks
|
||||
* that don't have them, in the background. Idempotent and bounded —
|
||||
* each recording is tried once (a miss is cached), and a run stops
|
||||
* after a fixed number of passes, resuming on the next launch.
|
||||
*/
|
||||
export function BackfillLibraryLyrics(): $CancellablePromise<void> {
|
||||
return $Call.ByID(4204427482);
|
||||
}
|
||||
|
||||
/**
|
||||
* BackfillReleaseGroupMBIDs resolves release groups whose scan only
|
||||
* found a release-level MBID (MUSICBRAINZ_ALBUMID — many taggers write
|
||||
* this instead of, or in addition to, MUSICBRAINZ_RELEASEGROUPID) into
|
||||
* the release-group MBID everything else on the album page is keyed
|
||||
* by. Bounded and resumable, in the background: a scan can't afford a
|
||||
* live MusicBrainz call, so `library.updateMBIDs` stashes the release
|
||||
* MBID in `pending_release_mbid` instead, and this is what resolves it
|
||||
* — the same "defer the network call out of the scan path" shape as
|
||||
* BackfillLibraryDiscographies.
|
||||
*/
|
||||
export function BackfillReleaseGroupMBIDs(): $CancellablePromise<void> {
|
||||
return $Call.ByID(2594807082);
|
||||
}
|
||||
|
||||
/**
|
||||
* BrowseReleaseGroups fetches release groups for a given artist MBID.
|
||||
* Checks the local index first for instant results, then fetches from
|
||||
* MusicBrainz for complete data (secondary types, precise dates).
|
||||
* Also adds results to the search index (Tier 5: organic growth).
|
||||
*/
|
||||
export function BrowseReleaseGroups(artistMBID: string): $CancellablePromise<$models.MBReleaseGroup[] | null> {
|
||||
return $Call.ByID(404562912, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* BrowseReleases fetches releases for a given release group MBID.
|
||||
*
|
||||
* Local-first, non-blocking: a warm response cache is served instantly;
|
||||
* on a miss the request does NOT block on a live MusicBrainz browse
|
||||
* (which pulls every version's full tracklist and can take seconds).
|
||||
* Instead it kicks off a background fetch and returns empty — the
|
||||
* AlbumReleasesReady event signals the caller to re-fetch once the cache
|
||||
* is warm.
|
||||
*/
|
||||
export function BrowseReleases(releaseGroupMBID: string): $CancellablePromise<$models.MBRelease[] | null> {
|
||||
return $Call.ByID(2551207897, releaseGroupMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* CAALimiter returns the shared Cover Art Archive rate limiter.
|
||||
* Consumers must respect it for any fresh CAA HTTP GETs.
|
||||
*/
|
||||
export function CAALimiter(): $CancellablePromise<$models.RateLimiter | null> {
|
||||
return $Call.ByID(1239092428);
|
||||
}
|
||||
|
||||
/**
|
||||
* CheckLibraryMBIDs returns which of the given MBIDs exist in the
|
||||
* local music library. Returns a map of MBID → entity type
|
||||
* ("artist", "release_group", "recording").
|
||||
*
|
||||
* It has no frontend caller — `downloadcatalog.go` is the one consumer,
|
||||
* asking about a single MBID at a time.
|
||||
*/
|
||||
export function CheckLibraryMBIDs(mbids: string[] | null): $CancellablePromise<{ [_ in string]?: string } | null> {
|
||||
return $Call.ByID(3168338597, mbids);
|
||||
}
|
||||
|
||||
/**
|
||||
* CoreCatalogImported reports whether a prebuilt catalog artifact has
|
||||
* been merged into this index.
|
||||
*/
|
||||
export function CoreCatalogImported(): $CancellablePromise<boolean> {
|
||||
return $Call.ByID(186364153);
|
||||
}
|
||||
|
||||
/**
|
||||
* CoverArtGroupURL returns the Cover Art Archive URL for a release
|
||||
* group's front cover at the default 250px size. This is the
|
||||
* correct endpoint for search results, which return release group
|
||||
* MBIDs rather than individual release MBIDs.
|
||||
*/
|
||||
export function CoverArtGroupURL(releaseGroupMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(2102228641, releaseGroupMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* CoverArtURL returns the Cover Art Archive URL for a release's
|
||||
* front cover at the default 250px size.
|
||||
*/
|
||||
export function CoverArtURL(releaseMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(3231496554, releaseMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GenerateMix returns the next batch of tracks for a dynamic-mix queue
|
||||
* fallback, built by expanding the seed's artists to their similar
|
||||
* artists (weighted by how often each appears in the seed, sharpened
|
||||
* by shared genre tags) and restricting candidates to what is actually
|
||||
* in the library — a queue can only play files that exist.
|
||||
*
|
||||
* continuing extends the current mix session — regenerating from its
|
||||
* original seed rather than seedPaths — instead of starting a fresh
|
||||
* one. Pass false whenever the queue that just exhausted was not
|
||||
* itself a mix batch (a real selection just ran out); pass true when
|
||||
* it was (the mix keeps going indefinitely). label names the batch
|
||||
* after its most-represented seed artist, for the "Playing from" UI.
|
||||
*/
|
||||
export function GenerateMix(seedPaths: string[] | null, continuing: boolean): $CancellablePromise<[string[] | null, string]> {
|
||||
return $Call.ByID(4293623744, seedPaths, continuing);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistImageCached returns a base64 data URL for the artist's
|
||||
* photo ONLY if it's already on disk — no MB/Wikidata resolution
|
||||
* or Wikimedia fetch. Returns "" if not cached.
|
||||
*/
|
||||
export function GetArtistImageCached(artistMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(670428351, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistImageCachedPath returns the asset-handler URL path for
|
||||
* the artist's cached medium thumbnail, e.g.
|
||||
* "/artist-images/b1/b10bbbfc-.../primary_md.jpg". No base64, no
|
||||
* network calls — just a disk existence check. Returns "" if no
|
||||
* image is cached.
|
||||
*/
|
||||
export function GetArtistImageCachedPath(artistMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(589683480, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistImageURL returns a base64 data URL for the artist's
|
||||
* photo. Cached on disk — first call resolves via MB/Wikidata and
|
||||
* fetches from Wikimedia Commons, subsequent calls are instant.
|
||||
* Returns "" if no image is available.
|
||||
*/
|
||||
export function GetArtistImageURL(artistMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(1780431074, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistImagesCachedPaths resolves artist portraits for many MBIDs
|
||||
* in one call, returning MBID → asset-handler path for the medium
|
||||
* thumbnail. Disk existence checks only: no MusicBrainz, no Wikidata,
|
||||
* no Wikimedia, no network of any kind. MBIDs with no cached portrait
|
||||
* are omitted rather than returned empty.
|
||||
*
|
||||
* It exists because the resolving entry point (GetArtistImageURL) was
|
||||
* being used where a cache check belonged: a page rendering a dozen
|
||||
* search results paid a full MB → Wikidata → Wikipedia → Wikimedia
|
||||
* resolution for every artist whose portrait was already on disk. Its
|
||||
* predecessor could not serve that — it keyed on artist *name* through
|
||||
* the library's own MBID map, so it only ever answered for artists the
|
||||
* user already owned, which on a catalog search is nearly none of them.
|
||||
*
|
||||
* Paths rather than base64: a portrait is ~128 kB as a data URL, and
|
||||
* the asset handler serves the same bytes without crossing the IPC
|
||||
* boundary or being retained by a JS string.
|
||||
*/
|
||||
export function GetArtistImagesCachedPaths(mbids: string[] | null): $CancellablePromise<{ [_ in string]?: string } | null> {
|
||||
return $Call.ByID(2104788604, mbids);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistMBID returns the MusicBrainz ID for a local library
|
||||
* artist by name, or "" if not found or no MBID tagged.
|
||||
*/
|
||||
export function GetArtistMBID(artistName: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(944736774, artistName);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetArtistPlayCount returns the total LB listen count for an artist.
|
||||
* Returns 0 if unknown.
|
||||
*/
|
||||
export function GetArtistPlayCount(artistMBID: string): $CancellablePromise<number> {
|
||||
return $Call.ByID(143535277, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetCandidateThumbnail returns CAA-only cover art for an autotag
|
||||
* candidate, skipping the library-by-name index so embedded ID3
|
||||
* art on the user's existing files doesn't pollute the candidate
|
||||
* preview. Disk cache → network on RG → network on release.
|
||||
*/
|
||||
export function GetCandidateThumbnail(releaseMBID: string, releaseGroupMBID: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(1946932424, releaseMBID, releaseGroupMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetExploreShelves builds the page Explore shows before a query.
|
||||
*
|
||||
* One call rather than one per shelf, for `home`'s reason: the shelves
|
||||
* share nothing expensive, but the page has nothing useful to render
|
||||
* until it knows which rows exist, and rows that pop in one at a time
|
||||
* reflow under the cursor.
|
||||
*/
|
||||
export function GetExploreShelves(): $CancellablePromise<$models.ShelfPage> {
|
||||
return $Call.ByID(144329614);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetIndexStatus returns the current search index build status.
|
||||
*/
|
||||
export function GetIndexStatus(): $CancellablePromise<$models.IndexStatus> {
|
||||
return $Call.ByID(3481063523);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLibrarySimilarArtists returns similar artists to the given
|
||||
* MBID that are also in the user's local library. Uses the
|
||||
* pre-computed similar_artist_map table (populated during Tier 4
|
||||
* index build) joined with the artists table. No API calls.
|
||||
*
|
||||
* The artists table allows multiple rows with the same MBID
|
||||
* (different artist credits like "A feat. B" that resolve to the
|
||||
* same MB artist), so we use EXISTS instead of JOIN to avoid
|
||||
* duplicating similar_artist_map rows.
|
||||
*/
|
||||
export function GetLibrarySimilarArtists(artistMBID: string): $CancellablePromise<$models.LBSimilarArtist[] | null> {
|
||||
return $Call.ByID(104313157, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetThumbnail returns a base64 data URL for the release group's
|
||||
* cover art. Checks local library art first (by album+artist
|
||||
* name), then disk cache, then Cover Art Archive.
|
||||
* Returns "" if no cover art is available.
|
||||
*/
|
||||
export function GetThumbnail(releaseGroupMBID: string, albumName: string, artistName: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(4046192225, releaseGroupMBID, albumName, artistName);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetThumbnails fetches multiple thumbnails in one call and returns
|
||||
* a map of MBID → base64 data URL. Entries with no art are omitted.
|
||||
* GetThumbnails returns ONLY cached/local art instantly — no network
|
||||
* fetches. For items missing from the cache, the frontend should
|
||||
* call GetThumbnail() individually so results stream in rather than
|
||||
* blocking on a batch.
|
||||
*/
|
||||
export function GetThumbnails(requests: $models.ThumbnailRequest[] | null): $CancellablePromise<{ [_ in string]?: string } | null> {
|
||||
return $Call.ByID(3124819542, requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetTrackLyrics returns lyrics for a recording. If the library
|
||||
* already has them (from embedded tags) they're returned as-is;
|
||||
* otherwise it fetches from LRCLIB, persists them (updating the FTS
|
||||
* index), and returns them. Never returns an error to the frontend —
|
||||
* a miss just yields an empty result.
|
||||
*/
|
||||
export function GetTrackLyrics(recordingID: number): $CancellablePromise<$models.TrackLyrics> {
|
||||
return $Call.ByID(1131284622, recordingID);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetTrackThumbnail returns cover art for a track. Accepts both
|
||||
* the track's CAA release MBID and the resolved parent release
|
||||
* group MBID (either may be empty). Tries the RG first to reuse
|
||||
* discography cache; falls back to the release-level CAA endpoint
|
||||
* when the RG isn't known — useful when the track's preferred CAA
|
||||
* release doesn't belong to any RG currently in the index.
|
||||
*/
|
||||
export function GetTrackThumbnail(releaseMBID: string, releaseGroupMBID: string, albumName: string, artistName: string): $CancellablePromise<string> {
|
||||
return $Call.ByID(4191599666, releaseMBID, releaseGroupMBID, albumName, artistName);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetTrackThumbnails returns ONLY cached/local art for track
|
||||
* requests, keyed by the caller-provided Key so callers can map
|
||||
* results back to rows in their UI.
|
||||
*/
|
||||
export function GetTrackThumbnails(requests: $models.TrackThumbnailRequest[] | null): $CancellablePromise<{ [_ in string]?: string } | null> {
|
||||
return $Call.ByID(2383043155, requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* IndexBaselineSeries returns the incremental listens series the index's
|
||||
* popularity is caught up to. A change across a refresh means new data
|
||||
* was folded in.
|
||||
*/
|
||||
export function IndexBaselineSeries(): $CancellablePromise<number> {
|
||||
return $Call.ByID(3317566669);
|
||||
}
|
||||
|
||||
/**
|
||||
* IndexImportComplete reports whether the dump import has finished all
|
||||
* of its stages. Distinct from IsIndexReady, which only means the index
|
||||
* holds enough rows to answer queries — a partially imported index is
|
||||
* ready but not complete. Used by the headless builder to decide
|
||||
* whether another run is needed.
|
||||
*/
|
||||
export function IndexImportComplete(): $CancellablePromise<boolean> {
|
||||
return $Call.ByID(3872948181);
|
||||
}
|
||||
|
||||
/**
|
||||
* IndexLastImported returns when the dump import last completed, or the
|
||||
* zero time if it never has.
|
||||
*/
|
||||
export function IndexLastImported(): $CancellablePromise<string> {
|
||||
return $Call.ByID(1889359471);
|
||||
}
|
||||
|
||||
/**
|
||||
* InvalidateIndexDiscographies clears the discography build
|
||||
* timestamp so the next index build re-runs Tiers 2-4. Call
|
||||
* after a library rescan that may have populated new MBIDs.
|
||||
*/
|
||||
export function InvalidateIndexDiscographies(): $CancellablePromise<void> {
|
||||
return $Call.ByID(2573191521);
|
||||
}
|
||||
|
||||
/**
|
||||
* InvalidateLibrarySync clears the "ready" markers guarding the gated
|
||||
* library-sync steps so they re-run on the next launch. Call after a
|
||||
* mutation that changes owned content outside a scan (e.g. removing a
|
||||
* library), which would otherwise leave stale in_library flags and
|
||||
* orphaned lyric-index rows.
|
||||
*/
|
||||
export function InvalidateLibrarySync(): $CancellablePromise<void> {
|
||||
return $Call.ByID(2446309672);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsIndexReady returns true once the index has been populated.
|
||||
*/
|
||||
export function IsIndexReady(): $CancellablePromise<boolean> {
|
||||
return $Call.ByID(1366461294);
|
||||
}
|
||||
|
||||
/**
|
||||
* LookupArtist fetches a single MusicBrainz artist by MBID.
|
||||
* Checks the local index first — has name, type, country,
|
||||
* disambiguation, sort_name for indexed artists. Falls back to
|
||||
* MB API for unknown artists and backfills the index for next time.
|
||||
*/
|
||||
export function LookupArtist(mbid: string): $CancellablePromise<$models.MBArtist | null> {
|
||||
return $Call.ByID(3986196952, mbid);
|
||||
}
|
||||
|
||||
/**
|
||||
* LookupReleaseGroup fetches a single MusicBrainz release group by MBID.
|
||||
*/
|
||||
export function LookupReleaseGroup(mbid: string): $CancellablePromise<$models.MBReleaseGroup | null> {
|
||||
return $Call.ByID(2946174711, mbid);
|
||||
}
|
||||
|
||||
/**
|
||||
* MusicBrainz returns the shared cached MB client so other services
|
||||
* (e.g. autotag) can reuse it without spinning up a second limiter.
|
||||
*/
|
||||
export function MusicBrainz(): $CancellablePromise<$models.MusicBrainzClient | null> {
|
||||
return $Call.ByID(3453528034);
|
||||
}
|
||||
|
||||
/**
|
||||
* PopulateLocalCrossReferences updates the local_*_id columns on
|
||||
* explore_index after a library scan.
|
||||
*/
|
||||
export function PopulateLocalCrossReferences(): $CancellablePromise<void> {
|
||||
return $Call.ByID(1058376024);
|
||||
}
|
||||
|
||||
/**
|
||||
* PopulateLocalCrossReferencesIfNeeded runs the library→index sync only
|
||||
* when it has not run since the last library change. Use it on the
|
||||
* unchanged-library launch path so the write-heavy re-sync is skipped in
|
||||
* steady state; the scan-completion path calls the unconditional form.
|
||||
*/
|
||||
export function PopulateLocalCrossReferencesIfNeeded(): $CancellablePromise<void> {
|
||||
return $Call.ByID(814782146);
|
||||
}
|
||||
|
||||
/**
|
||||
* PrefetchReleases warms the local response cache for a set of release
|
||||
* groups in the background so opening any of them is instant. Called from
|
||||
* the artist page once its top-releases / discography render — album
|
||||
* navigation almost always originates there. Already-cached groups are
|
||||
* skipped; a cap bounds how many live fetches a single artist view can
|
||||
* trigger so the MusicBrainz rate limiter isn't flooded.
|
||||
* A release group the user owns *completely* is skipped outright: since
|
||||
* tag-derived completeness landed, such an album opens with no catalog
|
||||
* call at all — identity from its MBID, tracklist from its own files —
|
||||
* so warming the most expensive request in the app on its behalf buys
|
||||
* nothing. The skip is not merely an optimisation; those slots go to
|
||||
* albums that will actually need the browse.
|
||||
*/
|
||||
export function PrefetchReleases(releaseGroupMBIDs: string[] | null): $CancellablePromise<void> {
|
||||
return $Call.ByID(306872972, releaseGroupMBIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* PrepareIndexRebuild clears the completion marker so the next build
|
||||
* re-imports from the newest published dump.
|
||||
*/
|
||||
export function PrepareIndexRebuild(): $CancellablePromise<void> {
|
||||
return $Call.ByID(2772457219);
|
||||
}
|
||||
|
||||
/**
|
||||
* RebuildLyricsIndex rebuilds the FTS lyrics index from the current
|
||||
* library. Cheap; safe to call after every scan.
|
||||
*/
|
||||
export function RebuildLyricsIndex(): $CancellablePromise<void> {
|
||||
return $Call.ByID(300335776);
|
||||
}
|
||||
|
||||
/**
|
||||
* RebuildLyricsIndexIfNeeded rebuilds the lyrics FTS only when it has not
|
||||
* been built since the last library change. The backfill keeps the index
|
||||
* in sync incrementally thereafter, so on an unchanged library the full
|
||||
* rebuild is redundant; the scan-completion path calls the unconditional
|
||||
* form.
|
||||
*/
|
||||
export function RebuildLyricsIndexIfNeeded(): $CancellablePromise<void> {
|
||||
return $Call.ByID(1447291626);
|
||||
}
|
||||
|
||||
/**
|
||||
* RecordSearchClick records that the user clicked a search result.
|
||||
* Called from the frontend when any search result is clicked.
|
||||
*/
|
||||
export function RecordSearchClick(query: string, mbid: string, entityType: string): $CancellablePromise<void> {
|
||||
return $Call.ByID(824485756, query, mbid, entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* RefreshIndexNow folds newly published incremental listens dumps into
|
||||
* the index synchronously. Pass 0 to bypass the cadence gate.
|
||||
*/
|
||||
export function RefreshIndexNow(minInterval: time$0.Duration): $CancellablePromise<void> {
|
||||
return $Call.ByID(4165220556, minInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* RefreshListenCounts folds any newly-published incremental listen dumps
|
||||
* into the index's popularity numbers, in the background. No-op when
|
||||
* offline, when a full build is running, when there is no baseline
|
||||
* import, or when the last refresh was within the weekly cadence. Fully
|
||||
* local — downloads the small daily dumps but makes no ListenBrainz API
|
||||
* calls.
|
||||
*/
|
||||
export function RefreshListenCounts(): $CancellablePromise<void> {
|
||||
return $Call.ByID(3813092323);
|
||||
}
|
||||
|
||||
/**
|
||||
* ResolveReleaseGroupMBIDs takes a list of CAA release MBIDs (from
|
||||
* recording metadata) and returns a map of release MBID → release
|
||||
* group MBID. The frontend uses this to fetch track cover art via
|
||||
* the parent release group, reusing whatever cache exists for the
|
||||
* album already.
|
||||
*/
|
||||
export function ResolveReleaseGroupMBIDs(caaReleaseMBIDs: string[] | null): $CancellablePromise<{ [_ in string]?: string } | null> {
|
||||
return $Call.ByID(325093206, caaReleaseMBIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* SearchLocal queries only the local FTS5 index and returns fully
|
||||
* ranked results instantly with no network calls. This is the
|
||||
* primary interactive search path: now that the index is populated
|
||||
* from the MetaBrainz dumps it covers essentially every popular
|
||||
* entity, so the frontend drives search entirely from here. The
|
||||
* old MusicBrainz network pipeline (Search) is retained for a future
|
||||
* opt-in "search online" affordance but is no longer called on the
|
||||
* hot path.
|
||||
*
|
||||
* Returns nil if the index has no hits for the query, so the caller
|
||||
* can fall back to whatever owned-library matches it already has.
|
||||
*/
|
||||
export function SearchLocal(query: string): $CancellablePromise<$models.MBSearchResult | null> {
|
||||
return $Call.ByID(189423736, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* SearchLyrics finds library tracks whose lyrics contain the given
|
||||
* fragment, ranked by relevance. Pure local FTS — no network.
|
||||
*/
|
||||
export function SearchLyrics(query: string): $CancellablePromise<$models.LyricsResult[] | null> {
|
||||
return $Call.ByID(4153164053, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* SetAlbumComplete injects the completeness check. It is injected
|
||||
* rather than imported because `library` and `explore` do not depend on
|
||||
* each other in either direction today, and one prefetch heuristic is
|
||||
* not a reason to introduce that edge — the alternative, re-deriving
|
||||
* "complete" from SQL here, would be a second definition of it.
|
||||
*/
|
||||
export function SetAlbumComplete(fn: $models.AlbumCompleteFunc): $CancellablePromise<void> {
|
||||
return $Call.ByID(942474493, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* SetJobRegistry wires the background job registry into the search
|
||||
* index so its build reports progress and controls to the frontend.
|
||||
*/
|
||||
export function SetJobRegistry(reg: jobs$0.Registry | null): $CancellablePromise<void> {
|
||||
return $Call.ByID(4291900709, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* SimilarArtists returns artists similar to the given artist MBID.
|
||||
*/
|
||||
export function SimilarArtists(artistMBID: string): $CancellablePromise<$models.LBSimilarArtist[] | null> {
|
||||
return $Call.ByID(2048211426, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* StartIndexBuild kicks off the background search index build.
|
||||
* Call this after the library scan completes so the indexer doesn't
|
||||
* starve the scan for DB access.
|
||||
*/
|
||||
export function StartIndexBuild(): $CancellablePromise<void> {
|
||||
return $Call.ByID(1444396415);
|
||||
}
|
||||
|
||||
/**
|
||||
* StopIndexBuild cancels the background search index build.
|
||||
* Call before a full rescan to free the DB for the scan.
|
||||
*/
|
||||
export function StopIndexBuild(): $CancellablePromise<void> {
|
||||
return $Call.ByID(3056245285);
|
||||
}
|
||||
|
||||
/**
|
||||
* TopRecordingsForArtist returns the most-listened recordings for an
|
||||
* artist. Serves instantly from the local index when available; when the
|
||||
* artist isn't indexed yet it returns empty immediately and fetches the
|
||||
* discography in the background, emitting ArtistDiscographyReady so the
|
||||
* caller can re-fetch — the request never blocks on a live fetch.
|
||||
*/
|
||||
export function TopRecordingsForArtist(artistMBID: string): $CancellablePromise<$models.LBTopRecording[] | null> {
|
||||
return $Call.ByID(2077579960, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* TopReleaseGroupsForArtist returns the most-listened release groups for
|
||||
* an artist. Same non-blocking contract as TopRecordingsForArtist: index
|
||||
* hit is instant, a miss kicks off a background discography fetch and
|
||||
* returns empty, and ArtistDiscographyReady signals when to re-fetch.
|
||||
*/
|
||||
export function TopReleaseGroupsForArtist(artistMBID: string): $CancellablePromise<$models.LBTopReleaseGroup[] | null> {
|
||||
return $Call.ByID(602197643, artistMBID);
|
||||
}
|
||||
|
||||
/**
|
||||
* WaitForIndexIdle blocks until no index build or artist indexing
|
||||
* goroutine is running. Does not cancel a running build.
|
||||
*/
|
||||
export function WaitForIndexIdle(): $CancellablePromise<void> {
|
||||
return $Call.ByID(3200929511);
|
||||
}
|
||||
Reference in New Issue
Block a user