Channel Vault NAS logo

Channel Vault NAS

English · 한국어

Turn your YouTube channel into a recoverable NAS archive.
Register a channel, start a schedule, and see the backup state at a glance. Channel Vault reuses what is already on disk and saves only what is missing with yt-dlp.

CI Release Docker pulls MIT license Docs

Channel Vault NAS Home showing the three-step automatic backup flow

Quick start  ·  Bring an existing archive  ·  Is it for me?

## Three steps, then check one clear status 1. **Register a channel.** Paste its URL, `@handle`, or channel ID and confirm the result. 2. **Start a schedule.** Choose how often to check and how many videos to save per run. 3. **Check the status.** See what is saved, what remains, and when the next check will run.

Channel screen showing saved and remaining counts, automatic backup status, and the next run

The default navigation stays focused on **Home**, **Channels**, **Saved videos**, and **Settings**. Queue inspection, storage diagnostics, runtime controls, and one-pass tools remain under **Advanced management** until you need them. ## The part other download queues leave out - **Keep your current archive.** Scan existing video folders, thumbnails, subtitles, and `info.json` sidecars without downloading them again. - **See what `archive.txt` knows.** Downloaded, missing, queued, and skipped videos are visible in the UI instead of disappearing inside a command flag. - **Notice source-listing changes.** When a saved video is no longer listed by its source, Channel Vault can flag the local copy as preserved and export a preservation manifest. This does not prove deletion or that no other copy exists. Checks normally cover up to 500 recent uploads; the default time threshold is 24 hours since the video was last seen. - **Recover from disk.** Media stays the source of truth; SQLite is a searchable index that can be rebuilt from the NAS folders. - **Set it once.** Choose a download interval and batch size, start automatic backup, and pause it from the same channel screen. From the maker of [`youtube-dl-nas`](https://github.com/hyeonsangjeon/youtube-dl-nas), rebuilt for long-lived channel archives rather than one-off URL downloads. ## Is it for you? Channel Vault is an **archive operations console**, not a media player. It fits best when you already have NAS folders or an `archive.txt` and want every download, skip, and missing decision visible and recoverable from disk. It is honest about where other tools are stronger: | If you want… | Start with | | --- | --- | | A polished media server with in-app playback and a large community | [TubeArchivist](https://github.com/tubearchivist/tubearchivist) | | A simple, mature subscription downloader | [Pinchflat](https://github.com/kieraneglin/pinchflat) | | Channel subscriptions with filesystem-oriented downloading | [TubeSync](https://github.com/meeb/tubesync) · [ytdl-sub](https://github.com/jmbannon/ytdl-sub) | | **Disk-first channel archiving that reuses existing media, makes `archive.txt` decisions visible, and flags saved videos absent from the source listing** | **Channel Vault NAS** | Full breakdown: [Is it for me?](docs/about/comparison.md) ## Quick Start Channel Vault NAS runs as **two containers** — `channel-vault-nas-api` (backend) and `channel-vault-nas-web` (UI). There is no single all-in-one image; the command below pulls and starts **both**. No repository clone and no local build are required: ```bash mkdir channel-vault-nas && cd channel-vault-nas curl -fsSLO https://raw.githubusercontent.com/hyeonsangjeon/channel-vault-nas/main/compose.release.yml docker compose -f compose.release.yml up -d ``` On older Synology Docker packages, use `docker-compose` in place of `docker compose`. The release file is verified with both Compose v2 and legacy Compose 1.28.5. If Docker runs on your NAS, open **`http://:5173/`** from your computer. Use **`http://127.0.0.1:5173/`** only when Docker and your browser run on the same computer. Replace `5173` if you changed `CVN_WEB_PORT`. Then: 1. On **Home**, select **Register channel**, paste a channel URL or `@handle`, select **Check channel**, then confirm with **Register channel**. 2. Choose the all-channel check interval and videos per run, then select **Start automatic backup**. 3. Confirm the channel shows **Automatic backup is on** or **Automatic backup is running**. The same screen shows saved, remaining, and next-run details. Backup progress covers **tracked videos**, not proof that the entire channel has been scanned. Each check reads at most `CVN_CHANNEL_PROBE_VIDEO_LIMIT` uploads (`500` by default). Source-absent videos without local files are not counted as backed up. Already have files or an `archive.txt`? Follow [Bring an existing archive](docs/usage/migrate-existing-archive.md) first so Channel Vault can index them and skip unnecessary downloads. See the [compatibility matrix and real NAS report thread](docs/install/compatibility.md) before installing on new hardware. > Guardrail: this self-hosted release is built for localhost, private LAN, VPN, or trusted > reverse-proxy use. Do not expose it directly to the public internet. ## How the archive survives the app The filesystem is durable data. The database is the index and operation log. That means a future rescan can rebuild library state from media and sidecars instead of forcing a second download. ## Registry Links Both images are required. The `…-api` and `…-web` containers run together, and the Quick Start Compose file pulls both. - Docker Hub API image: [`modenaf360/channel-vault-nas-api`](https://hub.docker.com/r/modenaf360/channel-vault-nas-api) - Docker Hub web image: [`modenaf360/channel-vault-nas-web`](https://hub.docker.com/r/modenaf360/channel-vault-nas-web) - GHCR mirror: [`ghcr.io/hyeonsangjeon/channel-vault-nas-api`](https://github.com/hyeonsangjeon/channel-vault-nas/pkgs/container/channel-vault-nas-api) and [`ghcr.io/hyeonsangjeon/channel-vault-nas-web`](https://github.com/hyeonsangjeon/channel-vault-nas/pkgs/container/channel-vault-nas-web) - Documentation (install + usage manual, EN/KO): [`hyeonsangjeon.github.io/channel-vault-nas`](https://hyeonsangjeon.github.io/channel-vault-nas/) - NAS compatibility reports: [`GitHub Discussions #7`](https://github.com/hyeonsangjeon/channel-vault-nas/discussions/7) ## Why It Exists Most download tools answer one question: "Can this URL be downloaded?" Channel Vault NAS answers the NAS operator question: > "What changed, what is already archived, what is safe to download next, and > can I recover the archive if the app database disappears?" The filesystem remains the durable archive. SQLite is the index over that archive. ## Status **Out of alpha and in active development (0.3.1).** The core loop runs in Docker and local development today: register a channel, start a schedule, back up missing videos, audit what happened, and rebuild the index from disk. The default UI stays on Home, Channels, Saved videos, and Settings, with everything else tucked under Advanced management.
Everything working today (click to expand) - Channel registration and source probing - Metadata sync and automatic metadata scheduler - Per-channel policies, including `auto_download` - Candidate generation for missing videos - Download queue with preflight, retry, cancel, and bounded worker passes - Real `yt-dlp` downloads when explicitly enabled - Worker run audit with completed/skipped/failed/slow filters, scheduler tick logs, and event drawers - Runtime settings with `.env.runtime` apply/restart guidance - Storage scanner for real NAS folders, drift, pressure, and orphan sidecars - Library index with media files, sidecar fidelity, codec/profile filters, in-app preview, and portable saved views - A simple default UI with Home, Channels, Saved videos, and Settings - Queue, Insights, runtime controls, and diagnostic tools separated under Advanced management - Safe in-app demo workspace for empty installs, without YouTube calls or downloads - Versioned Docker Hub and GHCR images, with Docker Hub pull-based Compose smoke verified
Not ready yet: - Multi-user auth/session hardening for exposed networks - NAS-vendor-specific (Synology/QNAP) first-run install videos The current release direction and release gate are tracked in [`docs/roadmap.md`](docs/roadmap.md) and [`CHANGELOG.md`](CHANGELOG.md). Do not expose the app directly to the public internet. For private LAN or NAS access, enable the optional operator token described below and still prefer VPN or a trusted reverse proxy. See [`docs/deployment-security.md`](docs/deployment-security.md) for concrete Nginx, Caddy, and Cloudflare Tunnel examples. ## Known Limitations This is a guarded self-hosted release. Knowing the boundaries up front keeps deployments safe: - Built for localhost, private LAN, VPN, or trusted reverse-proxy use, not direct public internet exposure. - Downloads depend on `yt-dlp` behavior and source availability; most failures reflect upstream changes rather than app state. - There is no supported cookies/private-video workflow yet. Sources that require authenticated browser state may not be available. - There is no multi-user account system yet. Access is a single shared operator view. - The optional `CVN_AUTH_TOKEN` is an operator gate, not a full identity provider. - Public internet exposure should sit behind SSO, VPN, or reverse-proxy policy. - Some NAS package-manager restart hooks are guidance/copy-first unless a safe supervised hook is configured (`CVN_RESTART_ADAPTER_EXECUTE=true` plus a verified command). - You are responsible for backing up the metadata database and archive folders; the app does not manage off-NAS backups. See [`docs/roadmap.md`](docs/roadmap.md) for non-goals and [`SECURITY.md`](SECURITY.md) for exposure and token boundaries. For a practical fit check, see [Is Channel Vault NAS for me?](docs/about/comparison.md). ## More screens The Home and channel-status screenshots above, together with the supporting screens below, are generated from the seeded browser smoke fixture, not from static mockups. | Register a channel | Bring an existing archive | | --- | --- | | ![Channel registration with a checked result before saving](docs/assets/user-manual/en/03-channel-registration.png) | ![Import kit for existing NAS folders and archive.txt](docs/assets/screenshots/existing-archive-import.png) | Advanced management screens stay available without crowding the everyday flow: | Queue | Saved videos | Technical settings | | --- | --- | --- | | ![Download queue with candidate and worker detail](docs/assets/screenshots/queue-console.png) | ![Global library shelf with saved views, sidecar fidelity, and filtered archive coverage](docs/assets/screenshots/library-shelf.png) | ![Runtime env guide with the public access guard token setup, restart adapter, and Compose smoke verification](docs/assets/screenshots/runtime-guide.png) | Refresh the public screenshot set: ```bash cd frontend CVN_CAPTURE_PUBLIC_SCREENSHOTS=true npx playwright test e2e/public-screenshots.spec.ts --project=chromium ``` Record the deterministic public demo WebM: ```bash scripts/capture-public-demo.sh ``` The generated recording is written to `docs/assets/demo/channel-vault-public-alpha.webm` and is ignored by git until a reviewed final asset is ready to publish. ## Product Tour ### Home Home is the everyday three-step overview: register a channel, start its schedule, and read the current backup state. It keeps the next useful action, saved and remaining counts, and schedule together. ### Channels The Channels tab gives each registered channel the same focused schedule and status view: 1. Register a channel. Paste a URL / `@handle` / `UC…` ID, select **Check channel**, review it, then **Register channel**. 2. Choose the interval and per-run count, then select **Start automatic backup**. 3. Read the backup state and Total / Downloaded / Remaining counts on the same screen. 4. Bring in existing NAS folders or `archive.txt` before downloading when you already have an archive. ### Queue Queue is an **Advanced management** view for candidate, queued, running, completed, failed, and cancelled jobs. Stale failures for already-archived videos are hidden. Automatic passes are bounded by the configured per-run count; the advanced manual pass keeps its confirmation step. ### Saved videos Saved videos shows archived and missing videos together. It indexes sidecars, media files, codec/profile metadata, thumbnails, subtitles, queue state, and path integrity. Saved views make repeated NAS checks fast, and portable JSON export/import lets operators move useful views between installs. Media detail drawers can preview indexed files in-app through range-capable, per-file stream endpoints. Archive counts are disk-aware across Saved videos, channel detail, and the Home status, so stale DB rows show as missing media instead of pretending the file is still on the NAS. ### Insights Insights is an **Advanced management** view. It reads the actual archive root and reports storage pressure, folder structure, extension totals, unindexed media, indexed-but-missing files, and orphan sidecars. ### Settings Settings leads with everyday choices such as language and automatic-backup readiness. Worker flags, scheduler flags, binary paths, restart adapters, tick logs, and runtime audit events stay inside the collapsed **Technical settings** section. ## Source Build (Advanced) This section shows the source-build path. For the fastest no-build install, use [Quick Start](#quick-start) or [Run a published image](#run-a-published-image-no-build). Both paths store archive data in bind-mounted folders. There are three ways to run Channel Vault NAS: - **Local development** — run the backend and frontend dev servers directly (see [Quickstart: Local Development](#quickstart-local-development)). - **Compose build from source** — build images from this repo with Docker Compose (the steps below). Best for evaluating the current `main`/branch code. - **Pull a published image** — run tagged images from Docker Hub or GHCR without building (see [Run a published image](#run-a-published-image-no-build)). Best for a fast, reproducible install. ```bash git clone https://github.com/hyeonsangjeon/channel-vault-nas.git cd channel-vault-nas cp .env.example .env mkdir -p metadata downfolder runtime docker compose up --build ``` For NAS deployment, keep SQLite metadata, downloaded media, and runtime overrides on separate host folders before the first start: ```bash mkdir -p /volume1/channel-vault-nas/{metadata,archive,runtime} ``` ```env CVN_METADATA_HOST_DIR=/volume1/channel-vault-nas/metadata CVN_DOWNLOAD_HOST_DIR=/volume1/channel-vault-nas/archive CVN_RUNTIME_HOST_DIR=/volume1/channel-vault-nas/runtime ``` After startup, the dashboard `NAS Mount Doctor` strip verifies those paths are writable and separated. The same preset is copyable from Settings -> Env guide. For anything beyond localhost, edit `.env` first: - set `CVN_AUTH_TOKEN` to a long random value - when using a reverse proxy, publish only the web port and set `CVN_API_PORT=127.0.0.1:8000` Open: ```text http://127.0.0.1:5173/ ``` If you see only `{"detail":"Not Found"}`, you opened the raw API port instead of the web app. Open the `web` port (`CVN_WEB_PORT`, default `5173`) or point your reverse proxy at the web service. The API port is only for paths such as `/api/health`. The compose stack runs: - `api`: FastAPI backend with `yt-dlp`, `ffmpeg`, and `ffprobe` - `web`: nginx-served React app - `./metadata`: SQLite DB and startup backups - `./downfolder`: archived media and sidecars - `./runtime/.env.runtime`: Settings tab runtime overrides To verify Compose without touching your working archive folders, override the ports and host folders: ```bash mkdir -p /tmp/channel-vault-compose/{metadata,downfolder,runtime} CVN_WEB_PORT=15173 \ CVN_API_PORT=18000 \ CVN_METADATA_HOST_DIR=/tmp/channel-vault-compose/metadata \ CVN_DOWNLOAD_HOST_DIR=/tmp/channel-vault-compose/downfolder \ CVN_RUNTIME_HOST_DIR=/tmp/channel-vault-compose/runtime \ docker compose up -d --build ``` Then open `http://127.0.0.1:15173/` or call `http://127.0.0.1:18000/api/health`. The same safe verification path is available as a smoke script. It uses a separate Compose project name by default, starts the stack, waits for API, proxied API, and web health, checks the Runtime restart adapter, then prints the cleanup command: ```bash scripts/compose-smoke.sh ``` Useful overrides: ```bash CVN_COMPOSE_SMOKE_BUILD=false scripts/compose-smoke.sh CVN_COMPOSE_SMOKE_CLEANUP=true scripts/compose-smoke.sh CVN_WEB_PORT=15174 CVN_API_PORT=18001 scripts/compose-smoke.sh CVN_WEB_PORT=127.0.0.1:15174 CVN_API_PORT=127.0.0.1:18001 scripts/compose-smoke.sh ``` The smoke script checks for occupied ports before building. If your normal Compose stack is already using the default smoke ports, pass alternate `CVN_WEB_PORT` and `CVN_API_PORT` values as shown above. For an already-running NAS, LAN, or reverse-proxy deployment, run the live deployment smoke against the exposed web endpoint. When a token is provided it verifies `/api/health`, protected `/api/dashboard` `401`/`200` behavior, bearer and `X-CVN-Token` headers, and WebSocket upgrade through the web/proxy path: ```bash CVN_DEPLOYMENT_SMOKE_WEB_URL=https://vault.example.test \ CVN_DEPLOYMENT_SMOKE_AUTH_TOKEN="$CVN_AUTH_TOKEN" \ scripts/deployment-smoke.sh ``` If you also want to prove the backend API port is not exposed at a public address, pass the address that should fail: ```bash CVN_DEPLOYMENT_SMOKE_WEB_URL=https://vault.example.test \ CVN_DEPLOYMENT_SMOKE_AUTH_TOKEN="$CVN_AUTH_TOKEN" \ CVN_DEPLOYMENT_SMOKE_FORBIDDEN_API_URL=http://vault.example.test:8000 \ scripts/deployment-smoke.sh ``` Real downloads remain disabled until **Start automatic backup** is clicked in a channel. The UI hot-applies the worker and scheduler settings; no container restart is required. Operators can still set `CVN_DOWNLOAD_WORKER_ENABLED=true` in `.env` and restart manually. The Compose profile also sets `CVN_RESTART_ADAPTER=docker-compose` and `CVN_RESTART_SERVICE_NAME=api` so the Settings tab can show the correct restart command. It remains copy-only by default because the backend container does not mount the host Docker socket or ship with a Docker CLI. ### Run a published image (no build) The current `Release images` workflow publishes `api` and `web` images to both Docker Hub and GitHub Container Registry (`.github/workflows/release-images.yml`, triggered on `v*` tags or manually with `workflow_dispatch`). Docker Hub is the most familiar pull path for NAS operators; GHCR remains the GitHub-linked release registry. Run the published Docker Hub images without cloning or building the repository: ```bash mkdir channel-vault-nas && cd channel-vault-nas curl -fsSLO https://raw.githubusercontent.com/hyeonsangjeon/channel-vault-nas/main/compose.release.yml docker compose -f compose.release.yml up -d ``` Equivalent GHCR image overrides: ```bash CVN_API_IMAGE=ghcr.io/hyeonsangjeon/channel-vault-nas-api:0.3.1 CVN_WEB_IMAGE=ghcr.io/hyeonsangjeon/channel-vault-nas-web:0.3.1 ``` Direct `docker run` is also possible. Compose is still recommended because it keeps ports, volumes, health checks, and restart policy in one file, but these commands are useful for registry smoke tests. Choose Docker Hub: ```bash export CVN_API_IMAGE=modenaf360/channel-vault-nas-api:0.3.1 export CVN_WEB_IMAGE=modenaf360/channel-vault-nas-web:0.3.1 ``` Or choose GHCR: ```bash export CVN_API_IMAGE=ghcr.io/hyeonsangjeon/channel-vault-nas-api:0.3.1 export CVN_WEB_IMAGE=ghcr.io/hyeonsangjeon/channel-vault-nas-web:0.3.1 ``` Then run both containers on one Docker network. The `api` network alias is required because the web image proxies `/api` and `/ws` to `http://api:8000`. ```bash mkdir -p metadata downfolder runtime docker network create channel-vault-nas 2>/dev/null || true docker run -d \ --name channel-vault-nas-api \ --network channel-vault-nas \ --network-alias api \ -p 8000:8000 \ -e CVN_DATABASE_URL='sqlite+aiosqlite:///./metadata/app.db' \ -e CVN_METADATA_DIR='./metadata' \ -e CVN_DOWNLOAD_DIR='./downfolder' \ -e CVN_RUNTIME_ENV_FILE='/app/runtime/.env.runtime' \ -e CVN_DB_MIGRATE_ON_STARTUP=true \ -v "$PWD/metadata:/app/metadata" \ -v "$PWD/downfolder:/app/downfolder" \ -v "$PWD/runtime:/app/runtime" \ "$CVN_API_IMAGE" docker run -d \ --name channel-vault-nas-web \ --network channel-vault-nas \ -p 5173:80 \ "$CVN_WEB_IMAGE" ``` Open `http://127.0.0.1:5173/`. Cleanup: ```bash docker rm -f channel-vault-nas-web channel-vault-nas-api docker network rm channel-vault-nas ``` Notes: - Docker Hub packages are published under `modenaf360/channel-vault-nas-api` and `modenaf360/channel-vault-nas-web`. - Publishing to Docker Hub requires repository Actions secrets: `DOCKERHUB_USERNAME=modenaf360` and `DOCKERHUB_TOKEN=`. - Docker Hub and GHCR packages are public and support anonymous pulls. The `0.3.1` manifests are verified for both `linux/amd64` and `linux/arm64`. - `manifest unknown` means the requested tag has not been published. Use a listed release tag or build from source. - Set `CVN_API_IMAGE` and `CVN_WEB_IMAGE` together. If only one is set, Compose tries to pull the other from its default local tag and the pull fails. - `docker-compose.yml` defaults to local build tags (`channel-vault-nas-api:local` / `channel-vault-nas-web:local`), so unset both overrides to go back to building from source. The same `CVN_METADATA_HOST_DIR`, `CVN_DOWNLOAD_HOST_DIR`, and `CVN_RUNTIME_HOST_DIR` volume separation and `CVN_AUTH_TOKEN` guidance above apply to published images too; the NAS Mount Doctor strip still verifies the mounted host folders. ### Optional Local Access Token For LAN/NAS demos, set an operator token before starting the stack: ```env CVN_AUTH_TOKEN=replace-with-a-long-random-token ``` You can also generate, copy, and verify a token without leaving the app: open **Settings -> Env guide -> Public access guard**. It creates a strong token in your browser, copies the `CVN_AUTH_TOKEN=...` line for `.env.runtime`, and copies a 401/200 smoke-test command. The token is generated locally and is never sent to the backend, logged, or included in support bundles. When enabled, every API route except `/api/health` requires the token. The UI shows an access gate and stores the token only in the current browser. API clients can send either: ```bash curl -H "Authorization: Bearer $CVN_AUTH_TOKEN" http://127.0.0.1:8000/api/dashboard ``` or: ```bash curl -H "X-CVN-Token: $CVN_AUTH_TOKEN" http://127.0.0.1:8000/api/dashboard ``` This is a local operator guardrail, not full production internet auth. Use a VPN, trusted reverse proxy, and network-level access control for anything outside your private network. Deployment examples for private LAN or tunnel access are in [`docs/deployment-security.md`](docs/deployment-security.md). ### First Backup And Safe Demo On **Home**, select **Register channel**, paste a URL, `@handle`, or `UC...` ID, select **Check channel**, then **Register channel**. Pick the all-channel check interval and videos per run, then select **Start automatic backup**. The channel screen keeps Total / Downloaded / Remaining, the current status, and next run together. **Save schedule** applies later changes and **Pause** stops future passes. An advanced manual test remains available for one bounded pass. A fully archived channel is a completed state, not a failure. The secondary safe demo workspace action seeds a deterministic `Signal Lab` channel, one archived media item, missing-video candidates, queue history, scheduler ticks, library sidecars, storage drift, and orphan sidecars. The demo path does not call YouTube and does not start downloads. It is intended for first impressions, screenshots, public walkthroughs, and contributor orientation. If the workspace already has real registered channels, the backend refuses to seed the demo so existing archives are not mixed with fixture data. The clean-install gate says this plainly before seeding. Once loaded, the channel detail view shows a demo banner and a clear action that removes only the `Signal Lab` demo channel and its demo archive folder. ## Quickstart: Local Development Prerequisites: - Python 3.11+ - Node.js 20.19+ within the 20.x line, or 22.12+; CI verifies with Node.js 24 - `yt-dlp` - `ffmpeg` / `ffprobe` Backend: ```bash cd backend python3 -m venv .venv source .venv/bin/activate pip install -e ".[dev]" CVN_DB_MIGRATE_ON_STARTUP=true uvicorn app.main:app --host 127.0.0.1 --port 8000 ``` Frontend: ```bash cd frontend npm ci --include=dev VITE_API_BASE_URL=http://127.0.0.1:8000 npm run dev -- --host 127.0.0.1 --port 5173 ``` Open: ```text http://127.0.0.1:5173/ ``` Health check: ```bash curl http://127.0.0.1:8000/api/health ``` ## Enable Real Downloads The app is safe by default. It can plan and queue jobs without starting media transfer. Real downloads require the worker flag. For local development: ```bash CVN_DOWNLOAD_WORKER_ENABLED=true CVN_YTDLP_BINARY=yt-dlp CVN_FFPROBE_BINARY=ffprobe ``` Restart the backend after changing runtime env. **Settings → Technical settings** can persist non-secret runtime overrides into `.env.runtime` and shows whether a restart is still required. Worker passes are intentionally bounded: - Starting automatic backup enables real downloads; each pass claims only the configured **Per run** batch size (5 by default). - The advanced Manual one-pass test runs up to that same batch size once, behind a confirmation modal. - API `run-once` limits are capped. - Per-channel policy can pause worker claims. - Candidate creation can continue even when workers are paused. ## Demo And Release Verification Flow 1. Start with Docker Compose or the local development commands above. 2. Open Home and confirm the simple register → schedule → status flow. 3. Select **Register channel**, paste a channel URL, `@handle`, or `UC...` channel ID, and select **Check channel** before anything is registered. 4. Review the channel name and source, then select **Register channel**. 5. Review Total / Downloaded / Remaining, select interval and per-run count, then select **Start automatic backup**. 6. Real downloads run only after automatic backup starts (or you confirm the advanced manual test). 7. For a no-network walkthrough, expand the secondary safe demo panel and load `Signal Lab` without external calls. 8. Open **Advanced management → Queue** to inspect progress, failures, retries, and worker audit detail (stale failures for already-archived videos are hidden). 9. Open **Saved videos** and confirm completed media/index coverage changed. 10. Open **Advanced management → Insights** to inspect storage pressure, drift, and orphan sidecars. 11. Open **Settings → Technical settings** to inspect runtime flags, scheduler ticks, restart guidance, and backup confidence. 12. Return to **Home** and confirm that its single status matches the channel state. The `archive.txt` path supports the classic workflow: ```bash youtube-dl --download-archive archive.txt "https://www.youtube.com/playlist?list=..." ``` In Channel Vault NAS, that ledger becomes an app workflow: - Paste or drop `archive.txt`. - Preview already archived, known missing, unknown, duplicate, and invalid rows. - Stage only videos that still need records/candidates. - Sync metadata for placeholder rows. - Queue/download only fresh candidates. ## Filesystem Contract The default archive layout is per-video folders under the configured download root: ```text downfolder/ channels/ @handle [UC...channel_id]/ 2026/ 2026-06-03 - Video title [video_id]/ video.mp4 video.info.json *.jpg / *.webp *.vtt / *.srt ``` Design principles: - `video.info.json` sidecars live beside media. - The database indexes the filesystem, not the other way around. - Source title changes do not rename existing folders automatically. - Source deletion/private/block events never delete local media by default. - Existing NAS folders can be rescanned and indexed without moving files. ## Runtime Flags Common local flags: ```bash CVN_DOWNLOAD_DIR=./downfolder CVN_DATABASE_URL=sqlite+aiosqlite:///./metadata/app.db CVN_DB_MIGRATE_ON_STARTUP=true CVN_DOWNLOAD_WORKER_ENABLED=false CVN_DOWNLOAD_WORKER_SCHEDULER_ENABLED=false CVN_DOWNLOAD_WORKER_SCHEDULER_INTERVAL_SECONDS=300 CVN_DOWNLOAD_WORKER_SCHEDULER_LIMIT=5 CVN_METADATA_SYNC_SCHEDULER_ENABLED=false CVN_METADATA_SYNC_SCHEDULER_INTERVAL_SECONDS=900 CVN_METADATA_SYNC_SCHEDULER_LIMIT=2 CVN_YTDLP_BINARY=yt-dlp CVN_FFPROBE_BINARY=ffprobe ``` Restart adapter flags are documented in the Settings tab. Supported adapter families in the backend are manual/local dev, Docker Compose guidance, systemd, supervisor, Synology package, QNAP package, and an explicit supervised restart hook. ## Tests Backend: ```bash cd backend source .venv/bin/activate pytest ``` Frontend build: ```bash cd frontend npm run build ``` Browser smoke: ```bash cd frontend npm run e2e:smoke ``` The smoke suite starts an isolated FastAPI backend, Vite frontend, temporary SQLite DB, and temporary NAS fixture, then verifies registration, queue actions, library views, runtime/tick surfaces, storage scan panels, worker controls, and rescan flows on desktop and mobile. Protected access smoke: ```bash cd frontend CVN_E2E_AUTH_TOKEN=cvn-local-test-token npm run e2e:auth -- --project=chromium ``` This starts the same isolated stack with `CVN_AUTH_TOKEN` enabled, verifies that unauthenticated API calls return `401`, verifies bearer and `X-CVN-Token` requests, and confirms the browser access gate unlocks the app. Public release gate: ```bash scripts/public-alpha-check.sh ``` This runs backend lint/tests, locale key consistency, frontend build, Chromium browser smoke, protected access smoke, and `git diff --check`. Set `CVN_PUBLIC_ALPHA_SKIP_BROWSER=true` when you only need the fast non-browser checks. Public screenshot refresh: ```bash cd frontend CVN_CAPTURE_PUBLIC_SCREENSHOTS=true npx playwright test e2e/public-screenshots.spec.ts --project=chromium ``` Public demo recording: ```bash scripts/capture-public-demo.sh ``` For guided, screen-by-screen operator walkthroughs, open the rendered [usage manual](https://hyeonsangjeon.github.io/channel-vault-nas/usage/) ([한국어](https://hyeonsangjeon.github.io/channel-vault-nas/ko/usage/)). GitHub Pages builds the MkDocs documentation site from `docs/` and `mkdocs.yml` through the `Docs Pages` workflow. ## Documentation - [Documentation site](https://hyeonsangjeon.github.io/channel-vault-nas/) - [Install guide](https://hyeonsangjeon.github.io/channel-vault-nas/install/) ([한국어](https://hyeonsangjeon.github.io/channel-vault-nas/ko/install/)) - [Usage manual](https://hyeonsangjeon.github.io/channel-vault-nas/usage/) ([한국어](https://hyeonsangjeon.github.io/channel-vault-nas/ko/usage/)) - [Product Brief (EN)](docs/product-brief.en.md) - [Product Brief (KO)](docs/product-brief.md) - [Architecture](docs/architecture.md) - [Design Direction](docs/design-direction.md) - [Release Roadmap](docs/roadmap.md) - [Changelog](CHANGELOG.md) - [Public Demo Runbook](docs/public-alpha-demo.md) - [Docker Hub Description Source](docs/dockerhub-description.md) - [NAS Install Guide (Synology/QNAP)](docs/nas-install.md) - [Deployment Security](docs/deployment-security.md) - [Backup & Restore](docs/backup-restore.md) - [Deployment examples (systemd/supervisor)](deploy/README.md) - [Archive Priorities](docs/archive-priorities.md) - [Storage Recovery](docs/storage-recovery.md) - [Use Boundaries](docs/use-boundaries.md) - [Contributing](CONTRIBUTING.md) - [Security Policy](SECURITY.md) - [License](LICENSE) ## Public Release Checklist The goal is a public repo that can earn real adoption, not just a working local prototype. For each guarded public release: - Run `scripts/public-alpha-check.sh`. - Validate Docker Compose on macOS, Linux, and one NAS-like host. - Publish versioned container images and verify anonymous pulls from both Docker Hub and GHCR. - Keep README screenshot assets current from the Playwright seeded fixture. - Record/share a short demo video or GIF with `scripts/capture-public-demo.sh`. - Keep the safe first-run demo and runtime error copy polished. - Run full backend, frontend build, and browser smoke tests. - Tag a reviewed release, such as `v0.3.1`. ## Relationship To youtube-dl-nas This repository is a new product line. It is not a drop-in replacement for `youtube-dl-nas` v1 and does not take over the existing `modenaf360/youtube-dl-nas:latest` Docker image. The new app reuses proven platform patterns from [`hyeonsangjeon/youtube-dl-nas`](https://github.com/hyeonsangjeon/youtube-dl-nas) but changes the product model from a URL download queue to a channel archive app.