og:image: prave dimenzije naslovnice namesto fiksnih 1200x630 (slike so 1200x900); nadomestni logotip zdaj 1200x675, prej 1050x630 pod Googlovim minimumom; opozorilo v log, ko clanek nima naslovnice

This commit is contained in:
claude
2026-08-23 10:34:31 +02:00
parent c8b7def69c
commit 1e9f854f26
2 changed files with 38 additions and 2 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 141 KiB

+38 -2
View File
@@ -2,11 +2,41 @@ import express, { type Express } from "express";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { storage } from "./storage"; import { storage } from "./storage";
import sharp from "sharp";
function escapeHtml(str: string): string { function escapeHtml(str: string): string {
return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
} }
// Dejanske dimenzije naslovnice. Prej sta bili sirina in visina v meta
// oznakah fiksno zapisani kot 1200x630, slike pa so v resnici 1200x900 —
// Facebook in Google sta dobila napacno vrednost. Ce dimenzij ne moremo
// prebrati, oznak raje ne zapisemo.
const ogDimCache = new Map<string, { w: number; h: number } | null>();
async function ogImageDims(imgUrl: string, publicDir: string) {
if (ogDimCache.has(imgUrl)) return ogDimCache.get(imgUrl) ?? null;
let dims: { w: number; h: number } | null = null;
try {
const m = /\/(uploads|images)\/([^/?#]+)$/.exec(imgUrl);
if (m) {
const cand = [
path.join(publicDir, m[1], m[2]),
path.join(publicDir, m[1], m[2].replace(/\.jpg$/, ".webp")),
];
for (const p of cand) {
if (!fs.existsSync(p)) continue;
const meta = await sharp(p).metadata();
if (meta.width && meta.height) { dims = { w: meta.width, h: meta.height }; break; }
}
}
} catch (e) {
dims = null;
}
ogDimCache.set(imgUrl, dims);
return dims;
}
function ogImageUrl(coverImage: string, baseUrl: string): string { function ogImageUrl(coverImage: string, baseUrl: string): string {
if (!coverImage) return ""; if (!coverImage) return "";
let imgPath = coverImage; let imgPath = coverImage;
@@ -173,6 +203,10 @@ export function serveStatic(app: Express) {
const articleUrl = `${canonicalBase}/article/${article.slug}`; const articleUrl = `${canonicalBase}/article/${article.slug}`;
const imageUrl = ogImageUrl(article.coverImage || "", canonicalBase); const imageUrl = ogImageUrl(article.coverImage || "", canonicalBase);
const finalImage = imageUrl || `${canonicalBase}/og-image.jpg`; const finalImage = imageUrl || `${canonicalBase}/og-image.jpg`;
const articleImgDims = await ogImageDims(finalImage, distPath);
if (!imageUrl) {
console.warn(`[og] clanek brez naslovnice, pada na logotip: ${article.slug}`);
}
let template = await fs.promises.readFile(indexPath, "utf-8"); let template = await fs.promises.readFile(indexPath, "utf-8");
template = stripExistingMeta(template); template = stripExistingMeta(template);
@@ -249,8 +283,10 @@ export function serveStatic(app: Express) {
`<meta property="og:url" content="${escapeHtml(articleUrl)}" />`, `<meta property="og:url" content="${escapeHtml(articleUrl)}" />`,
`<meta property="og:image" content="${escapeHtml(finalImage)}" />`, `<meta property="og:image" content="${escapeHtml(finalImage)}" />`,
`<meta property="og:image:secure_url" content="${escapeHtml(finalImage)}" />`, `<meta property="og:image:secure_url" content="${escapeHtml(finalImage)}" />`,
`<meta property="og:image:width" content="1200" />`, ...(articleImgDims
`<meta property="og:image:height" content="630" />`, ? [`<meta property="og:image:width" content="${articleImgDims.w}" />`,
`<meta property="og:image:height" content="${articleImgDims.h}" />`]
: []),
`<meta property="og:image:type" content="image/jpeg" />`, `<meta property="og:image:type" content="image/jpeg" />`,
`<meta property="og:site_name" content="Folx Music Television" />`, `<meta property="og:site_name" content="Folx Music Television" />`,
`<meta property="og:locale" content="de_DE" />`, `<meta property="og:locale" content="de_DE" />`,