# YAAR — YouTube Auto-Archiver and Retagger Self-hosted YouTube archival system designed for Proxmox LXC (Alpine Linux). Archives YouTube videos as H.264/AAC MKVs with embedded metadata, written directly into a Jellyfin-compatible folder structure. --- ## What it does - Web UI for submitting YouTube URLs with one click - **Probes** the URL first to pre-fill title, author, and upload date - Archives as one of three Jellyfin-native types: - **YouTube video** → `/media/yaar/YouTube//.mkv` - **TV series episode** → `/media/yaar/Shows/<Series>/Season NN/SNNENN - <Title>.mkv` - **Movie** → `/media/yaar/Movies/<Title> (Year)/<Title> (Year).mkv` - Downloads best quality with **H.264 video + AAC audio** (Jellyfin-safe, no transcoding needed) - Remuxes to **MKV** with: - Embedded metadata: title, artist/channel, date, original URL, description - Embedded thumbnail - Chapter markers (if available) - Writes **NFO sidecar files** for Jellyfin scraping (series and movies) - Real-time job queue with progress bars and error reporting - Jobs persist across restarts (JSON files in `/opt/yaar/jobs/`) - Weekly **auto-update** of yt-dlp via cron --- ## Requirements - Proxmox VE 7+ (any version with LXC support) - Alpine Linux 3.20 LXC template - A storage volume or directory on the host for media (bind-mounted into the container) --- ## Quick start YAAR installs entirely from **inside your existing Alpine LXC container**. The only thing done on the Proxmox host is attaching the Jellyfin bind-mount. ### Step 1 — Attach the bind-mount in Proxmox (one-time, host only) See `proxmox-mount.md` for the full guide. In short: **Web UI:** Container → Resources → Add → Mount Point - Host path: `/mnt/nas/jellyfin` (your NAS location on the host) - Container path: `/nas/jellyfin` - Read-only: No **Or via the Proxmox host shell:** ```sh pct set <CTID> -mp0 /mnt/nas/jellyfin,mp=/nas/jellyfin pct restart <CTID> ``` ### Step 2 — Get YAAR into the container ```sh # From the Proxmox host: pct push <CTID> yaar.tar.gz /root/yaar.tar.gz # Or via scp from any machine: scp yaar.tar.gz root@<container-ip>:/root/ ``` ### Step 3 — Run setup inside the container ```sh pct enter <CTID> # enter the container, or ssh into it tar xzf /root/yaar.tar.gz -C /root/ sh /root/yaar/setup.sh ``` `setup.sh` detects if it's accidentally run on the Proxmox host and exits immediately — it will not proceed unless it's running inside a container. The script installs: - Python 3, pip, venv - ffmpeg - yt-dlp (latest), Flask, Gunicorn - OpenRC init script (`/etc/init.d/yaar`) - Weekly yt-dlp auto-update cron --- ## Service management (Alpine / OpenRC) ```sh rc-service yaar start rc-service yaar stop rc-service yaar restart rc-service yaar status ``` Logs: ```sh tail -f /opt/yaar/logs/yaar.log # Application log tail -f /opt/yaar/logs/gunicorn.log # Web server log ``` --- ## Jellyfin integration Point Jellyfin at the three library roots: | Library type | Path | |---|---| | Movies | `/media/yaar/Movies` | | Shows | `/media/yaar/Shows` | | Other (YouTube) | `/media/yaar/YouTube` | For the **Shows** library, enable NFO metadata reading so episode details from yt-dlp populate correctly. For YouTube videos, the library type "Other Videos" or "Shows" both work — choose based on preference. --- ## Format choices | Setting | Value | Why | |---|---|---| | Video codec | H.264 (avc1) | Universal Jellyfin direct-play, no transcoding | | Audio codec | AAC (mp4a) | Universal, no transcoding on any client | | Container | MKV | Supports metadata, chapters, thumbnails | | Quality | Best available H.264 | yt-dlp format selector: `bestvideo[vcodec^=avc1]+bestaudio[acodec^=mp4a]` | If a video is only available as VP9/AV1 (e.g. high-res YouTube uploads), yt-dlp falls back to the best available VP9 + audio, then remuxes to MKV. The web UI shows whatever was actually used. --- ## File structure ``` /opt/yaar/ web/ app.py ← Flask application templates/ index.html ← Web UI venv/ ← Python virtualenv logs/ yaar.log gunicorn.log access.log jobs/ ← Persisted job JSON files /media/yaar/ Movies/ Fantastic Voyage (1966)/ Fantastic Voyage (1966).mkv Fantastic Voyage (1966).nfo Shows/ Kurzgesagt/ Season 01/ S01E01 - The Egg.mkv S01E01 - The Egg.nfo YouTube/ Veritasium/ Does Planet 9 Exist.mkv ``` --- ## Configuration Environment variables (set in `/etc/yaar.env`): | Variable | Default | Description | |---|---|---| | `YAAR_BASE` | `/opt/yaar` | App, logs, jobs directory | | `YAAR_MEDIA` | `/media/yaar` | Root media output directory | | `YAAR_PORT` | `7474` | Web UI port | --- ## Updating yt-dlp manually ```sh /opt/yaar/venv/bin/pip install --upgrade yt-dlp rc-service yaar restart ``` --- ## Troubleshooting **Download fails with "Sign in to confirm your age"** YouTube sometimes requires cookies for age-restricted content. Export cookies from a logged-in browser and pass them to yt-dlp via `--cookies` in `build_ydl_opts()` in `app.py`. **H.264 format not available / falls back to VP9** Some YouTube videos are only available in VP9. YAAR will still download and remux, but Jellyfin may transcode on lower-powered clients. This is a YouTube limitation, not a YAAR bug. **Container can't write to media directory** Ensure the bind mount path exists on the host and the container has write permission. For unprivileged containers, the UID/GID mapping may need adjustment: `pct set <CT_ID> --mp0 /host/path,mp=/media/yaar,uid=0,gid=0`. **Port already in use** Edit `YAAR_PORT` in `/etc/yaar.env` and restart the service.