Speak Through Song
Created with https://github.com/Felitendo/jellyfin-plugin-lyrics in mind, allowing you to speak like Bumblebee in Discord calls, professional meetings, or.. having your Pi Agent do it as well!
Bumblebee lets you search your music library by lyrics, find the exact line you want, and export it as a professional MP3 snippet. Just like Bumblebee from Transformers communicates through radio song clips, you can now "speak" through your music collection.
- What is Bumblebee?
- Architecture Overview
- Project Structure
- Quick Start
- The Bootstrap Pipeline (7 Stages)
- The Search Engine (3 Strategies)
- API Reference
- Data Flow
- Configuration
- Technology Stack
- License
- Acknowledgments
Remember how Bumblebee from Transformers communicates? Instead of speaking, he plays clips from songs on his radio. This project lets you do the same thing with your own music library.
Here is how it works:
- Organize your music using the
bumblebee-bootstraptool -- it fingerprints your MP3s, downloads lyrics, album art, and restructures everything into a clean library. - Search by lyrics using the
bumblebeeengine -- type any line you remember, and it finds the song, the exact timestamp, and the surrounding context. - Export snippets as professional-quality MP3s -- with crossfade and proper tagging, ready to share.
Whether you are building meme audio clips, creating song-clip messages, or just want to find that one line you cannot get out of your head, Bumblebee has you covered.
Bumblebee is a two-part system. Each part is a separate, self-contained Python project managed by uv:
User's Disorganized MP3s
|
v
+-----------------------------+
| bumblebee-bootstrap | <-- Part 1: Library Bootstrap
| (Python CLI tool) |
| - Audio fingerprinting |
| - Metadata enrichment |
| - Album art + lyrics |
| - Directory restructuring |
| - Jellyfin Docker setup |
+-------------+---------------+
|
v
Organized Library
(Artist/Album/Track)
|
v
+-----------------------------+
| bumblebee | <-- Part 2: Engine
| (Python package) |
| - SQLite FTS5 search index |
| - Multi-strategy search |
| - Audio snippet extraction |
| - MP3 export + crossfade |
| - FastAPI REST backend |
| - Rich interactive TUI |
+-------------+---------------+
|
v
+-----------------+
| Web UI | <-- React + Vite + Tailwind
| (bumblebee/web)|
| - Search page |
| - Lyric viewer |
| - Chain builder|
+-----------------+
Part 1: bumblebee-bootstrap is a one-time CLI tool that takes your messy MP3 collection and transforms it into an organized, metadata-rich library. It runs seven stages from discovery to organization.
Part 2: bumblebee is the engine you use every day. It builds a search index, provides a terminal UI, a web interface, and a REST API for finding lyrics and exporting audio snippets.
Important: These are two separate uv projects. They have their own pyproject.toml files, their own dependency sets, and are used at different times. You bootstrap once, then use the engine forever.
bumblebee/
├── SPEC.md # Full technical specification
├── README.md # Comprehensive documentation
│
├── bumblebee-bootstrap/ # PART 1: Library Bootstrap
│ ├── pyproject.toml
│ └── bootstrap/
│ ├── __init__.py # Main CLI orchestration
│ ├── models.py # TrackInfo, LibraryConfig
│ ├── fingerprint.py # AcoustID + 3-tier fallback
│ ├── metadata.py # MusicBrainz + ID3 operations
│ ├── lyrics.py # lrclib.net API client
│ ├── organize.py # Artist/Album/ restructuring
│ ├── jellyfin.py # Docker Compose + plugin
│ ├── console.py # Rich progress UI
│ └── utils.py # File discovery, sanitization
│
└── bumblebee/ # PART 2: Bumblebee Engine
├── pyproject.toml
├── bumblebee/
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli.py # argparse + TUI launcher
│ ├── models.py # LyricLine, Song, Match
│ ├── lrc_parser.py # LRC file parser
│ ├── db.py # SQLite FTS5 search index
│ ├── search.py # FTS → fuzzy → word fallback
│ ├── audio.py # pydub: slice, play, export
│ ├── tui.py # Rich interactive terminal
│ └── web_api.py # FastAPI REST backend
└── web/ # REACT WEB UI
├── dist/ # Built & deployed
└── src/
├── App.tsx # Router + layout
├── api.ts # API + mock data
├── types.ts
├── components/ # 10 full components
│ ├── Navbar.tsx
│ ├── SearchBar.tsx
│ ├── ResultsList.tsx
│ ├── MatchCard.tsx
│ ├── LyricViewer.tsx # Click/shift-click selection
│ ├── AudioPlayer.tsx
│ ├── WaveformVisualizer.tsx
│ ├── SnippetExporter.tsx
│ ├── ExportPanel.tsx
│ └── ChainBuilder.tsx
└── hooks/ # 3 custom hooks
├── useAudio.ts
├── useSearch.ts
└── useSnippet.ts
For detailed technical specifications -- including exact module signatures, database schemas, API request/response shapes, and the full component inventory -- see SPEC.md.
You need two things installed: uv (the Python package manager) and npm (for the web UI only).
curl -LsSf https://astral.sh/uv/install.sh | sh
uvis a fast Python package manager and runner. It handles dependency resolution, virtual environments, and execution in one tool. All Python commands below useuv run-- notpythonorpython3directly.
cd bumblebee-bootstrap
uv run bootstrap/__init__.py --source ~/Downloads/my_mp3s --output ~/Music/Library --with-jellyfinThis runs the full 7-stage pipeline on your MP3 collection. It will fingerprint, enrich, and reorganize everything into ~/Music/Library/ in Artist/Album/Track format. The --with-jellyfin flag also generates a docker-compose.yml for running Jellyfin with the lyrics plugin.
cd ../bumblebee
uv run -m bumblebee --library ~/Music/LibraryThis opens the interactive terminal UI. Type any lyric to search, preview snippets, and export them as MP3s.
Open two terminal windows:
Terminal 1 -- Start the API server:
cd bumblebee
uv run -m uvicorn bumblebee.web_api:app --port 8000Terminal 2 -- Start the React frontend:
cd bumblebee/web
npm install
npm run devThe web UI will be available at http://localhost:5173 (or the port Vite assigns).
bumblebee-bootstrap transforms a disorganized pile of MP3 files into a clean, searchable library. Here is what happens during the 7-stage pipeline:
Recursively scans your source directory and finds all .mp3 files. Skips hidden files, system directories, and anything that is not a valid audio file.
Extracts existing ID3 tags from each MP3: title, artist, album, year, track number. These tags are used as hints for the fingerprinting stage.
Identifies each track using audio fingerprinting:
- First attempt: Use existing ID3 tags to query MusicBrainz directly.
- Second attempt: Run
fpcalc(Chromaprint binary) to generate an acoustic fingerprint, then query AcoustID. - Third attempt: Use whatever metadata is already embedded as a fallback.
Queries the MusicBrainz API for detailed metadata: full album info, release dates, track positions, artist credits, and MusicBrainz IDs. This is the authoritative source for all library metadata.
Downloads high-quality album artwork from the Cover Art Archive and embeds it directly into the MP3 files as ID3 APIC frames.
Downloads timestamp-synced lyrics (.lrc format) from lrclib.net. These lyrics include millisecond-precise timestamps for every line, which is what enables the exact snippet extraction.
Restructures all files into a clean Artist/Album/Track directory hierarchy. Renames files with sanitized names, writes a docker-compose.yml for Jellyfin with the lyrics plugin pre-configured, and ensures everything is ready for the search engine.
The bumblebee engine uses a cascading fallback system to find lyrics. When you type a query, it tries three strategies in order:
The fastest path. Every lyric line is indexed in a SQLite FTS5 virtual table. FTS5 supports prefix matching, AND/OR queries, and near-instant results even on large libraries.
- Speed: Sub-millisecond
- Best for: Exact or prefix matches
- Example: Typing "hello darkness" immediately finds Simon & Garfunkel
When FTS5 returns no results, the engine falls back to fuzzy string matching using rapidfuzz.partial_ratio. This handles typos, slight variations, and misspellings.
- Threshold: 60 (configurable)
- Best for: Queries with typos or close matches
- Example: "hello dorkness" still finds "hello darkness"
If fuzzy matching also fails, the query is split into individual words. Each word is matched independently, and results are scored by coverage percentage (how many words matched).
- Best for: Very loose queries where only some words are remembered
- Example: "darkness old friend" matches "hello darkness my old friend"
Results from all strategies are deduplicated, ranked by score, and presented as unified Match objects with the song, lyric line, timestamp, and surrounding context.
The FastAPI backend (bumblebee/web_api.py) provides a REST API used by both the web UI and available for third-party integrations.
| Endpoint | Method | Description |
|---|---|---|
/api/search?q={query} |
GET | Search lyrics using the 3-strategy cascade. Returns ranked matches. |
/api/song/{id}/lyrics |
GET | Get full lyrics (all lines with timestamps) for a song. |
/api/song/{id}/audio |
GET | Stream audio. Accepts optional start and end query params (seconds) for snippet playback. |
/api/export |
POST | Export a snippet as a standalone MP3. Body: { "song_id": str, "start": float, "end": float, "crossfade_ms": int } |
curl "http://localhost:8000/api/search?q=hello%20darkness"Returns a JSON array of Match objects:
[
{
"song": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "The Sound of Silence",
"artist": "Simon & Garfunkel",
"album": "Sounds of Silence",
"path": "/home/user/Music/Library/Simon & Garfunkel/Sounds of Silence/01 The Sound of Silence.mp3"
},
"lyric_line": {
"text": "Hello darkness, my old friend",
"timestamp": 7.42
},
"score": 1.0,
"context": {
"before": ["I've come to talk with you again"],
"after": ["Because a vision softly creeping"]
}
}
]curl -X POST "http://localhost:8000/api/export" \
-H "Content-Type: application/json" \
-d '{
"song_id": "550e8400-e29b-41d4-a716-446655440000",
"start": 7.42,
"end": 12.80,
"crossfade_ms": 200
}'Returns:
{
"success": true,
"file_path": "/home/user/Music/Bumblebee Exports/hello_darkness_my_old_friend.mp3",
"duration_seconds": 5.38
}Understanding how data flows through the system helps with debugging and customization:
Stage 1: LRC Files (bootstrap output)
|
v
+---------------------------+
| lrc_parser.py |
| Parses .lrc timestamps |
+-------------+-------------+
|
v
+---------------------------+
| db.py |
| Builds SQLite FTS5 index |
| (lyrics, songs tables) |
+-------------+-------------+
|
v
+---------------------------+
| search.py |
| 3-strategy cascade |
| FTS5 -> fuzzy -> words |
+-------------+-------------+
|
v
+---------------------------+
| web_api.py (FastAPI) |
| REST endpoints |
+-------------+-------------+
|
v
+---------------------------+
| React frontend |
| Search / Viewer / Chain |
+---------------------------+
|
v
+---------------------------+
| audio.py (pydub) |
| Slice, crossfade, export |
+----------------------------
|
v
MP3 Snippet
Bootstrapping creates the .lrc files and organized library. Indexing (db.py) reads those .lrc files and populates the SQLite FTS5 index. Searching queries that index. Exporting uses pydub to slice the original MP3 at the timestamps found in the .lrc file, applies crossfade, and writes a new MP3.
All configuration is done through environment variables. No config files needed.
| Variable | Default | Description |
|---|---|---|
BUMBLEBEE_LIBRARY |
~/Music/Library |
Path to your organized music library (the output from bootstrap) |
BUMBLEBEE_DB |
~/.local/share/bumblebee/bumblebee.db |
Path to the SQLite search index |
BUMBLEBEE_EXPORT_DIR |
~/Music/Bumblebee Exports |
Directory where exported MP3 snippets are saved |
export BUMBLEBEE_LIBRARY=/media/music/organized
export BUMBLEBEE_DB=/var/lib/bumblebee/index.db
export BUMBLEBEE_EXPORT_DIR=/media/music/snippets| Technology | Purpose |
|---|---|
| Python 3.10+ | Core language |
| uv | Package management and script execution |
| SQLite + FTS5 | Full-text search index for lyrics |
| pydub | Audio manipulation: slicing, crossfade, export |
| FastAPI | REST API backend |
| Uvicorn | ASGI server for FastAPI |
| Rich | Terminal UI framework (colors, tables, progress bars) |
| rapidfuzz | Fuzzy string matching for search fallback |
| mutagen | ID3 tag reading and writing |
| requests | HTTP client for MusicBrainz, lrclib.net, Cover Art Archive |
| Chromaprint / fpcalc | Audio fingerprinting |
| Technology | Purpose |
|---|---|
| React 19 | UI framework |
| TypeScript | Type safety |
| Vite | Build tool and dev server |
| Tailwind CSS | Utility-first styling |
| React Router | Client-side routing |
| Service | Used For |
|---|---|
| MusicBrainz | Music metadata database |
| AcoustID | Audio fingerprint identification |
| Cover Art Archive | High-quality album artwork |
| lrclib.net | Timestamp-synced lyrics |
| Jellyfin | Optional media server for library browsing |
This project is licensed under the GNU Affero General Public License v3.0 (AGPLv3).
Bumblebee - Speak Through Song
A random vibe-code project, with Pi-Agent integration.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
The full license text is available in the LICENSE file.
Why AGPLv3? Because Bumblebee includes a web interface. AGPL ensures that anyone running Bumblebee as a network service must share their modifications, keeping the project and all its derivatives free and open.
Bumblebee builds on the shoulders of giants. Special thanks to:
- Jellyfin -- The free software media system. Bumblebee generates Jellyfin-compatible configurations and uses the lyrics plugin for a complete media experience.
- Felitendo/jellyfin-plugin-lyrics -- The Jellyfin lyrics plugin that displays synced lyrics in Jellyfin. Bumblebee pre-configures this plugin in the generated Docker setup.
- lrclib.net -- An incredible free resource for timestamp-synced lyrics. The entire lyric-search capability depends on their community-maintained database.
- AcoustID / Chromaprint -- Open-source audio fingerprinting that identifies tracks even with no metadata at all.
- MusicBrainz -- The open music encyclopedia. The authoritative source for all track, album, and artist metadata.
- Rich -- The Python library that makes the terminal UI beautiful.
- rapidfuzz -- Blazing-fast fuzzy string matching in Python.
- pydub -- Simple and intuitive audio manipulation.
Speak through song.
