From 590584b893b34e5410a98db810cdc382103b1da4 Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Fri, 13 Feb 2026 17:53:37 +0000 Subject: [PATCH] Add an artist listing page and improve SEO for various pages Introduces a new `/kuenstler` page, API endpoint `/api/artists`, and enhances meta tags on `index.html` and for crawler requests on `/kuenstler`. Adds `KuenstlerPage.tsx` and updates `routes.ts` and `index.html`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 401e2ec0-e00d-4f10-9d0e-60f3d479f9a5 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 69ee4fdb-c617-4cdd-b9f6-d3fab268d533 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/60d372ff-2c10-46c7-b01b-10c3435136b0/401e2ec0-e00d-4f10-9d0e-60f3d479f9a5/qFrskyV --- client/index.html | 1 + client/src/App.tsx | 2 + client/src/pages/KuenstlerPage.tsx | 162 +++++++++++++++++++++++++++++ client/src/pages/home.tsx | 7 ++ server/routes.ts | 134 +++++++++++++++++++++++- 5 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 client/src/pages/KuenstlerPage.tsx diff --git a/client/index.html b/client/index.html index 5be0427..03db3e7 100644 --- a/client/index.html +++ b/client/index.html @@ -19,6 +19,7 @@ + diff --git a/client/src/App.tsx b/client/src/App.tsx index 45c9944..c4ff039 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -11,6 +11,7 @@ import GeschichteLiedPage from "@/pages/GeschichteLiedPage"; import GipfelstammtischPage from "@/pages/GipfelstammtischPage"; import LivePage from "@/pages/LivePage"; import PlayerPage from "@/pages/PlayerPage"; +import KuenstlerPage from "@/pages/KuenstlerPage"; import AdminPage from "@/pages/admin"; import PrivacyPolicy from "@/pages/PrivacyPolicy"; import TermsOfService from "@/pages/TermsOfService"; @@ -27,6 +28,7 @@ function Router() { + diff --git a/client/src/pages/KuenstlerPage.tsx b/client/src/pages/KuenstlerPage.tsx new file mode 100644 index 0000000..78835f6 --- /dev/null +++ b/client/src/pages/KuenstlerPage.tsx @@ -0,0 +1,162 @@ +import { useQuery } from '@tanstack/react-query'; +import { Link, useLocation } from 'wouter'; +import { ArrowLeft, Music, Users, Search, Menu, X } from 'lucide-react'; +import { useState, useEffect } from 'react'; +import HeaderAd from '@/components/HeaderAd'; + +interface Artist { + name: string; + videoCount: number; +} + +export default function KuenstlerPage() { + const [searchQuery, setSearchQuery] = useState(""); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [, setLocation] = useLocation(); + + useEffect(() => { + document.title = 'Alle Künstler & Interpreten | Folx TV - Video'; + const metaDescription = document.querySelector('meta[name="description"]'); + if (metaDescription) { + metaDescription.setAttribute('content', 'Entdecken Sie alle Volksmusik- und Schlager-Künstler auf Folx TV. Nummer 1 in Europa für Volksmusik und Schlager.'); + } + }, []); + + const { data, isLoading } = useQuery<{ artists: Artist[], total: number }>({ + queryKey: ['/api/artists'], + }); + + const artists = data?.artists || []; + const filteredArtists = searchQuery + ? artists.filter(a => a.name.toLowerCase().includes(searchQuery.toLowerCase())) + : artists; + + const letters = Array.from(new Set(filteredArtists.map(a => a.name.charAt(0).toUpperCase()))).sort((a, b) => a.localeCompare(b, 'de')); + + if (isLoading) { + return ( +
+
+
+ ); + } + + return ( +
+
+
+
+ + + Folx TV + + +
+ + + + +
+ + {isMobileMenuOpen && ( + + )} +
+ + + +
+
+ + + + +

Alle Künstler & Interpreten

+ + {artists.length} Künstler + +
+ +
+ + setSearchQuery(e.target.value)} + className="w-full pl-10 pr-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-purple-500" + /> +
+ +
+ {letters.map(letter => ( + + {letter} + + ))} +
+ + {letters.map(letter => { + const letterArtists = filteredArtists.filter(a => a.name.charAt(0).toUpperCase() === letter); + return ( +
+

{letter}

+
+ {letterArtists.map(artist => ( + +
+ +
+
+

{artist.name}

+

{artist.videoCount} Video{artist.videoCount > 1 ? 's' : ''}

+
+ + ))} +
+
+ ); + })} + + {filteredArtists.length === 0 && ( +
+ +

Keine Künstler gefunden für "{searchQuery}"

+
+ )} +
+ +
+
+

Folx TV - Nummer 1 in Europa für Volksmusik und Schlager

+
+
+
+ ); +} diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index f83e56c..4bfd6a6 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -56,6 +56,13 @@ export default function Home() { if (metaDescription) { metaDescription.setAttribute('content', 'Folx TV - Nummer 1 in Europa für Volksmusik und Schlager. Video Streaming Plattform mit Musik, Unterhaltung und Live-Streaming.'); } + let metaKeywords = document.querySelector('meta[name="keywords"]'); + if (!metaKeywords) { + metaKeywords = document.createElement('meta'); + metaKeywords.setAttribute('name', 'keywords'); + document.head.appendChild(metaKeywords); + } + metaKeywords.setAttribute('content', 'Volksmusik, Schlager, Folx TV, Kastelruther Spatzen, Monika Martin, Oswald Sattler, Angela Wiedl, Die Grubertaler, Michael Hirte, Sašo Avsenik, Jonny Hill, Rosanna Rocci, Linda Feller, Julia Buchner, Melanie Payer, Marlena Martinelli, Musikvideo, Streaming'); }, []); // Update videos when new data comes in diff --git a/server/routes.ts b/server/routes.ts index e805085..7eaa3e7 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -20,6 +20,30 @@ import { setupAuth, isAuthenticated, isAdmin } from "./replitAuth"; import { ObjectStorageService, ObjectNotFoundError } from "./objectStorage"; import { generateVideoDescription, generateBulkDescriptions } from "./aiService"; +// Extract unique artist names from video titles +function extractArtists(videos: any[]): { name: string; videoCount: number; videos: any[] }[] { + const artistMap = new Map(); + for (const v of videos) { + const title = v.title || ''; + let artist = ''; + if (title.includes('–')) { + artist = title.split('–')[0].trim(); + } else if (title.includes(' - ')) { + artist = title.split(' - ')[0].trim(); + } + if (artist && !artist.toUpperCase().startsWith('FOLX')) { + const normalized = artist.replace(/\s+/g, ' ').trim(); + if (!artistMap.has(normalized)) { + artistMap.set(normalized, []); + } + artistMap.get(normalized)!.push(v); + } + } + return Array.from(artistMap.entries()) + .map(([name, vids]) => ({ name, videoCount: vids.length, videos: vids })) + .sort((a, b) => a.name.localeCompare(b.name, 'de')); +} + // Find video by short or long ID - moved to top level for export export async function findVideoByAnyId(id: string) { try { @@ -439,6 +463,95 @@ export async function registerRoutes(app: Express): Promise { res.send(html); }); + // API endpoint for artists list + app.get('/api/artists', async (req, res) => { + try { + const allVideos = await storage.getVideos(600, 0); + const artists = extractArtists(allVideos); + res.json({ artists: artists.map(a => ({ name: a.name, videoCount: a.videoCount })), total: artists.length }); + } catch (error) { + res.status(500).json({ message: 'Error fetching artists' }); + } + }); + + // Server-side meta tags for /kuenstler page (crawlers + SEO) + app.get('/kuenstler', async (req, res, next) => { + const userAgent = req.headers['user-agent']?.toLowerCase() || ''; + const crawlers = [ + 'facebookexternalhit', 'facebot', 'twitterbot', 'whatsapp', + 'telegrambot', 'linkedinbot', 'pinterest', 'slackbot', + 'viberbot', 'discordbot', 'applebot', 'googlebot', + 'bingbot', 'yandex', 'baiduspider', 'duckduckbot' + ]; + const isCrawler = crawlers.some(crawler => userAgent.includes(crawler)); + if (!isCrawler) return next(); + + const baseUrl = 'https://video.folx.tv'; + const pageUrl = `${baseUrl}/kuenstler`; + const allVideos = await storage.getVideos(600, 0); + const artists = extractArtists(allVideos); + const topArtists = artists.slice(0, 30).map(a => a.name).join(', '); + const title = `Alle Künstler & Interpreten (${artists.length}) | Folx TV - Video`; + const description = `Entdecken Sie ${artists.length} Volksmusik- und Schlager-Künstler auf Folx TV: ${topArtists} und viele mehr. Nummer 1 in Europa für Volksmusik und Schlager.`; + const keywords = artists.map(a => a.name).join(', ') + ', Volksmusik, Schlager, Folx TV'; + + const escapeHtml = (s: string) => s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + + const jsonLd = { + "@context": "https://schema.org", + "@type": "CollectionPage", + "name": title, + "description": description, + "url": pageUrl, + "numberOfItems": artists.length, + "publisher": { "@type": "Organization", "name": "FOLX.TV", "url": "https://folx.tv" }, + "inLanguage": "de", + "mainEntity": { + "@type": "ItemList", + "numberOfItems": artists.length, + "itemListElement": artists.map((a, i) => ({ + "@type": "ListItem", + "position": i + 1, + "item": { + "@type": "MusicGroup", + "name": a.name, + "url": `${pageUrl}#letter-${a.name.charAt(0).toUpperCase()}` + } + })) + } + }; + + const html = ` + + + + + ${escapeHtml(title)} + + + + + + + + + + + + + + + +

Alle Künstler & Interpreten auf Folx TV

+

${escapeHtml(description)}

+

Insgesamt ${artists.length} Künstler mit ${allVideos.length} Musikvideos.

+
    ${artists.map(a => `
  • ${escapeHtml(a.name)} (${a.videoCount} Video${a.videoCount > 1 ? 's' : ''})
  • `).join('')}
+ +`; + res.set('Content-Type', 'text/html'); + res.send(html); + }); + // Server-side meta tags for /folx-stadl page (crawlers + SEO) app.get('/folx-stadl', async (req, res, next) => { const userAgent = req.headers['user-agent']?.toLowerCase() || ''; @@ -520,7 +633,7 @@ export async function registerRoutes(app: Express): Promise { const pageUrl = `${baseUrl}/geschichte-lied`; const title = 'Die Geschichte des Liedes - Musikdokumentation | Folx TV - Video'; const description = 'Die Geschichte des Liedes - Entdecken Sie die Entstehung und Hintergründe der beliebtesten Volksmusik- und Schlagerlieder. Eine einzigartige Musikdokumentation auf Folx TV.'; - const keywords = 'Geschichte des Liedes, Musikdokumentation, Volksmusik Geschichte, Schlager Historie, Liedgeschichte, Folx TV, Musiksendung'; + const keywords = 'Geschichte des Liedes, Musikdokumentation, Volksmusik Geschichte, Schlager Historie, Liedgeschichte, Folx TV, Musiksendung, Kastelruther Spatzen, Monika Martin, Oswald Sattler, Angela Wiedl, Die Grubertaler'; const allVideos = await storage.getVideos(600, 0); const geschichteVideos = allVideos.filter(v => v.title.includes('Geschichte des Liedes')); @@ -585,7 +698,7 @@ export async function registerRoutes(app: Express): Promise { const pageUrl = `${baseUrl}/gipfelstammtisch`; const title = 'Gipfelstammtisch - Volksmusik Talkshow | Folx TV - Video'; const description = 'Gipfelstammtisch - Die gemütliche Volksmusik-Talkshow auf Folx TV. Gespräche mit Stars der Volksmusik- und Schlagerszene in einzigartiger Alpenatmosphäre. Jetzt alle Folgen ansehen!'; - const keywords = 'Gipfelstammtisch, Volksmusik Talkshow, Schlager Talk, Alpen, Volksmusik Stars, Folx TV, Musiksendung'; + const keywords = 'Gipfelstammtisch, Volksmusik Talkshow, Schlager Talk, Alpen, Volksmusik Stars, Folx TV, Musiksendung, Kastelruther Spatzen, Monika Martin, Oswald Sattler, Angela Wiedl, Michael Hirte'; const allVideos = await storage.getVideos(600, 0); const gipfelVideos = allVideos.filter(v => v.title.toLowerCase().includes('gipfelstammtisch')); @@ -674,8 +787,25 @@ export async function registerRoutes(app: Express): Promise { weekly 0.7 + + ${baseUrl}/kuenstler + weekly + 0.8 + `; + // Add artist letter-index anchors to sitemap + const artists = extractArtists(videos); + const artistLetters = Array.from(new Set(artists.map(a => a.name.charAt(0).toUpperCase()))).sort(); + for (const letter of artistLetters) { + xml += ` + ${baseUrl}/kuenstler#letter-${escapeXml(letter)} + weekly + 0.6 + +`; + } + for (const video of videos) { const shortId = video.id.replace(/-/g, '').substring(0, 8); const lastmod = video.createdAt ? new Date(video.createdAt).toISOString().split('T')[0] : new Date().toISOString().split('T')[0];