# Octo-Fiesta A Subsonic API proxy server that transparently integrates multiple music streaming providers as sources. When a song is not available in your local Navidrome library, it is automatically fetched from your configured provider, downloaded, and served to your Subsonic-compatible client. The downloaded song is then added to your library, making it available locally for future listens. ## Why "Octo-Fiesta"? The name was randomly generated by GitHub when creating the repository. We found it amusing and somewhat fitting for a music application — after all, "fiesta" evokes a party atmosphere, which goes well with music streaming. So we kept it! ## Features - **Multi-Provider Architecture**: Pluggable music service system supporting multiple streaming providers (Deezer, Qobuz, and more to come) - **Transparent Proxy**: Acts as a middleware between Subsonic clients (like Aonsoku, Sublime Music, etc.) and your Navidrome server - **Seamless Integration**: Automatically searches and streams music from your configured provider when not available locally - **Automatic Downloads**: Songs are downloaded on-the-fly and cached for future use - **Hi-Res Audio Support**: Qobuz provider supports up to 24-bit/192kHz FLAC quality - **Full Metadata Embedding**: Downloaded files include complete ID3 tags (title, artist, album, track number, year, genre, BPM, ISRC, etc.) and embedded cover art - **Organized Library**: Downloads are saved in a clean `Artist/Album/Track` folder structure - **Artist Deduplication**: Merges local and streaming provider artists to avoid duplicates in search results - **Album Enrichment**: Local albums are enriched with missing tracks from streaming providers - **Cover Art Proxy**: Serves cover art for external content transparently ## Compatible Clients ### PC - [Aonsoku](https://github.com/victoralvesf/aonsoku) - [Feishin](https://github.com/jeffvli/feishin) - [Subplayer](https://github.com/peguerosdc/subplayer) - [Aurial](https://github.com/shrimpza/aurial) ### Android - [Tempus](https://github.com/eddyizm/tempus) - [Substreamer](https://substreamerapp.com/) > **Want to improve client compatibility?** Pull requests are welcome! ### Incompatible Clients These clients are **not compatible** with octo-fiesta due to architectural limitations: - [Symfonium](https://symfonium.app/) - Uses offline-first architecture and never queries the server for searches, making streaming provider integration impossible. [See details](https://support.symfonium.app/t/suggestions-on-search-function/1121/) ## Supported Music Providers - **[Deezer](https://www.deezer.com/)** - Quality: FLAC, MP3_320, MP3_128 - **[Qobuz](https://www.qobuz.com/)** - Quality: FLAC, FLAC_24_HIGH (Hi-Res 24-bit/192kHz), FLAC_24_LOW, FLAC_16, MP3_320 Choose your preferred provider via the `MUSIC_SERVICE` environment variable. Additional providers may be added in future releases. ## Requirements - A running Subsonic-compatible server (developed and tested with [Navidrome](https://www.navidrome.org/)) - Credentials for at least one music provider: - **Deezer**: ARL token from browser cookies - **Qobuz**: User ID + User Auth Token from browser localStorage ([see Wiki guide](https://github.com/V1ck3s/octo-fiesta/wiki/Getting-Qobuz-Credentials-(User-ID-&-Token))) - Docker and Docker Compose (recommended) **or** [.NET 9.0 SDK](https://dotnet.microsoft.com/download/dotnet/9.0) for manual installation ## Quick Start (Docker) The easiest way to run Octo-Fiesta is with Docker Compose. 1. **Create your environment file** ```bash cp .env.example .env ``` 2. **Edit the `.env` file** with your configuration: ```bash # Navidrome/Subsonic server URL SUBSONIC_URL=http://your-navidrome-server:4533 # Path where downloaded songs will be stored on the host DOWNLOAD_PATH=./downloads # Music service provider (Deezer or Qobuz) MUSIC_SERVICE=Qobuz # === Qobuz Configuration (if using Qobuz) === QOBUZ_USER_AUTH_TOKEN=your-qobuz-token QOBUZ_USER_ID=your-qobuz-user-id QOBUZ_QUALITY=FLAC # FLAC, FLAC_24_HIGH, FLAC_24_LOW, FLAC_16, MP3_320 # === Deezer Configuration (if using Deezer) === DEEZER_ARL=your-deezer-arl-token DEEZER_QUALITY=FLAC # FLAC, MP3_320, MP3_128 ``` 3. **Start the container** ```bash docker-compose up -d ``` The proxy will be available at `http://localhost:5274`. 4. **Configure your Subsonic client** Point your Subsonic client to `http://localhost:5274` instead of your Navidrome server directly. > **Tip**: Make sure the `DOWNLOAD_PATH` points to a directory that Navidrome can scan, so downloaded songs appear in your library. ## Configuration ### General Settings | Setting | Description | |---------|-------------| | `Subsonic:Url` | URL of your Navidrome/Subsonic server | | `Subsonic:MusicService` | Music provider to use: `Deezer` or `Qobuz` (default: `Deezer`) | | `Library:DownloadPath` | Directory where downloaded songs are stored | ### Deezer Settings | Setting | Description | |---------|-------------| | `Deezer:Arl` | Your Deezer ARL token (required if using Deezer) | | `Deezer:ArlFallback` | Backup ARL token if primary fails | | `Deezer:Quality` | Preferred audio quality: `FLAC`, `MP3_320`, `MP3_128`. If not specified, the highest available quality for your account will be used | ### Qobuz Settings | Setting | Description | |---------|-------------| | `Qobuz:UserAuthToken` | Your Qobuz User Auth Token (required if using Qobuz) - [How to get it](https://github.com/V1ck3s/octo-fiesta/wiki/Getting-Qobuz-Credentials-(User-ID-&-Token)) | | `Qobuz:UserId` | Your Qobuz User ID (required if using Qobuz) | | `Qobuz:Quality` | Preferred audio quality: `FLAC`, `FLAC_24_HIGH`, `FLAC_24_LOW`, `FLAC_16`, `MP3_320`. If not specified, the highest available quality will be used | ### Getting Credentials #### Deezer ARL Token See the [Wiki guide](https://github.com/V1ck3s/octo-fiesta/wiki/Getting-Deezer-Credentials-(ARL-Token)) for detailed instructions on obtaining your Deezer ARL token. #### Qobuz Credentials See the [Wiki guide](https://github.com/V1ck3s/octo-fiesta/wiki/Getting-Qobuz-Credentials-(User-ID-&-Token)) for detailed instructions on obtaining your Qobuz User ID and User Auth Token. ## Limitations - **Playlist Search**: Subsonic clients like Aonsoku filter playlists client-side from a cached `getPlaylists` call. Streaming provider playlists appear in global search (`search3`) but not in the Playlists tab filter. - **Region Restrictions**: Some tracks may be unavailable depending on your region and provider. - **Token Expiration**: Provider authentication tokens expire and need periodic refresh. ## Architecture ``` ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Subsonic │────▶│ Octo-Fiesta │────▶│ Navidrome │ │ Client │◀────│ (Proxy) │◀────│ Server │ │ (Aonsoku) │ │ │ │ │ └─────────────────┘ └────────┬─────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Music Providers │ │ - Deezer │ │ - Qobuz │ │ - (more...) │ └─────────────────┘ ``` ## Manual Installation If you prefer to run Octo-Fiesta without Docker: 1. **Clone the repository** ```bash git clone https://github.com/your-username/octo-fiesta.git cd octo-fiesta ``` 2. **Restore dependencies** ```bash dotnet restore ``` 3. **Configure the application** Edit `octo-fiesta/appsettings.json`: ```json { "Subsonic": { "Url": "http://your-navidrome-server:4533", "MusicService": "Qobuz" }, "Library": { "DownloadPath": "./downloads" }, "Qobuz": { "UserAuthToken": "your-qobuz-token", "UserId": "your-qobuz-user-id", "Quality": "FLAC" }, "Deezer": { "Arl": "your-deezer-arl-token", "ArlFallback": "", "Quality": "FLAC" } } ``` 4. **Run the server** ```bash cd octo-fiesta dotnet run ``` The proxy will start on `http://localhost:5274` by default. 5. **Configure your Subsonic client** Point your Subsonic client to `http://localhost:5274` instead of your Navidrome server directly. ## API Endpoints The proxy implements the Subsonic API and adds transparent streaming provider integration to: | Endpoint | Description | |----------|-------------| | `GET /rest/search3` | Merged search results from Navidrome + streaming provider | | `GET /rest/stream` | Streams audio, downloading from provider if needed | | `GET /rest/getSong` | Returns song details (local or from provider) | | `GET /rest/getAlbum` | Returns album with tracks from both sources | | `GET /rest/getArtist` | Returns artist with albums from both sources | | `GET /rest/getCoverArt` | Proxies cover art for external content | All other Subsonic API endpoints are passed through to Navidrome unchanged. ## External ID Format External (streaming provider) content uses typed IDs: | Type | Format | Example | |------|--------|---------| | Song | `ext-{provider}-song-{id}` | `ext-deezer-song-123456`, `ext-qobuz-song-789012` | | Album | `ext-{provider}-album-{id}` | `ext-deezer-album-789012`, `ext-qobuz-album-456789` | | Artist | `ext-{provider}-artist-{id}` | `ext-deezer-artist-259`, `ext-qobuz-artist-123` | Legacy format `ext-deezer-{id}` is also supported (assumes song type). ## Download Folder Structure Downloaded music is organized as: ``` downloads/ ├── Artist Name/ │ ├── Album Title/ │ │ ├── 01 - Track One.mp3 │ │ ├── 02 - Track Two.mp3 │ │ └── ... │ └── Another Album/ │ └── ... └── Another Artist/ └── ... ``` ## Metadata Embedding Downloaded files include: - **Basic**: Title, Artist, Album, Album Artist - **Track Info**: Track Number, Total Tracks, Disc Number - **Dates**: Year, Release Date - **Audio**: BPM, Duration - **Identifiers**: ISRC (in comments) - **Credits**: Contributors/Composers - **Visual**: Embedded cover art (high resolution) - **Rights**: Copyright, Label ## Development ### Build ```bash dotnet build ``` ### Run Tests ```bash dotnet test ``` ### Project Structure ``` octo-fiesta/ ├── Controllers/ │ └── SubsonicController.cs # Main API controller ├── Middleware/ │ └── GlobalExceptionHandler.cs # Global error handling ├── Models/ │ ├── Domain/ # Domain entities │ │ ├── Song.cs │ │ ├── Album.cs │ │ └── Artist.cs │ ├── Settings/ # Configuration models │ │ ├── SubsonicSettings.cs │ │ ├── DeezerSettings.cs │ │ └── QobuzSettings.cs │ ├── Download/ # Download-related models │ │ ├── DownloadInfo.cs │ │ └── DownloadStatus.cs │ ├── Search/ │ │ └── SearchResult.cs │ └── Subsonic/ │ └── ScanStatus.cs ├── Services/ │ ├── Common/ # Shared services │ │ ├── BaseDownloadService.cs # Template method base class │ │ ├── PathHelper.cs # Path utilities │ │ ├── Result.cs # Result pattern │ │ └── Error.cs # Error types │ ├── Deezer/ # Deezer provider │ │ ├── DeezerDownloadService.cs │ │ ├── DeezerMetadataService.cs │ │ └── DeezerStartupValidator.cs │ ├── Qobuz/ # Qobuz provider │ │ ├── QobuzDownloadService.cs │ │ ├── QobuzMetadataService.cs │ │ ├── QobuzBundleService.cs │ │ └── QobuzStartupValidator.cs │ ├── Local/ # Local library │ │ ├── ILocalLibraryService.cs │ │ └── LocalLibraryService.cs │ ├── Subsonic/ # Subsonic API logic │ │ ├── SubsonicProxyService.cs # Request proxying │ │ ├── SubsonicModelMapper.cs # Model mapping │ │ ├── SubsonicRequestParser.cs # Request parsing │ │ └── SubsonicResponseBuilder.cs # Response building │ ├── Validation/ # Startup validation │ │ ├── IStartupValidator.cs │ │ ├── BaseStartupValidator.cs │ │ ├── SubsonicStartupValidator.cs │ │ ├── StartupValidationOrchestrator.cs │ │ └── ValidationResult.cs │ ├── IDownloadService.cs # Download interface │ ├── IMusicMetadataService.cs # Metadata interface │ └── StartupValidationService.cs ├── Program.cs # Application entry point └── appsettings.json # Configuration octo-fiesta.Tests/ ├── DeezerDownloadServiceTests.cs # Deezer download tests ├── DeezerMetadataServiceTests.cs # Deezer metadata tests ├── QobuzDownloadServiceTests.cs # Qobuz download tests (127 tests) ├── LocalLibraryServiceTests.cs # Local library tests ├── SubsonicModelMapperTests.cs # Model mapping tests ├── SubsonicProxyServiceTests.cs # Proxy service tests ├── SubsonicRequestParserTests.cs # Request parser tests └── SubsonicResponseBuilderTests.cs # Response builder tests ``` ### Dependencies - **BouncyCastle.Cryptography** - Blowfish decryption for Deezer streams - **TagLibSharp** - ID3 tag and cover art embedding - **Swashbuckle.AspNetCore** - Swagger/OpenAPI documentation - **xUnit** - Unit testing framework - **Moq** - Mocking library for tests - **FluentAssertions** - Fluent assertion library for tests ## License GPL-3.0 ## Acknowledgments - [Navidrome](https://www.navidrome.org/) - The excellent self-hosted music server - [Deezer](https://www.deezer.com/) - Music streaming service - [Qobuz](https://www.qobuz.com/) - Hi-Res music streaming service - [Subsonic API](http://www.subsonic.org/pages/api.jsp) - The API specification