Skip to content
Technical Proposal: External Service Provider Abstraction

Technical Proposal: External Service Provider Abstraction

Technical Proposal: External Service Provider Abstraction

This document outlines a strategy to refactor the SoundTouch Service’s content handling into a modular provider-based system.

1. Problem Statement

Currently, content handling for BMX (Bose Media Exchange) services like TuneIn or RadioBrowser is deeply intertwined with the HTTP handlers and XML models. Adding a new content provider (e.g., Local Media, Podcast RSS) requires modifying several files and duplicating boilerplate code for HTTP requests and error handling.

2. Proposed Architecture

2.1 The Provider Interface

We define a generic ContentProvider interface that abstracts away the source-specific logic (API calls, data parsing).

package provider

import "github.com/gesellix/bose-soundtouch/pkg/models"

type ContentProvider interface {
    // ID returns the unique identifier for this provider (e.g. "RADIO_BROWSER")
    ID() string

    // Resolve returns playback details for a given content identifier
    Resolve(id string) (*models.BmxPlaybackResponse, error)

    // Search allows finding content within this provider
    Search(query string) ([]models.ContentItem, error)
}

2.2 Provider Registry

A central registry in soundtouch-service manages the lifecycle and selection of providers.

type Registry struct {
    providers map[string]ContentProvider
}

func (r *Registry) Register(p ContentProvider) { ... }
func (r *Registry) Get(id string) ContentProvider { ... }

3. Implementation Plan

3.1 Phase 1: Modularize RadioBrowser

  1. Extract Logic: Move current RadioBrowser logic from bmx.go into a new package pkg/service/providers/radiobrowser.
  2. Add Failover: Implement the API Failover logic inspired by OpenCloudTouch.
    • Maintain a list of active RadioBrowser mirrors (e.g., de1.api.radio-browser.info, nl1.api.radio-browser.info).
    • Implement a round-robin or health-based selection strategy.
  3. Implements Interface: Ensure the new package satisfies the ContentProvider interface.

3.2 Phase 2: Refactor BMX Handlers

  • Update HandleTuneInPlayback and HandleOrionPlayback to use the registry.
  • The handlers will look up the provider based on the request context or URL parameters and delegate the resolution.

3.3 Phase 3: Dynamic Service Advertising

  • Modify HandleBMXRegistry to dynamically generate the bmx_services.json content based on the currently registered and enabled providers.

4. Benefits

  • Resilience: Centralized error handling and failover strategies for all external APIs.
  • Extensibility: New services can be added by simply implementing the interface and registering them at startup.
  • Testability: Providers can be unit-tested in isolation without mocking the entire HTTP server stack.
  • Unified UI: A future Web UI can query the registry to show available content sources and their statuses.

5. Next Steps

  1. Refine the ContentProvider interface to include metadata (icons, user-friendly names).
  2. Create a prototype for the radiobrowser provider with failover support.
Last updated on