Convert anything into a chapterized .m4b audiobook — from your local files, a YouTube video, an entire playlist, or a spreadsheet of links.
One script. Fully interactive. No config files needed.
- Five input sources — folder of audio files, single YT video, YT playlist, Excel/CSV spreadsheet, parent folder of subfolders (batch)
- Smart encoding — detects hardware acceleration (Apple AudioToolbox) and uses CBR; falls back to software VBR automatically
- Smart bitrate — measures source bitrate, adds a 10% buffer, and snaps up to the next CBR rung
- Original audio, never auto-dubs — YouTube encodes its machine-dubbed tracks at a higher bitrate than the original, so the tool filters to the original-language track before picking quality
- Chapter naming — keep original titles, number-only, or number + title
- Long-book splitting — books over 20h (which can stall playback on older iPods/car systems) are split into roughly-equal
(Part 1)/(Part 2)/… books at chapter boundaries, with no re-encode - Cover art — auto-detects a JPG/PNG in the source folder; falls back to YouTube thumbnail or manual path
- Rich metadata — author, narrator, year, genre, description embedded in the M4B
- Clean progress UI — per-track download bars, overall progress bar, encoding progress bar
- Audio notification — spoken "Your audiobook is ready" on completion (macOS); system sound on Windows/Linux
- Redo loop — after each audiobook finishes, offers to make another without restarting the script
- Playlist cache — playlist metadata is cached so re-runs skip the slow extraction step
- Cross-platform — macOS, Linux, Windows
| # | Input | Output |
|---|---|---|
| 1 | YouTube video URL | Single .m4b — YouTube chapters embedded automatically |
| 2 | YouTube playlist URL | Three options: one combined .m4b, pick specific videos, or one .m4b per video |
| 3 | Folder of .mp3 / .m4a / .wav etc. |
Single .m4b with chapters |
| 4 | Parent folder of subfolders (nested OK) | One .m4b per audio-containing folder at any depth (batch mode) |
| 5 | Excel / CSV — title column + URL column | Single .m4b — each row is one chapter |
- Nested folders supported — every folder at any depth that directly contains audio
becomes one audiobook, so
Parent/Theme/Level/*.mp3yields one book per level - Title from the hierarchy — joined by
-(e.g.Basics - Level 1). When nesting exists you're asked whether to include the parent folder(s) in the title or use the leaf name only; if leaf-only names would collide it keeps parents automatically - Shared metadata (author, narrator, year, genre) is asked once and applied to all
- Cover art is auto-detected per folder; a leaf with no cover inherits the nearest cover from a parent folder (one cover in a theme folder covers all its sub-books)
- Already-converted books (
.m4bin the parent) are skipped automatically - Bitrate is detected per folder independently; if >30% above source it auto-adjusts
- Python 3.10+
- FFmpeg (with
ffprobe)
# macOS
brew install ffmpeg
# Ubuntu / Debian
sudo apt install ffmpeg
# Windows — download from https://ffmpeg.org/download.htmlpip install yt-dlp tqdm pandas openpyxl
openpyxlis only needed for.xlsxfiles (mode 4). You can skip it if you use CSV instead.
git clone https://github.com/YOUR_USERNAME/audiobook-maker-pro.git
cd audiobook-maker-pro
pip install -r requirements.txtpython audiobook_maker.pyThe tool guides you through every decision interactively — no flags, no config files.
──────────────────── SPREADSHEET → ONE AUDIOBOOK ────────────────────
┌─ EXPECTED FORMAT ──────────────────────────────────────────────────┐
│ Your file must have exactly these two column headers │
│ in the first row (case-insensitive, extra spaces OK): │
│ │
│ title | link │
│ ─────────┼────────────────────────────────── │
│ Intro │ https://youtube.com/watch?v=... │
│ Chapter 1 │ https://youtube.com/watch?v=... │
│ Chapter 2 │ https://youtube.com/watch?v=... │
│ │
│ Each row = one chapter. Blank rows are skipped. │
└────────────────────────────────────────────────────────────────────┘
Path to Excel (.xlsx) or CSV file: ~/Books/my_list.xlsx
✓ 12 chapter(s) ready
...chapter naming, title, cover, metadata prompts...
──────────────────── DOWNLOADING ────────────────────────────────────
┌─ [1/12] Introduction
│ Downloading ████████████████████| 100% 3.1MB/s
└─ ✓ 1/12 audio downloaded
┌─ [2/12] Part One — Laying Plans
│ Downloading ████████████████████| 100% 2.8MB/s
└─ ✓ 2/12 audio downloaded
...
✓ 12 of 12 audio tracks downloaded successfully
──────────────────── ENCODING ───────────────────────────────────────
Encoder : Apple AudioToolbox (hardware, macOS)
Mode : Hardware · CBR
Chapters : 12
Step 1/4 Analysing source files
████████████████████| 12/12
✓ Total duration : 06:14:30
Step 3/4 Encoding [CBR 128k]
████████████████████| 22470/22470 s
✓ Encoded (CBR 128k)
┌─ DONE ─────────────────────────────────────────────────────────────┐
│ AUDIOBOOK CREATED │
│ │
│ File : my_list.m4b │
│ Location : /Users/you │
│ Size : 287.3 MB │
│ Duration : 06:14:30 │
│ Chapters : 12 │
└────────────────────────────────────────────────────────────────────┘
Your file must have exactly these two column headers in the first row:
| title | link |
|---|---|
| Introduction | https://youtube.com/watch?v=... |
| Chapter One | https://youtube.com/watch?v=... |
| Chapter Two | https://youtube.com/watch?v=... |
Rules:
- Headers are case-insensitive —
Title,TITLE,title,Titleall work - Leading/trailing spaces in headers and cell values are stripped automatically
- Blank rows are skipped silently
- Column order doesn't matter as long as both headers are present
- Both
.xlsxand.csvare supported; for.xlsxinstallopenpyxl
The tool will show a preview of the first 3 rows after loading so you can confirm it parsed correctly before anything is downloaded.
| Condition | Encoder | Mode |
|---|---|---|
| Apple hardware available | aac_at |
CBR — snapped up to next rung ≥ source × 1.10 |
| Fraunhofer FDK installed | libfdk_aac |
VBR quality level matching source × 1.10 |
| Fallback | aac (FFmpeg native) |
VBR quality level matching source × 1.10 |
CBR always rounds up to the next ladder rung, so the output is never below the source quality. The tool warns you and asks for confirmation if the computed target is more than 30% above the detected source bitrate.
CBR ladder: 64 / 96 / 128 / 160 / 192 / 256 / 320 kbps
All output files are standard .m4b (MPEG-4 Audiobook) compatible with:
- Apple Books / iTunes
- VLC
- Prologue, Bound, BookPlayer (iOS)
- Any AAC-capable player
The download is slow — is that normal? Download speed depends on your internet connection and YouTube's throttling. The progress bar shows live speed.
Can I re-run after a partial download? For playlists, failed tracks are skipped with a warning and the rest are stitched together. There is no per-track resume yet.
My audiobook is over 20 hours and stops playing on my old iPod — can it split?
Yes. When a book works out to more than 20 hours, the tool warns you (older iPods, nanos, and some car head units stop resuming playback on very long books once the screen sleeps or the app closes) and offers to split it into roughly-equal parts named (Part 1), (Part 2), … which you add as separate books. Part count is ceil(total ÷ 20h) split evenly (a 50h book becomes three ~16/17/16h parts, not 20/20/10), and you can override the count. Cuts land on chapter boundaries so no chapter is cut in half, each part keeps its own chapters and cover, and the audio is never re-encoded — it's a stream copy of the already-encoded audio, so quality is identical to the unsplit book. To change the threshold or part length, edit SPLIT_THRESHOLD_MS / MAX_PART_MS near the top of the script.
The YouTube video came out in the wrong voice or language — why? It won't any more. YouTube attaches machine-generated dubbed audio tracks to many videos and encodes them at a higher bitrate than the original, so a plain "best audio" pick lands on the dub. The tool now filters to the original-language track first and only then picks the best quality, printing which track it chose:
Audio track : en (original) — auto-dubs skipped
Videos without dubs are unaffected.
What if my folder has mixed audio formats?
Supported: .mp3 .m4a .m4b .mp4 .wav .flac .aac .ogg .opus .wma. All are concatenated via FFmpeg's concat demuxer.
Does it work with private YouTube videos? Yes — when you select a YouTube mode (2, 3, or 4), the tool asks which browser to pull cookies from. As long as you're logged into YouTube in that browser, private and Premium videos will download. Supports Safari, Chrome, Firefox, Edge, Brave, and Opera. Skip this prompt to download public videos only.
See Browser cookie permissions if you get a permission error.
Can I disable the voice notification?
The notify() function at the bottom of the script can be commented out, or you can call main() with a quick edit.
When you pick a browser in the YouTube authentication prompt, yt-dlp reads the cookie database directly from disk. On macOS, Chrome, Brave, and Edge store their cookie database in a location that requires Full Disk Access — without it you'll see this error:
ERROR: Could not copy Chrome cookie database.
- Open System Settings → Privacy & Security → Full Disk Access
- Click the + button
- Add your terminal app (Terminal.app, iTerm2, Warp, etc.)
- Re-run the script
Safari does not require Full Disk Access and works out of the box — use it if you want to avoid the permission step.
Chrome/Edge on Windows may show:
PermissionError: [Errno 13] Permission denied: '...Cookies'
Close Chrome/Edge completely before running the script, as the browser locks the cookie file while open.
No special permissions needed. Firefox cookies work without any extra steps.
MIT License — see LICENSE.
Built on top of:
