diff --git a/.ai/HANDOFF.md b/.ai/HANDOFF.md index ec73d60..34d1ef1 100644 --- a/.ai/HANDOFF.md +++ b/.ai/HANDOFF.md @@ -51,3 +51,42 @@ Append-only role handoff log. Each role adds one entry when its step is complete | Next Role | none | --- + +### T-002 — implement — 2026-09-07T08:52:07Z + +| Field | Value | +|-------|-------| +| Agent | codex | +| Summary | Added the Docker container definition and documented how to build, run, and use the downloader. | +| Files Changed | Dockerfile, README.md, .ai/TASKS.md, .ai/HANDOFF.md | +| Validation | `docker build --quiet -t yt-dl .` passed; container smoke test returned `GET /` 200 with "Download MP3"; `git diff --check` passed | +| Commit | Pending reviewer approval | +| Next Role | review | + +--- + +### T-002 — review — 2026-09-07T00:10:00Z + +| Field | Value | +|-------|-------| +| Agent | claude | +| Summary | Reviewed Dockerfile + README against `.ai/PLAN.md`; re-ran `docker build` and container smoke test, plus a live end-to-end MP3 and video download through the container against a real YouTube URL — all passed. | +| Files Changed | .ai/REVIEW.md, .ai/TASKS.md, .ai/HANDOFF.md | +| Verdict | PASS | +| Blocking Findings | none | +| Next Role | implement | + +--- + +### T-002 — implement — 2026-09-07T08:56:18Z + +| Field | Value | +|-------|-------| +| Agent | codex | +| Summary | Squashed the reviewed container and documentation changes into the task commit. | +| Files Changed | Dockerfile, README.md, .ai/REVIEW.md, .ai/TASKS.md, .ai/HANDOFF.md | +| Validation | Reviewer Docker smoke test and live MP3/video download verification passed; `git diff --check` passed | +| Commit | Created by this handoff's task commit | +| Next Role | none | + +--- diff --git a/.ai/REVIEW.md b/.ai/REVIEW.md index a950a69..5d4ba0a 100644 --- a/.ai/REVIEW.md +++ b/.ai/REVIEW.md @@ -37,3 +37,38 @@ No blocker or major findings. **Risks:** - No live network test against real YouTube was performed (would require external network access and a real video URL); mocked yt-dlp calls confirm the FastAPI plumbing (routing, form validation, error handling, file streaming, temp-dir cleanup) is correct, but do not confirm yt-dlp/ffmpeg behavior against a live video. This risk carries into the Docker-level validation planned for T-002 (`docker build` + smoke test), where a live download should be attempted at least once. - Large/long-running downloads have no timeout or size cap — acceptable for v1 per `ROADMAP.md` (out of scope), but worth revisiting if this moves beyond local/dev use. + +--- + +## T-002 — Dockerfile + README.md (build/run docs) + +**Verdict:** PASS + +### Findings + +1. **[nit]** `Dockerfile` — the container runs as root (no `USER` directive). Not required for a local/self-hosted v1 tool per `ROADMAP.md`, but worth adding a non-root user if this is ever exposed beyond a trusted local network. + - Required fix: No. + +No blocker, major, or minor findings. + +### Verification + +**Steps performed:** +- Re-read `.ai/PLAN.md` (Phase 2 spec for T-002) and diffed it against `Dockerfile` / `README.md`; matches the planned Dockerfile contents and documented build/run/usage/size-note requirements. +- `docker build -t yt-dl-review .` — exited 0. +- `docker run --rm -d -p 8091:8080 yt-dl-review` — container started; `curl http://localhost:8091/` returned HTTP 200 with both "Download MP3" and "Download Video" present in the body. +- `POST /download` with an invalid URL against the running container → 400 JSON `{"message": "..."}"`, confirming the containerized app behaves the same as the local dev checks from T-001; `docker logs` showed clean request handling with no crash/traceback. +- **Live end-to-end test** (real network, real YouTube video `https://www.youtube.com/watch?v=jNQXAC9IVRw`, "Me at the zoo"): + - `mode=mp3` → 200, `content-type: audio/mpeg`, valid ID3-tagged MP3 file returned (verified with `file`), `Content-Disposition` filename correctly derived from video title. + - `mode=video` → 200, `content-type: video/mp4`, valid ISO-Media MP4 file returned (verified with `file`). + - This closes the live-download risk flagged in the T-001 review — yt-dlp + ffmpeg inside the container work correctly end-to-end for both modes. +- Cleaned up: stopped test container, removed the `yt-dl-review` test image, removed downloaded test files. + +**Findings from verification:** All acceptance criteria for T-002 hold: +- `docker build -t yt-dl .` exits 0. +- `docker run --rm -p 8080:8080 yt-dl` starts the server. +- `curl http://localhost:8080/` returns HTML with both download buttons. +- (Bonus, beyond stated AC) A real MP3 and a real video download both succeed end-to-end through the container. + +**Risks:** +- None outstanding. The live-download risk noted in the T-001 review has been verified and closed here. diff --git a/.ai/TASKS.md b/.ai/TASKS.md index 038656d..aa99739 100644 --- a/.ai/TASKS.md +++ b/.ai/TASKS.md @@ -21,4 +21,4 @@ Command expectations: | Task ID | Scope | Status | Acceptance Criteria | Evidence | Next Role | | --- | --- | --- | --- | --- | --- | | T-001 | FastAPI backend (`app.py`) + inline HTML/JS frontend (`requirements.txt`) | done | `GET /` returns 200 with HTML containing "Download MP3"; `POST /download` with valid URL + mode streams a file; invalid URL returns 400 JSON with `.message` | Reviewer re-ran mocked FastAPI route checks (GET /, valid download, invalid/empty/missing-field errors, yt-dlp failure, unicode filename) — all passed; see `.ai/REVIEW.md` | none | -| T-002 | Dockerfile + README.md (build/run docs) | ready_for_implement | `docker build -t yt-dl .` exits 0; `docker run --rm -p 8080:8080 yt-dl` starts server; `curl http://localhost:8080/` returns HTML with download buttons | n/a | implement | +| T-002 | Dockerfile + README.md (build/run docs) | done | `docker build -t yt-dl .` exits 0; `docker run --rm -p 8080:8080 yt-dl` starts server; `curl http://localhost:8080/` returns HTML with download buttons | Reviewer re-ran `docker build` + container smoke test, plus a live end-to-end MP3 and video download against a real YouTube URL through the container — all passed; see `.ai/REVIEW.md` | none | diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..02d40af --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.12-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ffmpeg \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app.py . + +EXPOSE 8080 + +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"] diff --git a/README.md b/README.md index 90496be..e73ec7d 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,29 @@ ## Overview -TODO: Describe this project. +A small, self-hosted YouTube downloader with a browser interface. Paste a video URL and choose whether to download the best available audio as MP3 or the best available video with audio. ## Getting Started -TODO: Add setup instructions. +### Prerequisites + +- Docker + +### Build + +```bash +docker build -t yt-dl . +``` + +### Run + +```bash +docker run --rm -p 8080:8080 yt-dl +``` + +Open [http://localhost:8080](http://localhost:8080) in a browser, paste a YouTube URL, then select **Download MP3** or **Download Video**. + +Downloads are prepared on the server before they are sent to your browser. Large videos and higher-quality formats can take several minutes, depending on the source video and your network connection. ## AI Workflow