Optimize images and improve social media sharing previews
Convert images to JPG for optimization and ensure correct Open Graph tags are used for social media sharing. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 1f7e7e89-a520-4970-9645-37daadc466dc Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 30e90049-0ceb-4261-a159-b687b34f680b Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/1f7e7e89-a520-4970-9645-37daadc466dc/s81zXmM Replit-Helium-Checkpoint-Created: true
BIN
client/public/images/article-1.jpg
Normal file
|
After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/images/article-2.jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/images/article-3.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/images/article-4.jpg
Normal file
|
After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
BIN
client/public/images/article-5.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 98 KiB |
BIN
client/public/uploads/recipe-apfelstrudel.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/uploads/recipe-dampfnudeln.jpg
Normal file
|
After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
BIN
client/public/uploads/recipe-flammkuchen.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-germknoedel.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/uploads/recipe-gruenkohl.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-kaerntner-kasnudeln.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-kaesespaetzle.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/uploads/recipe-kaiserschmarrn.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-kartoffelpuffer.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-maultaschen.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-obatzda.jpg
Normal file
|
After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
BIN
client/public/uploads/recipe-sachertorte.jpg
Normal file
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-sauerbraten.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-schlutzkrapfen.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
BIN
client/public/uploads/recipe-schwarzwaelder-kirschtorte.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-schweinshaxe.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-tafelspitz.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
BIN
client/public/uploads/recipe-tiroler-knoedel.jpg
Normal file
|
After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
client/public/uploads/recipe-wiener-schnitzel.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
BIN
client/public/uploads/recipe-zwiebelrostbraten.jpg
Normal file
|
After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 82 KiB |
@ -10,14 +10,14 @@ interface WidgetRecipe {
|
||||
}
|
||||
|
||||
const WIDGET_RECIPES: WidgetRecipe[] = [
|
||||
{ title: "Kaiserschmarrn", image: "/uploads/recipe-kaiserschmarrn.png", time: "25 Min.", servings: "2" },
|
||||
{ title: "Wiener Schnitzel", image: "/uploads/recipe-wiener-schnitzel.png", time: "30 Min.", servings: "4" },
|
||||
{ title: "Apfelstrudel", image: "/uploads/recipe-apfelstrudel.png", time: "60 Min.", servings: "6" },
|
||||
{ title: "Schweinshaxe", image: "/uploads/recipe-schweinshaxe.png", time: "180 Min.", servings: "4" },
|
||||
{ title: "Käsespätzle", image: "/uploads/recipe-kaesespaetzle.png", time: "45 Min.", servings: "4" },
|
||||
{ title: "Sachertorte", image: "/uploads/recipe-sachertorte.png", time: "90 Min.", servings: "8" },
|
||||
{ title: "Maultaschen", image: "/uploads/recipe-maultaschen.png", time: "90 Min.", servings: "4" },
|
||||
{ title: "Schlutzkrapfen", image: "/uploads/recipe-schlutzkrapfen.png", time: "60 Min.", servings: "4" },
|
||||
{ title: "Kaiserschmarrn", image: "/uploads/recipe-kaiserschmarrn.jpg", time: "25 Min.", servings: "2" },
|
||||
{ title: "Wiener Schnitzel", image: "/uploads/recipe-wiener-schnitzel.jpg", time: "30 Min.", servings: "4" },
|
||||
{ title: "Apfelstrudel", image: "/uploads/recipe-apfelstrudel.jpg", time: "60 Min.", servings: "6" },
|
||||
{ title: "Schweinshaxe", image: "/uploads/recipe-schweinshaxe.jpg", time: "180 Min.", servings: "4" },
|
||||
{ title: "Käsespätzle", image: "/uploads/recipe-kaesespaetzle.jpg", time: "45 Min.", servings: "4" },
|
||||
{ title: "Sachertorte", image: "/uploads/recipe-sachertorte.jpg", time: "90 Min.", servings: "8" },
|
||||
{ title: "Maultaschen", image: "/uploads/recipe-maultaschen.jpg", time: "90 Min.", servings: "4" },
|
||||
{ title: "Schlutzkrapfen", image: "/uploads/recipe-schlutzkrapfen.jpg", time: "60 Min.", servings: "4" },
|
||||
];
|
||||
|
||||
export function RecipeWidget() {
|
||||
|
||||
@ -73,7 +73,7 @@ function RelatedArticles({ currentSlug }: { currentSlug: string }) {
|
||||
<div className="group cursor-pointer" data-testid={`card-related-${article.id}`}>
|
||||
<div className="relative overflow-hidden rounded-md mb-3">
|
||||
<img
|
||||
src={article.coverImage ? article.coverImage.replace(".webp", "-thumb.webp") : "/images/article-1.png"}
|
||||
src={article.coverImage ? article.coverImage.replace(".webp", "-thumb.webp") : "/images/article-1.jpg"}
|
||||
alt={article.title}
|
||||
className="w-full aspect-video object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
style={{ objectPosition: "center 25%" }}
|
||||
|
||||
@ -159,7 +159,7 @@ export default function CategoryPage() {
|
||||
<div className="relative rounded-t-md">
|
||||
<div className="overflow-hidden rounded-t-md">
|
||||
<img
|
||||
src={article.coverImage || "/images/article-1.png"}
|
||||
src={article.coverImage || "/images/article-1.jpg"}
|
||||
alt={article.title}
|
||||
className="w-full aspect-video object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
style={{ objectPosition: "center 25%" }}
|
||||
|
||||
@ -66,7 +66,7 @@ interface GalleryImage {
|
||||
}
|
||||
|
||||
function thumbUrl(src: string | null): string {
|
||||
if (!src) return "/images/article-1.png";
|
||||
if (!src) return "/images/article-1.jpg";
|
||||
if (src.endsWith(".webp")) return src.replace(".webp", "-thumb.webp");
|
||||
return src;
|
||||
}
|
||||
@ -88,7 +88,7 @@ function HeroCard({ article, focalPoints }: { article: Article; focalPoints?: Re
|
||||
<Link href={`/article/${article.slug}`}>
|
||||
<div className="relative group cursor-pointer rounded-lg overflow-hidden h-full" data-testid={`card-hero-${article.id}`}>
|
||||
<div className="relative h-full min-h-[280px]">
|
||||
<SmartImage src={article.coverImage || "/images/article-1.png"} alt={article.title} className="transition-transform duration-700 group-hover:scale-105" focalPoints={focalPoints} />
|
||||
<SmartImage src={article.coverImage || "/images/article-1.jpg"} alt={article.title} className="transition-transform duration-700 group-hover:scale-105" focalPoints={focalPoints} />
|
||||
{isVideo && (
|
||||
<div className="absolute inset-0 flex items-center justify-center z-10">
|
||||
<div className="w-14 h-14 rounded-full bg-primary/90 flex items-center justify-center group-hover:bg-primary transition-colors shadow-lg">
|
||||
|
||||
@ -28,7 +28,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
recipes: [
|
||||
{
|
||||
title: "Kaiserschmarrn",
|
||||
image: "/uploads/recipe-kaiserschmarrn.png",
|
||||
image: "/uploads/recipe-kaiserschmarrn.jpg",
|
||||
time: "25 Min.",
|
||||
servings: "2 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -38,7 +38,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Wiener Schnitzel",
|
||||
image: "/uploads/recipe-wiener-schnitzel.png",
|
||||
image: "/uploads/recipe-wiener-schnitzel.jpg",
|
||||
time: "30 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -48,7 +48,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Apfelstrudel",
|
||||
image: "/uploads/recipe-apfelstrudel.png",
|
||||
image: "/uploads/recipe-apfelstrudel.jpg",
|
||||
time: "60 Min.",
|
||||
servings: "6 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -58,7 +58,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Tiroler Knödel",
|
||||
image: "/uploads/recipe-tiroler-knoedel.png",
|
||||
image: "/uploads/recipe-tiroler-knoedel.jpg",
|
||||
time: "40 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -68,7 +68,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Sachertorte",
|
||||
image: "/uploads/recipe-sachertorte.png",
|
||||
image: "/uploads/recipe-sachertorte.jpg",
|
||||
time: "90 Min.",
|
||||
servings: "8 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -78,7 +78,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Kärntner Kasnudeln",
|
||||
image: "/uploads/recipe-kaerntner-kasnudeln.png",
|
||||
image: "/uploads/recipe-kaerntner-kasnudeln.jpg",
|
||||
time: "50 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -88,7 +88,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Germknödel",
|
||||
image: "/uploads/recipe-germknoedel.png",
|
||||
image: "/uploads/recipe-germknoedel.jpg",
|
||||
time: "120 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -98,7 +98,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Tafelspitz",
|
||||
image: "/uploads/recipe-tafelspitz.png",
|
||||
image: "/uploads/recipe-tafelspitz.jpg",
|
||||
time: "180 Min.",
|
||||
servings: "6 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -113,7 +113,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
recipes: [
|
||||
{
|
||||
title: "Schweinshaxe",
|
||||
image: "/uploads/recipe-schweinshaxe.png",
|
||||
image: "/uploads/recipe-schweinshaxe.jpg",
|
||||
time: "180 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -123,7 +123,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Obatzda",
|
||||
image: "/uploads/recipe-obatzda.png",
|
||||
image: "/uploads/recipe-obatzda.jpg",
|
||||
time: "15 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Vorspeise",
|
||||
@ -133,7 +133,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Dampfnudeln",
|
||||
image: "/uploads/recipe-dampfnudeln.png",
|
||||
image: "/uploads/recipe-dampfnudeln.jpg",
|
||||
time: "90 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -143,7 +143,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Käsespätzle",
|
||||
image: "/uploads/recipe-kaesespaetzle.png",
|
||||
image: "/uploads/recipe-kaesespaetzle.jpg",
|
||||
time: "45 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -158,7 +158,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
recipes: [
|
||||
{
|
||||
title: "Maultaschen",
|
||||
image: "/uploads/recipe-maultaschen.png",
|
||||
image: "/uploads/recipe-maultaschen.jpg",
|
||||
time: "90 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -168,7 +168,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Zwiebelrostbraten",
|
||||
image: "/uploads/recipe-zwiebelrostbraten.png",
|
||||
image: "/uploads/recipe-zwiebelrostbraten.jpg",
|
||||
time: "40 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -178,7 +178,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Flammkuchen",
|
||||
image: "/uploads/recipe-flammkuchen.png",
|
||||
image: "/uploads/recipe-flammkuchen.jpg",
|
||||
time: "30 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -193,7 +193,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
recipes: [
|
||||
{
|
||||
title: "Schlutzkrapfen",
|
||||
image: "/uploads/recipe-schlutzkrapfen.png",
|
||||
image: "/uploads/recipe-schlutzkrapfen.jpg",
|
||||
time: "60 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -203,7 +203,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Sauerbraten",
|
||||
image: "/uploads/recipe-sauerbraten.png",
|
||||
image: "/uploads/recipe-sauerbraten.jpg",
|
||||
time: "240 Min.",
|
||||
servings: "6 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -213,7 +213,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Schwarzwälder Kirschtorte",
|
||||
image: "/uploads/recipe-schwarzwaelder-kirschtorte.png",
|
||||
image: "/uploads/recipe-schwarzwaelder-kirschtorte.jpg",
|
||||
time: "120 Min.",
|
||||
servings: "12 Portionen",
|
||||
category: "Nachspeise",
|
||||
@ -228,7 +228,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
recipes: [
|
||||
{
|
||||
title: "Grünkohl mit Pinkel",
|
||||
image: "/uploads/recipe-gruenkohl.png",
|
||||
image: "/uploads/recipe-gruenkohl.jpg",
|
||||
time: "120 Min.",
|
||||
servings: "6 Portionen",
|
||||
category: "Hauptspeise",
|
||||
@ -238,7 +238,7 @@ const RECIPE_REGIONS: RecipeRegion[] = [
|
||||
},
|
||||
{
|
||||
title: "Kartoffelpuffer",
|
||||
image: "/uploads/recipe-kartoffelpuffer.png",
|
||||
image: "/uploads/recipe-kartoffelpuffer.jpg",
|
||||
time: "30 Min.",
|
||||
servings: "4 Portionen",
|
||||
category: "Hauptspeise",
|
||||
|
||||
@ -23,7 +23,7 @@ interface PaginatedResponse {
|
||||
function VideoCard({ article }: { article: Article }) {
|
||||
const thumbSrc = article.coverImage
|
||||
? article.coverImage.replace(".webp", "-thumb.webp")
|
||||
: "/images/article-1.png";
|
||||
: "/images/article-1.jpg";
|
||||
|
||||
return (
|
||||
<Link href={`/article/${article.slug}`}>
|
||||
|
||||
@ -16,6 +16,14 @@ function ogImageUrl(coverImage: string, baseUrl: string): string {
|
||||
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)) {
|
||||
@ -26,7 +34,7 @@ export function serveStatic(app: Express) {
|
||||
|
||||
app.use(express.static(distPath, {
|
||||
setHeaders(res, filePath) {
|
||||
if (filePath.endsWith("og-image.jpg") || filePath.includes("/uploads/")) {
|
||||
if (filePath.endsWith("og-image.jpg") || filePath.includes("/uploads/") || filePath.includes("/images/")) {
|
||||
res.setHeader("Cache-Control", "public, max-age=86400");
|
||||
}
|
||||
},
|
||||
@ -36,30 +44,35 @@ export function serveStatic(app: Express) {
|
||||
const url = req.originalUrl;
|
||||
const indexPath = path.resolve(distPath, "index.html");
|
||||
|
||||
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 host = req.get("host") || "folx.tv";
|
||||
const protocol = req.get("x-forwarded-proto") || "https";
|
||||
const baseUrl = `${protocol}://${host}`;
|
||||
const articleUrl = `${baseUrl}/article/${article.slug}`;
|
||||
const imageUrl = ogImageUrl(article.coverImage || "", baseUrl);
|
||||
const finalImage = imageUrl || `${baseUrl}/og-image.jpg`;
|
||||
|
||||
let template = await fs.promises.readFile(indexPath, "utf-8");
|
||||
template = stripExistingMeta(template);
|
||||
|
||||
const finalImage = imageUrl || `${baseUrl}/og-image.jpg`;
|
||||
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:width" content="1200" />`,
|
||||
`<meta property="og:image:height" content="630" />`,
|
||||
`<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)}" />`,
|
||||
@ -68,9 +81,6 @@ export function serveStatic(app: Express) {
|
||||
`<title>${escapeHtml(article.title)} - Folx Music Television</title>`,
|
||||
].join("\n ");
|
||||
|
||||
template = template.replace(/<meta property="og:[^>]*>\s*/g, "");
|
||||
template = template.replace(/<meta name="description"[^>]*>\s*/g, "");
|
||||
template = template.replace(/<meta name="twitter:[^>]*>\s*/g, "");
|
||||
template = template.replace(/<title>[^<]*<\/title>/, ogTags);
|
||||
|
||||
res.status(200).set({ "Content-Type": "text/html" }).end(template);
|
||||
@ -80,10 +90,6 @@ export function serveStatic(app: Express) {
|
||||
}
|
||||
}
|
||||
|
||||
const host = req.get("host") || "folx.tv";
|
||||
const protocol = req.get("x-forwarded-proto") || "https";
|
||||
const baseUrl = `${protocol}://${host}`;
|
||||
|
||||
let template = await fs.promises.readFile(indexPath, "utf-8");
|
||||
template = template.replace(/https:\/\/www\.folx\.tv\//g, `${baseUrl}/`);
|
||||
template = template.replace(/https:\/\/www\.folx\.tv\/og-image\.jpg/g, `${baseUrl}/og-image.jpg`);
|
||||
|
||||