import { useQuery } from "@tanstack/react-query"; import { useParams, Link, useLocation } from "wouter"; import { type Article } from "@shared/schema"; import { format } from "date-fns"; import { de } from "date-fns/locale"; import { ArrowLeft, Eye, Calendar, User, Clock } from "lucide-react"; import { usePageMeta } from "@/hooks/use-page-meta"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; import Header from "@/components/header"; import Footer from "@/components/footer"; import { InArticleAd, PageSideAds, MultiplexAd } from "@/components/adsense"; import { useIsMobile } from "@/hooks/use-mobile"; import DOMPurify from "dompurify"; import ShareButtons from "@/components/share-buttons"; import { useEffect, useMemo } from "react"; import { useFocalPoints, objectPositionFor } from "@/lib/focal"; const ALLOWED_IFRAME_DOMAINS = [ "iframe.mediadelivery.net", "video.bunny.net", "www.facebook.com", "www.instagram.com", "www.tiktok.com", "www.youtube.com", "youtube.com", "player.vimeo.com", ]; function sanitizeContent(html: string): string { return DOMPurify.sanitize(html, { ADD_TAGS: ["iframe", "blockquote"], ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling", "src", "loading", "style", "class", "title", "data-instgrm-permalink", "data-instgrm-version", "data-instgrm-captioned", "cite"], ALLOW_UNKNOWN_PROTOCOLS: false, }); } function ArticleSkeleton() { return (
); } function RelatedArticles({ currentSlug }: { currentSlug: string }) { const { data: articles } = useQuery({ queryKey: ["/api/articles/popular"], }); const filtered = articles?.filter((a) => a.slug !== currentSlug); const focalPoints = useFocalPoints(); if (!filtered || filtered.length === 0) return null; return (

Weitere Artikel

{filtered.slice(0, 3).map((article) => (
{article.title}

{article.title}

{format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}

))}
); } export default function ArticlePage() { const focalPoints = useFocalPoints(); const { slug } = useParams<{ slug: string }>(); const isMobile = useIsMobile(); const [, navigate] = useLocation(); const { data: article, isLoading, error } = useQuery
({ queryKey: ["/api/articles", slug], }); // Kartice (horoskop, recept) samo napotijo naprej — tudi pri kliku znotraj strani. const targetUrl = (article as any)?.targetUrl as string | undefined; useEffect(() => { if (targetUrl) navigate(targetUrl, { replace: true }); }, [targetUrl, navigate]); const articleUrl = article ? `${window.location.origin}/article/${article.slug}` : ""; const articleImage = article?.coverImage ? (article.coverImage.startsWith("http") ? article.coverImage : `${window.location.origin}${article.coverImage}`) : ""; usePageMeta( article ? `${article.title} - Volksmusik & Schlager` : "Volksmusik & Schlager Artikel", article?.excerpt || "Aktuelle Nachrichten aus der Volksmusik- und Schlagerszene bei FOLX TV.", article ? { ogTitle: article.title, ogDescription: article.excerpt, ogImage: articleImage || undefined, ogType: "article", ogUrl: articleUrl, articlePublishedTime: new Date(article.publishedAt).toISOString(), articleAuthor: article.author || "Folx Music Television", articleSection: article.category || "News", } : undefined ); useEffect(() => { if (!article) return; const jsonLd = { "@context": "https://schema.org", "@type": "NewsArticle", "headline": article.title, "description": article.excerpt, "image": articleImage ? [articleImage] : [], "datePublished": new Date(article.publishedAt).toISOString(), "dateModified": new Date(article.publishedAt).toISOString(), "author": { "@type": "Organization", "name": article.author || "Folx Music Television", "url": "https://folx.tv" }, "publisher": { "@type": "Organization", "name": "Folx Music Television", "url": "https://folx.tv", "logo": { "@type": "ImageObject", "url": `${window.location.origin}/favicon.png` } }, "mainEntityOfPage": { "@type": "WebPage", "@id": articleUrl }, "articleSection": article.category || "News", "inLanguage": "de", "keywords": `Volksmusik, Schlager, ${article.category || "News"}, ${article.title}` }; const breadcrumbLd = { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "FOLX TV", "item": "https://folx.tv" }, { "@type": "ListItem", "position": 2, "name": article.category || "News", "item": `https://folx.tv/category/${encodeURIComponent(article.category || "News")}` }, { "@type": "ListItem", "position": 3, "name": article.title, "item": articleUrl } ] }; const script = document.createElement("script"); script.type = "application/ld+json"; script.id = "article-jsonld"; script.textContent = JSON.stringify([jsonLd, breadcrumbLd]); const existing = document.getElementById("article-jsonld"); if (existing) existing.remove(); document.head.appendChild(script); return () => { const el = document.getElementById("article-jsonld"); if (el) el.remove(); }; }, [article, articleUrl, articleImage]); useEffect(() => { if (!article?.content) return; if (article.content.includes("instagram.com")) { const existing = document.querySelector('script[src*="instagram.com/embed.js"]'); if (existing) existing.remove(); const script = document.createElement("script"); script.src = "https://www.instagram.com/embed.js"; script.async = true; document.body.appendChild(script); script.onload = () => { if ((window as any).instgrm) { (window as any).instgrm.Embeds.process(); } }; } if (article.content.includes("tiktok.com")) { if (!document.querySelector('script[src*="tiktok.com/embed.js"]')) { const script = document.createElement("script"); script.src = "https://www.tiktok.com/embed.js"; script.async = true; document.body.appendChild(script); } } }, [article?.content]); // Replace Bunny iframe embeds with native HLS player (folxvideos S3 origin) useEffect(() => { if (!article?.content) return; let cancelled = false; const loadHlsJs = (): Promise => new Promise((resolve, reject) => { if ((window as any).Hls) return resolve((window as any).Hls); const s = document.createElement("script"); s.src = "https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js"; s.async = true; s.onload = () => resolve((window as any).Hls); s.onerror = reject; document.head.appendChild(s); }); const transform = async () => { const iframes = document.querySelectorAll( 'iframe[src*="mediadelivery.net/embed/"], iframe[src*="iframe.mediadelivery.net/embed/"]' ); if (iframes.length === 0) return; let Hls: any = null; try { Hls = await loadHlsJs(); } catch {} for (const iframe of Array.from(iframes)) { if (cancelled) break; const m = iframe.src.match(/embed\/\d+\/([a-f0-9-]+)/i); if (!m) continue; const guid = m[1]; const folxUrl = `https://folxvideos.b-cdn.net/folx-tv/${guid}/master.m3u8`; try { const head = await fetch(folxUrl, { method: "HEAD" }); if (!head.ok) continue; } catch { continue; } const video = document.createElement("video"); video.controls = true; video.preload = "metadata"; video.playsInline = true; video.style.cssText = iframe.getAttribute("style") || "width:100%;aspect-ratio:16/9;border:none;"; video.className = iframe.className || ""; if (Hls && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(folxUrl); hls.attachMedia(video); } else if (video.canPlayType("application/vnd.apple.mpegurl")) { video.src = folxUrl; } else { continue; // can't play, keep iframe } iframe.replaceWith(video); } }; // Run after content is in DOM (next tick) const t = setTimeout(transform, 50); return () => { cancelled = true; clearTimeout(t); }; }, [article?.content]); if (targetUrl) return null; if (isLoading) { return (
); } if (error || !article) { return (

Artikel nicht gefunden

Der gesuchte Artikel existiert nicht oder wurde entfernt.

); } return (
{article.coverImage && (
{article.title}
)}

{article.title}

{article.author} {format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })} {article.views.toLocaleString()} Aufrufe
{(() => { const sanitized = sanitizeContent(article.content); const blocks = sanitized.split(/(?=<(?:p|h[2-4]|div)[\s>])/i).filter(Boolean); const AD_INTERVAL = isMobile ? 2 : 3; const segments: string[] = []; for (let i = 0; i < blocks.length; i += AD_INTERVAL) { segments.push(blocks.slice(i, i + AD_INTERVAL).join("")); } const proseClasses = `prose prose-base dark:prose-invert max-w-none prose-headings:text-foreground prose-headings:font-semibold prose-headings:text-lg prose-p:text-foreground/85 prose-p:leading-relaxed prose-p:text-[15px] prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-strong:text-foreground prose-img:rounded-md prose-img:w-full prose-img:object-cover [&_iframe]:rounded-md [&_iframe]:my-5 [&_iframe]:max-w-full [&_div[style]]:flex [&_div[style]]:justify-center [&_blockquote:not(.instagram-media)]:border-l-primary [&_blockquote:not(.instagram-media)]:bg-accent/50 [&_blockquote:not(.instagram-media)]:rounded-r-md [&_blockquote:not(.instagram-media)]:py-1 [&_.instagram-media]:!bg-transparent [&_.instagram-media]:!border-0 [&_.instagram-media]:!shadow-none [&_.instagram-media]:!p-0 [&_.instagram-media]:mx-auto`; // Najvec dva oglasa v besedilu: po prvem odstavku in na sredini. const last = segments.length - 1; const AD_AFTER = last <= 0 ? [] : (last === 1 ? [0] : [0, Math.floor(last / 2)]); return (
{ if (!el) return; el.querySelectorAll("a[href]").forEach((a) => { const href = a.getAttribute("href") || ""; const isBunny = href.includes("mediadelivery.net") || href.includes("bunny.net") || href.includes("b-cdn.net"); const isInternal = href.startsWith("/") || href.includes("folx.tv"); if (!isBunny && !isInternal && href.startsWith("http")) { a.setAttribute("target", "_blank"); a.setAttribute("rel", "noopener noreferrer"); } }); }}> {segments.map((html, idx) => (
{AD_AFTER.includes(idx) && }
))}
); })()}
Anzeige
); }