Skip to content

Fix Rekordbox USB Access in macOS Sandbox (#13624)#16237

Open
xARSENICx wants to merge 2 commits intomixxxdj:2.6from
xARSENICx:fix-rekordbox-sandbox-13624
Open

Fix Rekordbox USB Access in macOS Sandbox (#13624)#16237
xARSENICx wants to merge 2 commits intomixxxdj:2.6from
xARSENICx:fix-rekordbox-sandbox-13624

Conversation

@xARSENICx
Copy link
Copy Markdown
Contributor

@xARSENICx xARSENICx commented Mar 26, 2026

Fix Rekordbox USB Access in macOS Sandbox (Issue #13624)

Summary

This PR fixes an issue where Mixxx, when running in a sandboxed macOS environment, was unable to discover Rekordbox USB drives because the /Volumes directory is restricted. It implements a manual file picker fallback and uses Security Scoped Bookmarks to persist access permissions across multiple devices and restarts. This is based on the ideas used in #16205.

The Problem

When Mixxx is sandboxed on macOS (e.g., Mac App Store builds or with sandbox entitlements enabled), it does not have permission to read the contents of /Volumes by default. As a result, the automatic scanning logic in findRekordboxDevices() fails to discover Rekordbox exported databases on external USB or SD devices, leading to a blank interface or "Rekordbox USB not working" issues.

Unlike Traktor (which reads a single, static collection.nml), Rekordbox is designed around multiple external disks. A DJ commonly has several USB sticks/SD cards plugged in simultaneously. This means the fix needs to handle multiple devices, not just one.

The Solution

Based on the logic used for the Traktor sandbox fix (#16205):

  1. Manual File Picker Fallback: Modified RekordboxFeature::activate() to prompt the user to manually select their export.pdb file via a native QFileDialog if no previously bookmarked USB is currently accessible.
  2. OS-Level Permissions: Selecting the file through the native dialog triggers the macOS NSOpenPanel, which explicitly grants Mixxx permission to read the chosen directory.
  3. Security Scoped Bookmarks: Used Sandbox::createSecurityToken() to create a Security Scoped Bookmark per device, ensuring permissions persist across application restarts without re-prompting.
  4. Multi-Device Persistence: All granted paths are stored as a ;-delimited list in SettingsDAO (mixxx.rekordboxfeature.sandboxed_usb_paths). On each activate(), all stored paths are validated against the current filesystem — those that are currently plugged in are passed to the scanner, and stale entries are ignored until the device is reconnected.
  5. Enhanced Discovery: Updated findRekordboxDevices() to accept a QStringList of manually granted volume roots. All accessible USBs appear in the sidebar simultaneously.

Changes

  • src/library/rekordbox/rekordboxfeature.cpp:
    • Added #include <QFileDialog> and SettingsDAO for configuration and UI.
    • Enhanced activate() to validate and iterate all stored USB paths, prompting the picker only when none are currently accessible.
    • Updated findRekordboxDevices() to accept a QStringList of manual paths instead of a single QString, enabling multiple simultaneous Rekordbox USBs in the sidebar.
    • Cleaned up unused headers (engine.h, color.h, waveform.h).

Verification Required

Fixes: #13624

@xARSENICx xARSENICx force-pushed the fix-rekordbox-sandbox-13624 branch from 0d9bc86 to 52b3f2b Compare March 26, 2026 20:37
@xARSENICx xARSENICx changed the base branch from main to 2.6 March 26, 2026 20:38
@xARSENICx xARSENICx force-pushed the fix-rekordbox-sandbox-13624 branch from 52b3f2b to a9e834b Compare March 26, 2026 20:57
@xARSENICx
Copy link
Copy Markdown
Contributor Author

@JoergAtGithub This requires review as well. Can this be triaged too?

Copy link
Copy Markdown

@ghztomash ghztomash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!
I could try giving this a spin in the next days, unfortunately the macBook I have can only read SD cards.


if (!savedDbFile.isEmpty()) {
mixxx::FileInfo dbFileInfo(savedDbFile);
if (Sandbox::canAccess(&dbFileInfo) && dbFileInfo.checkFileExists()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if a different USB is plugged in? Is it safe to assume that checkFileExists will fail and the dialog will appear again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. Currently, checkFileExists will fail for a different USB, which will trigger the QFileDialog again. This allows the user to 'switch' access to the new USB, but it will overwrite the previously saved path in SettingsDAO. This means if they plug the first USB back in later, they'll have to go through the picker again. It’s functional but not yet persistent for multiple devices.

Comment on lines +1520 to +1523
QString newDbFile = QFileDialog::getOpenFileName(nullptr,
tr("Select your Rekordbox external database"),
defaultPath,
"Rekordbox Database (export.pdb)");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this allow access only to a single USB at a time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Because the macOS Sandbox restricts access to the entire /Volumes directory, findRekordboxDevices() can't automatically discover other drives. Since we are currently only storing a single path in the settings, only one USB can be 'unlocked' and visible at a time.

I agree this is a significant limitation for DJs who use multiple Rekordbox devices simultaneously. I'm looking into expanding this to store a list of persistent paths/bookmarks to support multiple simultaneous USBs.

I really appreciate your review. Thanks.

Store bookmarked USB paths as a semicolon-delimited list instead of
a single path (mixxx.rekordboxfeature.sandboxed_usb_paths). On
activate(), all stored paths are validated and each accessible one
contributes a volume root to the device scan. The file picker only
appears when no previously bookmarked USB is currently plugged in.

Addresses review feedback that previous single-path approach would
limit sandboxed access to one USB at a time.
@xARSENICx xARSENICx force-pushed the fix-rekordbox-sandbox-13624 branch from f075349 to 695b4e0 Compare March 27, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rekordbox USB not working, can crash Mixxx

3 participants