Rename project: youtube-summarizer → recap

The product was always more than YouTube — it handles podcast feeds
too, and the upcoming multi-provider work makes it less Gemini-
specific. New name: Recap.

This is a coordinated identity change across:

  • StartOS package id: youtube-summarizer → recap
    (manifest.id; the .s9pk filename, Docker image namespace, and
    install path under StartOS all derive from this automatically)
  • Display name: "YouTube Summarizer" → "Recap"
    (manifest title, activation screen heading, page <title>, console
    log on boot, i18n strings, ABOUT.md, Dockerfile header,
    docker_entrypoint banner)
  • Keysat product slug: youtube-summarizer → recap
    (server/license.js PRODUCT_SLUG; frontend fallback strings)
  • Daemon subscription id: youtube-summarizer-sub → recap-sub
  • Env var prefix: YT_SUMMARIZER_* → RECAP_*
    (LICENSE_KEY, LICENSE_KEY_PATH, MAX_OFFLINE_DAYS,
    VALIDATE_INTERVAL_MS)
  • localStorage keys: yt-summarizer-* → recap-*
    (gemini-key, activation-skipped, clips)
  • Library export filename: youtube-summarizer-library.json →
    recap-library.json
  • npm package names: youtube-summarizer-{startos,server} → recap-*
  • Deploy paths: youtube-summarizer_x86_64.s9pk → recap_x86_64.s9pk
    (default values in bin/deploy.sh; .deploy.env on dev machine
    needs the same update before next push)
  • Self-hosted registry directory: startos-registry/packages/
    youtube-summarizer → .../recap (with package.json + INSTRUCTIONS
    rewritten)

What does NOT change:
  • Filesystem repo path (still /Users/.../youtube-summarizer/)
  • Git history / commit messages
  • Existing version files in startos/versions/ (kept as-is — the
    version chain belongs to the package's own history regardless of
    its display name)

User-side follow-ups required:
  1. Create "recap" product in Keysat admin, set up Core/Pro tier
     policies (same entitlements as before), mint a fresh test
     license. Old "youtube-summarizer" licenses won't activate
     against the new slug.
  2. Update .deploy.env (gitignored) so FILEBROWSER_PATH and
     REGISTRY_PUBLIC_URL point at recap_x86_64.s9pk.

StartOS will treat this as a brand-new app on install — existing
youtube-summarizer installs will not auto-migrate (acknowledged
intentional given no real users yet).
This commit is contained in:
Keysat
2026-05-08 13:35:27 -05:00
parent 1aaa7a453a
commit 9282440143
23 changed files with 59 additions and 59 deletions
+15 -15
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YouTube Transcript Summarizer</title>
<title>Recap</title>
<link rel="icon" type="image/png" href="/assets/icon.png">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -1211,7 +1211,7 @@
// ── State ────────────────────────────────────────────────────────────────
const state = {
url: "",
apiKey: localStorage.getItem("yt-summarizer-gemini-key") || "",
apiKey: localStorage.getItem("recap-gemini-key") || "",
hasServerKey: false, // will be set by health check
lanMode: null, // null = unknown, true = home, false = traveling
serverStatus: "connecting", // "connected" | "sleeping" | "disconnected" | "connecting"
@@ -1275,7 +1275,7 @@
entitlements: [],
expiresAt: null,
isTrial: false,
productSlug: "youtube-summarizer",
productSlug: "recap",
keysatBaseUrl: "",
},
licenseActivating: false,
@@ -1284,7 +1284,7 @@
// Free tier: once dismissed, the activation screen no longer
// hard-gates the UI. Persisted so returning unlicensed users land
// straight in the app.
activationSkipped: localStorage.getItem("yt-summarizer-activation-skipped") === "1",
activationSkipped: localStorage.getItem("recap-activation-skipped") === "1",
};
const MODELS = ["gemini-3.1-pro-preview", "gemini-3-pro-preview", "gemini-3-flash-preview"];
@@ -1624,7 +1624,7 @@
return `
<div class="activation-screen">
<div class="activation-card">
<h1>YouTube Summarizer</h1>
<h1>Recap</h1>
<p class="activation-sub">
${loading
? "Checking license…"
@@ -1651,7 +1651,7 @@
</button>
</div>
<div class="activation-meta">
Product: <strong>${escHtml(lic.productSlug || "youtube-summarizer")}</strong>
Product: <strong>${escHtml(lic.productSlug || "recap")}</strong>
${lic.keysatBaseUrl ? ` &middot; Issuer: <strong>${escHtml(lic.keysatBaseUrl.replace(/^https?:\/\//, ""))}</strong>` : ""}
</div>
`}
@@ -1662,7 +1662,7 @@
function dismissActivation() {
state.activationSkipped = true;
try { localStorage.setItem("yt-summarizer-activation-skipped", "1"); } catch {}
try { localStorage.setItem("recap-activation-skipped", "1"); } catch {}
render();
}
@@ -1730,7 +1730,7 @@
function showActivationScreen() {
// Take user back to the activation modal (e.g. from an upgrade banner).
state.activationSkipped = false;
try { localStorage.removeItem("yt-summarizer-activation-skipped"); } catch {}
try { localStorage.removeItem("recap-activation-skipped"); } catch {}
render();
}
@@ -2057,7 +2057,7 @@
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "youtube-summarizer-library.json";
a.download = "recap-library.json";
a.click();
URL.revokeObjectURL(url);
showToast("Library exported!", "✓");
@@ -3492,7 +3492,7 @@
function toggleShowKey() { state.showKey = !state.showKey; render(); }
function setApiKey(v) {
state.apiKey = v;
localStorage.setItem("yt-summarizer-gemini-key", v);
localStorage.setItem("recap-gemini-key", v);
}
function setModel(m) { state.model = m; render(); }
function toggleExpandAll() {
@@ -3921,12 +3921,12 @@
}
function saveClipCollection() {
localStorage.setItem("yt-summarizer-clips", JSON.stringify(state.clipCollection));
localStorage.setItem("recap-clips", JSON.stringify(state.clipCollection));
}
function loadClipCollection() {
try {
const saved = localStorage.getItem("yt-summarizer-clips");
const saved = localStorage.getItem("recap-clips");
if (saved) state.clipCollection = JSON.parse(saved);
} catch {}
}
@@ -4112,7 +4112,7 @@
entitlements: data.entitlements || [],
expiresAt: data.expiresAt || null,
isTrial: !!data.isTrial,
productSlug: data.productSlug || "youtube-summarizer",
productSlug: data.productSlug || "recap",
keysatBaseUrl: data.keysatBaseUrl || "",
};
} catch {
@@ -4150,7 +4150,7 @@
entitlements: data.entitlements || [],
expiresAt: data.expiresAt,
isTrial: !!data.isTrial,
productSlug: data.productSlug || "youtube-summarizer",
productSlug: data.productSlug || "recap",
keysatBaseUrl: data.keysatBaseUrl || "",
};
state.licenseActivationKey = "";
@@ -4193,7 +4193,7 @@
}
function upgradeToProUrl() {
const base = state.license.keysatBaseUrl || "https://licensing.keysat.xyz";
return `${base.replace(/\/$/, "")}/buy/${state.license.productSlug || "youtube-summarizer"}`;
return `${base.replace(/\/$/, "")}/buy/${state.license.productSlug || "recap"}`;
}
function showToast(message, icon = "✓", duration = 4000) {