- Python 76.4%
- Go 17.5%
- Shell 6.1%
| .opencode/skills/media-dedup | ||
| scripts/media-dedup | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| docker-compose.yml | ||
| install_zellij.sh | ||
| manga-stack.md | ||
| README.md | ||
| root@media-stack.code-workspace | ||
*arr Stack
Utils
scp root@proxmox.lan:~/media-stack/docker-compose.yml ./
sudo docker exec caddy cat /data/caddy/pki/authorities/local/root.crt > ~/caddy-root.crt
scp root@192.168.1.50:/root/caddy-root.crt ~/Downloads/
Speedtest
curl -s https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh | sudo bash
apt install speedtest
speedtest
apt install nload -y
nload enp3s0
apt update && apt install ethtool -y
ethtool enp3s0 | grep -i Speed
docker run --rm --network=container:qbittorrent \
robinmanuelthiel/speedtest:latest
Calibre-Web
# Change admin password
sudo docker exec -it calibre-web python3 /app/calibre-web/cps.py -p /config/app.db -s admin:new_password
Transcription
docker exec subsai sh -c 'find /media/podcasts -type f \( -name "*.mp3" -o -name "*.m4b" -o -name "*.m4a" -o -name "*.ogg" \) | while read file; do
dest=$(dirname "$file")
if [ ! -f "${file%.*}.vtt" ]; then
echo "Processing: $file"
subsai "$file" -m openai/whisper -mc "{\"model_type\": \"small.en\"}" -f vtt -df "$dest"
fi
done'
watch -n 2 free -h
ls -R /mnt/data/media/podcasts/ | grep "\.vtt"
Mount Proxmox Drives
nvim /etc/fstab
mount -a
systemctl daemon-reload
Git
#!/bin/bash
LOCKFILE="/tmp/wol-media-stack.lock"
if [ ! -f "$LOCKFILE" ]; then
touch "$LOCKFILE"
wakeonlan C8:FF:BF:06:2B:75 >/dev/null 2>&1 &
fi
## TODO
### Usenet Fallback
- Add sabnzbd or nzbget as a download client
- Add usenet indexers in Prowlarr (already supports them)
- Provides a fallback when torrent trackers are down
### Backup Strategy
- Multiple Postgres instances + SQLite databases with no automated backup
- Set up `pg_dumpall` cron for all Postgres instances
- Use restic or borg for nightly backups of `/opt/docker-config/` and database dumps
- Store backups off-host (e.g. Proxmox host storage or remote)
### Database Consolidation
**Current layout:**
| Service | PG Version | Volume | User/Pass | DB Name |
|---|---|---|---|---|
| `autobrr-db` | 17 | Docker named volume | `autobrr` / from `.env` | `autobrr` |
| `rmab-db` | 15-alpine | bind mount | `rmab` / `rmab` | `readmeabook` |
| `pinepods-db` | 17 | bind mount | `postgres` / `postgres` | `pinepods_database` |
| `bitmagnet-db` | 16-alpine | bind mount | `postgres` / `postgres` | `bitmagnet` |
Goal: consolidate into a single Postgres 17 instance with 4 databases.
---
#### 1. Add new unified Postgres service
Add to `.env`:
```bash
POSTGRES_PASSWORD=<generate-strong-password>
Add to docker-compose.yml:
postgres:
image: postgres:17
container_name: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- /opt/docker-config/postgres:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
start_period: 20s
interval: 10s
mkdir -p /opt/docker-config/postgres
chown -R 1001:1001 /opt/docker-config/postgres
docker compose up -d postgres
Create databases:
docker exec postgres psql -U postgres -c "CREATE DATABASE autobrr;"
docker exec postgres psql -U postgres -c "CREATE DATABASE readmeabook;"
docker exec postgres psql -U postgres -c "CREATE DATABASE pinepods_database;"
docker exec postgres psql -U postgres -c "CREATE DATABASE bitmagnet;"
2. Dump existing databases (apps stopped, DBs running)
docker compose stop autobrr readmeabook pinepods bitmagnet
# autobrr (password from .env)
docker exec autobrr-db pg_dump -U autobrr autobrr > /opt/docker-config/postgres/dump_autobrr.sql
# readmeabook (user/pass: rmab/rmab)
docker exec readmeabook-db pg_dump -U rmab readmeabook > /opt/docker-config/postgres/dump_readmeabook.sql
# pinepods (user/pass: postgres/postgres)
docker exec pinepods-db pg_dump -U postgres pinepods_database > /opt/docker-config/postgres/dump_pinepods.sql
# bitmagnet (user/pass: postgres/postgres)
docker exec bitmagnet-postgres pg_dump -U postgres bitmagnet > /opt/docker-config/postgres/dump_bitmagnet.sql
Verify dumps (each must end with -- PostgreSQL database dump complete):
for f in /opt/docker-config/postgres/dump_*.sql; do
echo "$f: $(wc -l < "$f") lines, ends with: $(tail -1 "$f")"
done
3. Restore into new unified Postgres
docker exec -i postgres psql -U postgres -d autobrr < /opt/docker-config/postgres/dump_autobrr.sql
docker exec -i postgres psql -U postgres -d readmeabook < /opt/docker-config/postgres/dump_readmeabook.sql
docker exec -i postgres psql -U postgres -d pinepods_database < /opt/docker-config/postgres/dump_pinepods.sql
docker exec -i postgres psql -U postgres -d bitmagnet < /opt/docker-config/postgres/dump_bitmagnet.sql
If a restore fails with role/owner errors, re-dump with --no-owner --no-privileges:
docker exec <old-db> pg_dump --no-owner --no-privileges -U <user> <db> > dump.sql
4. Reconfigure applications
autobrr (docker-compose.yml):
# Change AUTOBRR__POSTGRES_HOST=autobrr-db → postgres
- AUTOBRR__POSTGRES_HOST=postgres
- AUTOBRR__POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# depends_on: autobrr-db → postgres
pinepods (docker-compose.yml):
# Change DB_HOST=pinepods-db → postgres, DB_PASSWORD=postgres → ${POSTGRES_PASSWORD}
- DB_HOST=postgres
- DB_PASSWORD=${POSTGRES_PASSWORD}
# depends_on: pinepods-db → postgres
bitmagnet (docker-compose.yml):
# Change POSTGRES_HOST=bitmagnet-db → postgres, POSTGRES_PASSWORD=postgres → ${POSTGRES_PASSWORD}
- POSTGRES_HOST=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# depends_on: bitmagnet-db → postgres
readmeabook — check /opt/docker-config/readmeabook/ for DB config file, update DB_HOST=rmab-db to DB_HOST=postgres:
docker compose stop readmeabook
ls /opt/docker-config/readmeabook/ # look for config.yaml, .env, or similar
# Update DB host + password in the config file
# depends_on: rmab-db → postgres
Critical: autobrr runs in network_mode: service:gluetun (VPN). The new postgres service must be on the default bridge network so Docker DNS resolves postgres from within the gluetun network stack.
5. Start apps and verify
docker compose up -d autobrr # check logs + web UI
docker compose up -d readmeabook
docker compose up -d pinepods
docker compose up -d bitmagnet
Verify each app's web UI loads and data is intact before proceeding.
6. Clean up old services (after full verification)
docker compose stop autobrr-db rmab-db pinepods-db bitmagnet-db
docker compose rm -f autobrr-db rmab-db pinepods-db bitmagnet-db
docker volume rm media-stack_autobrr_postgres
Remove old service definitions from docker-compose.yml (autobrr-db, rmab-db, pinepods-db, bitmagnet-db blocks).
Keep old bind mount data for 2-week grace period (do not delete yet):
/opt/docker-config/readmeabook-db//opt/docker-config/pinepods-db//opt/docker-config/bitmagnet-db/
Rollback (if anything goes wrong)
- Revert env vars back to old hostnames
- Restart old
*-dbcontainers docker compose up -d <app>- Old data is untouched — nothing was deleted from old volumes
Mylar3 Cleanup ✅
- Caddy and Homepage entries have been commented out
Container Updates
- Watchtower or diun for update notifications (currently commented out)
- Even a notify-only mode would be useful
Push Notifications
- Add ntfy, Gotify, or Apprise for push notifications across services
- Most arr apps and profilarr support webhook push notifications