BeetstreamNext exposes your Beets music library over the OpenSubsonic API, allowing you to stream your music to any Subsonic client.
BeetstreamNext implements the vast majority of the OpenSubsonic API specification, excluding video streaming and podcast management.
It also introduces several structural enhancements and features.
- Authentication: Supports modern API key authentication and legacy MD5 token authentication for older clients.
- Multi-user system: Individual bookmarks, ratings, favorites, play statistics, and play queues (allowing you to save and restore your active queue across devices).
- Metadata integration: Retrieves artist biographies, top tracks, and similar artists from Last.fm or Wikipedia.
- Album artworks / Artists images: Grabs and serves the local album art path from your Beets library, or fetches and saves the images from Cover Art Archive and Deezer.
- Advanced Beets queries (search hook): You can execute complex Beets queries (e.g. regex, field-specific queries, fuzzy matching) directly inside your Subsonic client's search bar. Simply prefix your query with
beets:orb:(e.g.beets:length:..3:30to find tracks shorter than 3:30). - Zero-file-modification architecture: Designed for users who manage metadata inside Beets but do not want to modify or write metadata tags directly to their media files, for archival purposes.
- Lyrics retrieval: Serves internal Beets lyrics or fetches them on-the-fly using the Beets
lyricsplugin. - On-the-fly transcoding: Serves raw files directly or transcodes lossy/lossless targets on-the-fly using FFmpeg.
- HTTP Live Streaming (HLS): AAC-encoded dynamic HLS streaming with full Adaptive Bitrate (ABR) support for clients that request multi-bitrate variant playlists.
- Public shares: Generates public landing pages for shared files with a secure download endpoint.
- Access controls: Built-in IP whitelisting, blacklisting, and adaptive login rate-limiting (monitored and cleared via the admin panel).
- Admin WebUI: Settings can be changed via a rather simple but useful WebUI.
- Clone and Install:
git clone https://github.com/FlorentLM/BeetstreamNext.git cd BeetstreamNext pip install .
- Enable in Beets'
config.yaml:plugins: beetstreamnext
- Create your admin user:
beet beetstreamnext --create-user
- Run:
beet beetstreamnext
Settings can be managed initially via Beets' config.yaml, and subsequently adjusted directly inside the Admin WebUI (which takes precedence).
beetstreamnext:
host: 0.0.0.0
port: 8080
reverse_proxy: false # Enable if running behind Nginx/Caddy
# Network & Access restrictions
admin_hostname: '' # Restrict admin panel to this host (e.g., admin.local)
external_hostname: '' # Force public shares to generate with this domain name
ip_whitelist: '' # List of IPs (space or comma-separated) to allow
ip_blacklist: '' # List of IPs (space or comma-separated) to block
cors: '' # Allowed CORS origins for web-based clients
# Library options
enable_public_now_playing: false # Toggle the public homepage widget
fetch_artists_images: true # Fetch artist photos from Deezer
save_artists_images: true # Save fetched artist photos to music folders
save_album_art: true # Save fetched album art to music foldersBEETSTREAMNEXT_KEY: Secret key used to encrypt legacy passwords at rest.LASTFM_API_KEY: (Optional) To enable biographies, top tracks, and similar artist queries.
BeetstreamNext uses modern standard HTTP headers to know the original client's IP, so the configuration should be pretty straightforward.
Nginx for instance would look like this:
location /beetstreamnext {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# If hosting in a subfolder, tell BeetstreamNext what the subfolder is!
proxy_set_header X-Forwarded-Prefix /beetstreamnext;
}
Caddy (v2) passes all the required headers by default, so it's just:
example.com {
reverse_proxy 127.0.0.1:8080
}
By default, BeetstreamNext is configured with CORS (Cross-Origin Resource Sharing) disabled. If you use native mobile or desktop apps, you probably do not need to change anything (native apps ignore CORS and will work out of the box).
If you want to use a web-based Subsonic player hosted on a different domain, you must allow the web player's URL in your Beets config, otherwise your web browser will block the connection for security reasons.
beetstreamnext:
cors: 'https://music.example.com' # also accepts a comma-separated list or a wildcard '*'If you are using a SSO gateway (Authelia, Authentik, etc.), or if the web-based player is a bit quirky, you might also need to enable this:
beetstreamnext:
cors_supports_credentials: trueWarning: DO NOT set cors: '*' alongside cors_supports_credentials: yes.
Doing so could allow any malicious website you visit to silently interact with your BeetstreamNext server in the background.
BeetstreamNext should be compatible with virtually any Subsonic/OpenSubsonic client. I tested it and confirmed it working with:
See here
This project is licensed under the MIT License. See the LICENSE file for details.

