Update meta tags, title, and description for the gallery page to accurately describe it as featuring unique moments from recordings and backstage snapshots, rather than solely concert photos. This includes changes in client/src/pages/gallery.tsx, server/static.ts, and server/vite.ts. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 67a932ea-d8a9-4376-a0ba-5b355f4f70b7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/OPD8Ro3 Replit-Helium-Checkpoint-Created: true
196 lines
9.3 KiB
TypeScript
196 lines
9.3 KiB
TypeScript
import { type Express } from "express";
|
||
import { createServer as createViteServer, createLogger } from "vite";
|
||
import { type Server } from "http";
|
||
import viteConfig from "../vite.config";
|
||
import fs from "fs";
|
||
import path from "path";
|
||
import { nanoid } from "nanoid";
|
||
import { storage } from "./storage";
|
||
|
||
const viteLogger = createLogger();
|
||
|
||
function escapeHtml(str: string): string {
|
||
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
||
}
|
||
|
||
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, "");
|
||
html = html.replace(/<link\s+rel="canonical"[^>]*>\s*/gi, "");
|
||
return html;
|
||
}
|
||
|
||
export async function setupVite(server: Server, app: Express) {
|
||
const serverOptions = {
|
||
middlewareMode: true,
|
||
hmr: { server, path: "/vite-hmr" },
|
||
allowedHosts: true as const,
|
||
};
|
||
|
||
const vite = await createViteServer({
|
||
...viteConfig,
|
||
configFile: false,
|
||
customLogger: {
|
||
...viteLogger,
|
||
error: (msg, options) => {
|
||
viteLogger.error(msg, options);
|
||
process.exit(1);
|
||
},
|
||
},
|
||
server: serverOptions,
|
||
appType: "custom",
|
||
});
|
||
|
||
app.use(vite.middlewares);
|
||
|
||
app.use("/{*path}", async (req, res, next) => {
|
||
const url = req.originalUrl;
|
||
const canonicalBase = "https://folx.tv";
|
||
|
||
try {
|
||
const clientTemplate = path.resolve(
|
||
import.meta.dirname,
|
||
"..",
|
||
"client",
|
||
"index.html",
|
||
);
|
||
|
||
let template = await fs.promises.readFile(clientTemplate, "utf-8");
|
||
template = template.replace(
|
||
`src="/src/main.tsx"`,
|
||
`src="/src/main.tsx?v=${nanoid()}"`,
|
||
);
|
||
|
||
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`;
|
||
|
||
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 property="fb:pages" content="1428520781492675" />`,
|
||
`<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)}" />`,
|
||
`<meta name="keywords" content="Volksmusik, Schlager, ${escapeHtml(article.title)}, ${escapeHtml(article.category || 'News')}, FOLX TV" />`,
|
||
`<link rel="canonical" href="${escapeHtml(articleUrl)}" />`,
|
||
`<title>${escapeHtml(article.title)} - Volksmusik & Schlager | Folx Music Television</title>`,
|
||
].join("\n ");
|
||
|
||
template = template.replace(/<title>[^<]*<\/title>/, ogTags);
|
||
}
|
||
} catch (e) {
|
||
}
|
||
}
|
||
|
||
if (url.match(/^\/gallery(\/|$|\?)/)) {
|
||
template = stripExistingMeta(template);
|
||
const galTitle = "Fotogalerie \u2013 Einzigartige Momente von unseren Aufzeichnungen | FOLX TV";
|
||
const galDesc = "Spannende Schnappsch\u00fcsse und besondere Augenblicke, eingefangen bei unseren Aufzeichnungen. Authentische Bilder der Volksmusik- und Schlager-Stars in einzigartigen Momenten bei FOLX TV.";
|
||
const galUrl = `${canonicalBase}/gallery`;
|
||
const galImage = `${canonicalBase}/images/og-image.jpg`;
|
||
|
||
const galTags = [
|
||
`<meta property="og:title" content="${escapeHtml(galTitle)}" />`,
|
||
`<meta property="og:description" content="${escapeHtml(galDesc)}" />`,
|
||
`<meta property="og:type" content="website" />`,
|
||
`<meta property="og:url" content="${escapeHtml(galUrl)}" />`,
|
||
`<meta property="og:image" content="${escapeHtml(galImage)}" />`,
|
||
`<meta property="og:image:secure_url" content="${escapeHtml(galImage)}" />`,
|
||
`<meta property="og:image:width" content="1200" />`,
|
||
`<meta property="og:image:height" content="630" />`,
|
||
`<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(galTitle)}" />`,
|
||
`<meta name="twitter:description" content="${escapeHtml(galDesc)}" />`,
|
||
`<meta name="twitter:image" content="${escapeHtml(galImage)}" />`,
|
||
`<meta name="description" content="${escapeHtml(galDesc)}" />`,
|
||
`<meta name="keywords" content="Fotogalerie, Volksmusik Fotos, Schlager Bilder, Aufzeichnungen, Schnappschüsse, FOLX TV, Volksmusik Stars" />`,
|
||
`<link rel="canonical" href="${escapeHtml(galUrl)}" />`,
|
||
`<title>${escapeHtml(galTitle)}</title>`,
|
||
].join("\n ");
|
||
|
||
template = template.replace(/<title>[^<]*<\/title>/, galTags);
|
||
}
|
||
|
||
if (url.match(/^\/horoskop(\/|$|\?)/)) {
|
||
template = stripExistingMeta(template);
|
||
const signMatch = url.match(/^\/horoskop\/([^?#]+)/);
|
||
const signName = signMatch ? decodeURIComponent(signMatch[1]) : null;
|
||
const capitalSign = signName ? signName.charAt(0).toUpperCase() + signName.slice(1) : null;
|
||
|
||
const title = capitalSign
|
||
? `${capitalSign} Horoskop – Tages-, Wochen- & Monatshoroskop | Folx Music Television`
|
||
: "Horoskop – Tages-, Wochen- & Monatshoroskop für alle Sternzeichen | Folx Music Television";
|
||
const desc = capitalSign
|
||
? `${capitalSign} Horoskop: Tägliches, wöchentliches und monatliches Horoskop. Liebe, Beruf & Gesundheit bei FOLX TV.`
|
||
: "Kostenloses Tageshoroskop, Wochenhoroskop & Monatshoroskop für alle 12 Sternzeichen. Liebe, Beruf, Gesundheit bei FOLX TV.";
|
||
const horoUrl = `${canonicalBase}${signName ? `/horoskop/${signName}` : "/horoskop"}`;
|
||
const horoImage = `${canonicalBase}/images/horoskop-og.jpg`;
|
||
|
||
const horoTags = [
|
||
`<meta property="og:title" content="${escapeHtml(title)}" />`,
|
||
`<meta property="og:description" content="${escapeHtml(desc)}" />`,
|
||
`<meta property="og:type" content="website" />`,
|
||
`<meta property="og:url" content="${escapeHtml(horoUrl)}" />`,
|
||
`<meta property="og:image" content="${escapeHtml(horoImage)}" />`,
|
||
`<meta property="og:image:secure_url" content="${escapeHtml(horoImage)}" />`,
|
||
`<meta property="og:image:width" content="1200" />`,
|
||
`<meta property="og:image:height" content="675" />`,
|
||
`<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(title)}" />`,
|
||
`<meta name="twitter:description" content="${escapeHtml(desc)}" />`,
|
||
`<meta name="twitter:image" content="${escapeHtml(horoImage)}" />`,
|
||
`<meta name="description" content="${escapeHtml(desc)}" />`,
|
||
`<meta name="keywords" content="Horoskop, Tageshoroskop, Wochenhoroskop, Monatshoroskop, Sternzeichen, Volksmusik, FOLX TV${capitalSign ? `, ${capitalSign}` : ""}" />`,
|
||
`<link rel="canonical" href="${escapeHtml(horoUrl)}" />`,
|
||
`<title>${escapeHtml(title)}</title>`,
|
||
].join("\n ");
|
||
|
||
template = template.replace(/<title>[^<]*<\/title>/, horoTags);
|
||
}
|
||
|
||
const page = await vite.transformIndexHtml(url, template);
|
||
res.status(200).set({ "Content-Type": "text/html" }).end(page);
|
||
} catch (e) {
|
||
vite.ssrFixStacktrace(e as Error);
|
||
next(e);
|
||
}
|
||
});
|
||
}
|