getArtistInfo/2 and getAlbumInfo/2 now return a real MusicBrainz disambiguation/cover-art lookup for entities that carry a locally tagged MusicBrainz ID, gated behind the new VIBESONIC_ENABLE_EXTERNAL_METADATA flag (default off). Responses are cached in the existing external_metadata_cache table for 30 days to avoid hammering the free MusicBrainz/CAA services. VibeSonic still works completely offline: with the flag off, or when an entity has no tagged MusicBrainz ID, or on any network/lookup failure, the handlers fall back to local-only fields exactly as before — nothing is ever fabricated, and a failed external lookup never fails the request. internal/metadataenrich is a small, independently-testable HTTP client for the two real APIs (base URLs overridable for tests, exercised against httptest servers rather than the live network). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014r98AtcBbevpscWLsfwVvv
40 lines
1.5 KiB
Go
40 lines
1.5 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"time"
|
|
|
|
"git.noroutes.net/NoRoutes/vibetunes/internal/idgen"
|
|
)
|
|
|
|
// GetCachedExternalMetadata returns a previously fetched MusicBrainz/
|
|
// Cover Art Archive response for (entityType, mbid, source), if any.
|
|
// found is false when nothing has been cached yet — callers decide
|
|
// whether/how to refresh, this layer never guesses an age-based expiry.
|
|
func GetCachedExternalMetadata(db *sql.DB, entityType, mbid, source string) (dataJSON string, fetchedAt time.Time, found bool, err error) {
|
|
var fetchedAtStr string
|
|
err = db.QueryRow(`SELECT data_json, fetched_at FROM external_metadata_cache WHERE entity_type = ? AND mbid = ? AND source = ?`,
|
|
entityType, mbid, source).Scan(&dataJSON, &fetchedAtStr)
|
|
if err == sql.ErrNoRows {
|
|
return "", time.Time{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return "", time.Time{}, false, err
|
|
}
|
|
fetchedAt, _ = time.Parse("2006-01-02T15:04:05.000Z", fetchedAtStr)
|
|
return dataJSON, fetchedAt, true, nil
|
|
}
|
|
|
|
// PutCachedExternalMetadata stores (or replaces) the cached response
|
|
// for (entityType, mbid, source).
|
|
func PutCachedExternalMetadata(db *sql.DB, entityType, mbid, source, dataJSON string) error {
|
|
_, err := db.Exec(`
|
|
INSERT INTO external_metadata_cache (id, entity_type, mbid, source, data_json, fetched_at)
|
|
VALUES (?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
ON CONFLICT(entity_type, mbid, source) DO UPDATE SET
|
|
data_json = excluded.data_json,
|
|
fetched_at = excluded.fetched_at`,
|
|
idgen.New("emc"), entityType, mbid, source, dataJSON)
|
|
return err
|
|
}
|