A MagicMirror² module that displays a grid of numbered buttons for your audio tracks and lets you play them individually or in a randomized loop. Supports local files stored on the SD card, USB paths (securely streamed via the backend), and URL sources. Includes pagination, hover/active styling, and an optional autostart random loop. Number of buttons on the grid will automatically match the number of sound files
- Author: gitgitaway
- MagicMirror² Compatibility: Tested with current MM² versions
- Files:
MMM-JukeBox.js
,node_helper.js
,MMM-JukeBox.css
- Auto-scan of audio files from a local
soundFiles
folder or a configured USB folder - Random Play with continuous looping
- Shuffle control bar icon that matches the existing symbol formatting
- Buttons inactive until clicked when
autostartRandomLoop: false
- Pagination to handle large libraries (configurable page size)
- USB file streaming via an Express route to avoid
file:///
browser restrictions - Optional USB→Local Sync: when
source: "USB"
andsyncUsbToLocal: true
, files are copied fromusbPath
to./soundFiles
and played locally (UI shows syncing with a small spinner and results) - Autostart Random Loop on startup (optional)
- Continue playing on HIDE (optional)
- Allowed extensions filter (front-end configurable and enforced in the backend)
- Navigate to your MagicMirror modules directory:
cd ~/MagicMirror/modules
- Clone or copy this module into
MMM-JukeBox/
.
git clone https://github.com/gitgitaway/MMM-JukeBox.git
- Place your audio files in:
- Local mode (default):
MMM-JukeBox/soundFiles/
- USB mode: your USB directory (e.g.,
D:/soundFiles
) and setsource: "USB"
in config
- Local mode (default):
Add the module to your config/config.js
:
{
module: "MMM-JukeBox",
position: "top_left", // Explanation: choose any MagicMirror position
config: {
source: "file", // "file" | "USB" | "URL"
usbPath: "D:/soundFiles", // Explanation: only used when source === "USB"
allowedExtensions: [".mp3", ".wav", ".ogg", ".m4a"],
pageSize: 40, // Explanation: number of buttons per page
showControlBar: true, // NEW: use symbol bar; hides legacy Random button
randomButtonText: "Random Play", // Explanation: label for the legacy random button (when control bar is off)
stopButtonText: "Stop", // Explanation: label for the stop button
infoText: "Select a number or use Random Play.",
continueOnHide: true, // Explanation: true = audio continues when module hides
syncUsbToLocal: false, // Explanation: optional backend copy from USB to ./soundFiles
autostartRandomLoop: false // Explanation: true = auto start random loop on startup
}
},
Option | Type | Default | Description |
---|---|---|---|
source |
string | "file" |
Audio source. "file" uses the module's soundFiles directory. "USB" streams via backend from usbPath and, if syncUsbToLocal: true , will first copy to ./soundFiles and then play locally. "URL" expects you to provide url values for tracks. |
usbPath |
string | "D:/soundFiles" |
Path to your USB music folder when source === "USB" . Example for Windows shown. |
allowedExtensions |
string[] | [".mp3", ".wav", ".ogg", ".m4a"] |
File extensions included during scanning. Case-insensitive. |
pageSize |
number | 40 |
Number of track buttons per page. Must be ≥ 1. |
randomButtonText |
string | "Random Play" |
Label of the Random Play button. |
stopButtonText |
string | "Stop" |
Label of the Stop button. |
infoText |
string | "Select a number or use Random Play." |
Info text shown above the grid. |
continueOnHide |
boolean | true |
If true , audio keeps playing when the module receives HIDE . Otherwise it stops on HIDE /SUSPEND /STOP . |
syncUsbToLocal |
boolean | false |
If true , backend can copy from usbPath into the module's soundFiles directory (see Notifications). |
autostartRandomLoop |
boolean | false |
Start randomized playback automatically after the scan completes (once at startup). |
tracks |
array | [] |
Populated automatically by the scan. For URL source, you can provide objects with { url, title, artist } . |
backupLocal |
boolean | false |
If true and source: "USB" , copy the current ./soundFiles into ./backupFiles once before the first USB scan/sync. |
darkMode |
boolean/null | null |
Theme control: null = auto (default CSS), true = force dark mode, false = force light mode. |
fontColorOverride |
string/null | null |
Override all font colors with a specific color (e.g., "#FFFFFF" for white). Set to null to use default CSS colors. |
opacityOverride |
number/null | null |
Override all opacity values (e.g., 1.0 for full opacity). Set to null to use default CSS opacity values. |
- On start, the module sends
SCAN_SONGS
with the resolved scan path and allowed extensions. - When the backend replies with
SONG_LIST
, a button grid is rendered with pagination. - Clicking a button plays that track; clicking Random Play starts a continuous random loop.
- The Now Playing area shows title/artist and (once known) duration.
- For
USB
source, audio is streamed via/MMM-JukeBox/usb?base=...&file=...
to avoid browserfile:///
restrictions.
- Scans the given directory (non-recursive) and filters by
allowedExtensions
. - Normalizes titles from filenames (removes prefix numbers like
01 -
, replaces underscores with spaces). - Provides a secure Express route for USB streaming that prevents path traversal and sets basic
Content-Type
.
GET /MMM-JukeBox/usb?base=<encodedPath>&file=<encodedFilename>
# Explanation: Streams the requested audio file if it exists within <base>.
# - base: URL-encoded absolute directory path (e.g., D:/soundFiles)
# - file: URL-encoded filename within that base (e.g., 01 - Song.mp3)
SCAN_SONGS
- Payload:
{ path, source, extensions }
- Explanation: Request the backend to scan for audio files.
- Payload:
SYNC_USB_TO_LOCAL
(optional)- Payload:
{ usbBase, extensions }
- Explanation: Copy matching audio files from
usbBase
to the module's./soundFiles
directory.
- Payload:
SONG_LIST
- Payload:
[{ file, title, artist }]
- Explanation: Result of the scan, used to build the grid and play audio.
- Payload:
SYNC_DONE
- Payload:
{ ok: boolean, copied?: number, skipped?: number, dest?: string, error?: string }
- Explanation: Outcome of a sync request.
- Payload:
Key classes from MMM-JukeBox.css
you can theme in your custom CSS:
.jukebox-wrapper
: Outer container.jukebox-info
: Info text above the grid.jukebox-grid
: Grid container for numbered buttons.jukebox-btn
: Individual track buttons (use.active
for the playing state).jukebox-random-btn
,.jukebox-stop-btn
: Action buttons.jukebox-nowplaying
: Now playing footer area.jukebox-pager
,.jukebox-pager-btn
,.jukebox-page-info
: Pagination controls
- No tracks appear
- Explanation: Ensure your files are in the correct folder for your chosen
source
and that their extensions matchallowedExtensions
.
- Explanation: Ensure your files are in the correct folder for your chosen
- USB files don't play
- Explanation: Verify
source: "USB"
and thatusbPath
points to a valid directory accessible by the MagicMirror process.
- Explanation: Verify
- Browser cannot play certain formats
- Explanation: Not all browsers support every codec/container. Convert problematic files to widely supported formats (e.g., MP3).
- Large libraries
- Explanation: Increase
pageSize
or curate files in subfolders (module scans non-recursively by design).
- Explanation: Increase
- Scanning is non-recursive for simplicity and performance.
- For
URL
source, providetracks
with{ url, title, artist }
and setsource: "URL"
(the scan will return an empty list by design). - The backend title formatter strips numeric prefixes and underscores to create cleaner display titles.
This is the 4th module in my Celtic themed man cave magicmirror.
The other modules can be found here:-
- Module 1: https://github.com/gitgitaway/MMM-MyTeams-Clock
- Module 2: https://github.com/gitgitaway/MMM-MyTeams-LeaugeTable
- Module 3: https://github.com/gitgitaway/MMM-MyTeams-Fixtures
- Module 5: https://github.com/gitgitaway/MMM-Celtic-OnThisDay
Thanks to the MagicMirror community for inspiration and guidance! Special thanks to @jasonacox for his work on MMM-MusicPlayer which served as a starting point.
- All tracks are the property of their respective owners; included tracks are for demonstration purposes only and should be replaced with your own
MIT