Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit dcc6501471c9d7f0cc6c65b79cd9df408732b774
parent fc175654d01b10966ba45fa5933e39f5b6c3b742
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 10 Oct 2026 00:43:16 -0400

plans: release 21 D2, as shipped (the saved-container tier for clip windows)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Meditor/CHANGELOG.md | 1+
Mplans/release-21.md | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- **A clip window of a video whose source is saved is cut from it, not fetched.** `fetch_clip`, `POST /api/media/fetch-window` and `pnpm ops fetch-windows` now cut a window out of the video's saved container (a persisted source, a full-source fetch, or media attached from a local archive) when it covers the seconds asked for, and answer at once as a cached window — no request to the platform, so a deleted channel's held videos are clippable. The window's sidecar records `source: "saved-video"`, and the video page marks it "cut from the saved video". A batch runs such windows as their own job on `clips:saved-video`, outside every platform's queue, hold and cooldown. A saved video whose file cannot be read (its drive unplugged, the file gone) is refused with the media guard's sentence rather than fetched; one that ends before the window is fetched as before. - **An X fetch with a `limit` stops at that many posts.** "Fetch posts" with `limit` (`pnpm ops fetch-posts {"limit": 400}`) on a gallery-dl X channel read the whole history instead — a new channel walked 3,803 posts under the rate limit and held the platform queue for hours — because the cap counted media files, which a metadata-only read has almost none of. It now caps the posts themselves. - **A home seeder of last resort, behind a VPN.** `archilyzer seed` seeds the playable torrents of the sites named in the new `settings.seeder` (`sites`, `trackers`, `maxUploadKiBps`, `maxConnections`, `pollSeconds`, `standbyAfterSeconds`, `bindInterface`; SETTINGS.md) to desktop clients over TCP and to browsers over WebRTC — but each torrent only while no other seeder has it: other seeders seen on every poll for `standbyAfterSeconds` puts that torrent on standby (it stops announcing and closes its peers, keeping the data), and it comes back at once when a leecher is waiting with no other source, or after the same window with no other seeder. Every change is logged with its reason. No DHT, no local discovery, no UPnP. `archilyzer tracker` is a self-hosted HTTP + WebSocket tracker that tracks only those torrents. `docker-compose.seeder.yml` (profile `seeder`) runs both inside a WireGuard container's network namespace (gluetun, its firewall always on), so a tunnel that is down means no network, never the home connection; the WireGuard config is yours (`SEEDER_WG_CONF`, required, mounted read-only). `archilyzer doctor` compares the seeder's egress address with the host's and fails when they are the same; it says "seeder not configured" until `seeder.sites` names a site. - **Saved videos can be made browser-playable, with a torrent each.** `pnpm ops prepare-playable` (`POST /api/ops/prepare-playable`) and `archilyzer media playable <slug>` remux each of a channel's saved containers — without re-encoding (`-c copy`) — into an mp4 with its index in front, or a webm when it already is one (VP9/AV1 with Opus), drop subtitles, metadata and chapters, and make one single-file torrent of the copy: named `<id>.<ext>`, no web seed, no comment, no "created by", 256 KiB–1 MiB pieces. They go to `playable/<slug>/<id>/` beside the saved-video store, listed in `playable/<slug>/playable.json` with each infohash. `"trackers"` is the announce list written into each torrent (none by default); it is not part of the infohash, so the same torrent can be announced elsewhere later. A video already prepared from the same source (by sha256) is skipped, so a re-run is a no-op; a codec a browser cannot play without re-encoding (HEVC, MPEG-4 Part 2) is listed and left alone. diff --git a/plans/release-21.md b/plans/release-21.md @@ -299,6 +299,68 @@ the three new records is the operator's (`transcribe-one`), as ruled. D2, D4, D5 `test:scripts` 708 + 3 skipped, four builds, the full editor suite (start mode) green after re-running three load flakes alone. The pilot below waits for D2. +#### D2, as shipped — clip windows cut from a saved container + +Release 21's D2, on `r20/d2-r20` off `r20/integration` (`585be292`), overnight 2026-10-10 (Track D, part 1). + +**What it does.** `common/lib/savedVideoWindow-server.ts`: `savedWindowSource` reads the video's saved-video +pointer (any pointer — a persist, a `full: true` fetch, a D1 `local-archive` attach), stats the container through +the drive watchdog (`onDrive`) and probes it once (`probeMedia`), answering `none` (no pointer), `unreadable`, +`not-covering` (the window ends past the container's duration, to `WIN_EPS`) or `covers`; `cutSavedVideoWindow` +cuts with evidenceClip-server's `evidenceCutArgs` (input-seeked, H.264 + AAC mp4 fitted inside 1280×720; a container +with no picture is cut as sound) to a temp name, renames it to `clips/<from>-<to>.mp4`, and writes the fetched +sidecar shape (`requestedBy`, `manifest`, `clipId`, `reason`, `requestedAt`, `pad`, `bytes`, `fetchedAt` = when it +was cut) plus `source: "saved-video"` — a new optional `ClipProvenance.source` that `parseClipProvenance` reads; +absent on every fetched window. +- **Single** (`fetchWindowAction`): the clip cache, then the in-flight jobs (A5), then the saved container, then + the network. `covers` → the channel's text guard (`assertChannelTextReadable`, which a `fetch-window` job's + `needsText` would have asked), the cut, `cached: true` with the window's probed `height`, no job. `unreadable` → + 503 with the media guard's sentence (`Channel "<slug>": media is not reachable — its saved video <path> is not + there (drive not mounted?)`, or `… could not be read by ffprobe`, or the watchdog's `drive not answering …`), or + the store guard's (`SavedVideosStoreInTransitionError`) when the file is missing while the store's move marker + is present. `none` and `not-covering` → the network path, unchanged. A failed cut → 500 with ffmpeg's last lines. +- **Batch** (`fetchWindowsAction` → `controller/fetchWindows.ts`): after the cache and the in-flight check, a + covered window joins one group of its own — platform `saved-video` on `clips:saved-video` + (`SAVED_VIDEO_CLIP_QUEUE` / `SAVED_VIDEO_CLIP_PLATFORM`, `lib/queueKeys.ts`), which `groupRefusal` does not + ask about a hold or cooldown; an unreadable one is `unresolved` with the guard's sentence; a not-covering one joins + its platform's group. The controller asks the same tier for every item before the URL and the gap: a cut costs no + pause and is not a network attempt (`result.cut`, logged `✂`, and "N cut from saved videos" in the summary); + `unreadable` fails the item as `unreachable`; a failed cut is the new class `cut-failed` and the run carries on. + A5's dedupe covers the new queue unchanged: a queued `saved-video` job's items are in its spec. +- The video page's fetched-windows card adds "· cut from the saved video" to such a window. `mcp/src/instructions.ts` + (the clip step): "A video the archive holds locally is cut from its saved copy without a fetch (cached at once)." + +**Rulings applied.** No pointer → the network exactly as before; a pointer whose container is unreadable → refused, +never a fall-through; a container that does not cover the window → the network (orchestrator, 2026-10-10). + +**Found and left.** +- A local cut is at most 1280×720 (evidenceCutArgs' box), whatever `maxHeight` asks; the answer carries the window's + `height`, as a cached window's does. A smaller `maxHeight` gets a cut taller than it asked for. +- `ops-api.spec` cannot reach a cut: the e2e server runs with `FFMPEG_BIN`/`FFPROBE_BIN` set to the fixture fakes + (`editor/package.json` `dev:test`/`start:test`), whose ffprobe answers a bare duration, never `-of json`, so every + saved container there probes as unreadable. The nearest tests run the real thing instead: the route test cuts + over HTTP with real ffmpeg, and the action test runs the `saved-video` batch job through `runManagedFunction` to + `done` (below). No e2e case was added. + +**Commits** + +| Commit | What | +|---|---| +| `11753809` | `channels:` release 21 D2 — the saved-container tier in the single and batch window paths, `ClipProvenance.source`, the `clips:saved-video` queue, the card's marker, the MCP line; 18 tests | + +**Gates.** `pnpm -r --no-bail --workspace-concurrency=1 exec tsc --noEmit` clean. New tests, all real ffmpeg over +8 s lavfi containers in temp dirs: `lib/savedVideoWindow-server.test.ts` 9 (no pointer; not covering; a missing +container; an unmounted store dir; the store mid-move; a file ffprobe cannot read; the cut and its sidecar, read +back by the clip cache; sound only; a failing ffmpeg leaves nothing), `controller/fetchWindows.test.ts` +2 (cut / +unreadable / not-covering in one run with no request and no pause; a failed cut), `app/api/media/fetch-window/ +route.saved.test.ts` 4 (a covered window → 200 `cached: true`, `provenance.source` `saved-video`, height 90, no job, +then a clip-cache hit; past the container's end → the network door, a YouTube cooldown's 409; a missing container +→ 503 with the guard's sentence; no pointer → the network door), `app/channels/[slug]/videos/ +fetchWindowsAction.test.ts` 3 (the dry run's groups and unresolved; a real run whose `saved-video` job ends `done` +with the window and sidecar on disk while the cooling YouTube group is refused; A5's dedupe on `clips:saved-video`). +Editor unit 225/225; the touched common files (clipWindow, evidenceClip, savedVideo*, fetchWindows, windowJobs) +61/61; architecture 6/6; mcp 293/293. The whole common suite runs once at the end of the track (part 2). + ## Rollout (pilot) 1. `pnpm ops attach-media --json '{"slug":"the-incredible-salt-mine","source":"<archive>/Uploads/YouTube.zip","dryRun":true}'`.