From 93eb346a001f82323f49e5ac3079616c9362d94a Mon Sep 17 00:00:00 2001 From: Dasemu Date: Mon, 24 Aug 2026 03:48:18 +0200 Subject: [PATCH] docs: update AGENTS.md and CLAUDE.md for current architecture Both were merged in from the original history and still described the old three-module, MP3-only tool. Bring them in line with the actual video-mode/x_api/models architecture. Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 22 +++++++++++++--------- CLAUDE.md | 18 +++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f5e991a..061c5ab 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,27 +1,31 @@ # X Space Downloader -Three-module CLI tool that wraps yt-dlp to download X/Twitter Space recordings as MP3. +CLI tool that downloads X/Twitter Space recordings and renders them as an MP4 replay (participant view + audio) by default, or as plain MP3 audio. ## Commands ```bash pip install -e . # Install (editable) -x-space-dl # Run the CLI +x-space-dl # Run the CLI (video mode by default) +x-space-dl --mode audio # Audio-only MP3 mode python -m src.main # Alternative invocation -pytest # Run all tests -pytest -m "not integration" # Unit tests only -pytest -m integration # Integration tests only +pytest # Run all tests +pytest -m "not integration" # Unit tests only +pytest -m integration # Integration tests only pytest tests/test_validator.py::test_valid_x_url # Single test ``` ## Architecture -- **`src/main.py`** -- Click CLI entry point. Validates URL via validator, delegates to downloader. Registered as `x-space-dl` console script. +- **`src/main.py`** -- Click CLI entry point. Validates URL via validator, then delegates to `download_space` (audio) or `download_space_video` (video, default). Registered as `x-space-dl` console script. - **`src/validator.py`** -- `validate_space_url()` returns `(is_valid, space_id, error_message)`. Accepts both `x.com` and `twitter.com` domains. -- **`src/downloader.py`** -- `download_space()` configures yt-dlp with `bestaudio/best` format and FFmpeg MP3 postprocessor. Output: `space_{SPACE_ID}.mp3`. Raises `DownloadError` on failure. +- **`src/downloader.py`** -- `download_space()` wraps yt-dlp for audio extraction. `download_space_video()` fetches Space metadata/timeline via `XApiClient`, downloads audio, then renders the MP4 via `video.render_space_video()`. +- **`src/x_api.py`** -- `XApiClient` calls X's web GraphQL (`AudioSpaceById`) and Periscope replay chat endpoints to fetch title, host, participants, and a speaker timeline. Requires the `X_BEARER_TOKEN` environment variable. +- **`src/video.py`** -- Renders the MP4 participant-view frames (Pillow) and pipes them through ffmpeg alongside the audio track. +- **`src/models.py`** -- Shared dataclasses: `Participant`, `SpaceMetadata`, `SpeakerInterval`. ## Dependencies -Runtime: `yt-dlp`, `click`. System: `ffmpeg`. Dev: `pytest`, `pytest-mock`. +Runtime: `yt-dlp`, `click`, `requests`, `Pillow`. System: `ffmpeg`. Dev: `pytest`, `pytest-mock`. -Tests mock `yt_dlp.YoutubeDL` -- no network calls in unit tests. Integration tests use `@pytest.mark.integration`. +Tests mock `yt_dlp.YoutubeDL` and network calls -- no real network access in unit tests. Integration tests use `@pytest.mark.integration`. diff --git a/CLAUDE.md b/CLAUDE.md index bb68683..fe6cec7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,8 +8,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co # Install (editable) pip install -e . -# Run the CLI +# Run the CLI (video mode by default) x-space-dl +x-space-dl --mode audio python -m src.main # Run all tests @@ -27,14 +28,17 @@ pytest -m integration ## Architecture -Three-module CLI tool that wraps yt-dlp to download X/Twitter Space recordings as MP3: +CLI tool that downloads X/Twitter Space recordings and renders them as an MP4 replay with a participant view, or as plain MP3 audio: -- **`src/main.py`** — Click CLI entry point (`cli`). Validates URL via validator, then delegates to downloader. Registered as `x-space-dl` console script. -- **`src/validator.py`** — `validate_space_url()` returns `(is_valid, space_id, error_message)` tuple. Accepts both `x.com` and `twitter.com` domains. -- **`src/downloader.py`** — `download_space()` configures yt-dlp with `bestaudio/best` format and FFmpeg MP3 postprocessor. Output files are named `space_{SPACE_ID}.mp3`. Raises `DownloadError` on failure. +- **`src/main.py`** — Click CLI entry point (`cli`). Validates the URL, then delegates to `download_space` (audio mode) or `download_space_video` (video mode, default). Registered as `x-space-dl` console script. +- **`src/validator.py`** — `validate_space_url()` returns `(is_valid, space_id, error_message)`. Accepts both `x.com` and `twitter.com` domains. +- **`src/downloader.py`** — `download_space()` wraps yt-dlp for audio extraction. `download_space_video()` fetches metadata/timeline through `XApiClient`, downloads the audio, and renders the MP4 via `video.render_space_video()`. +- **`src/x_api.py`** — `XApiClient` calls X's web GraphQL (`AudioSpaceById`) and the Periscope replay chat endpoints to build participant metadata and a speaker timeline. Requires the `X_BEARER_TOKEN` environment variable (see README). +- **`src/video.py`** — Renders MP4 frames (Pillow) of the participant view and pipes them into ffmpeg alongside the audio track. +- **`src/models.py`** — Shared dataclasses: `Participant`, `SpaceMetadata`, `SpeakerInterval`. -Tests mock `yt_dlp.YoutubeDL` — no network calls in unit tests. Integration tests use the `@pytest.mark.integration` marker. +Tests mock `yt_dlp.YoutubeDL` and outbound HTTP calls — no real network access in unit tests. Integration tests use the `@pytest.mark.integration` marker. ## Dependencies -Runtime: `yt-dlp`, `click`. System: `ffmpeg`. Dev: `pytest`, `pytest-mock`. +Runtime: `yt-dlp`, `click`, `requests`, `Pillow`. System: `ffmpeg`. Dev: `pytest`, `pytest-mock`.