feat: autotag mixed-bag splitting, search relevance fixes, and multi-library download imports
Build & publish Arch package / arch-package (push) Successful in 2m2s
Search index maintenance / maintain-index (push) Successful in 7s

Autotag: detect "junk drawer" folders with no artist/album consensus
and split them into synthetic per-cluster groups instead of forcing
one match on an unrelated pile of tracks; repair tagging_items rows
left behind by a prior scan orphan-cleanup gap.

Explore: fix an exact artist-name search being drowned out by its own
catalog entries in intent-prior scoring, and prune stale in_library
bookkeeping left behind when a referenced library row is deleted.

Download: fix a multi-library regression where every import failed
with "no library root configured" — the importer resolved the
library root from a legacy single-library config field that nothing
populates in the current multi-library model. It now resolves the
destination library per-request from the request's own library_id.
Also widen the Soulseek search window (12s -> 20s), measured against
real request history to be missing available peers on live queries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Agd9af5hE7qzti2ackiS
This commit is contained in:
2026-08-10 11:52:26 -04:00
co-authored by Claude Sonnet 5
parent e190fd75b9
commit cbd82a5a74
70 changed files with 3617 additions and 129 deletions
+2
View File
@@ -37,6 +37,8 @@ export function SetContext(arg1:context.Context):Promise<void>;
export function Skip(arg1:string):Promise<void>;
export function SplitMixedFolder(arg1:string):Promise<Array<autotagservice.PendingItem>>;
export function StartAutotagQueue(arg1:number):Promise<void>;
export function StartBackgroundPrefetch():Promise<void>;
@@ -70,6 +70,10 @@ export function Skip(arg1) {
return window['go']['autotagservice']['Service']['Skip'](arg1);
}
export function SplitMixedFolder(arg1) {
return window['go']['autotagservice']['Service']['SplitMixedFolder'](arg1);
}
export function StartAutotagQueue(arg1) {
return window['go']['autotagservice']['Service']['StartAutotagQueue'](arg1);
}
+2
View File
@@ -57,6 +57,8 @@ export function IsScanActive():Promise<boolean>;
export function IsScanPaused():Promise<boolean>;
export function LibraryPath(arg1:number):Promise<string>;
export function PauseScan():Promise<void>;
export function QueuedLibraryNames():Promise<Array<string>>;
+4
View File
@@ -106,6 +106,10 @@ export function IsScanPaused() {
return window['go']['library']['Library']['IsScanPaused']();
}
export function LibraryPath(arg1) {
return window['go']['library']['Library']['LibraryPath'](arg1);
}
export function PauseScan() {
return window['go']['library']['Library']['PauseScan']();
}
+12
View File
@@ -207,6 +207,8 @@ export namespace autotagservice {
bestMatchReleaseMbid: string;
score: number;
status: string;
synthetic: boolean;
likelyMixedBag: boolean;
static createFrom(source: any = {}) {
return new PendingItem(source);
@@ -225,6 +227,8 @@ export namespace autotagservice {
this.bestMatchReleaseMbid = source["bestMatchReleaseMbid"];
this.score = source["score"];
this.status = source["status"];
this.synthetic = source["synthetic"];
this.likelyMixedBag = source["likelyMixedBag"];
}
}
@@ -233,6 +237,8 @@ export namespace autotagservice {
localTracks: LocalTrackView[];
candidates: CandidateView[];
recommendation: string;
mixedBag: boolean;
synthetic: boolean;
static createFrom(source: any = {}) {
return new ScoreView(source);
@@ -244,6 +250,8 @@ export namespace autotagservice {
this.localTracks = this.convertValues(source["localTracks"], LocalTrackView);
this.candidates = this.convertValues(source["candidates"], CandidateView);
this.recommendation = source["recommendation"];
this.mixedBag = source["mixedBag"];
this.synthetic = source["synthetic"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {
@@ -443,6 +451,7 @@ export namespace download {
enabled: boolean;
priority: number;
settings: Record<string, string>;
setSecrets?: Record<string, boolean>;
static createFrom(source: any = {}) {
return new Config(source);
@@ -456,6 +465,7 @@ export namespace download {
this.enabled = source["enabled"];
this.priority = source["priority"];
this.settings = source["settings"];
this.setSecrets = source["setSecrets"];
}
}
export class Field {
@@ -464,6 +474,7 @@ export namespace download {
placeholder?: string;
help?: string;
secret: boolean;
path: boolean;
required: boolean;
default?: string;
@@ -478,6 +489,7 @@ export namespace download {
this.placeholder = source["placeholder"];
this.help = source["help"];
this.secret = source["secret"];
this.path = source["path"];
this.required = source["required"];
this.default = source["default"];
}