Skip to content

aroundmyroom/mStream

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,700 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mStream Velvet

A heavily extended fork of mStream by aroundmyroom.

Current version: 7.5.18-velvet — June 2026

Discord

Join our Discord server for direct contact — questions, feature requests, bug reports, and general chat about mStream Velvet.

All code changes in this fork were generated by Claude Sonnet 4.6 through VS Code with GitHub Copilot. This application is not vibe coded — we know what we develop and we know how we want it to function. All features are extensively documented.

mStream Velvet is a personal music streaming server forked from mStream 5.14.3 (sqlite branch). Both projects have continued to evolve independently since the fork.

Release Notice - Electron Auto Builds Discontinued

With the release of v7.5.13, automated Electron desktop builds are discontinued. Version 7.5.13 is the last official Electron release produced through this build pipeline.

The Electron implementation is not equal to the original version and is only a web client wrapper. It was used as a learning project to better understand GitHub workflows, automated builds, packaging, and release management. As the project and development process matured, maintaining Electron releases no longer had practical use.

This fork is not intended to compete with mStream. We remain grateful to the upstream project and its developers for their work and for providing the foundation that made this project possible.

Player UI Admin UI
Player UI Admin UI

Full feature comparison — mStream Velvet vs mStream (upstream)


Features Overview

Player

  • 3-theme system — Velvet (navy/purple), Dark (near-black), Light (lavender-grey); OS colour-scheme auto-detection
  • Visualizer modes — Mini spectrum analyser, analogue VU needle dials (L+R), RTW 1206 PPM bar meters
  • Waveform display — Server-generated via ffmpeg, RMS-based, γ=0.7 loudness curve, cached per file
  • Dynamic album-art colouring--primary and --accent CSS variables resampled from cover art on every track change
  • Crossfade — True Web Audio element swap; configurable 0–12 s
  • Gapless playback — Scheduled via Web Audio clock, 20 ms ramp, zero gap
  • Stereo balance — Post-EQ StereoPannerNode; balance-aware VU/PPM metering
  • EQ — 8-band parametric, ±12 dB, presets, bypass toggle
  • Sleep timer — Presets with 40-step volume fade-out
  • Full-screen visualizer — Milkdrop/Butterchurn (preset cycling), Custom Spectrum (7 modes), AudioMotion-analyzer (6 curated presets: Mirror Peaks, LED Dual, Radial, Octave Reflex, Velvet, Line Stereo)
  • Cross-device sync — All preferences and queue saved to DB; any device/browser resumes where you left off
  • FTS5 search — Full-text index across title, artist, album artist, album, filepath; BM25 relevance ranking; prefix matching (talk*); exclusion queries (talking -heads); diacritic folding; results split into Folders, Artists, and Songs sections; clicking an artist or album result opens the full album profile
  • Navigation customisation — Show/hide Genres and Decades nav buttons per user
  • Queue drag-and-drop reordering — With persistent localStorage state
  • CUE sheet markers — Tick marks on seek bar with seek-on-click and tooltips
  • ALBUMARTIST supportALBUMARTIST / album_artist tag used throughout the player and queue; album context shows album artist; optional "Use Album Artist in queue" toggle in Settings
  • Recently Added — redesigned as a 7-day grouped timeline: sticky day-pill navigation bar, album-folder tiles per day (with art, artist, and track count), click-to-explore
  • Genre & Decade browsing — Sidebar views with virtual scroll
  • Player bar position — Top or bottom, configurable per user
  • Auto-Resume — Opt-in setting to resume playback on page reload

Auto-DJ

  • Similar Artists mode — Last.fm API, artist-fair two-stage selection (equal weight per artist)
  • Artist cooldown — 15-song window persisted across reloads
  • Minimum rating filter — Persisted per user
  • vpath filter — Restrict picks to specific music folders
  • BPM continuity & harmonic mixing — Essentia-analyzed BPM and musical key; session-anchored tempo window (±8 % + half/double-tempo octave matching) and Camelot wheel harmonic compatibility; BPM anchor chip shown in player bar while active
  • Genre filter — whitelist to restrict picks to specific genre groups or blacklist to skip genres; organised by admin-defined genre groups; real-time text search to narrow the genre dropdown; per-user persisted
  • Crossfade integration — Shared slider with Playback Settings

Album Library

  • DB-driven, no filesystem walking — entire album tree built in memory from the indexed files table; ~60 ms first load, instant thereafter (5-minute cache)
  • Automatic structure detection from folder layout: standalone album, multi-disc album (disc naming patterns → tabs), or series (sub-folders that are not discs → grouped under a series banner)
  • Cover art resolution — on-disk image file → disc sub-folder image → embedded DB art (aaFile), in priority order
  • Library grid — series cards and standalone album cards with live search filter
  • Series drill-down → album detail with disc tabs, full track list, per-track and batch play/queue controls
  • Queue disc separators — multi-disc albums show a labelled divider (CD 1, CD 2, …) in the queue panel
  • CUE sheet virtual tracks — Play all / Add all from a CUE album expands into individual per-track queue entries; clicking a track row in the album detail starts playback from that CUE position; Repeat-one correctly loops the CUE track

Your Stats

  • Local listening history — every play, skip, podcast episode, and radio session recorded in your own SQLite DB; no external calls, no telemetry
  • Period picker — Week / Month / Quarter / Half-Year / Year with ← / → navigation
  • Summary strip — total plays, unique songs, total listening time
  • Top Songs / Top Artists / Top Albums — with album art
  • Listening clock — hour-of-day and day-of-week bar charts
  • Personality card — inferred listening archetype (Night Owl, Explorer, Loyalist, …)
  • Radio card and Podcast card — top stations and top shows when used
  • Admin tools — per-user event count, storage estimate, per-user purge (precise date-range window)
  • Year-jump navigation — ⇐ / ⇒ buttons jump one full year; a Now button appears when not on the current period

Play History

  • 7-day play timeline — album-art card grid of every song you played in the last 7 days; artist, title, and exact play time on each card
  • Day pills — instant switching between days ("Today", "Yesterday", "Monday 19 May …"); clicking a pill replaces the grid with that day's listening
  • Hour pills — appear below the day pills when a day's listening spans multiple hours; filter the grid to a specific hour slot (e.g. "21:00")
  • Three density modes — Comfy (large art tiles), Compact (small art grid), List (no art)
  • Play-all — queues the full day's history or just the filtered hour slot
  • Live refresh — grid updates automatically as new songs play; clicking a card plays just that one song

Server Audio & Sonos

  • Play music through the server's own speakers via mpv controlled by mStream's JSON IPC socket
  • Cast to Sonos — active push to any Sonos device via UPnP SOAP: transport control (play/pause/next/prev/seek), volume, queue auto-advance; per-user allow-mpv-cast permission gate; admin panel with device discovery, probe, and test playback
  • Full metadata (title, artist, album, art) displays correctly in the native Sonos S2 app and third-party Sonos controllers such as Clic (iOS)
  • The output picker in the player routes audio to Browser (Web Audio with ReplayGain), Server Speaker (mpv), or Sonos — switchable live without interrupting the queue
  • Any browser that can reach the server becomes a remote control at /server-remote — no app needed; same 3-output picker available there
  • Remote includes: Now Playing bar with seek, transport controls, volume (0–130 incl. software boost), Queue tab, Auto-DJ tab (Random + Similar Artists), Browse tab
  • Crossfade is automatically disabled when casting to Server or Sonos (same as the main player) — re-enabled when you switch back to Browser
  • Admin → Config → Server Audio — enable toggle, mpv binary path, Detect button, Start/Stop, Open Remote link
  • Admin → Sonos — enable/disable toggle, device discovery, probe by IP, set default room, test playback

DLNA / UPnP Media Server

  • Built-in MediaServer — exposes your music library on the local network so smart TVs, AV receivers, and DLNA/UPnP clients can discover and play without any special app or mStream login
  • Browse hierarchy mirrors the real folder tree of your albumsOnly vpaths — the same set of albums visible in the Album Library, never random junk folders
  • SSDP auto-discovery — devices find the server automatically (no IP typing needed on the TV)
  • Streams in the original file format (FLAC, MP3, Opus, …) — no transcoding required
  • Album art served from the mStream art cache
  • Configurable server name, HTTP port, enable/disable toggle — all live without a process restart
  • Disabled by default; enable in Admin → DLNA / UPnP
  • Security note: the DLNA port is unauthenticated — use on trusted LANs only, never port-forward to the internet

Subsonic API

  • Full Subsonic REST 1.16.1 with Open Subsonic extensions (openSubsonic: true)
  • Works with DSub, Substreamer, Symfonium, Ultrasonic, and other Subsonic clients
  • MD5 token auth and plaintext auth; separate per-user Subsonic password (does not conflict with mStream's PBKDF2 passwords)
  • XML and JSON response formats; JSONP supported
  • Folder-browsing mode (getIndexes, getMusicDirectory) with real filesystem hierarchy
  • Cover art for folders and songs; SVG folder-icon fallback
  • Starred, rated, bookmarks, playlists, scrobble all implemented

Admin Panel

  • Fully restyled with GUIv2 CSS variables (no Materialize)
  • Rich library stats: tracks, artists, albums, genres, formats, art coverage, ReplayGain, decades, per-vpath breakdowns
  • Scan error log with type filter, retention setting, in-place FLAC/MP3/WAV repair (stream-copy + frame-level re-encode fallback), unrecoverable file detection, gone-from-library indicator, and post-rescan confirmation status
  • Live scan progress polling ("files checked" + "added to DB" counters, shown in admin and player header)
  • Directory access test (read/write per vpath, OS-specific advice)
  • Excluded from index — mark any sub-folder as excluded; files are skipped during scan and existing entries purged on the next scan of the parent folder
  • Discogs: allow-update toggle; cover art sources (Discogs / Deezer / iTunes) each independently toggleable
  • Last.fm: server-side enable/disable toggle
  • ID3 tag editor toggle (per-installation setting)
  • Server-wide default theme — admin sets the starting theme for new users; each user's personal choice always wins
  • Logout confirmation + BroadcastChannel to stop player in all open tabs
  • Genre Groups ("Groups & Genres") — define named buckets that map raw genre tags into display groups; used in genre browsing sidebar and as filter options in smart playlists; drag-to-reorder, inline add/delete, auto-seeded with defaults on first visit
  • Metadata fallback — untagged files get artist/album derived from folder name at scan time; one-shot admin backfill for existing null-artist rows
  • Genre Enricher — background worker queries Last.fm, MusicBrainz, and Discogs in parallel for genre suggestions per artist; review-and-apply table with Applied audit trail; feeds directly into the Auto-DJ genre filter
  • Duplicate Workshop — finds and removes duplicate songs in three tiers: Exact (byte-identical files via file hash), Audio (same audio content in different containers via audio hash), and Similar (matching normalised artist + title with configurable duration threshold)
  • Normalisation Workshop — background ReplayGain loudness measurement using bundled rsgain (with ffmpeg -ebur128 fallback); start / stop controls; live progress (measured / queued / failed); results feed the Browser output's ReplayGain mode; auto-triggers after every library scan

Internet Radio

  • Stream any HTTP/HTTPS radio station through the built-in proxy (required for ICY headers in modern browsers)
  • Station artwork fetched and cached on subscribe; SSRF-protected (no private IPs)
  • ICY icy-title now-playing metadata polled and shown in the player bar; stream bitrate badge (kbps) shown when advertised; library badge is clickable — navigates directly to a search for the current track
  • ICY metadata auto-recovers after empty tags (ads) and after server restarts
  • Admin enable/disable toggle; per-user station list with add/edit/delete/reorder
  • Drag-to-reorder stations; filter pills by Genre and Country
  • On-demand recording — users with the allow-radio-recording permission (admin-granted per user) can record any stream to a configured Recordings folder; file naming includes station name, date, and time; station logo embedded as cover art; write-permission checked before start
  • Scheduled recording — tabbed Record modal with a Schedule tab; recurrence modes: Once, Every day, Weekdays, Custom days; 30 s server-side ticker fires recordings even when the browser is closed; active schedules shown with On/Off toggle and delete

Podcasts

  • Subscribe to any RSS podcast feed — no external account required
  • Episode list with title, date, duration, and play button
  • Per-episode play-position progress saved to DB; resume on next visit
  • One-click feed refresh — re-downloads missing artwork automatically
  • Drag-to-reorder feeds
  • Inline edit panel per feed: rename display name and update the RSS URL
  • Save episode to server — download any episode directly to the AudioBooks vpath (<feed title>/<YYYY-MM-DD title.ext>); streaming pipeline (no RAM buffering); SSRF-guarded; per-button states (idle → spinner → ✓ / ✕)

Smart Playlists

  • Filter builder — combine genre group, year range, minimum rating, play status (played / unplayed), artist name search, and library (vpath) selection into a single rule-based playlist
  • Fresh Picks — per-playlist toggle for daily-shuffle mode: auto-shuffles once per day on first open, "New picks" button to reshuffle at any time; shuffle icon shown in the nav sidebar
  • Library filter — narrow picks to one or more configured music directories; child vpaths resolved to filepath prefix automatically
  • CRUD management — create, rename, edit filters, delete; each playlist remembers its own sort order
  • Inline preview — run a playlist before saving to see the live track count

ZIP Download

  • ZIP button in the page header — appears when viewing an album or playlist; hidden on all other views
  • Albums download with the album name as filename; playlists use the playlist name
  • Server performs a pre-flight size check; rejects with HTTP 413 and a descriptive toast if over the limit
  • Configurable max size (default 500 MB) in Admin → DB Scan Settings → Max ZIP Download Size

ListenBrainz

  • Admin enables ListenBrainz server-wide; each user connects with their own user token
  • Token validated against the ListenBrainz API on connect
  • Scrobble fires 30 s after track start (listen_type: "single")
  • Instant "Listening Now" ping — fires immediately on track start so the current track appears on the LB dashboard in real time
  • Runs alongside Last.fm — both can be active simultaneously; the scrobble status badge shows combined state

Home Screen

  • Personalised dashboard shown on login — replaces the blank start screen
  • Continue Listening — resume the album or playlist you were last playing
  • On This Day — tracks you played on this calendar date in previous years
  • Mood Quick-Picks — one-click Auto-DJ presets (Energetic, Chill, Random)
  • Most Played shelf — your all-time top songs surfaced at a glance
  • Drag-to-reorder shelves — Customize mode lets each user arrange cards in any order or hide individual cards; layout persisted to DB

Tag Workshop

  • MusicBrainz batch tag editor — match entire albums against the MusicBrainz database; review per-track artist, title, date, track number suggestions before accepting
  • Enrich mode — background job cycles through untagged or poorly-tagged files with AcoustID fingerprint matching; errors and skipped tracks managed separately
  • Bulk casing fix — accept consistent title-case / sentence-case corrections across all matched tracks in one click
  • Shelve / unshelve — defer ambiguous albums without losing progress
  • Writes ALBUMARTIST tag — MB release artist written alongside title, artist, and date; priority: MusicBrainz release artist → existing album_artist tag
  • Admin-controlled: requires allowId3Edit to be enabled

AcoustID Fingerprinting

  • Background acoustic fingerprinting service using fpcalc (Chromaprint) bundled in bin/fpcalc/
  • Identifies untagged or mis-tagged files by their acoustic fingerprint via the AcoustID + MusicBrainz lookup APIs
  • Admin → AcoustID — start / stop the fingerprinting job; live progress shown (queued / done / errors)
  • Results fed directly into Tag Workshop for review before any tags are written

BPM Workshop

  • Step 1 — AcousticBrainz lookup — fetches BPM and musical key for every MBID-matched file from the AcousticBrainz API (~3 req/s); no local analysis required for matched files
  • Step 2 — Essentia local analysis — local BPM and key extraction using the bundled Essentia WASM engine for files AcousticBrainz does not cover (local recordings, rare releases, bootlegs); estimates-based octave detection halves doubled readings at analysis time
  • Step 3 — Genre-matrix octave correction — dry-run preview with per-genre-family breakdown of doubled/halved BPM candidates; per-track approval (pre-select all or uncheck individual rows); one-click apply or full undo
  • BPM and key results feed directly into Auto-DJ BPM continuity and harmonic mixing — the session-anchor tempo window and Camelot wheel compatibility check
  • All three steps auto-trigger after every library scan

Installing

Docker

Pull the pre-built image directly — no clone or build needed:

docker pull ghcr.io/aroundmyroom/mstream-velvet:latest

Create a compose.yaml:

services:
  mstream:
    image: ghcr.io/aroundmyroom/mstream-velvet:latest
    container_name: mstream-velvet
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - ./save:/app/save            # config, database, logs
      - /media/music:/music         # your music library (adjust host path)
      - ./waveform-cache:/app/waveform-cache
      - ./image-cache:/app/image-cache
    environment:
      MSTREAM_MUSIC_DIR: /music     # must match the volume target above

      # Admin account (optional).
      # If omitted the server starts in open mode — no login required.
      # MSTREAM_ADMIN_USER: admin
      # MSTREAM_ADMIN_PASS: changeme

      # Extra feature folders — uncomment to enable.
      # By default each type is applied directly to MSTREAM_MUSIC_DIR (/music).
      # If your files live in a sub-folder, add the matching *_SUBDIR variable:
      #   MSTREAM_ENABLE_YOUTUBE: "true"
      #   MSTREAM_YOUTUBE_SUBDIR: YouTube        # → folder root becomes /music/YouTube
      # You can also add, change or remove folders at any time in the Admin panel.
      # For full control, skip env vars and edit save/conf/default.json directly.

      # AudioBooks & Podcasts  (type: audio-books)
      # MSTREAM_ENABLE_AUDIOBOOKS: "true"
      # MSTREAM_AUDIOBOOKS_SUBDIR: Audiobooks    # optional — omit to use /music directly

      # Radio Recordings  (type: recordings — also enables the radio feature)
      # MSTREAM_ENABLE_RECORDINGS: "true"
      # MSTREAM_RECORDINGS_SUBDIR: Recordings    # optional — omit to use /music directly

      # YouTube Downloads  (type: youtube)
      # MSTREAM_ENABLE_YOUTUBE: "true"
      # MSTREAM_YOUTUBE_SUBDIR: YouTube          # optional — omit to use /music directly
docker compose up -d

Open http://localhost:3000 — on a fresh install with no users the admin panel is accessible without login.

The environment: block is optional — env vars only apply on the first boot when no config exists yet. For multiple mount points, child-vpaths, albumsOnly, or any advanced layout, skip the env vars and edit save/conf/default.json directly instead. See docs/docker.md.

Or pin to a specific release:

  docker pull ghcr.io/aroundmyroom/mstream-velvet:v7.5.18-velvet

Build from source (optional):

git clone https://github.com/aroundmyroom/mStream.git
cd mStream
docker build -t mstream-velvet .
# then use  image: mstream-velvet  in compose.yaml

See docs/docker.md for the full Docker guide: volume setup, adding your music library, user creation, updating, and reverse-proxy tips.

Bare-metal (Linux / systemd)

git clone https://github.com/aroundmyroom/mStream.git
cd mStream
npm install --only=prod
node cli-boot-wrapper.js

When you upgrade from git later, rerun npm install --only=prod after git pull so new production dependencies are installed locally.

See docs/install.md for running as a background service with systemd or PM2.

See docs/deploy.md for reverse-proxy (nginx) configuration — required for large FLAC libraries to avoid stall on idle connections.

See docs/technology-choices.md for a full explanation of every technology and service used.


Updating

Docker:

git pull
docker build -t mstream-velvet .
docker compose up -d

Bare-metal:

git pull
npm install --only=prod
systemctl restart music.service   # or: pm2 restart all

That dependency refresh is what picks up new packages such as Helmet.


Mobile Apps

Official mStream app (uses native mStream API)

mStream iOS App

mStream Android App

Made by Niera Tech — connects directly to the mStream API (not Subsonic).

Subsonic-compatible clients

The built-in Subsonic REST API also lets you use any Subsonic-compatible app:

Client Platform Tested
DSub Android
Substreamer iOS
Symfonium Android ✅ Full sync verified
Ultrasonic Android
Feishin Desktop
Any Subsonic 1.16.1 client Should work

Technical Details

  • Node.js: v22 or greater (v24 used in Docker image; tested on v22.22.0)
  • Database: SQLite via Node.js built-in node:sqlite (DatabaseSync) — default engine
  • Docker base image: node:24-slim (Debian slim)
  • Supported audio formats: flac, mp3, mp4, wav, ogg, opus, aac, m4a, w64, aiff
  • ffmpeg: auto-downloaded to bin/ffmpeg/ at startup if missing or below v6 (bare-metal and Docker); waveform generation, radio recording, YouTube tagging, and transcoding all use this bundled binary
  • Cross-platform: Linux, macOS, Windows, FreeBSD, ARM (Raspberry Pi)

Releases

Individual release notes are in the releases/ folder.
Full combined changelog: changes-fork-velvet.md


Credits

mStream Velvet is built on mStream by IrosTheBeggar and on these open-source libraries:

About

mStream-Velvet a forked version with a new GUI and extra improved features of the easiest enhanced music streaming server available

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • JavaScript 87.3%
  • CSS 6.8%
  • HTML 5.8%
  • Other 0.1%