${escapeHtml(article.title)}
`, imageUrl ? `${escapeHtml(article.excerpt)}
`, article.content || "", "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, "&").replace(/"/g, """).replace(//g, ">"); } function ogImageUrl(coverImage: string, baseUrl: string): string { if (!coverImage) return ""; let imgPath = coverImage; // Cloudinary: vsili FB razmerje 1200x630 z g_faces (da FB ne reze glav) if (imgPath.includes("res.cloudinary.com")) { imgPath = imgPath.replace(/([,&/?])h_\d+/i, "$1h_630").replace(/([,&/?])w_\d+/i, "$1w_1200"); // ce ni g_faces, ga dodaj if (!/g_faces/.test(imgPath)) { imgPath = imgPath.replace(/\/(image\/(upload|fetch))\//, "/$1/g_faces,"); } return imgPath; } if (imgPath.endsWith(".webp")) { imgPath = imgPath.replace(/\.webp$/, ".jpg"); } return imgPath.startsWith("http") ? imgPath : `${baseUrl}${imgPath}`; } // Rubrike, ki jih pisemo enkrat in objavimo tudi na onemusic.news. Besedilo je // isto na obeh domenah, zato jih na folx.tv drzimo zunaj Googlovega indeksa — // v bazi in v /api/articles ostanejo, ker jih bere sidebar na TV kanalih. const ONE_RUBRIKEN = new Set(["Politik", "Promis", "Sport", "Musik & Film", "Wetter", "Finanzen", "Aktuelles"]); function setRobots(html: string, content: string): string { const tag = ``; if (/]*>/i.test(html)) { return html.replace(/]*>/i, tag); } return html.replace("", ` ${tag}\n `); } function stripExistingMeta(html: string): string { html = html.replace(/]*>\s*/gi, ""); html = html.replace(/]*>\s*/gi, ""); html = html.replace(/]*>\s*/gi, ""); html = html.replace(/]*>\s*/gi, ""); html = html.replace(/]*>\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://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 && (article as any).targetUrl) { res.redirect(302, (article as any).targetUrl); return; } 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 pubDate = article.publishedAt ? new Date(article.publishedAt as any).toISOString() : new Date().toISOString(); // dateModified: ce je clanek dopolnjen (enrich), preberi marker const modDate = (() => { const mm = //.exec(article.content || ""); if (mm) { try { return new Date(mm[1]).toISOString(); } catch (e) { /* ignore */ } } return pubDate; })(); // VideoObject: ce je v clanku vgrajen YouTube video const videoId = (() => { const mm = /youtube(?:-nocookie)?\.com\/embed\/([A-Za-z0-9_-]{6,})/.exec(article.content || ""); return mm ? mm[1] : null; })(); const jsonLd = { "@context": "https://schema.org", "@type": "NewsArticle", "headline": article.title, "description": article.excerpt, "image": [finalImage], "datePublished": pubDate, "dateModified": modDate, "articleSection": article.category || "News", "author": { "@type": "Organization", "name": article.author || "Folx Music Television", "url": canonicalBase, }, "publisher": { "@type": "Organization", "name": "Folx Music Television", "logo": { "@type": "ImageObject", "url": `${canonicalBase}/og-image.jpg`, }, }, "mainEntityOfPage": { "@type": "WebPage", "@id": articleUrl, }, }; const jsonLdTag = ``; const videoLd = videoId ? { "@context": "https://schema.org", "@type": "VideoObject", "name": article.title, "description": article.excerpt, "thumbnailUrl": [`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`], "uploadDate": pubDate, "embedUrl": `https://www.youtube.com/embed/${videoId}`, "contentUrl": `https://www.youtube.com/watch?v=${videoId}`, "publisher": { "@type": "Organization", "name": "Folx Music Television", "logo": { "@type": "ImageObject", "url": `${canonicalBase}/og-image.jpg` }, }, } : null; const videoLdTag = videoLd ? `` : ""; const ogTags = [ ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, `
${escapeHtml(article.excerpt)}
`, article.content || "", "