add video backend server, fix styling and more #54

Merged
quoije merged 131 commits from 2026-video.backend into prod 2025-12-22 05:42:04 -05:00
Showing only changes of commit 9e825eb1a6 - Show all commits
+78 -25
View File
@@ -4,16 +4,65 @@ const moment = require("moment-timezone");
const router = express.Router();
let latestCommitCache = null;
let lastFetchedTime = 0;
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds
const TIMEZONE = "America/New_York";
// Cache is stored in the exact response shape expected by the client.
let latestCommitCache = null;
// Avoid noisy logs when GitHub isn't configured or is temporarily unavailable.
let lastLogTime = 0;
const LOG_THROTTLE_MS = 60 * 60 * 1000; // 1h
function nowFormatted() {
return moment(Date.now()).tz(TIMEZONE).format("YYYY-MM-DD HH:mm:ss");
}
function getGitHubConfig() {
const owner = typeof process.env.GITHUB_OWNER === "string" ? process.env.GITHUB_OWNER.trim() : "";
const repo = typeof process.env.GITHUB_REPO === "string" ? process.env.GITHUB_REPO.trim() : "";
return { owner, repo, configured: !!owner && !!repo };
}
function getPackageVersion() {
try {
// routes/version.js -> ../package.json
const pkg = require("../package.json");
return typeof pkg?.version === "string" && pkg.version.trim() ? pkg.version.trim() : "dev";
} catch (_) {
return "dev";
}
}
function setFallbackCache(message, { configured } = { configured: false }) {
latestCommitCache = {
version: getPackageVersion(),
message: message || "Version info not available.",
author: "",
date: nowFormatted(),
configured: !!configured,
source: "fallback",
};
}
function logThrottled(...args) {
const t = Date.now();
if (t - lastLogTime < LOG_THROTTLE_MS) return;
lastLogTime = t;
// eslint-disable-next-line no-console
console.error(...args);
}
async function fetchLatestCommitFromGitHub() {
const githubOwner = process.env.GITHUB_OWNER;
const githubRepo = process.env.GITHUB_REPO;
const { owner, repo, configured } = getGitHubConfig();
if (!configured) {
// Never attempt GitHub calls if not configured.
setFallbackCache("Version endpoint is not configured.", { configured: false });
return;
}
try {
const url = `https://api.github.com/repos/${githubOwner}/${githubRepo}/commits`;
const url = `https://api.github.com/repos/${owner}/${repo}/commits`;
const response = await axios.get(url, {
headers: {
"Content-Type": "application/json",
@@ -23,40 +72,44 @@ async function fetchLatestCommitFromGitHub() {
if (response.data && response.data.length > 0) {
const latestCommit = response.data[0];
latestCommitCache = {
sha: latestCommit.sha,
message: latestCommit.commit.message,
author: latestCommit.commit.author.name,
date: latestCommit.commit.author.date,
version: String(latestCommit.sha || "").substring(0, 5),
message: latestCommit?.commit?.message || "",
author: latestCommit?.commit?.author?.name || "",
date: moment(latestCommit?.commit?.author?.date || Date.now())
.tz(TIMEZONE)
.format("YYYY-MM-DD HH:mm:ss"),
configured: true,
source: "github",
};
lastFetchedTime = Date.now();
} else {
throw new Error("No commits found.");
}
} catch (error) {
console.error("Error fetching commit:", error.message);
// Keep serving a non-500 response, and don't spam logs.
logThrottled("Error fetching commit:", error?.message || error);
setFallbackCache("GitHub commit data is not available.", { configured: true });
}
}
// Initial fetch to populate cache
// Initialize cache (without crashing / spamming when not configured).
const initialCfg = getGitHubConfig();
if (!initialCfg.configured) {
setFallbackCache("Version endpoint is not configured.", { configured: false });
} else {
fetchLatestCommitFromGitHub();
// Refresh cache every 5 minutes
setInterval(fetchLatestCommitFromGitHub, CACHE_DURATION);
const timer = setInterval(fetchLatestCommitFromGitHub, CACHE_DURATION);
// Don't keep the process alive just for this polling.
if (typeof timer.unref === "function") timer.unref();
}
// Route to get the latest commit (cached)
router.get("/", async (req, res) => {
// Always return something (client clears footer on non-2xx).
if (!latestCommitCache) {
return res.status(500).json({ message: "Commit data is not available yet." });
const cfg = getGitHubConfig();
setFallbackCache("Version info not available.", { configured: cfg.configured });
}
res.json({
version: latestCommitCache.sha.substring(0, 5),
message: latestCommitCache.message,
author: latestCommitCache.author,
date: moment(latestCommitCache.date)
.tz("America/New_York")
.format("YYYY-MM-DD HH:mm:ss"),
});
return res.status(200).json(latestCommitCache);
});
module.exports = router;