Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ workflows:
- test:
matrix:
parameters:
py-version: ['3.11', '3.12', '3.13', '3.14']
py-version: ['3.11', '3.12', '3.13']
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ MAM_ID=your-mam-session-cookie-value
# Optional: known safe torrent ID for manual download integration testing
# MAM_TEST_TID=1234567

# =============================================================================
# AUDIBLE SETTINGS (OPTIONAL AUTHENTICATED SEARCH)
# =============================================================================

# Optional override for the encrypted Audible auth file consumed by mkb79/Audible
# AUDIBLE_AUTH_FILE=secrets/audible-auth.json

# Password used to decrypt the Audible auth file (not your Audible/Amazon account password)
# AUDIBLE_AUTH_FILE_PASSWORD=your-audible-auth-file-password

# NOTE: The repo install path adds mkb79/Audible from GitHub. The auth file and
# decrypt password are required only when the authenticated Audible backend is enabled.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
# =============================================================================
# QBITTORRENT SETTINGS
# =============================================================================
Expand Down
43 changes: 42 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -56,6 +56,47 @@ jobs:
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}

audible-install:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v6

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'

- name: Verify no-deps Audible install path
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
make install-audible
python - <<'PY'
import asyncio
from pathlib import Path

from src.audible_client import AudibleClientProvider

auth_file = Path("tmp-audible-auth.json")
auth_file.write_text("{}")

async def main() -> None:
provider = AudibleClientProvider(auth_file=str(auth_file), auth_file_password="test-password")
client = await provider.get_client("us")
assert client is None
await provider.aclose()

try:
asyncio.run(main())
finally:
auth_file.unlink(missing_ok=True)
PY

security:
runs-on: ubuntu-latest
steps:
Expand Down
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Makefile for audiobook-dev project

.PHONY: help install install-dev test test-fast test-integration lint lint-fix format format-check type-check clean run pre-commit ci
.PHONY: help install install-dev install-audible test test-fast test-integration lint lint-fix format format-check type-check clean run pre-commit ci

AUDIBLE_GIT_REF := 458131b4702cca48a8a6eb68c19c21b91b276d37
AUDIBLE_PIP_SPEC := git+https://github.com/mkb79/Audible.git@$(AUDIBLE_GIT_REF)

help:
@echo "Available commands:"
@echo " make install - Install production dependencies"
@echo " make install-dev - Install development dependencies"
@echo " make install-audible - Install mkb79/Audible from GitHub"
@echo " make test - Run tests with coverage"
@echo " make test-fast - Run tests without coverage"
@echo " make test-integration - Run integration tests only"
Expand All @@ -19,12 +23,17 @@ help:

install:
pip install -r requirements.txt
$(MAKE) install-audible

install-dev:
pip install -r requirements.txt
$(MAKE) install-audible
pip install -e ".[dev]"
pre-commit install

install-audible:
pip install --force-reinstall --no-deps "$(AUDIBLE_PIP_SPEC)"

test:
pytest --cov=src --cov-branch --cov-report=term-missing --cov-report=html --cov-fail-under=50 -v

Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A modern, secure, and delightfully over-engineered FastAPI microservice for auto
## ✨ Features

- **🔒 Secure Webhook Endpoint** - Token-validated integration with Autobrr/MAM
- **📖 Metadata Enrichment** - Audnex API and Audible scraping for rich book data
- **📖 Metadata Enrichment** - Audnex API and authenticated Audible lookups for rich book data
- **💾 Persistent Storage** - SQLite database with comprehensive audit trails
- **⏰ Time-Limited Tokens** - Cryptographically secure, single-use approval tokens
- **📱 Multi-Platform Notifications** - Pushover, Discord, Gotify, and Ntfy support
Expand Down Expand Up @@ -66,7 +66,7 @@ python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt
make install-dev

# Configure the system
cp config/config.yaml.example config/config.yaml
Expand All @@ -87,7 +87,7 @@ For detailed setup instructions, see the [Getting Started Guide](docs/user-guide

## 🏗️ Project Structure

```
```text
audiobook_dev/
├── docs/ # 📚 Comprehensive documentation
│ ├── user-guide/ # User documentation and guides
Expand Down Expand Up @@ -145,9 +145,11 @@ audiobook_dev/
3. **Install dependencies**

```bash
pip install -r requirements.txt
make install-dev
```

This installs the upstream `mkb79/Audible` package from GitHub for the authenticated Audible backend.

4. **Copy and edit config**
- Edit `config/config.yaml` for your environment (API URLs, notification settings, etc).
- Create a `.env` file with your secrets (see `.env.example`).
Expand Down Expand Up @@ -179,7 +181,7 @@ Configure each in `config/config.yaml` and `.env`.
## Metadata

- Uses Audnex API for fast, reliable metadata.
- Falls back to Audible scraping if needed.
- Uses `mkb79/Audible` with an encrypted auth file for Audible-backed search.
- Cleans and normalizes author, narrator, series, and description fields.
- Caches lookups with LRU cache for efficiency.

Expand Down
1 change: 1 addition & 0 deletions config/config.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ metadata:
audible:
base_url: "https://api.audible.com"
search_endpoint: "/1.0/catalog/products"
auth_file: "secrets/audible-auth.json" # Optional mkb79/Audible auth file for authenticated fallback searches


notifications:
Expand Down
2 changes: 1 addition & 1 deletion docs/PR1_REVIEW_FIXES.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Most Round 3 review comments re-flagged issues already resolved in Round 2:
- **File**: [src/audible_scraper.py](https://github.com/H2OKing89/audiobook_dev/pull/1#discussion_r2642782765)
- **Lines**: 260, 272
- **Issue**: Catching broad `Exception` instead of specific exceptions
- **Note**: Deferred - requires deeper analysis of Audible scraping error modes
- **Note**: Deferred - requires deeper analysis of authenticated Audible backend error modes
- **Status**: ⏳ Future Enhancement

### 8. ✅ Missing Cleanup - `alpine-components.js` Loading Screen (FIXED)
Expand Down
2 changes: 1 addition & 1 deletion docs/SYSTEM_COMPLETION_SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- **Modular Architecture**: Refactored metadata workflow into separate, focused modules
- `mam_api/` - MAM JSON API client, models, and metadata adapter
- `audnex_metadata.py` - Comprehensive metadata cleaning and enrichment
- `audible_scraper.py` - Audible fallback scraping
- `src/audible_scraper.py` - Authenticated Audible metadata backend
- `metadata_coordinator.py` - Orchestrates the entire workflow

### ⚡ **Async & Concurrency**
Expand Down
4 changes: 2 additions & 2 deletions docs/api/config-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ logging:

- **Type:** Boolean
- **Default:** `true`
- **Description:** Enable Audible scraping for metadata
- **Description:** Enable authenticated Audible lookups for metadata

### `metadata.cache_expiry_hours`

Expand Down Expand Up @@ -520,7 +520,7 @@ The system validates configuration on startup:

Configuration errors are reported clearly:

```
```text
Configuration Error: notifications.discord.webhook_url is required when Discord is enabled
Configuration Error: server.port must be between 1 and 65535
Configuration Error: security.token_expiry_hours cannot exceed 168 (1 week)
Expand Down
21 changes: 19 additions & 2 deletions docs/user-guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ metadata:
timeout_seconds: 10
audible:
enabled: true
timeout_seconds: 15
base_url: "https://api.audible.com"
search_endpoint: "/1.0/catalog/products"
auth_file: "secrets/audible-auth.json" # Optional - required only for authenticated Audible lookups
```

### Notifications
Expand Down Expand Up @@ -94,6 +96,10 @@ NTFY_URL=https://ntfy.sh/your-topic

# MAM API auth (optional, required for MAM metadata lookups)
MAM_ID=your-mam-session-cookie-value

# Authenticated Audible backend
# AUDIBLE_AUTH_FILE=secrets/audible-auth.json
# AUDIBLE_AUTH_FILE_PASSWORD=your-audible-auth-file-password
```

## 🔍 MAM API Configuration (Optional)
Expand All @@ -108,6 +114,16 @@ MAM_ID=your-mam-session-cookie-value

Security note: `MAM_ID` is a session token. Keep it only in `.env`, never commit it, and rotate it if it is shared or exposed.

## 🎧 Authenticated Audible Integration

The Audible backend now uses `mkb79/Audible`. Configure `AUDIBLE_AUTH_FILE` and `AUDIBLE_AUTH_FILE_PASSWORD` only when you want authenticated Audible lookups so the app can decrypt the stored auth JSON and authenticate requests.

The encrypted auth file format used by `Authenticator.from_file(...)` matches the `salt` / `iv` / `ciphertext` JSON envelope already used by this project.

`AUDIBLE_AUTH_FILE_PASSWORD` is the decryption password for the auth file. It is not your Audible or Amazon login password.

Installation note: this repo installs `mkb79/Audible` directly from GitHub because the PyPI release is behind upstream. The supported Python range for the Audible install path is 3.11-3.13.

## 🎯 Configuration Examples

### Development/Testing
Expand Down Expand Up @@ -137,7 +153,7 @@ Test your configuration:

```bash
# Test main config
python -c "from src.config import load_config; print('✅ Config valid')"
python -c "from src.config import load_config; load_config(); print('✅ Config valid')"

# Test MAM API auth (if configured)
pytest tests/test_mam_api.py -k Integration --no-cov
Expand Down Expand Up @@ -177,6 +193,7 @@ cp config/config.yaml.example config/config.yaml
- [ ] `config/config.yaml` created and configured
- [ ] `.env` file created with required tokens
- [ ] `MAM_ID` set in `.env` (if using MAM)
- [ ] `AUDIBLE_AUTH_FILE` and `AUDIBLE_AUTH_FILE_PASSWORD` set if using authenticated Audible lookups
- [ ] Configuration validated with test scripts
- [ ] Notification services tested (if enabled)
- [ ] Rate limiting configured appropriately
128 changes: 128 additions & 0 deletions docs/vendor/audible/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Audiobook Approval System - Environment Variables Template
# Copy this file to .env and fill in your actual values
# NEVER commit .env with real values to version control

# =============================================================================
# SECURITY SETTINGS
# =============================================================================

# Force HTTPS redirects (set to 'true' in production)
FORCE_HTTPS=false

# API Key for admin endpoints (generate a strong random key)
# API_KEY=your-secure-api-key-here

# =============================================================================
# DATABASE
# =============================================================================

# Path to SQLite database file
# DB_PATH=/var/lib/audiobook/db.sqlite

# =============================================================================
# AUTOBRR INTEGRATION
# =============================================================================

# Token for webhook authentication (set in autobrr)
AUTOBRR_TOKEN=your-autobrr-webhook-token

# =============================================================================
# MAM (MYANONAMOUSE) SETTINGS
# =============================================================================

# MAM session cookie value for API access
# Get this from your browser after logging into MAM (cookie name: mam_id)
# SECURITY: Never share this value - it grants full access to your MAM account
MAM_ID=your-mam-session-cookie-value

# Optional: known safe torrent ID for manual download integration testing
# MAM_TEST_TID=1234567

# =============================================================================
# AUDIBLE SETTINGS (OPTIONAL AUTHENTICATED SEARCH)
# =============================================================================

# Optional override for the encrypted Audible auth file consumed by mkb79/Audible
# AUDIBLE_AUTH_FILE=secrets/audible-auth.json

# Password used to decrypt the Audible auth file (not your Audible/Amazon account password)
# AUDIBLE_AUTH_FILE_PASSWORD=your-audible-auth-file-password

# NOTE: The repo install path adds mkb79/Audible from GitHub. The auth file and
# decrypt password are required for the Audible backend to return results.

# =============================================================================
# QBITTORRENT SETTINGS
# =============================================================================

# qBittorrent connection details
QB_HOST=http://localhost:8080
QB_USERNAME=admin
QB_PASSWORD=your-qbittorrent-password

# =============================================================================
# NOTIFICATION SERVICES
# =============================================================================

# Discord Webhook
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/your/webhook/url

# Gotify Notifications
GOTIFY_SERVER_URL=https://gotify.example.com
GOTIFY_APP_TOKEN=your-gotify-app-token

# Ntfy Notifications
NTFY_TOPIC=audiobook_requests
NTFY_TOKEN=optional-ntfy-bearer-token

# Pushover Notifications
PUSHOVER_USER_KEY=your-pushover-user-key
PUSHOVER_API_TOKEN=your-pushover-api-token

# =============================================================================
# APPLICATION SETTINGS
# =============================================================================

# Environment (development, staging, production)
ENVIRONMENT=development

# Base URL for the application (used for redirects and notifications)
BASE_URL=https://audiobook-requests.example.com

# Server host and port
HOST=0.0.0.0
PORT=8000

# =============================================================================
# LOGGING
# =============================================================================

# Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
LOG_LEVEL=INFO

# Log file path
LOG_FILE=logs/audiobook_requests.log

# =============================================================================
# SECURITY NOTES
# =============================================================================

# 1. Generate strong, unique passwords for all services
# 2. Use HTTPS in production (set FORCE_HTTPS=true)
# 3. Keep this file secure and never commit it to version control
# 4. Rotate secrets regularly
# 5. Use environment-specific configurations
# 6. Monitor logs for security events

# =============================================================================
# PRODUCTION CHECKLIST
# =============================================================================

# [ ] FORCE_HTTPS=true
# [ ] Strong API_KEY set
# [ ] All webhook tokens configured
# [ ] Database path secured
# [ ] Log rotation configured
# [ ] File permissions secured (600 for .env, 640 for logs, or 600 where feasible) using a dedicated service user and log group for intentional group-read access
# [ ] Verify deployed log files are not world-readable (for example: `stat -c '%a %n' logs/*`)
# [ ] Regular security updates scheduled
Loading
Loading