Archilyzer · Source

archilyzer

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

commit 41f43b3ba1471294a0dde8ef3a0295d279b1ce12
parent 9a61334a986324dae398051625c8f92aed5d8122
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu, 24 Sep 2026 21:56:14 -0400

common: site.json transcriptDownloads — per-video export controls, opt-out, absent = on

The archives pattern: type, SITE_FIELD_DOCS entry, zod field that is off only
on an explicit false, and siteToDisk writes the key only when false. SITE.md
regenerated.

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

Diffstat:
MSITE.md | 7+++++++
Mcommon/lib/siteSchema.test.ts | 13++++++++++++-
Mcommon/lib/siteSchema.ts | 7+++++++
3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/SITE.md b/SITE.md @@ -26,6 +26,7 @@ Regenerate this file with `pnpm --filter yt-dlp-transcript-common exec tsx bin/f | [`pwa`](#pwa) | `false` | | [`archives`](#archives) | `true` | | [`duplicates`](#duplicates) | `true` | +| [`transcriptDownloads`](#transcriptdownloads) | `true` | | [`archiveMaxBytes`](#archivemaxbytes) | absent | | [`hubUrl`](#huburl) | absent | @@ -185,6 +186,12 @@ Whether this site publishes the Duplicates page (and its header link). Opt-OUT: Default: `true` +## `transcriptDownloads` + +Whether a visitor gets the per-video export controls in the transcript modal: the Download menu (txt / srt / json), Copy MD and Copy download command. Opt-OUT: absent/true = on, only an explicit `false` hides them. The machine contract (`/corpus.json`, manifests, shards, `llms.txt`) is served either way. The editor always shows them. + +Default: `true` + ## `archiveMaxBytes` Per-site served-file size cap in bytes: any archive larger is dropped from what is served and flagged in the manifest, so a capped host (Cloudflare Pages: 25 MB) will not reject the deploy. 0 = no cap. Absent = the global default. Negative or non-numeric values are dropped. diff --git a/common/lib/siteSchema.test.ts b/common/lib/siteSchema.test.ts @@ -58,6 +58,7 @@ test("empty, null, [] and a number all read as the defaults, every key emitted", assert.equal(want.defaultGroupId, "default"); assert.equal(want.archives, true); assert.equal(want.duplicates, true); + assert.equal(want.transcriptDownloads, true); assert.equal(want.pwa, false); assert.deepEqual(want.relatedSites, []); assert.equal(want.socialLinks, undefined); @@ -104,13 +105,19 @@ test("socialLinks: absent inherits (undefined), [] overrides", () => { assert.equal(parseSite("s", { socialLinks: "x" }).socialLinks, undefined); }); -test("archives / duplicates are off only when explicitly false", () => { +test("archives / duplicates / transcriptDownloads are off only when explicitly false", () => { for (const v of [undefined, true, 0, "false", null]) { assert.equal(parseSite("s", { archives: v }).archives, true, String(v)); assert.equal(parseSite("s", { duplicates: v }).duplicates, true, String(v)); + assert.equal( + parseSite("s", { transcriptDownloads: v }).transcriptDownloads, + true, + String(v), + ); } assert.equal(parseSite("s", { archives: false }).archives, false); assert.equal(parseSite("s", { duplicates: false }).duplicates, false); + assert.equal(parseSite("s", { transcriptDownloads: false }).transcriptDownloads, false); }); test("siteToDisk persists only the non-defaults", () => { @@ -129,6 +136,7 @@ test("siteToDisk persists only the non-defaults", () => { parseSite("s", { archives: false, duplicates: false, + transcriptDownloads: false, pwa: true, archiveMaxBytes: 1024.9, siteUrl: "https://a.example/", @@ -141,6 +149,7 @@ test("siteToDisk persists only the non-defaults", () => { ); assert.equal(full.archives, false); assert.equal(full.duplicates, false); + assert.equal(full.transcriptDownloads, false); assert.equal(full.pwa, true); assert.equal(full.archiveMaxBytes, 1024); assert.equal(full.siteUrl, "https://a.example"); @@ -177,6 +186,7 @@ function fixtures(): Array<[string, unknown]> { archives: false, archiveMaxBytes: -1, duplicates: false, + transcriptDownloads: false, hubUrl: "ftp://nope", bogus: true, }, @@ -225,5 +235,6 @@ test("writeSite → getSite round-trips, and the file holds only non-defaults", const disk = JSON.parse(await readFile(siteConfigFile(paths, "s"), "utf8")); assert.equal(disk.archives, false); assert.equal("duplicates" in disk, false); + assert.equal("transcriptDownloads" in disk, false); assert.equal("pwa" in disk, false); }); diff --git a/common/lib/siteSchema.ts b/common/lib/siteSchema.ts @@ -85,6 +85,7 @@ export type Site = { pwa?: boolean; archives?: boolean; duplicates?: boolean; + transcriptDownloads?: boolean; archiveMaxBytes?: number; hubUrl?: string; }; @@ -118,6 +119,8 @@ export const SITE_FIELD_DOCS: FieldDocs<Site> = { "Whether the site build generates downloadable transcript/live-chat archive zips (and links them on the Downloads page). Opt-OUT: absent/true = on, only an explicit `false` disables. Also gated by the global setting and a per-build flag.", duplicates: "Whether this site publishes the Duplicates page (and its header link). Opt-OUT: absent/true = on, only an explicit `false` hides it. Even when on, the page auto-hides when the site has no in-scope duplicate clusters.", + transcriptDownloads: + "Whether a visitor gets the per-video export controls in the transcript modal: the Download menu (txt / srt / json), Copy MD and Copy download command. Opt-OUT: absent/true = on, only an explicit `false` hides them. The machine contract (`/corpus.json`, manifests, shards, `llms.txt`) is served either way. The editor always shows them.", archiveMaxBytes: "Per-site served-file size cap in bytes: any archive larger is dropped from what is served and flagged in the manifest, so a capped host (Cloudflare Pages: 25 MB) will not reject the deploy. 0 = no cap. Absent = the global default. Negative or non-numeric values are dropped.", hubUrl: @@ -239,6 +242,9 @@ export const siteFieldsSchema = z.object({ // Opt-out: only an explicit false disables. Absent/true stays on. archives: settingsField((v): boolean => v !== false).describe(d.archives), duplicates: settingsField((v): boolean => v !== false).describe(d.duplicates), + transcriptDownloads: settingsField((v): boolean => v !== false).describe( + d.transcriptDownloads, + ), archiveMaxBytes: settingsField(archiveMaxBytesOf).describe(d.archiveMaxBytes), hubUrl: settingsField(parseSiteUrl).describe(d.hubUrl), }); @@ -319,6 +325,7 @@ export function siteToDisk(site: Site): Site { // Persist only the non-default: archives is on unless explicitly disabled. ...(site.archives === false ? { archives: false } : {}), ...(site.duplicates === false ? { duplicates: false } : {}), + ...(site.transcriptDownloads === false ? { transcriptDownloads: false } : {}), ...(archiveMaxBytes !== undefined ? { archiveMaxBytes } : {}), ...(hubUrl ? { hubUrl } : {}), };