commit 68bdda4abfc6a81fe8e4d9445fb5489fa5b96716
parent 7370d0bb2ace02bf9efb4043f385247a2a2f9dc6
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sun, 20 Sep 2026 17:49:35 -0400
Make the read route's live counts opt-in
readChannelStat walks every video directory — eleven thousand readdirs on the
largest channel here — and a poll loop asking for a channel's state every few
seconds must not be the thing that hammers the platter. The report's totals
answer the same question from a file, so the walk is behind ?counts=1
(`pnpm ops get channel <slug> --counts`) and the field is named `counts` to say
what it is.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
4 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/RUNNING_IN_DOCKER.md b/RUNNING_IN_DOCKER.md
@@ -269,7 +269,9 @@ The read side needs no new routes for jobs: `/api/jobs/active`,
`/api/jobs/<id>/log`, `/api/scheduler/status` and `/api/auto-queue/status`
already exist. `GET /api/ops/channel/<slug>` is the one addition — config,
report totals, bucket sizes, priority and, the part no directory listing can
-tell you, whether the channel's media is actually **reachable**.
+tell you, whether the channel's media is actually **reachable**. Add `--counts`
+(`?counts=1`) for the live on-disk counts; it is opt-in because it walks every
+video directory, eleven thousand of them on the largest channel here.
### Booting without resuming work
diff --git a/editor/app/api/ops/channel/[slug]/route.ts b/editor/app/api/ops/channel/[slug]/route.ts
@@ -30,6 +30,12 @@ export const dynamic = "force-dynamic";
// tell an unmounted drive from an empty channel. Every enumerator else swallows
// ENOENT on data/ as "no videos", so a script reading counts alone would read an
// unmounted platter as a channel that has downloaded nothing.
+//
+// `?counts=1` ADDS THE LIVE ON-DISK COUNTS, and it is opt-in because
+// readChannelStat walks every video directory — eleven thousand readdirs on the
+// largest channel here. The report's totals answer the same question from a
+// file, and a poll loop asking for them every few seconds must not be the thing
+// that hammers the platter.
export async function GET(
request: Request,
{ params }: { params: Promise<{ slug: string }> },
@@ -46,9 +52,10 @@ export async function GET(
);
}
const priority = getSettings().channelPriority;
+ const wantCounts = new URL(request.url).searchParams.get("counts") === "1";
const [snapshot, stat, media] = await Promise.all([
readChannelSnapshot(paths, slug),
- readChannelStat(paths, slug),
+ wantCounts ? readChannelStat(paths, slug) : Promise.resolve(null),
inspectChannelMedia(paths, slug, config),
]);
const buckets = snapshot
@@ -68,7 +75,8 @@ export async function GET(
overrides: overridesOf(priority, slug),
rank: rankOf(priority, slug),
},
- stat,
+ // null unless ?counts=1 — see the header.
+ counts: stat,
media,
report: snapshot
? {
diff --git a/scripts/archilyzer-ops.mjs b/scripts/archilyzer-ops.mjs
@@ -9,7 +9,7 @@
// USAGE
//
// pnpm ops <action> [--json '<body>'] [--wait] [--quiet]
-// pnpm ops get channel <slug>
+// pnpm ops get channel <slug> [--counts]
// pnpm ops list
//
// ARCHILYZER_EDITOR_URL editor base URL (default http://localhost:3001)
@@ -42,7 +42,10 @@ const DEFAULT_URL = "http://localhost:3001";
// an ops API that let a caller assemble arbitrary GET paths would be a proxy,
// not an adapter.
const GETTERS = {
- channel: (slug) => `/api/ops/channel/${encodeURIComponent(slug)}`,
+ // --counts adds the LIVE on-disk counts, which walk every video directory —
+ // opt-in for the same reason the route makes it opt-in.
+ channel: (slug, counts) =>
+ `/api/ops/channel/${encodeURIComponent(slug)}${counts ? "?counts=1" : ""}`,
};
const ACTIONS = [
@@ -67,12 +70,15 @@ export function parseArgs(argv) {
let json = null;
let wait = false;
let quiet = false;
+ let counts = false;
for (let i = 0; i < argv.length; i++) {
const arg = argv[i];
if (arg === "--wait") {
wait = true;
} else if (arg === "--quiet") {
quiet = true;
+ } else if (arg === "--counts") {
+ counts = true;
} else if (arg === "--json") {
json = argv[++i];
if (json === undefined) {
@@ -111,7 +117,12 @@ export function parseArgs(argv) {
};
}
if (!positional[2]) return { error: `get ${noun}: needs an argument` };
- return { method: "GET", path: GETTERS[noun](positional[2]), wait: false, quiet };
+ return {
+ method: "GET",
+ path: GETTERS[noun](positional[2], counts),
+ wait: false,
+ quiet,
+ };
}
const action = positional[0];
if (!ACTIONS.includes(action)) {
@@ -130,7 +141,7 @@ export function parseArgs(argv) {
export function usage() {
return [
"Usage: pnpm ops <action> [--json '<body>'] [--wait]",
- " pnpm ops get channel <slug>",
+ " pnpm ops get channel <slug> [--counts]",
" pnpm ops list",
"",
`Actions: ${ACTIONS.join(", ")}`,
diff --git a/scripts/archilyzer-ops.test.mjs b/scripts/archilyzer-ops.test.mjs
@@ -63,3 +63,10 @@ test("get refuses an unknown noun and a missing argument", () => {
test("an unknown flag is refused", () => {
assert.match(parseArgs(["sync", "--force"]).error, /unknown flag/);
});
+
+test("get channel --counts asks for the live on-disk counts", () => {
+ const p = parseArgs(["get", "channel", "x", "--counts"]);
+ assert.equal(p.path, "/api/ops/channel/x?counts=1");
+ // Off by default: the counts walk every video directory.
+ assert.equal(parseArgs(["get", "channel", "x"]).path, "/api/ops/channel/x");
+});