Docs/Skills and code/src/

src/series-viewer/public/app.js

Code256 lines19.5 KBsrc/

What the file says about itself

Series analysis viewer client. Routes: / | /s/:series[?tab=videos|channels&channel=..] | /s/:series/v/:videoId

// Series analysis viewer client. Routes: / | /s/:series[?tab=videos|channels&channel=..] | /s/:series/v/:videoId
const app = document.getElementById("app");
const crumbs = document.getElementById("crumbs");

function h(tag, attrs, ...kids) {
  const el = document.createElement(tag);
  for (const [k, v] of Object.entries(attrs ?? {})) {
    if (v == null || v === false) continue;
    if (k === "class") el.className = v;
    else if (k.startsWith("on")) el.addEventListener(k.slice(2), v);
    else if (k === "checked" || k === "value" || k === "disabled") el[k] = v;
    else el.setAttribute(k, v);
  }
  for (const kid of kids.flat()) if (kid != null && kid !== false) el.append(kid.nodeType ? kid : document.createTextNode(String(kid)));
  return el;
}
const api = async (url, opts) => {
  const r = await fetch(url, opts);
  if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error ?? `${r.status} ${r.statusText}`);
  return r.json();
};
const compact = x => (x == null ? "–" : new Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(x));
const int = x => (x == null ? "–" : Number(x).toLocaleString("en-US"));
const fixed = (x, d = 2) => (x == null ? "–" : Number(x).toFixed(d));
const dur = s => (s == null ? "–" : `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`);
const ageText = r => {
  if (r.age_days != null) return r.age_days >= 365 ? `${(r.age_days / 365).toFixed(1)} y` : `${Math.round(r.age_days)} d`;
  if (r.published_at) { const d = (Date.now() - Date.parse(r.published_at)) / 864e5; return d >= 365 ? `${(d / 365).toFixed(1)} y` : `${Math.round(d)} d`; }
  return r.search_published_text ?? "–";
};
const thumb = (id, big) => `https://i.ytimg.com/vi/${id}/${big ? "maxresdefault" : "mqdefault"}.jpg`;
const link = (href, ...kids) => h("a", { href, onclick: e => { if (e.metaKey || e.ctrlKey) return; e.preventDefault(); go(href); } }, ...kids);
function go(href) { history.pushState({}, "", href); route(); }
window.addEventListener("popstate", route);
const setCrumbs = parts => { crumbs.replaceChildren(...parts.map(([label, href]) => (href ? link(href, label) : h("span", {}, label)))); };

async function route() {
  const url = new URL(location.href);
  const parts = url.pathname.split("/").filter(Boolean);
  app.replaceChildren(h("p", { class: "muted" }, "Loading…"));
  try {
    if (!parts.length) return await homePage();
    if (parts[0] === "s" && parts[2] === "v") return await videoPage(decodeURIComponent(parts[1]), parts[3]);
    if (parts[0] === "s") return await seriesPage(decodeURIComponent(parts[1]), url.searchParams);
    app.replaceChildren(h("p", {}, "Not found."));
  } catch (e) {
    app.replaceChildren(h("div", { class: "status err" }, `Could not load this page: ${e.message}`));
  }
}

// ------------------------------------------------------------------ home
async function homePage() {
  setCrumbs([]);
  document.title = "Series analysis viewer";
  const list = await api("/api/series");
  app.replaceChildren(h("h1", {}, "Series"), h("p", { class: "muted" }, "Each series is a packaging idea we searched YouTube for."),
    h("div", { class: "cards" }, list.map(s => h("div", { class: "card" },
      h("h3", {}, link(`/s/${s.id}`, s.name)),
      h("p", { class: "muted small" }, s.premise),
      h("p", {}, `${int(s.videos)} videos · ${int(s.channels)} channels`),
      h("p", { class: "small muted" }, `${s.transcripts} transcripts · ${s.teardowns} teardowns`)))));
}

// ------------------------------------------------------------------ series page (videos + channels)
async function seriesPage(S, q) {
  const [seriesList, videos, channels] = await Promise.all([api("/api/series"), api(`/api/series/${S}/videos`), api(`/api/series/${S}/channels`)]);
  const meta = seriesList.find(s => s.id === S);
  document.title = `${meta?.name ?? S} · Series analysis`;
  setCrumbs([[meta?.name ?? S, null]]);
  const state = { tab: q.get("tab") === "channels" ? "channels" : "videos", search: q.get("q") ?? "", channel: q.get("channel") ?? "",
    learn: q.get("learn") === "1", teardown: q.get("teardown") === "1", transcript: q.get("transcript") === "1", enriched: false, sort: q.get("sort") ?? "default", limit: 100 };
  const body = h("div");
  const sync = () => {
    const p = new URLSearchParams();
    if (state.tab !== "videos") p.set("tab", state.tab);
    if (state.search) p.set("q", state.search);
    if (state.channel) p.set("channel", state.channel);
    if (state.learn) p.set("learn", "1");
    if (state.teardown) p.set("teardown", "1");
    if (state.transcript) p.set("transcript", "1");
    if (state.sort !== "default") p.set("sort", state.sort);
    history.replaceState({}, "", `${location.pathname}${p.size ? "?" + p : ""}`);
  };
  const channelName = new Map(channels.map(c => [c.channel_key, c.name]));

  const sorters = {
    default: (a, b) => (b.selected ?? 0) - (a.selected ?? 0) || (a.rank ?? 1e9) - (b.rank ?? 1e9) || (b.views ?? 0) - (a.views ?? 0),
    views: (a, b) => (b.views ?? 0) - (a.views ?? 0),
    outlier: (a, b) => (b.outlier_ratio ?? -1) - (a.outlier_ratio ?? -1),
    score: (a, b) => (b.learn_score ?? -1) - (a.learn_score ?? -1),
    newest: (a, b) => (Date.parse(b.published_at) || 0) - (Date.parse(a.published_at) || 0),
  };

  function render() {
    sync();
    const tabs = h("div", { class: "tabs" }, ["videos", "channels"].map(t => h("button", { class: state.tab === t ? "on" : "", onclick: () => { state.tab = t; render(); } },
      t === "videos" ? `Videos (${videos.length})` : `Channels (${channels.length})`)));
    body.replaceChildren(tabs, state.tab === "videos" ? videosView() : channelsView());
  }

  function videosView() {
    const needle = state.search.toLowerCase();
    const rows = videos.filter(v => (!needle || `${v.title} ${v.channel_name} ${v.subject ?? ""}`.toLowerCase().includes(needle))
      && (!state.channel || v.channel_key === state.channel) && (!state.learn || v.selected) && (!state.teardown || v.has_teardown) && (!state.transcript || v.has_transcript))
      .sort(sorters[state.sort]);
    const toggle = (key, label) => h("label", {}, h("input", { type: "checkbox", checked: state[key], onchange: e => { state[key] = e.target.checked; state.limit = 100; render(); } }), label);
    const bar = h("div", { class: "bar" },
      h("input", { type: "search", placeholder: "Search title, channel, subject", value: state.search, oninput: e => { state.search = e.target.value; state.limit = 100; renderTable(); sync(); } }),
      h("select", { onchange: e => { state.sort = e.target.value; render(); } },
        [["default", "Learn-from first"], ["views", "Most views"], ["outlier", "Biggest outlier"], ["score", "Learn score"], ["newest", "Newest"]].map(([v, l]) => h("option", { value: v, ...(state.sort === v ? { selected: "" } : {}) }, l))),
      toggle("learn", "Learn-from set"), toggle("teardown", "Has teardown"), toggle("transcript", "Has transcript"),
      state.channel ? h("button", { class: "btn ghost", onclick: () => { state.channel = ""; render(); } }, `Channel: ${channelName.get(state.channel) ?? state.channel} ✕`) : null);
    const holder = h("div");
    function renderTable() {
      const needle2 = state.search.toLowerCase();
      const shown = videos.filter(v => (!needle2 || `${v.title} ${v.channel_name} ${v.subject ?? ""}`.toLowerCase().includes(needle2))
        && (!state.channel || v.channel_key === state.channel) && (!state.learn || v.selected) && (!state.teardown || v.has_teardown) && (!state.transcript || v.has_transcript))
        .sort(sorters[state.sort]);
      holder.replaceChildren(h("p", { class: "muted small" }, `${shown.length} videos`),
        h("table", {}, h("thead", {}, h("tr", {}, ["Video", "Channel", "Views", "Outlier", "Age", "Length", "Learn score", "Status"].map((c, i) => h("th", { class: i >= 2 && i <= 6 ? "num" : "" }, c)))),
          h("tbody", {}, shown.slice(0, state.limit).map(v => h("tr", {},
            h("td", {}, h("div", { class: "vrow" }, h("img", { src: thumb(v.video_id), loading: "lazy", alt: "" }),
              h("div", {}, h("div", { class: "t" }, link(`/s/${S}/v/${v.video_id}`, v.title)), v.subject ? h("div", { class: "small muted" }, v.subject) : null))),
            h("td", {}, link(`/s/${S}?channel=${encodeURIComponent(v.channel_key)}`, v.channel_name ?? "–"), v.subscribers ? h("div", { class: "small muted" }, `${compact(v.subscribers)} subs`) : null),
            h("td", { class: "num" }, compact(v.views)),
            h("td", { class: "num" }, v.outlier_ratio != null ? `${fixed(v.outlier_ratio, 1)}x` : "–"),
            h("td", { class: "num" }, ageText(v)),
            h("td", { class: "num" }, dur(v.duration_seconds)),
            h("td", { class: "num" }, v.learn_score != null ? fixed(v.learn_score, 2) : "–", v.rank ? h("div", { class: "small muted" }, `#${v.rank}`) : null),
            h("td", {}, v.selected ? h("span", { class: "chip good" }, "learn-from") : null, v.has_transcript ? h("span", { class: "chip" }, "transcript") : null,
              v.has_teardown ? h("span", { class: "chip good" }, "teardown") : v.job === "running" ? h("span", { class: "chip warn" }, "generating") : null,
              v.excluded ? h("span", { class: "chip warn", title: v.excluded }, "excluded") : null))))),
        shown.length > state.limit ? h("p", {}, h("button", { class: "btn ghost", onclick: () => { state.limit += 200; renderTable(); } }, `Show more (${shown.length - state.limit} left)`)) : null);
    }
    renderTable();
    return h("div", {}, bar, holder);
  }

  function channelsView() {
    const rows = [...channels].sort((a, b) => (b.selected ?? 0) - (a.selected ?? 0) || (b.subscribers ?? 0) - (a.subscribers ?? 0) || b.videos - a.videos);
    return h("table", {}, h("thead", {}, h("tr", {}, ["Channel", "Subscribers", "Typical views", "Found", "Learn-from", "Teardowns", "Best video"].map((c, i) => h("th", { class: i >= 1 && i <= 6 ? "num" : "" }, c)))),
      h("tbody", {}, rows.map(c => h("tr", {},
        h("td", {}, h("div", { class: "t" }, c.channel_url ? h("a", { href: c.channel_url, target: "_blank", rel: "noopener" }, c.name ?? "–") : c.name ?? "–"),
          h("div", { class: "small muted" }, [c.handle, c.country, c.joined ? `since ${String(c.joined).slice(0, 4)}` : null].filter(Boolean).join(" · ")),
          c.description ? h("div", { class: "small muted" }, c.description.slice(0, 140) + (c.description.length > 140 ? "…" : "")) : null),
        h("td", { class: "num" }, compact(c.subscribers)),
        h("td", { class: "num" }, compact(c.baseline_median_views)),
        h("td", { class: "num" }, link(`/s/${S}?channel=${encodeURIComponent(c.channel_key)}`, c.videos)),
        h("td", { class: "num" }, c.selected || 0), h("td", { class: "num" }, c.teardowns || 0), h("td", { class: "num" }, compact(c.best_views))))));
  }

  app.replaceChildren(h("h1", {}, meta?.name ?? S), h("p", { class: "muted" }, meta?.premise ?? ""), body);
  render();
}

// ------------------------------------------------------------------ video page
async function videoPage(S, id) {
  const [data, seriesList] = await Promise.all([api(`/api/series/${S}/videos/${id}`), api("/api/series")]);
  const { video: v, ranking, channel, queries, llm, transcript } = data;
  const meta = seriesList.find(s => s.id === S);
  document.title = `${v.title} · Series analysis`;
  setCrumbs([[meta?.name ?? S, `/s/${S}`], [v.title.length > 50 ? v.title.slice(0, 50) + "…" : v.title, null]]);
  const d = ranking?.detail ?? {};
  const views = v.views ?? v.search_views;
  const fact = (label, value) => h("div", { class: "fact" }, h("b", {}, value), h("span", {}, label));

  const teardownHolder = h("div");
  const img = h("img", { src: thumb(id, true), alt: v.title, onerror: e => { e.target.onerror = null; e.target.src = thumb(id, false); } });

  app.replaceChildren(
    h("div", { class: "hero" }, img,
      h("div", {}, h("h1", {}, v.title),
        h("div", {}, v.channel_url ? link(`/s/${S}?channel=${encodeURIComponent(v.channel_id ?? v.channel_url ?? v.channel_name)}`, v.channel_name) : v.channel_name,
          " · ", h("a", { href: `https://www.youtube.com/watch?v=${id}`, target: "_blank", rel: "noopener" }, "Open on YouTube")),
        h("div", { class: "facts" },
          fact("views", int(views)), fact("likes", int(v.likes)), fact("length", dur(v.duration_seconds ?? v.search_duration_seconds)),
          fact("published", v.published_at ? v.published_at.slice(0, 10) : v.search_published_text ?? "–"),
          fact("subscribers", channel ? compact(channel.subscriber_count) : compact(d.subscribers)),
          fact("vs channel typical", d.outlier_ratio != null ? `${fixed(d.outlier_ratio, 1)}x` : "–"),
          fact("learn score", ranking?.learn_score != null ? fixed(ranking.learn_score, 2) : "–"),
          fact("learn-from rank", ranking?.rank ? `#${ranking.rank}` : "–")),
        ranking?.excluded ? h("p", {}, h("span", { class: "chip warn" }, `Excluded from ranking: ${ranking.excluded}`)) : null,
        d.subject ? h("p", { class: "small muted" }, `Subject: ${d.subject}${d.failure_terms?.length ? " · failure terms: " + d.failure_terms.join(", ") : ""}${d.structures?.length ? " · structure: " + d.structures.join(", ") : ""}`) : null,
        llm?.note ? h("p", { class: "small muted" }, `LLM fit note: ${llm.note}`) : null,
        queries.length ? h("p", { class: "small muted" }, "Found by: ", queries.slice(0, 4).map(x => h("span", { class: "chip" }, `${x.query} (#${x.position})`))) : null)),
    h("h2", {}, "Teardown"), teardownHolder,
    h("h2", {}, "Description"), h("div", { class: "desc" }, v.description || "No description fetched for this video (it has not been enriched yet)."),
    h("h2", {}, "Transcript", transcript ? h("span", { class: "muted small" }, `  ${transcript.language ?? ""}${transcript.info ? " · " + transcript.info : ""}`) : null),
    transcript ? h("div", { class: "transcript" }, transcript.paragraphs.map(p => h("p", {}, h("span", { class: "ts" }, p.ts), h("span", {}, p.text))))
      : h("p", { class: "muted" }, "No transcript saved yet. Generating a teardown fetches it first."));

  renderTeardown(S, id, v, data.teardown, data.job, teardownHolder);
}

let pollTimer = null;
function renderTeardown(S, id, v, teardown, job, holder) {
  clearTimeout(pollTimer);
  if (teardown) {
    holder.replaceChildren(...teardownView(teardown, job?.status === "running"));
    return;
  }
  const running = job?.status === "running";
  const start = async () => {
    try { job = await api(`/api/series/${S}/videos/${id}/teardown`, { method: "POST" }); } catch (e) { job = { status: "error", error: e.message }; }
    renderTeardown(S, id, v, null, job, holder);
  };
  holder.replaceChildren(
    running ? h("div", { class: "status" }, h("span", { class: "spin" }), job.step ?? "Working") : null,
    job?.status === "error" ? h("div", { class: "status err" }, `Teardown failed: ${job.error}`) : null,
    !running ? h("div", { class: "card" }, h("p", {}, "No teardown for this video yet."),
      h("p", { class: "small muted" }, "A Sonnet analyst reads the full transcript and looks at the thumbnail, then explains what the video does well and how, with quoted moments checked against the transcript. It takes a few minutes and uses your Claude Code subscription."),
      h("button", { class: "btn", onclick: start }, job?.status === "error" ? "Try again" : "Generate teardown")) : null);
  if (running) {
    pollTimer = setTimeout(async () => {
      if (!document.body.contains(holder)) return;
      try { const r = await api(`/api/series/${S}/videos/${id}/teardown`); renderTeardown(S, id, v, r.teardown, r.job, holder); }
      catch { renderTeardown(S, id, v, null, job, holder); }
    }, 4000);
  }
}

const ev = list => (list ?? []).slice(0, 3).map(e => h("div", { class: "quote" }, h("span", { class: "ts" }, `[${e.ts}]`), `“${e.quote}”`, e.gloss ? h("div", { class: "small muted" }, e.gloss) : null));

function teardownView(a, regenerating) {
  const p = a.packaging ?? {}, s = a.script ?? {};
  const title = p.title ?? {}, th = p.thumbnail, pd = p.promise_delivery ?? {};
  const delivered = String(pd.delivered ?? "");
  return [
    h("div", { class: "lead" }, h("b", {}, "Why it works. "), a.one_line),
    h("div", { class: "td-section" },
      h("h3", {}, "Packaging"),
      h("ul", { class: "tight" },
        h("li", {}, h("b", {}, "Promise: "), `${title.promise ?? "–"}${title.specificity ? ` (specificity: ${title.specificity})` : ""}`),
        h("li", {}, h("b", {}, "Gap it opens: "), `${title.info_gap?.type ?? "n/a"}${title.info_gap?.what_is_withheld ? ": " + title.info_gap.what_is_withheld : ""}`),
        title.formula ? h("li", {}, h("b", {}, "Formula: "), title.formula) : null,
        ...(title.mechanisms ?? []).map(m => h("li", {}, h("span", { class: "chip" }, m.id), m.how)),
        th?.seen ? h("li", {}, h("b", {}, "Thumbnail: "), th.description, " ", ...(th.mechanisms ?? []).map(m => [h("span", { class: "chip" }, m.id), m.how, " "]).flat(),
          th.division_of_labour ? h("div", { class: "small muted" }, `Division of labour: ${th.division_of_labour}`) : null) : h("li", {}, h("b", {}, "Thumbnail: "), "not analysed")),
      h("p", {}, h("b", {}, "Does it earn the promise? "), h("span", { class: `chip ${/^yes|full/i.test(delivered) ? "good" : "warn"}` }, delivered || "–"),
        pd.delivered_at ? ` at ${pd.delivered_at}. ` : ". ", pd.clickbait_risk ? h("span", { class: `chip ${/low|none/i.test(pd.clickbait_risk) ? "good" : "warn"}` }, `clickbait risk: ${pd.clickbait_risk}`) : null, " ", pd.why)),
    h("div", { class: "td-section" }, h("h3", {}, "What it does well, and how"),
      (a.doing_well ?? []).map((m, i) => h("div", { class: "move" }, h("div", { class: "m" }, `${i + 1}. ${m.move}`), h("div", {}, m.how), ev(m.evidence)))),
    h("div", { class: "td-section" }, h("h3", {}, "Hook (first minute)"), h("p", {}, s.hook?.summary), s.hook?.time_to_promise_sec != null ? h("p", { class: "small muted" }, `Time to the promise: ${s.hook.time_to_promise_sec} s`) : null,
      h("h3", {}, "Structure"), h("ul", { class: "tight" }, (s.structure ?? []).map(x => h("li", {}, h("span", { class: "chip" }, `${x.from} – ${x.to}`), x.function, x.note ? h("span", { class: "muted" }, ` (${x.note})`) : null))),
      h("h3", {}, "Open loops"), (s.loops ?? []).length ? h("ul", { class: "tight" }, s.loops.map(l => h("li", {}, h("span", { class: "chip" }, `${l.opened_at} → ${l.closed_at ?? "never closed"}`), l.question, l.how_kept_alive ? h("span", { class: "muted" }, ` (kept alive by: ${l.how_kept_alive})`) : null))) : h("p", { class: "muted" }, "None."),
      h("h3", {}, "Voice and pacing"), h("p", {}, s.voice), h("ul", { class: "tight" }, (s.pacing_devices ?? []).map(x => h("li", {}, x))),
      s.ending ? h("p", {}, h("b", {}, "Ending: "), `${s.ending.type}: ${s.ending.what_it_does}`) : null),
    h("div", { class: "td-section" }, h("h3", {}, "Weak points"),
      (a.weak_points ?? []).length ? h("ul", { class: "tight" }, a.weak_points.map(w => h("li", {}, h("b", {}, `${w.where}: `), w.what, w.risk ? h("span", { class: "muted" }, ` (${w.risk})`) : null))) : h("p", { class: "muted" }, "None found."),
      h("h3", {}, "Moves to copy"), h("ul", { class: "tight" }, (a.transferable_moves ?? []).map(m => h("li", {}, m)))),
    h("p", { class: "small muted" }, `Analyst confidence: ${a.confidence ?? "–"}. ${a.transcript_quality_notes ?? ""} One analyst's reading; quotes are machine-checked against the transcript.`),
  ];
}

route();

Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.