feat: autotag scoring overhaul, dump-based explore index, and lyrics search
Consolidates in-progress work across autotag, explore, and library: - autotag: beets/Picard-informed scoring engine — ID-first matching, VA handling, recommendation tiers, and a merged distance/rank cascade, with an eval harness for regression tracking. - explore: offline MusicBrainz dump import/incremental refresh replaces the legacy tier crawl; index-first local search with fuzzy matching and a dedicated ranker; disk-free guards for dump downloads. - library: artist-credit extraction and matching. - lyrics: owned-library lyric search (FTS) with LRCLIB backfill. Also: rewrite README to be user-focused, and migrate upstream to git.ljones.me/yonlu/yellowjacket. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,8 @@ export function GetCandidates(arg1:string):Promise<autotagservice.ScoreView>;
|
||||
|
||||
export function GetCandidatesForPasteURL(arg1:string,arg2:string):Promise<autotagservice.ScoreView>;
|
||||
|
||||
export function GetLocalCoverArt(arg1:string):Promise<string>;
|
||||
|
||||
export function GetNextPending():Promise<autotagservice.PendingItem>;
|
||||
|
||||
export function GetPendingFolder(arg1:string):Promise<autotagservice.PendingItem>;
|
||||
@@ -27,6 +29,10 @@ export function ListPendingFolders(arg1:number):Promise<Array<autotagservice.Pen
|
||||
|
||||
export function RetagGroup(arg1:string):Promise<void>;
|
||||
|
||||
export function SearchCandidates(arg1:string,arg2:string,arg3:string):Promise<Array<autotagservice.SearchHitView>>;
|
||||
|
||||
export function SelectSearchCandidate(arg1:string,arg2:string,arg3:string):Promise<autotagservice.ScoreView>;
|
||||
|
||||
export function SetContext(arg1:context.Context):Promise<void>;
|
||||
|
||||
export function Skip(arg1:string):Promise<void>;
|
||||
|
||||
@@ -30,6 +30,10 @@ export function GetCandidatesForPasteURL(arg1, arg2) {
|
||||
return window['go']['autotagservice']['Service']['GetCandidatesForPasteURL'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function GetLocalCoverArt(arg1) {
|
||||
return window['go']['autotagservice']['Service']['GetLocalCoverArt'](arg1);
|
||||
}
|
||||
|
||||
export function GetNextPending() {
|
||||
return window['go']['autotagservice']['Service']['GetNextPending']();
|
||||
}
|
||||
@@ -50,6 +54,14 @@ export function RetagGroup(arg1) {
|
||||
return window['go']['autotagservice']['Service']['RetagGroup'](arg1);
|
||||
}
|
||||
|
||||
export function SearchCandidates(arg1, arg2, arg3) {
|
||||
return window['go']['autotagservice']['Service']['SearchCandidates'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function SelectSearchCandidate(arg1, arg2, arg3) {
|
||||
return window['go']['autotagservice']['Service']['SelectSearchCandidate'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function SetContext(arg1) {
|
||||
return window['go']['autotagservice']['Service']['SetContext'](arg1);
|
||||
}
|
||||
|
||||
+17
-9
@@ -3,6 +3,8 @@
|
||||
import {explore} from '../models';
|
||||
import {context} from '../models';
|
||||
|
||||
export function BackfillLibraryLyrics():Promise<void>;
|
||||
|
||||
export function BrowseReleaseGroups(arg1:string):Promise<Array<explore.MBReleaseGroup>>;
|
||||
|
||||
export function BrowseReleases(arg1:string):Promise<Array<explore.MBRelease>>;
|
||||
@@ -39,14 +41,16 @@ export function GetThumbnail(arg1:string,arg2:string,arg3:string):Promise<string
|
||||
|
||||
export function GetThumbnails(arg1:Array<explore.ThumbnailRequest>):Promise<Record<string, string>>;
|
||||
|
||||
export function GetTrackLyrics(arg1:number):Promise<explore.TrackLyrics>;
|
||||
|
||||
export function GetTrackThumbnail(arg1:string,arg2:string,arg3:string,arg4:string):Promise<string>;
|
||||
|
||||
export function GetTrackThumbnails(arg1:Array<explore.TrackThumbnailRequest>):Promise<Record<string, string>>;
|
||||
|
||||
export function IndexNewArtists():Promise<void>;
|
||||
|
||||
export function InvalidateIndexDiscographies():Promise<void>;
|
||||
|
||||
export function InvalidateLibrarySync():Promise<void>;
|
||||
|
||||
export function IsIndexReady():Promise<boolean>;
|
||||
|
||||
export function LookupArtist(arg1:string):Promise<explore.MBArtist>;
|
||||
@@ -57,19 +61,23 @@ export function MusicBrainz():Promise<explore.MusicBrainzClient>;
|
||||
|
||||
export function PopulateLocalCrossReferences():Promise<void>;
|
||||
|
||||
export function PopulateLocalCrossReferencesIfNeeded():Promise<void>;
|
||||
|
||||
export function PrefetchReleases(arg1:Array<string>):Promise<void>;
|
||||
|
||||
export function RebuildLyricsIndex():Promise<void>;
|
||||
|
||||
export function RebuildLyricsIndexIfNeeded():Promise<void>;
|
||||
|
||||
export function RecordSearchClick(arg1:string,arg2:string,arg3:string):Promise<void>;
|
||||
|
||||
export function RefreshListenCounts():Promise<void>;
|
||||
|
||||
export function ResolveReleaseGroupMBIDs(arg1:Array<string>):Promise<Record<string, string>>;
|
||||
|
||||
export function Search(arg1:string):Promise<explore.MBSearchResult>;
|
||||
|
||||
export function SearchArtists(arg1:string):Promise<Array<explore.MBArtist>>;
|
||||
|
||||
export function SearchLocal(arg1:string):Promise<explore.MBSearchResult>;
|
||||
|
||||
export function SearchRecordings(arg1:string):Promise<Array<explore.MBRecording>>;
|
||||
|
||||
export function SearchReleaseGroups(arg1:string):Promise<Array<explore.MBReleaseGroup>>;
|
||||
export function SearchLyrics(arg1:string):Promise<Array<explore.LyricsResult>>;
|
||||
|
||||
export function SetContext(arg1:context.Context):Promise<void>;
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function BackfillLibraryLyrics() {
|
||||
return window['go']['explore']['Service']['BackfillLibraryLyrics']();
|
||||
}
|
||||
|
||||
export function BrowseReleaseGroups(arg1) {
|
||||
return window['go']['explore']['Service']['BrowseReleaseGroups'](arg1);
|
||||
}
|
||||
@@ -74,6 +78,10 @@ export function GetThumbnails(arg1) {
|
||||
return window['go']['explore']['Service']['GetThumbnails'](arg1);
|
||||
}
|
||||
|
||||
export function GetTrackLyrics(arg1) {
|
||||
return window['go']['explore']['Service']['GetTrackLyrics'](arg1);
|
||||
}
|
||||
|
||||
export function GetTrackThumbnail(arg1, arg2, arg3, arg4) {
|
||||
return window['go']['explore']['Service']['GetTrackThumbnail'](arg1, arg2, arg3, arg4);
|
||||
}
|
||||
@@ -82,14 +90,14 @@ export function GetTrackThumbnails(arg1) {
|
||||
return window['go']['explore']['Service']['GetTrackThumbnails'](arg1);
|
||||
}
|
||||
|
||||
export function IndexNewArtists() {
|
||||
return window['go']['explore']['Service']['IndexNewArtists']();
|
||||
}
|
||||
|
||||
export function InvalidateIndexDiscographies() {
|
||||
return window['go']['explore']['Service']['InvalidateIndexDiscographies']();
|
||||
}
|
||||
|
||||
export function InvalidateLibrarySync() {
|
||||
return window['go']['explore']['Service']['InvalidateLibrarySync']();
|
||||
}
|
||||
|
||||
export function IsIndexReady() {
|
||||
return window['go']['explore']['Service']['IsIndexReady']();
|
||||
}
|
||||
@@ -110,32 +118,40 @@ export function PopulateLocalCrossReferences() {
|
||||
return window['go']['explore']['Service']['PopulateLocalCrossReferences']();
|
||||
}
|
||||
|
||||
export function PopulateLocalCrossReferencesIfNeeded() {
|
||||
return window['go']['explore']['Service']['PopulateLocalCrossReferencesIfNeeded']();
|
||||
}
|
||||
|
||||
export function PrefetchReleases(arg1) {
|
||||
return window['go']['explore']['Service']['PrefetchReleases'](arg1);
|
||||
}
|
||||
|
||||
export function RebuildLyricsIndex() {
|
||||
return window['go']['explore']['Service']['RebuildLyricsIndex']();
|
||||
}
|
||||
|
||||
export function RebuildLyricsIndexIfNeeded() {
|
||||
return window['go']['explore']['Service']['RebuildLyricsIndexIfNeeded']();
|
||||
}
|
||||
|
||||
export function RecordSearchClick(arg1, arg2, arg3) {
|
||||
return window['go']['explore']['Service']['RecordSearchClick'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function RefreshListenCounts() {
|
||||
return window['go']['explore']['Service']['RefreshListenCounts']();
|
||||
}
|
||||
|
||||
export function ResolveReleaseGroupMBIDs(arg1) {
|
||||
return window['go']['explore']['Service']['ResolveReleaseGroupMBIDs'](arg1);
|
||||
}
|
||||
|
||||
export function Search(arg1) {
|
||||
return window['go']['explore']['Service']['Search'](arg1);
|
||||
}
|
||||
|
||||
export function SearchArtists(arg1) {
|
||||
return window['go']['explore']['Service']['SearchArtists'](arg1);
|
||||
}
|
||||
|
||||
export function SearchLocal(arg1) {
|
||||
return window['go']['explore']['Service']['SearchLocal'](arg1);
|
||||
}
|
||||
|
||||
export function SearchRecordings(arg1) {
|
||||
return window['go']['explore']['Service']['SearchRecordings'](arg1);
|
||||
}
|
||||
|
||||
export function SearchReleaseGroups(arg1) {
|
||||
return window['go']['explore']['Service']['SearchReleaseGroups'](arg1);
|
||||
export function SearchLyrics(arg1) {
|
||||
return window['go']['explore']['Service']['SearchLyrics'](arg1);
|
||||
}
|
||||
|
||||
export function SetContext(arg1) {
|
||||
|
||||
@@ -87,8 +87,11 @@ export namespace autotagservice {
|
||||
export class ScoreBreakdownView {
|
||||
titleAvg: number;
|
||||
lengthAvg: number;
|
||||
artistFit: number;
|
||||
albumFit: number;
|
||||
trackCountFit: number;
|
||||
releaseMeta: number;
|
||||
evidence: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new ScoreBreakdownView(source);
|
||||
@@ -98,8 +101,11 @@ export namespace autotagservice {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.titleAvg = source["titleAvg"];
|
||||
this.lengthAvg = source["lengthAvg"];
|
||||
this.artistFit = source["artistFit"];
|
||||
this.albumFit = source["albumFit"];
|
||||
this.trackCountFit = source["trackCountFit"];
|
||||
this.releaseMeta = source["releaseMeta"];
|
||||
this.evidence = source["evidence"];
|
||||
}
|
||||
}
|
||||
export class CandidateView {
|
||||
@@ -111,6 +117,7 @@ export namespace autotagservice {
|
||||
originalDate: string;
|
||||
country: string;
|
||||
status: string;
|
||||
primaryType: string;
|
||||
trackCount: number;
|
||||
score: number;
|
||||
breakdown: ScoreBreakdownView;
|
||||
@@ -133,6 +140,7 @@ export namespace autotagservice {
|
||||
this.originalDate = source["originalDate"];
|
||||
this.country = source["country"];
|
||||
this.status = source["status"];
|
||||
this.primaryType = source["primaryType"];
|
||||
this.trackCount = source["trackCount"];
|
||||
this.score = source["score"];
|
||||
this.breakdown = this.convertValues(source["breakdown"], ScoreBreakdownView);
|
||||
@@ -224,6 +232,7 @@ export namespace autotagservice {
|
||||
groupKey: string;
|
||||
localTracks: LocalTrackView[];
|
||||
candidates: CandidateView[];
|
||||
recommendation: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new ScoreView(source);
|
||||
@@ -234,6 +243,7 @@ export namespace autotagservice {
|
||||
this.groupKey = source["groupKey"];
|
||||
this.localTracks = this.convertValues(source["localTracks"], LocalTrackView);
|
||||
this.candidates = this.convertValues(source["candidates"], CandidateView);
|
||||
this.recommendation = source["recommendation"];
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
@@ -254,6 +264,26 @@ export namespace autotagservice {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
export class SearchHitView {
|
||||
mbid: string;
|
||||
kind: string;
|
||||
title: string;
|
||||
artist: string;
|
||||
detail: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new SearchHitView(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.mbid = source["mbid"];
|
||||
this.kind = source["kind"];
|
||||
this.title = source["title"];
|
||||
this.artist = source["artist"];
|
||||
this.detail = source["detail"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -345,6 +375,7 @@ export namespace explore {
|
||||
trackName: string;
|
||||
totalListenCount: number;
|
||||
caaReleaseMbid: string;
|
||||
releaseGroupMbid?: string;
|
||||
releaseName: string;
|
||||
length: number;
|
||||
inLibrary: boolean;
|
||||
@@ -361,6 +392,7 @@ export namespace explore {
|
||||
this.trackName = source["trackName"];
|
||||
this.totalListenCount = source["totalListenCount"];
|
||||
this.caaReleaseMbid = source["caaReleaseMbid"];
|
||||
this.releaseGroupMbid = source["releaseGroupMbid"];
|
||||
this.releaseName = source["releaseName"];
|
||||
this.length = source["length"];
|
||||
this.inLibrary = source["inLibrary"];
|
||||
@@ -395,6 +427,28 @@ export namespace explore {
|
||||
this.localId = source["localId"];
|
||||
}
|
||||
}
|
||||
export class LyricsResult {
|
||||
recordingId: number;
|
||||
filePath: string;
|
||||
lengthMs: number;
|
||||
title: string;
|
||||
artist: string;
|
||||
album: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new LyricsResult(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.recordingId = source["recordingId"];
|
||||
this.filePath = source["filePath"];
|
||||
this.lengthMs = source["lengthMs"];
|
||||
this.title = source["title"];
|
||||
this.artist = source["artist"];
|
||||
this.album = source["album"];
|
||||
}
|
||||
}
|
||||
export class MBArtist {
|
||||
mbid: string;
|
||||
name: string;
|
||||
@@ -434,9 +488,13 @@ export namespace explore {
|
||||
title: string;
|
||||
length: number;
|
||||
artistCredit: string;
|
||||
artistMbid?: string;
|
||||
score: number;
|
||||
popularity: number;
|
||||
listenerCount: number;
|
||||
caaReleaseMbid?: string;
|
||||
releaseGroupMbid?: string;
|
||||
releaseName?: string;
|
||||
inLibrary: boolean;
|
||||
localId?: number;
|
||||
|
||||
@@ -450,9 +508,13 @@ export namespace explore {
|
||||
this.title = source["title"];
|
||||
this.length = source["length"];
|
||||
this.artistCredit = source["artistCredit"];
|
||||
this.artistMbid = source["artistMbid"];
|
||||
this.score = source["score"];
|
||||
this.popularity = source["popularity"];
|
||||
this.listenerCount = source["listenerCount"];
|
||||
this.caaReleaseMbid = source["caaReleaseMbid"];
|
||||
this.releaseGroupMbid = source["releaseGroupMbid"];
|
||||
this.releaseName = source["releaseName"];
|
||||
this.inLibrary = source["inLibrary"];
|
||||
this.localId = source["localId"];
|
||||
}
|
||||
@@ -530,6 +592,7 @@ export namespace explore {
|
||||
secondaryTypes?: string[];
|
||||
firstReleaseDate: string;
|
||||
artistCredit: string;
|
||||
artistMbid?: string;
|
||||
popularity: number;
|
||||
listenerCount: number;
|
||||
inLibrary: boolean;
|
||||
@@ -547,6 +610,7 @@ export namespace explore {
|
||||
this.secondaryTypes = source["secondaryTypes"];
|
||||
this.firstReleaseDate = source["firstReleaseDate"];
|
||||
this.artistCredit = source["artistCredit"];
|
||||
this.artistMbid = source["artistMbid"];
|
||||
this.popularity = source["popularity"];
|
||||
this.listenerCount = source["listenerCount"];
|
||||
this.inLibrary = source["inLibrary"];
|
||||
@@ -558,12 +622,16 @@ export namespace explore {
|
||||
mbid: string;
|
||||
name: string;
|
||||
artistCredit?: string;
|
||||
artistMbid?: string;
|
||||
intentScore: number;
|
||||
artistType?: string;
|
||||
country?: string;
|
||||
primaryType?: string;
|
||||
year?: string;
|
||||
length?: number;
|
||||
caaReleaseMbid?: string;
|
||||
releaseGroupMbid?: string;
|
||||
releaseName?: string;
|
||||
inLibrary: boolean;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
@@ -576,12 +644,16 @@ export namespace explore {
|
||||
this.mbid = source["mbid"];
|
||||
this.name = source["name"];
|
||||
this.artistCredit = source["artistCredit"];
|
||||
this.artistMbid = source["artistMbid"];
|
||||
this.intentScore = source["intentScore"];
|
||||
this.artistType = source["artistType"];
|
||||
this.country = source["country"];
|
||||
this.primaryType = source["primaryType"];
|
||||
this.year = source["year"];
|
||||
this.length = source["length"];
|
||||
this.caaReleaseMbid = source["caaReleaseMbid"];
|
||||
this.releaseGroupMbid = source["releaseGroupMbid"];
|
||||
this.releaseName = source["releaseName"];
|
||||
this.inLibrary = source["inLibrary"];
|
||||
}
|
||||
}
|
||||
@@ -664,6 +736,24 @@ export namespace explore {
|
||||
}
|
||||
|
||||
|
||||
export class TrackLyrics {
|
||||
plain: string;
|
||||
synced: string;
|
||||
instrumental: boolean;
|
||||
source: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new TrackLyrics(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.plain = source["plain"];
|
||||
this.synced = source["synced"];
|
||||
this.instrumental = source["instrumental"];
|
||||
this.source = source["source"];
|
||||
}
|
||||
}
|
||||
export class TrackThumbnailRequest {
|
||||
key: string;
|
||||
releaseMbid: string;
|
||||
@@ -693,6 +783,7 @@ export namespace library {
|
||||
ID: number;
|
||||
Name: string;
|
||||
ArtistName: string;
|
||||
ArtistMBID: string;
|
||||
MBID: string;
|
||||
CoverArtPath: string;
|
||||
CoverArtSmall: string;
|
||||
@@ -710,6 +801,7 @@ export namespace library {
|
||||
this.ID = source["ID"];
|
||||
this.Name = source["Name"];
|
||||
this.ArtistName = source["ArtistName"];
|
||||
this.ArtistMBID = source["ArtistMBID"];
|
||||
this.MBID = source["MBID"];
|
||||
this.CoverArtPath = source["CoverArtPath"];
|
||||
this.CoverArtSmall = source["CoverArtSmall"];
|
||||
|
||||
+4
@@ -38,12 +38,16 @@ export function GetPlaylistTracks(arg1:number):Promise<Array<playlist.Track>>;
|
||||
|
||||
export function GetSmartPlaylistRules(arg1:number):Promise<string>;
|
||||
|
||||
export function GetSmartPlaylistTracks(arg1:number):Promise<Array<playlist.Track>>;
|
||||
|
||||
export function ImportPlaylist(arg1:string):Promise<playlist.Summary>;
|
||||
|
||||
export function ImportPlaylists(arg1:Array<string>):Promise<Array<playlist.Summary>>;
|
||||
|
||||
export function PreviewSmartPlaylist(arg1:string):Promise<Array<library.Track>>;
|
||||
|
||||
export function RefreshSmartPlaylist(arg1:number):Promise<void>;
|
||||
|
||||
export function RemoveFromDefaultPlaylist(arg1:Array<string>):Promise<void>;
|
||||
|
||||
export function RemovePhantomTracks(arg1:number,arg2:Array<string>):Promise<void>;
|
||||
|
||||
@@ -70,6 +70,10 @@ export function GetSmartPlaylistRules(arg1) {
|
||||
return window['go']['playlist']['Service']['GetSmartPlaylistRules'](arg1);
|
||||
}
|
||||
|
||||
export function GetSmartPlaylistTracks(arg1) {
|
||||
return window['go']['playlist']['Service']['GetSmartPlaylistTracks'](arg1);
|
||||
}
|
||||
|
||||
export function ImportPlaylist(arg1) {
|
||||
return window['go']['playlist']['Service']['ImportPlaylist'](arg1);
|
||||
}
|
||||
@@ -82,6 +86,10 @@ export function PreviewSmartPlaylist(arg1) {
|
||||
return window['go']['playlist']['Service']['PreviewSmartPlaylist'](arg1);
|
||||
}
|
||||
|
||||
export function RefreshSmartPlaylist(arg1) {
|
||||
return window['go']['playlist']['Service']['RefreshSmartPlaylist'](arg1);
|
||||
}
|
||||
|
||||
export function RemoveFromDefaultPlaylist(arg1) {
|
||||
return window['go']['playlist']['Service']['RemoveFromDefaultPlaylist'](arg1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user