A locally-running Phoenix/Elixir web application for creating personal backups of audiobooks from the OHdio platform for offline listening only. Not intended for redistribution of any files.
This is a self-hosted application that runs entirely on your own machine - it is not a cloud service or hosted platform.
The easiest way to run OHdio is with Docker Compose:
# Start the application
./dc up -d
# View logs
./dc logs -f
# Stop the application
./dc downThe web interface will be available at http://localhost:4000
Prerequisites:
- Elixir 1.17+
- Erlang/OTP 27+
- Node.js 18+ (for asset compilation)
Setup:
# Install dependencies
mix deps.get
# Create and migrate database
mix ecto.create
mix ecto.migrate
# Install JavaScript dependencies and build assets
cd assets && npm install && cd ..
mix assets.build
# Start the Phoenix server
mix phx.serverVisit http://localhost:4000 to access the application.
- Single Audiobook: Paste an OHdio audiobook URL in the input field and click "Add to Queue"
- Category Scrape: Paste a category URL to discover and queue all audiobooks in that category
- Monitor Progress: Watch downloads process in real-time on the Home page
- Audiobook URLs:
https://ici.radio-canada.ca/ohdio/livres-audio/[id]/[title] - Category URLs:
https://ici.radio-canada.ca/ohdio/categories/[id]/[name]
- Browse your downloaded audiobooks
- Search by title or author
- Play audiobooks directly in the browser
- View cover art and metadata
- Toggle between card and list views
The ./dc script simplifies Docker operations:
# Docker Compose commands
./dc up -d # Start services in background
./dc down # Stop and remove containers
./dc logs -f # Follow logs
./dc ps # List containers
# Run commands inside the Phoenix container
./dc mix test # Run tests
./dc mix ecto.migrate # Run migrations
./dc iex -S mix # Start IEx console
./dc bash # Open bash shell# Run all tests
mix test
# Run specific test file
mix test test/ohdio/scraper/audiobook_scraper_test.exs
# Run with coverage
mix test --cover# Run formatter, credo, and tests
mix precommit
# Format code
mix format
# Run static analysis
mix credo# Create database
mix ecto.create
# Run migrations
mix ecto.migrate
# Rollback migration
mix ecto.rollback
# Reset database (drop, create, migrate)
mix ecto.reset
# Generate migration
mix ecto.gen.migration add_field_to_tableThe project includes several helper scripts in the scripts/ directory for debugging and management:
check_job_errors.exs- Check for failed Oban jobscheck_queue_state.exs- View current queue stateenqueue_missing_downloads.exs- Re-queue items that weren't processedreset_download_queue.exs- Reset all queue items to queued stateretry_failed_downloads.exs- Retry failed downloadsfind_bad_urls.exs- Find and report invalid URLs in the queue
Run scripts with: ./dc mix run scripts/<script_name.exs>
- Phoenix Framework: Web framework and LiveView for real-time UI
- Elixir: Functional programming language for concurrent operations
- Ecto: Database wrapper and query generator
- SQLite: Embedded database for easy deployment
- Oban: Reliable background job processing
- Req: Modern HTTP client for scraping
- Floki: HTML parsing for web scraping
- daisyUI: Beautiful Tailwind CSS components
lib/
├── ohdio/
│ ├── application.ex # Application supervisor
│ ├── repo.ex # Ecto repository
│ ├── library/ # Library context (Audiobooks)
│ ├── downloads/ # Downloads context (Queue)
│ ├── scraper/ # Web scraping logic
│ └── workers/ # Oban background workers
├── ohdio_web/
│ ├── controllers/ # Phoenix controllers
│ ├── live/ # LiveView modules
│ ├── components/ # Reusable components
│ └── router.ex # Route definitions
priv/
├── repo/migrations/ # Database migrations
└── static/ # Static assets
test/ # Test files
Configuration files are in config/:
config.exs- Base configurationdev.exs- Development environmenttest.exs- Test environmentruntime.exs- Runtime configuration
Key configuration options:
# Database
config :ohdio, Ohdio.Repo,
database: "ohdio_dev.db",
pool_size: 5
# Oban (background jobs)
config :ohdio, Oban,
engine: Oban.Engines.Lite,
queues: [default: 10, downloads: 1, scraping: 2]
# Phoenix Endpoint
config :ohdio, OhdioWeb.Endpoint,
http: [port: 4000],
secret_key_base: "..."OHdio follows linuxserver.io conventions for better portability and easier backups. All persistent data is stored in a single /config directory with PUID/PGID support for proper file permissions.
The included compose.yml is configured for development with hot-reloading:
# Start development environment
./dc up -d
# Access at http://localhost:4001All persistent data is stored in ./config/ in your project directory:
./config/db/- SQLite database./config/downloads/- Downloaded audiobooks./config/logs/- Application logs
For production, use compose.prod.yml as a template:
# 1. Copy and customize the production compose file
cp compose.prod.yml docker-compose.yml
# 2. Edit the file and set:
# - Your domain in PHX_HOST
# - SECRET_KEY_BASE (generate with: mix phx.gen.secret)
# - PUID/PGID to match your host user (run: id)
# - Volume path (e.g., /opt/ohdio/config:/config)
# 3. Start the service
docker compose up -dImportant Production Settings:
-
Data Directory: Change the bind mount to your preferred location:
volumes: - /opt/ohdio/config:/config # Host path : Container path
-
User Permissions: Set PUID/PGID to match your host user:
# Find your user/group ID id # Output: uid=1000(username) gid=1000(username) # Set in compose file environment: - PUID=1000 - PGID=1000
-
Secret Key: Generate and set a secure secret:
docker run --rm hexpm/elixir:1.17.3-erlang-27.1.2-debian-bookworm-20241016-slim \ mix phx.gen.secret
SECRET_KEY_BASE- Phoenix secret key (generate withmix phx.gen.secret)PHX_HOST- Your domain name (e.g., audiobooks.example.com)
PUID- User ID for file ownership (default: 1000)PGID- Group ID for file ownership (default: 1000)
MIX_ENV- Application environment (dev/prod)PORT- HTTP port (default: 4000)DATABASE_PATH- SQLite database path (default: /config/db/ohdio_prod.db)STORAGE_PATH- Download storage path (default: /config/downloads)LOG_PATH- Application logs path (default: /config/logs)
POOL_SIZE- Database connection pool size (default: 10)MAX_CONCURRENT_DOWNLOADS- Concurrent downloads (default: 3)MIN_DISK_SPACE_MB- Minimum free disk space (default: 1000)
With the linuxserver.io structure, backing up is simple:
# Backup all data
tar -czf ohdio-backup.tar.gz /opt/ohdio/config/
# Restore
tar -xzf ohdio-backup.tar.gz -C /
# Or migrate to new host
rsync -av /opt/ohdio/config/ newhost:/opt/ohdio/config/This tool is intended for personal backup purposes only to enable offline listening of content you have the right to access. Do not redistribute any downloaded files. Please respect copyright laws and terms of service.
Contributions are welcome! Please see the Development Guide for details.
This project uses Backlog.md for task management. View tasks in backlog/tasks/.
MIT License - see LICENSE file for details
The original Python implementation has been archived in archive/python_original/. See that directory for the legacy codebase.