Rebrand StreamHoard, strip Emergent.sh platform artifacts

- Remove .emergent/ state dir, tracked .gitconfig, @emergentbase/visual-edits
  dep + craco wiring, emergent.sh script/meta tags, PostHog telemetry snippet
- Rename UI/docs branding Kino -> StreamHoard (README, DEPLOY.md, Navbar,
  Login, Register, AdminShowEpisodes, FastAPI title, health check response)
- Rename docker-compose container/network names to streamhoard-*
- Default admin email domain -> admin@streamhoard.local
This commit is contained in:
Myron Blair
2026-07-23 20:20:29 -05:00
parent d4dffdb6fb
commit e27bb37f7b
18 changed files with 53 additions and 155 deletions
-20
View File
@@ -2,10 +2,6 @@
const path = require("path");
require("dotenv").config();
// Check if we're in development/preview mode (not production build)
// Craco sets NODE_ENV=development for start, NODE_ENV=production for build
const isDevServer = process.env.NODE_ENV !== "production";
// Environment variable overrides
const config = {
enableHealthCheck: process.env.ENABLE_HEALTH_CHECK === "true",
@@ -81,20 +77,4 @@ webpackConfig.devServer = (devServerConfig) => {
return devServerConfig;
};
// Wrap with visual edits (automatically adds babel plugin, dev server, and overlay in dev mode)
if (isDevServer) {
try {
const { withVisualEdits } = require("@emergentbase/visual-edits/craco");
webpackConfig = withVisualEdits(webpackConfig);
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND' && err.message.includes('@emergentbase/visual-edits/craco')) {
console.warn(
"[visual-edits] @emergentbase/visual-edits not installed — visual editing disabled."
);
} else {
throw err;
}
}
}
module.exports = webpackConfig;
-1
View File
@@ -76,7 +76,6 @@
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@craco/craco": "^7.1.0",
"@emergentbase/visual-edits": "https://assets.emergent.sh/npm/emergentbase-visual-edits-1.0.8.tgz",
"@eslint/js": "9.23.0",
"autoprefixer": "^10.4.20",
"eslint": "9.23.0",
+2 -74
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="A product of emergent.sh" />
<meta name="description" content="StreamHoard - self-hosted personal media server" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@600&display=swap" rel="stylesheet" />
@@ -21,9 +21,8 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Emergent | Fullstack App</title>
<title>StreamHoard</title>
<script>window.addEventListener("error",function(e){if(e.error instanceof DOMException&&e.error.name==="DataCloneError"&&e.message&&e.message.includes("PerformanceServerTiming")){e.stopImmediatePropagation();e.preventDefault()}},true);</script>
<script src="https://assets.emergent.sh/scripts/emergent-main.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
@@ -38,76 +37,5 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script>
!(function (t, e) {
var o, n, p, r;
e.__SV ||
((window.posthog = e),
(e._i = []),
(e.init = function (i, s, a) {
function g(t, e) {
var o = e.split(".");
2 == o.length && ((t = t[o[0]]), (e = o[1])),
(t[e] = function () {
t.push(
[e].concat(
Array.prototype.slice.call(
arguments,
0,
),
),
);
});
}
((p = t.createElement("script")).type =
"text/javascript"),
(p.crossOrigin = "anonymous"),
(p.async = !0),
(p.src =
s.api_host.replace(
".i.posthog.com",
"-assets.i.posthog.com",
) + "/static/array.js"),
(r =
t.getElementsByTagName(
"script",
)[0]).parentNode.insertBefore(p, r);
var u = e;
for (
void 0 !== a ? (u = e[a] = []) : (a = "posthog"),
u.people = u.people || [],
u.toString = function (t) {
var e = "posthog";
return (
"posthog" !== a && (e += "." + a),
t || (e += " (stub)"),
e
);
},
u.people.toString = function () {
return u.toString(1) + ".people (stub)";
},
o =
"init me ws ys ps bs capture je Di ks register register_once register_for_session unregister unregister_for_session Ps getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Es $s createPersonProfile Is opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing Ss debug xs getPageViewId captureTraceFeedback captureTraceMetric".split(
" ",
),
n = 0;
n < o.length;
n++
)
g(u, o[n]);
e._i.push([i, s, a]);
}),
(e.__SV = 1));
})(document, window.posthog || []);
posthog.init("phc_xAvL2Iq4tFmANRE7kzbKwaSqp1HJjN7x48s3vr0CMjs", {
api_host: "https://us.i.posthog.com",
person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well,
session_recording: {
recordCrossOriginIframes: true,
capturePerformance: false,
},
});
</script>
</body>
</html>
+1 -1
View File
@@ -29,7 +29,7 @@ export const Navbar = () => {
<div className="px-6 md:px-12 py-4 flex items-center justify-between">
<div className="flex items-center gap-10">
<Link to="/browse" className="flex items-center gap-2" data-testid="nav-logo">
<span className="font-display text-2xl font-black tracking-tighter text-white">Kino</span>
<span className="font-display text-2xl font-black tracking-tighter text-white">StreamHoard</span>
<span className="text-[#D9381E] text-2xl leading-none">.</span>
</Link>
{user && (
+1 -1
View File
@@ -61,7 +61,7 @@ export default function AdminShowEpisodes() {
const { data } = await api.post("/episodes/bulk-hide", { episode_ids: ids, hidden: false });
msg = `${data.modified} unhidden`;
} else if (action === "delete") {
if (!window.confirm(`Delete ${ids.length} episode(s) permanently? Files on disk are kept, but Kino entries and HLS output are removed.`)) return;
if (!window.confirm(`Delete ${ids.length} episode(s) permanently? Files on disk are kept, but StreamHoard entries and HLS output are removed.`)) return;
const { data } = await api.post("/episodes/bulk-delete", { episode_ids: ids });
msg = `${data.deleted} deleted`;
}
+2 -2
View File
@@ -48,7 +48,7 @@ export default function Login() {
<div className="flex items-center justify-center px-6 md:px-12 py-12">
<form onSubmit={onSubmit} className="w-full max-w-sm fade-up" data-testid="login-form">
<Link to="/" className="block mb-12" data-testid="login-logo">
<span className="font-display text-3xl font-black tracking-tighter text-white">Kino</span>
<span className="font-display text-3xl font-black tracking-tighter text-white">StreamHoard</span>
<span className="text-[#D9381E] text-3xl">.</span>
</Link>
<h2 className="font-display text-3xl font-bold tracking-tight text-white">Sign in</h2>
@@ -93,7 +93,7 @@ export default function Login() {
<div className="mt-8 p-4 border border-[#222] text-xs text-[#8A8A8A]" data-testid="login-demo-credentials">
<span className="text-[10px] uppercase tracking-[0.3em] text-[#D9381E] block mb-2">Demo Admin</span>
admin@kino.local / kino-admin-2026
admin@streamhoard.local / kino-admin-2026
</div>
</form>
</div>
+2 -2
View File
@@ -20,7 +20,7 @@ export default function Register() {
setSubmitting(true);
try {
await register(email, password, name);
toast.success("Welcome to Kino");
toast.success("Welcome to StreamHoard");
nav("/browse", { replace: true });
} catch (err) {
toast.error(err.response?.data?.detail || "Could not register");
@@ -49,7 +49,7 @@ export default function Register() {
<div className="flex items-center justify-center px-6 md:px-12 py-12">
<form onSubmit={onSubmit} className="w-full max-w-sm fade-up" data-testid="register-form">
<Link to="/" className="block mb-12">
<span className="font-display text-3xl font-black tracking-tighter text-white">Kino</span>
<span className="font-display text-3xl font-black tracking-tighter text-white">StreamHoard</span>
<span className="text-[#D9381E] text-3xl">.</span>
</Link>
<h2 className="font-display text-3xl font-bold tracking-tight text-white">Create account</h2>