package coverart import ( "context" "errors" "sync/atomic" ) // mbcaaProvider implements Provider, AlbumCoverProvider, and // TestableProvider. It wraps an *Fetcher (the existing // MBCAA-specific HTTP client) for the actual fetch logic, adapting // the Fetcher's Fetch method to the AlbumCoverProvider interface. // // The wrapping (rather than reimplementing) is temporary: A-T8 will // consolidate fetcher.go's logic into this file and delete fetcher.go. // During the T4–T8 window, this struct lets the new provider chain // coexist with the legacy Fetcher used by enricher.go and main.go. type mbcaaProvider struct { fetcher *Fetcher enabled atomic.Bool } // Sample MBID used by TestConnection. The Beatles' "Abbey Road" UK // release; verified present on MBCAA at design time. Both 200 (image // returned) and 404 (no art for the sample) are treated as "connection // works" since MBCAA needs no auth — only network failures surface. const mbcaaTestSampleMBID = "f4b3df80-8a6c-3e87-b51e-5c1ee70a78ee" func init() { // Register with a default-config Fetcher. main.go (in A-T8) will // call NewMBCAAProviderFromConfig to swap in the production // User-Agent + MinPeriod. Default config values come from // FetcherConfig's zero-value handling in NewFetcher. Register(&mbcaaProvider{ fetcher: NewFetcher(FetcherConfig{}), }) } // NewMBCAAProviderFromConfig replaces the registered MBCAA provider's // internal Fetcher with one built from the supplied config. main.go // calls this at boot to set the production User-Agent. Idempotent; // safe to call repeatedly. func NewMBCAAProviderFromConfig(cfg FetcherConfig) { p, err := ProviderByID("mbcaa") if err != nil { // init() should have registered it; if not, register fresh. Register(&mbcaaProvider{fetcher: NewFetcher(cfg)}) return } mp, ok := p.(*mbcaaProvider) if !ok { // Some other provider claimed the "mbcaa" ID — registry bug. panic("coverart: provider with ID 'mbcaa' is not *mbcaaProvider") } mp.fetcher = NewFetcher(cfg) } func (p *mbcaaProvider) ID() string { return "mbcaa" } func (p *mbcaaProvider) DisplayName() string { return "Cover Art Archive" } func (p *mbcaaProvider) RequiresAPIKey() bool { return false } func (p *mbcaaProvider) DefaultEnabled() bool { return true } func (p *mbcaaProvider) Configure(s ProviderSettings) error { p.enabled.Store(s.Enabled) return nil // MBCAA has no per-operator config beyond enabled } // FetchAlbumCover delegates to the wrapped Fetcher. The Fetcher's // existing Fetch method already returns ErrNotFound / ErrTransient // per the contract, so no error mapping is needed. func (p *mbcaaProvider) FetchAlbumCover(ctx context.Context, mbid string) ([]byte, error) { if !p.enabled.Load() { return nil, ErrNotFound // defensive; enricher already filters on enabled } return p.fetcher.Fetch(ctx, mbid) } // TestConnection hits the sample MBID's front-500 endpoint. A 200 // (image bytes) or 404 (no art for sample) both indicate the // connection works; 5xx / network errors surface as TestConnection // failures. func (p *mbcaaProvider) TestConnection(ctx context.Context) error { _, err := p.fetcher.Fetch(ctx, mbcaaTestSampleMBID) if err == nil { return nil } if errors.Is(err, ErrNotFound) { return nil } return err }