folx-tv/server/static.ts
sebastjanartic 0ab24d65a3 Update image links for the blog to ensure proper display
Replace old Dropbox image URLs with new Dropbox image URLs in the gallery data JSON file.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 1f7e7e89-a520-4970-9645-37daadc466dc
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 2488734a-5aee-4938-b09a-9086e35dacd2
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/1f7e7e89-a520-4970-9645-37daadc466dc/mwtHL8H
Replit-Helium-Checkpoint-Created: true
2026-03-05 15:24:26 +00:00

98 lines
4.0 KiB
TypeScript

import express, { type Express } from "express";
import fs from "fs";
import path from "path";
import { storage } from "./storage";
function escapeHtml(str: string): string {
return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function ogImageUrl(coverImage: string, baseUrl: string): string {
if (!coverImage) return "";
let imgPath = coverImage;
if (imgPath.endsWith(".webp")) {
imgPath = imgPath.replace(/\.webp$/, ".jpg");
}
return imgPath.startsWith("http") ? imgPath : `${baseUrl}${imgPath}`;
}
function stripExistingMeta(html: string): string {
html = html.replace(/<meta\s+property="og:[^"]*"[^>]*>\s*/gi, "");
html = html.replace(/<meta\s+name="twitter:[^"]*"[^>]*>\s*/gi, "");
html = html.replace(/<meta\s+name="description"[^>]*>\s*/gi, "");
html = html.replace(/<meta\s+name="keywords"[^>]*>\s*/gi, "");
return html;
}
export function serveStatic(app: Express) {
const distPath = path.resolve(__dirname, "public");
if (!fs.existsSync(distPath)) {
throw new Error(
`Could not find the build directory: ${distPath}, make sure to build the client first`,
);
}
app.use(express.static(distPath, {
setHeaders(res, filePath) {
if (filePath.endsWith("og-image.jpg") || filePath.includes("/uploads/") || filePath.includes("/images/")) {
res.setHeader("Cache-Control", "public, max-age=86400");
}
},
}));
app.use("/{*path}", async (req, res) => {
const url = req.originalUrl;
const indexPath = path.resolve(distPath, "index.html");
const canonicalBase = "https://www.folx.tv";
const host = req.get("host") || "folx.tv";
const protocol = req.get("x-forwarded-proto") || "https";
const baseUrl = `${protocol}://${host}`;
const articleMatch = url.match(/^\/article\/([^?#]+)/);
if (articleMatch) {
try {
const slug = decodeURIComponent(articleMatch[1]);
const article = await storage.getArticleBySlug(slug);
if (article) {
const articleUrl = `${canonicalBase}/article/${article.slug}`;
const imageUrl = ogImageUrl(article.coverImage || "", canonicalBase);
const finalImage = imageUrl || `${canonicalBase}/og-image.jpg`;
let template = await fs.promises.readFile(indexPath, "utf-8");
template = stripExistingMeta(template);
const ogTags = [
`<meta property="og:title" content="${escapeHtml(article.title)}" />`,
`<meta property="og:description" content="${escapeHtml(article.excerpt)}" />`,
`<meta property="og:type" content="article" />`,
`<meta property="og:url" content="${escapeHtml(articleUrl)}" />`,
`<meta property="og:image" content="${escapeHtml(finalImage)}" />`,
`<meta property="og:image:secure_url" content="${escapeHtml(finalImage)}" />`,
`<meta property="og:image:width" content="800" />`,
`<meta property="og:image:height" content="450" />`,
`<meta property="og:image:type" content="image/jpeg" />`,
`<meta property="og:site_name" content="Folx Music Television" />`,
`<meta property="og:locale" content="de_DE" />`,
`<meta name="twitter:card" content="summary_large_image" />`,
`<meta name="twitter:title" content="${escapeHtml(article.title)}" />`,
`<meta name="twitter:description" content="${escapeHtml(article.excerpt)}" />`,
`<meta name="twitter:image" content="${escapeHtml(finalImage)}" />`,
`<meta name="description" content="${escapeHtml(article.excerpt)}" />`,
`<title>${escapeHtml(article.title)} - Folx Music Television</title>`,
].join("\n ");
template = template.replace(/<title>[^<]*<\/title>/, ogTags);
res.status(200).set({ "Content-Type": "text/html" }).end(template);
return;
}
} catch (e) {
}
}
let template = await fs.promises.readFile(indexPath, "utf-8");
res.status(200).set({ "Content-Type": "text/html" }).end(template);
});
}