Skip to main content

Manage an ESPuino kids' audio player: library mirroring, printable RFID cards, and a local web dashboard

Project description

Funkuino

Manage an ESPuino kids' audio player from your Mac — library mirroring, printable RFID cards, and a web dashboard with an embedded Claude agent.

The ESPuino is a wonderful DIY, RFID-controlled audio player for children: put a card on the box, the story plays. What it doesn't come with is comfortable tooling for the grown-up side of the workflow — getting audio onto the device, keeping a library organised, and producing the physical cards. Funkuino is that missing half: a Mac app you can double-click, and the same tools as small, sharp command-line programs underneath.

Download Funkuino for macOS — a signed, notarised app for Apple Silicon (macOS 14+). It brings its own Python and ffmpeg, so there is nothing to install first.

Funkuino Studio — library view

Screenshots show a fictional demo library.

Funkuino Studio

Studio is a dashboard covering the entire pipeline per card — Download · Cover · Sync · Print · RFID — where the status boxes are also the actions: click a unit's sync box to upload it, select covers for printing via a floating print bar, assign RFID cards straight from the library view.

  • Live RFID assignment: Studio keeps a passive websocket to the device and hears every card placement. Put an unknown card on the box, click the row it should belong to — assigned (with sensible play-mode defaults per content type).
  • Integrated card printing with the same manifest and --undo semantics as the command line — every cover as a thumbnail (newest first, printed ones greyed out), hand-pick covers onto a sheet or one-click the oldest full page:

Funkuino Studio — card printing

  • Embedded Claude agent (optional, Claude Agent SDK): paste a URL into the library tab and an agent session handles the intake — probe, classify (song/album/audiobook), download with the right flags, verify naming and covers, report back — asking you whenever a judgment call is needed (episode numbering, attribution, intro wording), via question cards in the browser. Permission model: read-only tools and the project's own commands are auto-allowed, risky ones always raise an approval card. Needs your own Claude Code installation and a subscription token — the Agent tab walks you through both.

The tools underneath

Studio is a front end for these; each is also a command of its own, and the app puts them on your PATH as funkuino <command>.

  • funkuino sync — rsync-style mirror to the device. One-way mirror of a local files/ folder to the ESPuino over its HTTP API. Fast recursive listing, change detection via a local manifest (the device can't report file sizes cheaply), crash-safe incremental state (an interrupted upload is never trusted), size-scaled timeouts for big audiobook files, --delete with guard rails, automatic NFC/NFD Unicode normalisation (macOS vs. device), and per-device manifests keyed by MAC address — mirror the same library to two ESPuinos without confusion.
  • funkuino download — audio intake in the library's conventions. A yt-dlp wrapper that lands audio as your library expects it: songs, albums with ordered track numbers, or audiobooks (Hörspiele) — multi-part episodes merged into a single MP3 with a spoken title intro (macOS say), correct tags, and the full-resolution title image saved separately for card printing (covers are deliberately not embedded in the audio: the device has no display and a large leading ID3 tag makes playback start-stutter).
  • funkuino prepare / funkuino covers — the audiobook merge as a standalone tool, and batch extraction of embedded cover art from an existing library.
  • funkuino cards — printable RFID card sheets. Lays title images out as edge-to-edge 6×6 cm squares on A4 PDFs (12 per page) with cut tick marks in the margins. Print, stick an RFID tag on each card's back, laminate, cut. A print manifest makes a bare funkuino cards mean "everything new since last time", with stackable --undo.

Extensions — your own commands and your own agent

Some sources need handling the shipped download does not have, and everyone's library has conventions of its own. Both are extendable without touching this repository, because both live in your library folder:

  • extensions/<name>.py becomes funkuino <name>. A script dropped there is run with the project's own modules importable, so it can reuse the download pipeline, the naming rules and the device client. The one that grew this mechanism reconstructs complete audiobook series from a YouTube Music "Topic" channel, where the shipped downloader only sees a jumble of chapter tracks. An optional <name>.permissions.json ({"allow": [...], "ask": [...]}) declares how the embedded agent may call it — an extension that declares nothing simply needs your approval every time.
  • CLAUDE.md in your library folder teaches the agent your conventions. It is loaded into every agent session on top of the project's own instructions: how you want a particular series named, that a certain source needs cookies, which play mode a kind of content should get. This is how the intake flow learns your habits instead of you repeating them per download.

Install

Download the DMG from Releases, drag the app to Applications, start it. On first launch it asks for two things: where your library should live (a normal folder — put it on an external disk if you like) and your ESPuino's name or IP. Nothing else to install: the app carries its own Python runtime and a purpose-built ffmpeg.

First launch

Two limitations to know before you download:

  • The interface is German only. The tools, the code and this documentation are English, but every label and message a user sees is German. Translations would be welcome.
  • The app is Apple Silicon only (macOS 14+). The bundled Python is single-architecture, so an Intel build has to be built on an Intel Mac — possible (make release in mac/), just not something I can produce here. On Linux, install it with pipx instead (below); there the same Studio runs in your browser.

Linux (and Windows via WSL)

There is no app bundle outside macOS, but Studio and every command are plain Python and run anywhere:

pipx install funkuino
sudo apt install ffmpeg        # or dnf/pacman/zypper — funkuino tells you which

funkuino studio                # dashboard at http://127.0.0.1:8800
funkuino sync --dry-run        # see what would be uploaded
funkuino cards                 # printable PDF of the new covers

The library then defaults to ~/Funkuino/ (change it with funkuino --data-dir or a data_dir entry in ~/.config/funkuino/config.json), and configuration follows the platform: $XDG_CONFIG_HOME/funkuino on Linux, %APPDATA%\Funkuino on Windows.

Two things differ from macOS: the spoken intro in front of merged audiobooks uses macOS' say and is skipped elsewhere (the merge itself runs normally), and a finished print sheet is not opened for you — it is written to print-sheets/. Windows currently needs WSL, since the ./sync-style wrappers are shell scripts; the funkuino … commands themselves do not depend on a shell.

From source

The same tools work without any installation, and that is how they are developed:

git clone https://github.com/sadilek/Funkuino.git
cd Funkuino
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt

./sync --dry-run        # see what would be uploaded (files/ -> device)
./cards                 # lay out new cover images as a printable PDF
./studio                # open the dashboard at http://127.0.0.1:8800

bin/funkuino <command> is the same entry point the app uses; the ./sync, ./download, … wrappers in the root are one-liners onto it. A checkout keeps its library in the checkout, so cloning and running changes nothing outside it.

Requirements for the source route: Python ≥ 3.10 and ffmpeg on PATH.

Configuration: CLI flags > ESPUINO_* env vars > defaults (ESPUINO_HOST, ESPUINO_LOCAL_DIR, ESPUINO_REMOTE_ROOT, ESPUINO_HTTP_USER/_PASSWORD). FUNKUINO_DATA_DIR (or funkuino --data-dir) points the whole installation at a different library folder — that is what the app configures for you.

Library conventions

One RFID card = one unit of content, derived from file layout alone — no database:

Unit Layout
Song files/Lieder/<Artist> - <Title>.mp3
Album files/<Artist> - <Album>/<NN> <Title>.mp3
Audiobook episode files/<Series>/<NNN> - <Title>.mp3 (one merged file)
Multi-story episode files/<Series>/Folge <N>/<NN> <Story>.mp3 (folder = card, stories navigable with prev/next)

Cover images mirror the same paths under card-covers/ (one image per card).

A library folder holds files/, card-covers/, print-sheets/ and a visible status/ with the sync and print manifests — nothing hidden, so moving the library by hand cannot silently leave its state behind. Your Claude token is deliberately not in there: it lives with the installation, in ~/Library/Application Support/Funkuino/ (or ~/.config/funkuino/ on Linux).

Hard-won device knowledge

CLAUDE.md documents the ESPuino's HTTP API and a collection of quirks that took real debugging to learn — mDNS resolution cost, SD-writer wedging, why FTP is useless for diffing, NFC/NFD filename mismatches, and a full root-cause analysis of the PN5180 "resting card briefly lost during playback" problem (fixed upstream in ESPuino PR #444). If you script against an ESPuino, read it before relearning any of this the hard way.

A note on content

./download is a thin convenience wrapper around yt-dlp that organises audio into the library conventions above. Only download content you are entitled to download.

Credits & license

Built around the excellent ESPuino by biologist79 and contributors. Funkuino itself is MIT-licensed.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

funkuino-0.1.0.tar.gz (124.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

funkuino-0.1.0-py3-none-any.whl (133.9 kB view details)

Uploaded Python 3

File details

Details for the file funkuino-0.1.0.tar.gz.

File metadata

  • Download URL: funkuino-0.1.0.tar.gz
  • Upload date:
  • Size: 124.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for funkuino-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9987eb2df375eeabe9bab042e3fe98891cc724ac4fcbb09885b3ab76545117e3
MD5 68cf90d165a9ee85c0ed28aed322d6a2
BLAKE2b-256 9553dc503f5895b0a18309cc16049e9ddb760f2949e6293f369504b4d18afca5

See more details on using hashes here.

File details

Details for the file funkuino-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: funkuino-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 133.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.4

File hashes

Hashes for funkuino-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 809456f7ceffd8b2efc9d1ac713f465279b7c5d5047a76391abcada73a90a10d
MD5 ba0d9027997dd382694d067a52ebe237
BLAKE2b-256 3e9affb41b2130c7372f457f6c506784fd847f1aec399a8f236d92b058540f5c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page