Files
allstarr/ARCHITECTURE.md

184 lines
9.4 KiB
Markdown

# Architecture
This document describes the technical architecture of Allstarr.
## System Architecture
```
┌─────────────────┐
┌───▶│ Jellyfin │
┌─────────────────┐ ┌──────────────────┐ │ │ Server │
│ Music Client │────▶│ Allstarr │───┤ └─────────────────┘
│ (Aonsoku, │◀────│ (Proxy) │◀──┤
│ Finamp, etc.) │ │ │ │ ┌─────────────────┐
└─────────────────┘ └────────┬─────────┘ └───▶│ Navidrome │
│ │ (Subsonic) │
▼ └─────────────────┘
┌─────────────────┐
│ Music Providers │
│ - SquidWTF │
│ - Deezer │
│ - Qobuz │
└─────────────────┘
```
The proxy intercepts requests from your music client and:
1. Forwards library requests to your configured backend (Jellyfin or Subsonic)
2. Merges results with content from your music provider
3. Downloads and caches external tracks on-demand
4. Serves audio streams transparently
**Note**: Only the controller matching your configured `BACKEND_TYPE` is registered at runtime, preventing route conflicts and ensuring clean API separation.
## API Endpoints
### Jellyfin Backend (Primary Focus)
The proxy provides comprehensive Jellyfin API support with streaming provider integration:
| Endpoint | Description |
|----------|-------------|
| `GET /Items` | Search and browse library items (local + streaming providers) |
| `GET /Artists` | Browse artists with merged results from local + streaming |
| `GET /Artists/AlbumArtists` | Album artists with streaming provider results |
| `GET /Users/{userId}/Items` | User library items with external content |
| `GET /Audio/{id}/stream` | Stream audio, downloading from provider on-demand |
| `GET /Audio/{id}/Lyrics` | Lyrics from Jellyfin, Spotify, or LRCLib |
| `GET /Items/{id}/Images/{type}` | Proxy cover art for external content |
| `GET /Playlists/{id}/Items` | Playlist items (Spotify Import integration) |
| `POST /UserFavoriteItems/{id}` | Favorite items; copies external tracks to kept folder |
| `DELETE /UserFavoriteItems/{id}` | Unfavorite items |
| `POST /Sessions/Playing` | Playback reporting for external tracks |
| `POST /Sessions/Playing/Progress` | Playback progress tracking |
| `POST /Sessions/Playing/Stopped` | Playback stopped reporting |
| `WebSocket /socket` | Real-time session management and remote control |
**Admin API (Port 5275):**
| Endpoint | Description |
|----------|-------------|
| `GET /api/admin/health` | Health check endpoint |
| `GET /api/admin/config` | Get current configuration |
| `POST /api/admin/config` | Update configuration |
| `POST /api/admin/cache/clear` | Clear cache |
| `GET /api/admin/status` | Get system status |
| `GET /api/admin/memory-stats` | Get memory usage statistics |
| `POST /api/admin/force-gc` | Force garbage collection |
| `GET /api/admin/sessions` | Get active sessions |
| `GET /api/admin/debug/endpoint-usage` | Get endpoint usage statistics |
| `DELETE /api/admin/debug/endpoint-usage` | Clear endpoint usage log |
| `GET /api/admin/squidwtf-base-url` | Get SquidWTF base URL |
| `GET /api/admin/playlists` | List all playlists with status |
| `GET /api/admin/playlists/{name}/tracks` | Get tracks for playlist |
| `POST /api/admin/playlists/refresh` | Refresh all playlists |
| `POST /api/admin/playlists/{name}/match` | Match tracks for playlist |
| `POST /api/admin/playlists/{name}/clear-cache` | Clear playlist cache |
| `POST /api/admin/playlists/match-all` | Match all playlists |
| `POST /api/admin/playlists` | Add new playlist |
| `DELETE /api/admin/playlists/{name}` | Remove playlist |
| `POST /api/admin/playlists/{name}/map` | Save manual track mapping |
| `GET /api/admin/jellyfin/search` | Search Jellyfin library |
| `GET /api/admin/jellyfin/track/{id}` | Get Jellyfin track details |
| `GET /api/admin/jellyfin/users` | List Jellyfin users |
| `GET /api/admin/jellyfin/libraries` | List Jellyfin libraries |
| `GET /api/admin/jellyfin/playlists` | List Jellyfin playlists |
| `POST /api/admin/jellyfin/playlists/{id}/link` | Link Jellyfin playlist to Spotify |
| `DELETE /api/admin/jellyfin/playlists/{name}/unlink` | Unlink playlist |
| `PUT /api/admin/playlists/{name}/schedule` | Update playlist sync schedule |
| `GET /api/admin/spotify/user-playlists` | Get Spotify user playlists |
| `GET /api/admin/spotify/sync` | Trigger Spotify sync |
| `GET /api/admin/spotify/match` | Trigger Spotify track matching |
| `POST /api/admin/spotify/clear-cache` | Clear Spotify cache |
| `GET /api/admin/spotify/mappings` | Get Spotify track mappings (paginated) |
| `GET /api/admin/spotify/mappings/{spotifyId}` | Get specific Spotify mapping |
| `POST /api/admin/spotify/mappings` | Save Spotify track mapping |
| `DELETE /api/admin/spotify/mappings/{spotifyId}` | Delete Spotify mapping |
| `GET /api/admin/spotify/mappings/stats` | Get Spotify mapping statistics |
| `GET /api/admin/downloads` | List kept downloads |
| `DELETE /api/admin/downloads` | Delete kept file |
| `GET /api/admin/downloads/file` | Download specific file |
| `GET /api/admin/downloads/all` | Download all files as zip |
| `GET /api/admin/scrobbling/status` | Get scrobbling status |
| `POST /api/admin/scrobbling/lastfm/authenticate` | Authenticate Last.fm |
| `GET /api/admin/scrobbling/lastfm/auth-url` | Get Last.fm auth URL |
| `POST /api/admin/scrobbling/lastfm/get-session` | Get Last.fm session key |
| `POST /api/admin/scrobbling/lastfm/test` | Test Last.fm connection |
| `POST /api/admin/scrobbling/lastfm/debug-auth` | Debug Last.fm auth |
| `POST /api/admin/scrobbling/listenbrainz/validate` | Validate ListenBrainz token |
| `POST /api/admin/scrobbling/listenbrainz/test` | Test ListenBrainz connection |
All other Jellyfin API endpoints are passed through unchanged.
### Subsonic Backend
The proxy implements the Subsonic API with streaming provider integration:
| 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 |
| `GET /rest/star` | Stars items; triggers automatic playlist download for external playlists |
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
All downloads are organized under a single base directory (default: `./downloads`):
```
downloads/
├── permanent/ # Permanent downloads (STORAGE_MODE=Permanent)
│ ├── Artist Name/
│ │ ├── Album Title/
│ │ │ ├── 01 - Track One.flac
│ │ │ ├── 02 - Track Two.flac
│ │ │ └── ...
│ │ └── Another Album/
│ │ └── ...
│ └── playlists/
│ ├── My Favorite Songs.m3u
│ └── Chill Vibes.m3u
├── cache/ # Temporary cache (STORAGE_MODE=Cache)
│ └── Artist Name/
│ └── Album Title/
│ └── Track.flac
└── kept/ # Favorited external tracks (always permanent)
└── Artist Name/
└── Album Title/
└── Track.flac
```
**Storage modes:**
- **Permanent** (`downloads/permanent/`): Files saved permanently and registered in your media server
- **Cache** (`downloads/cache/`): Temporary files, auto-cleaned after `CACHE_DURATION_HOURS`
- **Kept** (`downloads/kept/`): External tracks you've favorited - always permanent, separate from cache
Playlists are stored as M3U files with relative paths, making them portable and compatible with most music players.
## 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