Audio Player Loader — Technical Specifications

A macOS shell tool that bulk-erases external USB disks and copies audio content onto them in parallel.

Script: load_content.sh · Platform: macOS (universal — Apple Silicon & Intel) · Licensed under AGPL-3.0 · © 2026 Seth Johnston · Source: github.com/rulingAnts/mac-audio-player-loader

This tool destroys data. It reformats whole external USB disks. It is designed to erase every selected device completely. Read §3 and §5 before running or re-publishing it.

This document is for engineers and power users deciding whether the script is safe to run, audit, or re-publish. It describes exactly what the script does, how it works, the safety guards and the reasoning behind them, what it deliberately does not do, and the licensing.

Contents
  1. Purpose & audience
  2. Environment & dependencies
  3. What it destroys
  4. Operational flow
  5. Safety guards & rationale
  6. Concurrency & performance
  7. macOS junk handling
  8. Failure model & operator verification
  9. Network & privacy
  10. Known limitations
  11. Auditing notes
  12. License & reuse rights

1. Purpose & audience

The tool provisions many identical USB audio-player devices (e.g. MegaVoice or any player that reads a FAT filesystem) in one operation: it erases each selected external disk, writes a fresh full-size FAT32 partition, and copies a folder of audio content onto every device in parallel. It is operated by non-technical field users through native macOS dialogs; the terminal output is the authoritative record.

The loader does not need to live in the content folder: at start-up it asks the operator to choose the content folder (a native choose folder dialog, defaulting to the Desktop), then copies that folder's contents (minus any helper files) to each device. Keeping the loader beside the content still works — just pick that folder. This fills the same role as Hope Tech Global's HTGv4.CMD on Windows.

2. Environment & dependencies

3. What it destroys

For every disk the operator selects, the script runs diskutil eraseDisk FAT32 <LABEL> MBRFormat /dev/diskN. This wipes the entire physical disk — every partition and every volume on it — and writes a new MBR partition map with a single full-size FAT32 volume. Selection is at the level of whole physical disks, never individual partitions.

The operator explicitly selects and confirms which disks are erased (§4, §5). The tool has no “erase everything automatically” mode; nothing is erased without an on-screen confirmation that lists the disks by size and volume names.

4. Operational flow

  1. Shell guard. Re-exec under /bin/bash if not already running there.
  2. Launch. Two entry points, same engine. Primary: a tiny sidecar AppleScript (Load Audio Players.applescript) that the operator double-clicks and Runs in Script Editor; it resolves its own folder via path to me, verifies load_content.sh is present — beside it, or (in the download disk image) in a hidden .loader/ sub-folder next to it, so the DMG window shows only the launcher and a non-technical operator cannot pick the wrong file — and issues tell application "Terminal" to do script "/bin/bash <loader>" — so the whole run happens in a real Terminal/TTY (live progress bar, colours, prompts, signal traps), identical to the manual drag-onto-Terminal path which remains the fallback. The wrapper is a script document, not an app bundle, so a downloaded copy is not Gatekeeper-blocked. The first-run prompts are the one-time "control Terminal" automation consent and — when run from the read-only DMG — a benign Script Editor "file is locked" notice the operator simply cancels (running, not editing, needs no unlock). Both launcher and loader are excluded from the device payload. The window runs the loader via exec, so on completion no shell process lingers (the window reads [Process completed]) and quitting Terminal never triggers the “terminate the running process?” prompt.
  3. Choose source folder. The first operator prompt: a native choose folder dialog (osascript, defaulting to the Desktop) asks which folder holds the content; the loader copies that folder's contents. A folder path may instead be passed as the first argument — how the run-again restart reuses the same folder without re-prompting — and text/SSH mode accepts a typed path. In firmware-update mode (--firmware, terminal-only) this step instead selects a single firmware file.
  4. Volume label prompt. Asks for the FAT label (default PLAYER); input is sanitized to [A-Za-z0-9], uppercased, truncated to 11 chars. REDO is reserved.
  5. Name mode. Optional per-run choice: keep original names, or rename every folder and file on the target to 3-digit numbers in play order (folders 001…, files 001.mp3… with extension preserved; one counter per directory covers folders and files together, restarting in each directory; the source is untouched). Children of a renamed folder are written under its renamed path.
  6. Target-player selection. The operator picks the player model (from the documented families in the operator guide) or “Other / not sure”. Encrypted-only players (MegaVoice Envision, Davar/Kivah Audibible) are refused with an explanation, before anything is touched.
  7. Resolve source disk(s). Determines which physical disk(s) hold the content folder (walking APFS synthesized→physical) so they can never be erased.
  8. Write manifest. Builds one ordered map (source → device path) of every folder and file in exact write order, with any simple-numbers renaming applied; both the copy and the preview read this same manifest, so what the operator previews is exactly what is written.
  9. Content check (profile-aware, warnings only). Runs before any disk is chosen. Validates the payload against the selected player's documented rules — playable file types, the folder depth audio is read from, documented folder-naming and name-length rules — plus generic checks (loose root files, empty folders, mixed numbered/un-numbered names, inconsistent structure). Every finding is itemized per path (path + short reason records): the dialog shows the first few per problem, the Terminal gets the complete list, and the write-order preview marks each flagged item in place. Warnings offer Cancel / Load anyway; nothing blocks, since firmware revisions vary. Name checks are skipped when simple-numbers renaming makes them moot.
  10. Order preview. A self-contained HTML page rendered from the manifest: a collapsible <details> folder tree in play order, original names alongside renamed device names, Expand/Collapse-all controls. Items flagged by the content check carry their specific reason inline; every ancestor folder of a flagged item is marked and pre-expanded, and the page opens automatically when anything is flagged. The tree is re-keyed (/ → byte 2, folders keyed just below their children) so a subtree is always contiguous even around prefix-named siblings (A / A extra); the manifest itself stays in true write order. The same preview is available on demand from the erase confirmation's Preview order… button (a failed open is contained and never aborts the confirmation), and text-mode runs (SSH) print the tree directly in the Terminal instead of opening a browser. In the erase dialog, Cancel folds into Back (3-button limit): Esc = Back, the re-shown disk list keeps the operator's previous selection, and the list's own Cancel aborts the run.
  11. Enumerate targets. Lists external physical disks, plus cards in a built-in SD slot: that reader enumerates as internal on many Macs, so internal physical disks are admitted only when diskutil reports them as removable media on a card-reader protocol (Secure Digital, or USB for USB-wired internal readers) — an internal SSD/HDD can never qualify (Apple Fabric / PCI-Express / SATA, not removable), and APFS synthesized containers are virtual, outside the physical listing. Skips the source disk(s) and any write-protected (read-only) media, e.g. an SD card with its lock slider set. Captures each disk's exact byte size for later re-checks.
  12. Pick & confirm (two dialogs). A native list of whole disks (all preselected; Cmd-click to deselect ones to keep), then an explicit “ERASE these / KEEP these” summary whose default button is Back.
  13. Consent-gated side effects. Only after confirmation: disable Finder .DS_Store writes to USB volumes (the pre-run value is captured first and restored on exit — §9). The source folder itself is never modified.
  14. Erase (parallel). At the hand-off from the erase confirmation, Terminal is re-activated once (tell application "Terminal" to activate, GUI only) so the progress bar is visible rather than buried behind the write-order preview or other windows — not looped, so the operator can switch away while it runs. Each disk is then re-verified (§5), cleanly unmounted (so the partition rewrite cannot fire a spurious “Disk Not Ejected Properly” notification), then eraseDisk'd, with one retry.
  15. Prepare & verify. Mount each freshly erased volume; proceed only if its name is the chosen label and it resolves to the expected device node.
  16. Copy (parallel). Write the content to each verified volume with the tool's own ordered copy loop (see the callout below), with before/after mount re-verification.
  17. Scrub & eject. Remove macOS junk that FAT can't avoid (§7), then eject (with retries).
  18. Results. Group every device into GOOD CHECK REDO; blink failed devices; always print device-verification advice.
  19. Run again. Offer to restart for the next batch (re-execs the script).
Files are copied in name order, recursively — by design. The tool enumerates the payload itself (find … | LC_ALL=C sort -z) and creates every folder and file with its final name, in strict byte-sorted path order — no temp files, no renames. Because the target volume is freshly formatted, each FAT directory entry is created in exactly that order, and minimal player firmware that reads files in directory-entry order (rather than sorting them itself) plays the content in the intended sequence. This is why the content folders and files are numbered (001…, 002…): the numbering is the play order, and the ordered writer preserves it onto the device.

Why not rsync? Earlier versions used rsync -rt, trusting its sorted file list — and a real player exposed the flaw: Apple's openrsync writes each file under a .name.XXXXXX temporary name and renames it into place, and on FAT every rename re-allocates the directory entry first-fit into slots freed by earlier temp entries, scrambling the final entry order (name-length dependent, so small tests can pass by luck). The fix was reproduced from the affected source folder and verified by parsing the raw FAT directory tables: the ordered writer yields exact name-sorted entry order in every directory. Any substitute copy tool must create files with final names in sorted order — an rsync-style temp/rename strategy will corrupt play order.

With the optional simple numbers mode the write is unchanged — files stream in the same sorted order — but each file is created under a per-directory 3-digit name. Directory entries therefore still follow the original play order. (Edge case: where files and sub-folders are siblings in one directory, a player that name-sorts instead of reading entry order will interleave the renamed files and the folders differently than the original names did.)

4A. Firmware-update mode (advanced, terminal-only)

Some players are firmware-updated by copying a single firmware file (typically a .ufw file, though a maker may ship any extension) onto the root of an otherwise-empty device, which self-installs on the next power-on. The --firmware flag reuses the entire engine above — whole-disk erase, volume label, ordered copy, junk scrub, eject, parallel across every selected device — but the manifest is a single entry (the chosen file, written to the volume root), so no folder walk, content check, simple-numbers renaming, or player profile applies.

5. Safety guards & rationale

These are the checks that matter for “is it safe to run/re-publish.” Most exist because an earlier version lacked them and adversarial review found a concrete failure.

GuardMechanismWhy
Never erase the source Resolve the content folder's physical disk(s) via dfPart of WholeAPFS Physical Store, and exclude them from the target list. df reports an APFS synthesized node; without the walk, a source kept on an external APFS SSD could be selected and erased.
Skip write-protected media Skip any disk whose diskutil info reports Media Read-Only: Yes. Hardware-locked cards (e.g. MegaVoice CSD lock) can't be written; skipping avoids confusing mid-run failures.
External physical only Targets come solely from diskutil list external physical, plus internal removable media on a card-reader protocol (the built-in SD slot) — never an internal SSD/HDD or an APFS synthesized container. Internal disks are never enumerated as candidates.
Two-step human confirmation A disk picker (deselect to keep) plus a distinct “ERASE / KEEP” summary dialog defaulting to Back. Shows exactly what will be wiped, by size and volume name, before any destruction; the plain-click-replaces-selection trap is defused by the second dialog.
Pre-erase identity re-check Immediately before each eraseDisk, re-verify the disk's exact byte size equals what was shown and it is still external+physical; else skip. macOS reuses diskN numbers; a device unplugged/replugged while the dialog was open could otherwise map the identifier to a different disk (TOCTOU).
Post-erase volume verify Copy only to a disk whose freshly mounted volume has the chosen label and whose mount resolves to /dev/diskNs1. If an erase silently failed, an old/foreign partition could otherwise be copied onto and reported OK.
Copy-time mount re-verify (ok_mount) Before and after the copy, confirm df <mount> is still /dev/diskNs1; during the copy the progress monitor re-checks the same identity every poll and, after two consecutive misses (~4 s), kills that transfer and removes any stray boot-disk folder the yank left behind. If a device vanishes, macOS can leave /Volumes/<name> as a plain folder on the boot disk; writing there would copy the payload onto the internal drive.
Blink write guard The LED-blink loop re-checks df == /dev/diskNs1 before every write, and only blinks volumes named as the current or REDO label. Devices are unplugged while the end-of-run dialog is up (the operator sorts them by light), and any hard-yank can leave a ghost mountpoint; without this guard the blink writes would land on the boot disk (same class as above).
Consent-first side effect The one host setting it toggles (DSDontWriteUSBStores) is changed only after the erase is confirmed, and restored on exit (§9). A user who cancels leaves their Mac untouched.
Stall timeout A copy with zero write progress for STALL_LIMIT (300 s) is killed and marked REDO. A dying device can't wedge the whole batch.
Interrupt handling trap on INT/TERM/HUP stops blink loops, kills jobs, and lists incomplete devices; an EXIT trap stops blinkers, removes the temp dir, and restores the host setting. Ctrl-C leaves a clear record of which devices must not be distributed; HUP covers a closed Terminal window.
Blinkers cannot outlive the script Each blink loop re-checks every iteration that the flag file exists and the main script's PID is still alive (kill -0 $$), exiting on its own otherwise. Even a force-quit / kill -9 (which fires no traps) cannot leave orphaned loops writing to devices after the script is gone.
Label sanitization Alphanumeric only, uppercased, ≤11 chars. FAT stores labels uppercase; punctuation can be transformed by diskutil, which would break the post-erase name check.

6. Concurrency & performance

Erase and copy both fan out one background subshell per device and wait. Each subshell writes a single status file into a private mktemp -d directory; the main process polls those files to drive the progress bar and the final grouping — there is no shared mutable state between workers. The LED-blink loops are background jobs governed by a flag file and stopped with kill/pkill (never an unbounded wait, so a device stuck in I/O can't hang the script); each loop also re-checks every iteration that the main script's PID is still alive, so no blinker can survive the script's exit — however it exits. ANSI colour is emitted only to a TTY and is kept out of the status files so parsing stays clean.

Why this is much faster than imaging a device. Restoring a disk image (e.g. with dd or Balena Etcher) writes the entire image — including empty space — to each device, and typically reads it all back to validate; a 2 GB image can mean up to ~4 GB of I/O per device. This tool instead does a plain ordered file copy of just the real content (only your actual content — ≈1.6 GB in the original deployment), with no image and no read-back verification pass. Three things compound the win: In practice the remaining bottleneck is the shared USB-hub/device bandwidth, not the Mac or the tool; splitting devices across multiple hubs on separate ports raises the ceiling further. The source location matters too: reading the content from the Mac's internal SSD (on its own high-bandwidth bus) never competes with the USB writes, whereas using a USB device as the source is capped by that device's own read speed and can bottleneck the whole batch even on a separate port.

7. macOS junk handling

macOS forces some metadata onto any FAT volume it mounts. The script's posture, verified against the OS:

Why scrubbing (rather than preventing) the ._* sidecars cannot affect play order. Creation is unpreventable without root: the sidecar is materialized by the kernel's AppleDouble shim because every new file is stamped with the com.apple.provenance xattr, which xattr -c cannot clear (verified empirically). But deletion is truly clean at the FAT level: parsing the raw directory table of a freshly loaded volume shows the content entries live and in exact sorted order, with the scrubbed sidecars reduced to 0xE5-marked free slots between them. A free slot is not a file — the FAT specification requires every reader, minimal player firmware included, to skip it (firmware that did not would fail on any disk that ever had a file deleted, including Windows-prepared ones). Verified against real hardware: a device loaded and scrubbed this way plays in correct order on a KULUMI Mini.

Net on each finished device: only .metadata_never_index and .fseventsd/no_log — two tiny hidden files, both purposeful (they keep Spotlight and fseventsd from writing anything bigger). The script does not set a read-only flag on the files (chflags uchg would re-create removable-but-annoying ._* sidecars, and a clean volume was judged more valuable; most players/Android ignore the flag anyway).

8. Failure model & operator verification

Every device ends in exactly one bucket:

Undetectable failures. A device that fully disconnected or lost power mid-copy cannot be reported accurately and will not blink (its light is dark). The script therefore always tells the operator to verify devices independently — the recommended check is to use a new/unique label per batch, then re-plug each device and confirm it returns with that label. A steady light means finished; a dark light means it failed too and must be redone. Note that the loading cable/hub may carry data only and not charge a flat battery, so a dark device should be fully recharged (e.g. via solar or a charging cable) before it is reconnected to reload.

The end-of-run dialog offers Run again (or Done) for both success and failure; on “Run again” the script cleans up (stops blink loops, removes its temp dir) and execs a fresh copy of itself for the next batch. Because successfully loaded devices are ejected and detach, a re-run naturally shows only the still-connected failures.

9. Network & privacy

The script makes no network connections and contains no telemetry, analytics, or update checks. It reads only the content folder and the attached disks, and writes only to the selected external devices. It reads the Mac's computer name (scutil --get ComputerName) solely to reference it in on-screen guidance.

It does not modify the source folder, and the one persistent host setting it touches is captured and restored, so nothing is left changed:

10. Known limitations / non-goals

11. Auditing notes

The script is a single self-contained file with no obfuscation; every destructive command is diskutil eraseDisk and every write target is validated against /dev/diskNs1 immediately before use. To audit quickly: read the guards in §5 against the code, and grep for the three writers that touch disks — eraseDisk, the ordered copy loop's cp, and the blink dd — confirming each is preceded by the identity/mount check described above. The tool was hardened across several rounds of adversarial review; the current guards are the result.

12. License & reuse rights

Audio Player Loader is licensed under the GNU Affero General Public License, version 3.0 (AGPL-3.0).
Copyright © 2026 Seth Johnston.

The full license text is included as LICENSE.txt and is the authoritative terms. The summary below is plain-language guidance, not legal advice.

What the license lets you do

You are free to use, study, modify, and redistribute this script — including on your own website, for your own devices and content. There is no fee and no need to ask permission.

Rebrand it freely. The APP_TITLE variable at the top of the script sets the name shown in every dialog, notification, and the Terminal title. Device manufacturers and others are explicitly welcome to change it to their own product name and ship it for their own players — the author encourages this. (Under AGPL-3.0 your rebranded version must still stay open source under the same license and keep the original copyright notice alongside your own.)

The conditions (copyleft)

In practice, for re-publishing on your own site

You may host it, adapt it for your own player devices and audio content, and share it, provided you (1) keep it under AGPL-3.0, (2) include LICENSE.txt and this copyright notice, and (3) offer your recipients (or your network users, if you run a modified version as a service) the corresponding source of whatever version you ship. If those terms don't fit your use, contact the copyright holder to ask about a separate licensing arrangement.