Activeweb appsPythonMIT

Mam Audiofinder

WebUI for audiobook downloads

78 stars8 forks41 viewsAdded 1mo ago

AI-Agent Assisted

Tier 2
Other AI Agent
Signals: vibe-coded-topic

README

MAM Audiobook Finder

A lightweight web app + API to quickly search MyAnonamouse for audiobooks, add them to qBittorrent, and import completed downloads into your Audiobookshelf library.

Search Import

Features

  • Search MAM by title, author, or narrator
  • One-click add to qBittorrent (with its own category)
  • History view of all books you've added
  • Inline import tool to copy or hard-link completed downloads into your Audiobookshelf library
  • Minimal, fast UI that works on desktop and mobile
  • ZERO AUTHENTICATION (Please don't put this on the open internet. Tailscale or a Cloudflare Tunnel with Cloudflare Access might be good options.)
  • Spouse tested and approved

Requirements

  • qBittorrent with WebUI enabled
  • A valid MAM session cookie
  • Docker & Docker Compose

Because You'll Ask

Why build this instead of using Readarr or one of its revivals, forks, or related projects?

  • This uses the MAM API directly, not just for finding books but also for metadata. It doesn't rely on any other systems or databases. This is great for me because when a book shows up in my search results I KNOW I can download it, and I know the metadata like narrator and format will be accurate.
  • I wanted something I could use from my phone that would be as fast as I could make it. This is very fast.
  • This also keeps things dead simple. There's no queue, no requests, no ranking of multiple sources, no usenet, no RSS. Just search, download, and import to library.

Quick Start

This repository includes a docker-compose.yml for Docker users. The usual flow is:

  1. Clone this repository and cd into it:
    git clone https://github.com/raygan/mam-audiofinder.git
    cd mam-audiofinder
    
  2. Copy .env.example.env and fill in the required env-only values:
    • App port and host paths (APP_PORT, DATA_DIR, and optionally MEDIA_ROOT if you use the single media mount for hard links)
    • Container user/permissions (PUID, PGID, UMASK)
    • You can either set MAM/qB details here (MAM_COOKIE, QB_URL, QB_USER, QB_PASS) or leave them commented out and fill them in later via the web setup UI.
  3. (Optional) I reccomend mounting a single Docker volume (MEDIA_ROOT, mounted as /media) that contains both your qBittorrent downloads AND your Audiobookshelf library, to allow for hard linking insteaed of copying between the two. If you prefer separate mounts instead of a single MEDIA_ROOT, adjust the volumes section in docker-compose.yml as shown in the storage examples below, and set DL_DIR / LIB_DIR in .env to match.
  4. Start the container with Docker Compose:
    docker compose up -d
    
  5. Visit http://localhost:8008 (or your mapped port). On first run, you should land on /setup to configure MAM, qBittorrent, and library paths.

Environment Variables

VariableDescription
MAM_COOKIEYour MAM session cookie (use ASN-locked cookie)
QB_URLqBittorrent WebUI URL (e.g. http://qbittorrent:8080)
QB_USERqBittorrent WebUI username
QB_PASSqBittorrent WebUI password
APP_PORTHost port that exposes the app’s web UI (used in docker-compose.yml)
MEDIA_ROOTHost path mounted at /media inside the container (often a root that contains qB downloads and/or Audiobookshelf library; single filesystem recommended for hardlinks)
DATA_DIRHost path where this app stores its state (e.g. SQLite DB)
DL_DIRIn-container path for qBittorrent downloads (default /media/torrents)
LIB_DIRIn-container path for Audiobookshelf library (default /media/audiobookshelf)
IMPORT_MODElink, copy, or move (default link)
QB_CATEGORYCategory assigned to new torrents (default mam-audiofinder)
QB_POSTIMPORT_CATEGORYCategory to set after import (empty = unset)
QB_SAVEPATHOptional explicit save path sent to qBittorrent when adding torrents
QB_TAGSComma-separated list of tags applied to new torrents (default MAM,audiobook)
QB_INNER_DL_PREFIXqBittorrent’s internal download path prefix (default /downloads)
QB_PATH_MAPOptional env form of qB → app path mapping (qb_prefix=app_prefix;…)
PUIDContainer user ID (for file permissions, default 99)
PGIDContainer group ID (for file permissions, default 100)
UMASKFile creation mask (default 0002)
DISABLE_SETUPWhen set to 1/true, hides the setup button and disables /setup and /api/setup after initial configuration

Storage configuration examples

The app only cares about the in‑container paths DL_DIR (qBittorrent downloads) and LIB_DIR (Audiobookshelf library). How you mount host paths into the container is up to you. For example:

1. Single media root (hardlink‑friendly)

If your downloads and library live under a common parent on the same filesystem, you can use the default single MEDIA_ROOT mount.

Example host layout:

  • qB downloads: /mnt/media/torrents
  • Audiobookshelf: /mnt/media/audiobookshelf

.env:

MEDIA_ROOT=/mnt/media
DL_DIR=/media/torrents
LIB_DIR=/media/audiobookshelf
IMPORT_MODE=link

docker-compose.yml (default) already contains:

volumes:
  - ${DATA_DIR}:/data
  - ${MEDIA_ROOT}:/media

Because both DL_DIR and LIB_DIR are under /media (and on the same filesystem), IMPORT_MODE=link can use hardlinks where possible.

2. Separate mounts (downloads and library on different paths)

If your downloads and library are on different host paths (for example, separate disks/volumes, or you don’t want to mount a large media tree), you must update docker-compose.yml to mount each path explicitly and then point DL_DIR / LIB_DIR at those in-container locations. In this setup, MEDIA_ROOT is not used.

Example host layout:

  • qB downloads: /mnt/disk1/torrents
  • Audiobookshelf: /mnt/disk2/audiobooks

docker-compose.yml (adjust or override the volumes section):

volumes:
  - ${DATA_DIR}:/data
  - /mnt/disk1/torrents:/downloads
  - /mnt/disk2/audiobooks:/library

.env:

DL_DIR=/downloads
LIB_DIR=/library
# MEDIA_ROOT is unused in this layout

Hardlinks will still work if /downloads and /library end up on the same underlying filesystem; otherwise the app automatically falls back to copying files.

This project was created to scratch a personal itch, and was almost entirely vibe-coded with OpenAI Codex. I will probably not be developing it further, looking at issues, or accepting pull requests. Do not run this on the open internet! Are you a real developer? Do you want to fork or rewrite this project and make it not suck? Go for it!

License

MIT — provided as-is, no warranty.

Tags

built-with-otherpython

Similar Tools