MusicBee TrueShuffle | Documentation | HALRAD Research

TrueShuffle

MusicBee TrueShuffle

Documentation

MusicBee TrueShuffle ensures every track in your library plays exactly once before any repeats.

Explain: How It Works

The Problem: Standard shuffle algorithms pick tracks randomly each time. With a large library, this means some tracks play repeatedly while others are rarely heard. It's like rolling dice - you might roll the same number multiple times before hitting others.

The Solution: TrueShuffle treats your library like a deck of cards. Each track is "dealt" exactly once. Only after every card has been played does the deck reshuffle.

How It Works

  1. AutoDJ queues tracks — After each song, TrueShuffle adds an unplayed track to your Now Playing queue
  2. Track plays past threshold — When you listen to enough of a track (e.g., 50%), it's marked as "played"
  3. State is saved — Your progress is stored in a JSON file that survives restarts, updates, and reboots
  4. Repeat — TrueShuffle keeps queueing unplayed tracks until all have been played
  5. Cycle completes — Reset manually or let it auto-reset to start fresh

But what determines when a track is marked "played"?

What Counts as "Played"?

TrueShuffle uses MusicBee's built-in play count threshold — the same setting that controls when MusicBee increments a track's play count. Find it in:

Edit → Preferences → Now Playing

MusicBee Now Playing Settings

Default: more than 50% played OR more than 240 seconds

Skipped tracks are not counted. If you skip a track before reaching the threshold, it stays "unplayed" and will come back around in shuffle. Only tracks that meet MusicBee's play count criteria get marked as played.

Enabling the Panel

To show the TrueShuffle progress panel:

  1. MAKE SURE YOU ARE NOT IN NOW PLAYING! Click on a different tab.
  2. Go to View → Arrange Panels
  3. Find TrueShuffle in the panel list
  4. Check the box to enable it, then click OK

1.

Enable Panel Menu

2.

View Arrange Panels Step 1

3.

View Arrange Panels Step 2

The TrueShuffle Panel

TrueShuffle Panel

Enabling and Disabling

TrueShuffle is always active when the plugin is loaded. To disable tracking:

Configuration Options

Access settings via Tools → TrueShuffle Settings... or click Configure in Preferences → Plugins.

Plugin Preferences

Configuration Dialog

TrueShuffle Configuration Dialog

Source Selection

Choose what to shuffle:

Each source maintains independent progress. Switching sources loads that source's state. State files are stored per-source (e.g., state_Library.json, state_MyPlaylist.json).

Setting Default Description
Shuffle Source Library Choose between Entire Library or a specific Playlist.
Queue unplayed tracks (AutoDJ mode) On Automatically queues the next unplayed track after each song. This is the core feature.
Discovery ↔ Favorites slider 50% Controls the balance between discovering new music and hearing favorites. See Shuffle Pools below.
Treat skipped tracks as played Off When enabled, skipped tracks are marked as played. When disabled, skipped tracks come back around.
Auto-reset after complete cycle Off Automatically restart when all tracks have been played.
Include new files in shuffle automatically On When files are added to your library, they're automatically included as unplayed tracks in the current shuffle. Disable if you prefer new files only appear after a reset.
Skip already-played tracks (aggressive mode) On If a track that was already played this cycle starts, TrueShuffle skips it automatically. Makes TrueShuffle more "in charge" of playback.
Resume last track position on start On When MusicBee restarts, resume the last track at the saved position.
Ignore queued tracks when skipping On When skipping banned/played tracks, pull from source instead of Now Playing queue. Prevents cascade-skipping through existing queue.
Play order Random How to select the next track: Random, By Album, By Track, Date Added (Oldest), Date Added (Newest).
On Options: Yes, there are a lot of settings. A "true shuffle" could just be one button that shuffles your library — but real-world use reveals edge cases: What about skipped tracks? New files added mid-shuffle? Playlists vs library? Album continuity? Each setting exists because someone asked "what if?" The irony isn't lost on us: a plugin about simplicity (play everything once) gained complexity to handle the exceptions. Just take a look at the wonderful AUTO DJ built right into Music Bee - many options and ways to shuffle it up.

Shuffle Pools (Discovery ↔ Favorites)

TrueShuffle divides your unplayed tracks into three pools:

Pool Description Base Chance
Discovery Tracks with 0 plays in MusicBee (never heard) Slider-controlled
Familiar Tracks with 1+ plays, not loved (heard but not special) 20% base
Favorites Tracks marked as "Loved" in MusicBee Slider-controlled

How the slider works:

When a pool is empty, TrueShuffle falls back to other pools to ensure continuous playback.

Play Order Modes

TrueShuffle Play Order Options
Mode Behavior
RandomPick any unplayed track randomly
By AlbumComplete album in track order, then pick random new album
By TrackPlay in library file path order
Date Added (Oldest)Play oldest additions first
Date Added (Newest)Play newest additions first

Love and Ban Controls

The TrueShuffle panel includes two quick-action controls:

Heart (♡ / ❤) - Love Toggle

Ban Link - No-Play List

Never want to hear a particular track again? Click the red Ban link. The track is immediately banned and skipped.

The banned list is just a text file with one file path per line. Delete a line to unban that track.

Resetting Progress

To start fresh and mark all tracks as unplayed:

Tools → TrueShuffle Settings... then click the Reset button.

Reset clears all played tracks AND refreshes the library to pick up any new files added since startup.

State Storage

The plugin stores its data in:

%AppData%\MusicBee\mb_trueshuffle\

Files:

State file includes resume information:

{
  "playedTracks": ["file://path/to/song1.mp3", "file://path/to/song2.mp3"],
  "libraryHash": "a3f8b2c1",
  "totalTracks": 12847,
  "lastReset": "2025-12-01T00:00:00Z",
  "lastPlayed": "2025-12-28T21:45:00Z",
  "resumeTrackUrl": "file://path/to/lastplaying.mp3",
  "resumePositionMs": 45000,
  "resumeTimestamp": "2025-12-30T10:30:00Z"
}

Technical Details

Architecture

MusicBee TrueShuffle/
├── Plugin.cs              # Main entry point, MusicBee integration
├── ShuffleState.cs        # Persisted state management
├── ShuffleEngine.cs       # Shuffle logic and track selection
├── ShuffleSettings.cs     # Configuration options
├── BanList.cs             # No-play list for banned tracks
└── MusicBeeInterface.cs   # MusicBee API definitions (from SDK)

MusicBee API Integration

API Method Purpose
Library_QueryFilesEx()Get all library tracks
NowPlaying_GetFileUrl()Current playing track (unique ID)
NowPlaying_GetDuration()Track duration for threshold calculation
Player_GetPosition()Current playback position
TrackChanged notificationTrigger to check if previous track was "played"
Setting_GetPersistentStoragePath()Plugin data folder location
Setting_GetValue(SettingId)Get MusicBee's play count threshold settings

Play Detection Logic

// On track change, check if PREVIOUS track was played long enough
// Uses MusicBee's play count threshold settings
if (lastTrackUrl != null && lastTrackDuration > 0)
{
    // Get MusicBee's thresholds (e.g., 50% or 240 seconds)
    int triggerPercent = Setting_GetValue(PlayCountTriggerPercent);
    int triggerSeconds = Setting_GetValue(PlayCountTriggerSeconds);

    double playedPercent = (double)lastTrackPosition / lastTrackDuration;
    int playedSeconds = lastTrackPosition / 1000;

    // More than X% played OR more than Y seconds
    if ((playedPercent * 100 > triggerPercent) || (playedSeconds > triggerSeconds))
    {
        engine.MarkPlayed(lastTrackUrl);
    }
}

Building from Source

Prerequisites

Build Commands

# Debug build
dotnet build -c Debug

# Release build
dotnet build -c Release

Output: bin\Release\net48\mb_trueshuffle.dll

Library Change Handling

When your library changes:

Known Limitations

Troubleshooting

Developer Mode

If tracks aren't being counted as played, you can enable debug logging through Developer Mode:

  1. Open TrueShuffle settings
  2. Click the version label 7 times to unlock Developer Mode
  3. A [DEV] indicator appears and a debug logging checkbox becomes visible
  4. Enable the debug logging checkbox
  5. Play some tracks and skip to the next
  6. Check the log file: %AppData%\MusicBee\mb_trueshuffle\debug.log

The log shows position, duration, percentage played, and threshold values for each track change.

To hide Developer Mode options, click the version label again.

Common Issues

License

GPL3 - See GNU General Public License v3 for details.

TrueShuffle