Improve page titles and meta descriptions for better search engine visibility

Updates titles, meta descriptions, and Open Graph tags across various pages and API responses for improved SEO and language consistency.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 401e2ec0-e00d-4f10-9d0e-60f3d479f9a5
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: b39b5688-81f4-4af3-b05c-9c9e8c4350ff
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/60d372ff-2c10-46c7-b01b-10c3435136b0/401e2ec0-e00d-4f10-9d0e-60f3d479f9a5/qFrskyV
This commit is contained in:
sebastjanartic
2026-02-13 17:39:39 +00:00
parent f8ed358592
commit 120fd478e8
9 changed files with 338 additions and 41 deletions
+279 -22
View File
@@ -146,12 +146,63 @@ export async function registerRoutes(app: Express): Promise<Server> {
.replace(/format=webp/gi, 'format=jpg');
}
// Extract artist name from title (format: "Artist – Song" or "Artist - Song")
const titleStr = video.title || '';
let artistName = '';
let songName = titleStr;
if (titleStr.includes('–')) {
const parts = titleStr.split('–');
artistName = parts[0].trim();
songName = parts.slice(1).join('–').trim();
} else if (titleStr.includes(' - ')) {
const parts = titleStr.split(' - ');
artistName = parts[0].trim();
songName = parts.slice(1).join(' - ').trim();
}
// Clean description for meta tags
const description = video.description
? video.description.substring(0, 200).replace(/[<>"']/g, '')
: `Schauen Sie ${video.title} auf video.folx.tv - Die beste Musik`;
: artistName
? `${artistName} – ${songName}. Jetzt ansehen auf Folx TV - Nummer 1 in Europa für Volksmusik und Schlager.`
: `${titleStr} auf Folx TV ansehen - Nummer 1 in Europa für Volksmusik und Schlager.`;
const title = video.title || 'video.folx.tv';
const title = video.title || 'Folx TV - Video';
const keywords = artistName
? `${artistName}, ${songName}, Volksmusik, Schlager, Folx TV, Musikvideo`
: `${titleStr}, Volksmusik, Schlager, Folx TV`;
// JSON-LD structured data for video with artist
const jsonLd: any = {
"@context": "https://schema.org",
"@type": "VideoObject",
"name": title,
"description": description,
"thumbnailUrl": thumbnailUrl,
"uploadDate": video.createdAt ? new Date(video.createdAt).toISOString() : new Date().toISOString(),
"duration": video.duration ? `PT${Math.floor(video.duration / 60)}M${video.duration % 60}S` : undefined,
"contentUrl": videoUrl,
"embedUrl": videoUrl,
"interactionStatistic": {
"@type": "InteractionCounter",
"interactionType": "https://schema.org/WatchAction",
"userInteractionCount": video.views || 0
},
"publisher": {
"@type": "Organization",
"name": "FOLX.TV",
"url": "https://folx.tv"
},
"inLanguage": "de"
};
if (artistName) {
jsonLd["byArtist"] = {
"@type": "MusicGroup",
"name": artistName
};
jsonLd["@type"] = "MusicVideoObject";
}
// Return HTML page with OG tags for crawlers
const html = `<!DOCTYPE html>
@@ -159,9 +210,10 @@ export async function registerRoutes(app: Express): Promise<Server> {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title} - video.folx.tv</title>
<title>${title} | Folx TV - Video</title>
<meta name="description" content="${description}">
<meta name="keywords" content="${keywords}">
<!-- Open Graph meta tags for Facebook/Social Media -->
<meta property="og:type" content="video.other">
<meta property="og:title" content="${title}">
<meta property="og:description" content="${description}">
@@ -171,21 +223,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
<meta property="og:image:height" content="630">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:url" content="${videoUrl}">
<meta property="og:site_name" content="video.folx.tv">
<meta property="og:site_name" content="Folx TV - Video">
<meta property="og:locale" content="de_DE">
<!-- Twitter Card meta tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${title}">
<meta name="twitter:description" content="${description}">
<meta name="twitter:image" content="${thumbnailUrl}">
<link rel="canonical" href="${videoUrl}">
<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>
</head>
<body>
<h1>${title}</h1>
${artistName ? `<h2>Interpret: ${artistName}</h2>` : ''}
<p>${description}</p>
<p><a href="${videoUrl}">Watch on video.folx.tv</a></p>
<p><a href="${videoUrl}">Jetzt ansehen auf Folx TV</a></p>
</body>
</html>`;
@@ -291,8 +344,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
const baseUrl = 'https://video.folx.tv';
const pageUrl = `${baseUrl}/player`;
const title = 'Professional Player - video.folx.tv';
const description = 'Professioneller Video Player mit MTV-Style Overlay Graphics und Streaming-Funktionen auf video.folx.tv';
const title = 'Professional Player - Folx TV - Video';
const description = 'Professioneller Video Player mit Overlay Graphics und Streaming-Funktionen. Folx TV - Nummer 1 in Europa für Volksmusik und Schlager.';
const imageUrl = `${baseUrl}/images/logo.svg`;
const html = `<!DOCTYPE html>
@@ -348,8 +401,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
const baseUrl = 'https://video.folx.tv';
const pageUrl = `${baseUrl}/live`;
const title = 'LIVE Stream - video.folx.tv';
const description = 'Live Stream auf video.folx.tv - Schauen Sie exklusive Inhalte in Echtzeit. FOLX TV Live Streaming rund um die Uhr.';
const title = 'LIVE Stream - Folx TV - Video';
const description = 'Live Stream auf video.folx.tv - Schauen Sie exklusive Inhalte in Echtzeit. Folx TV - Nummer 1 in Europa für Volksmusik und Schlager.';
const imageUrl = `${baseUrl}/images/logo.svg`;
const html = `<!DOCTYPE html>
@@ -386,6 +439,201 @@ export async function registerRoutes(app: Express): Promise<Server> {
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() || '';
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}/folx-stadl`;
const title = 'FOLX STADL - Die große Volksmusik Show | Folx TV - Video';
const description = 'FOLX STADL - Die beliebte Volksmusik- und Schlagershow auf Folx TV. Mit Stars wie Angela Wiedl, Oswald Sattler, Die Grubertaler, Kastelruther Spatzen und vielen mehr. Jetzt alle Folgen ansehen!';
const keywords = 'FOLX STADL, Volksmusik Show, Schlager, Angela Wiedl, Oswald Sattler, Die Grubertaler, Kastelruther Spatzen, Volksmusik TV, Folx TV';
const allVideos = await storage.getVideos(600, 0);
const stadlVideos = allVideos.filter(v => v.title.includes('FOLX STADL') || v.title.includes('FOLXSTADL'));
const html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<meta name="description" content="${description}">
<meta name="keywords" content="${keywords}">
<meta property="og:type" content="video.tv_show">
<meta property="og:title" content="${title}">
<meta property="og:description" content="${description}">
<meta property="og:url" content="${pageUrl}">
<meta property="og:site_name" content="video.folx.tv">
<meta property="og:locale" content="de_DE">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${title}">
<meta name="twitter:description" content="${description}">
<link rel="canonical" href="${pageUrl}">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TVSeries",
"name": "FOLX STADL",
"description": "${description}",
"url": "${pageUrl}",
"numberOfEpisodes": ${stadlVideos.length},
"genre": ["Volksmusik", "Schlager", "Unterhaltung"],
"inLanguage": "de",
"productionCompany": {"@type": "Organization", "name": "FOLX.TV"},
"publisher": {"@type": "Organization", "name": "FOLX.TV", "url": "https://folx.tv"}
}
</script>
</head>
<body>
<h1>${title}</h1>
<p>${description}</p>
<h2>Alle FOLX STADL Folgen (${stadlVideos.length} Videos)</h2>
<ul>${stadlVideos.map(v => `<li><a href="${baseUrl}/video/${v.id.replace(/-/g, '').substring(0, 8)}">${v.title}</a></li>`).join('')}</ul>
</body>
</html>`;
res.set('Content-Type', 'text/html');
res.send(html);
});
// Server-side meta tags for /geschichte-lied page (crawlers + SEO)
app.get('/geschichte-lied', 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}/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 allVideos = await storage.getVideos(600, 0);
const geschichteVideos = allVideos.filter(v => v.title.includes('Geschichte des Liedes'));
const html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<meta name="description" content="${description}">
<meta name="keywords" content="${keywords}">
<meta property="og:type" content="video.tv_show">
<meta property="og:title" content="${title}">
<meta property="og:description" content="${description}">
<meta property="og:url" content="${pageUrl}">
<meta property="og:site_name" content="video.folx.tv">
<meta property="og:locale" content="de_DE">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${title}">
<meta name="twitter:description" content="${description}">
<link rel="canonical" href="${pageUrl}">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TVSeries",
"name": "Die Geschichte des Liedes",
"description": "${description}",
"url": "${pageUrl}",
"numberOfEpisodes": ${geschichteVideos.length},
"genre": ["Musikdokumentation", "Volksmusik", "Schlager"],
"inLanguage": "de",
"productionCompany": {"@type": "Organization", "name": "FOLX.TV"},
"publisher": {"@type": "Organization", "name": "FOLX.TV", "url": "https://folx.tv"}
}
</script>
</head>
<body>
<h1>${title}</h1>
<p>${description}</p>
<h2>Alle Folgen (${geschichteVideos.length} Videos)</h2>
<ul>${geschichteVideos.map(v => `<li><a href="${baseUrl}/video/${v.id.replace(/-/g, '').substring(0, 8)}">${v.title}</a></li>`).join('')}</ul>
</body>
</html>`;
res.set('Content-Type', 'text/html');
res.send(html);
});
// Server-side meta tags for /gipfelstammtisch page (crawlers + SEO)
app.get('/gipfelstammtisch', 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}/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 allVideos = await storage.getVideos(600, 0);
const gipfelVideos = allVideos.filter(v => v.title.toLowerCase().includes('gipfelstammtisch'));
const html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<meta name="description" content="${description}">
<meta name="keywords" content="${keywords}">
<meta property="og:type" content="video.tv_show">
<meta property="og:title" content="${title}">
<meta property="og:description" content="${description}">
<meta property="og:url" content="${pageUrl}">
<meta property="og:site_name" content="video.folx.tv">
<meta property="og:locale" content="de_DE">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${title}">
<meta name="twitter:description" content="${description}">
<link rel="canonical" href="${pageUrl}">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TVSeries",
"name": "Gipfelstammtisch",
"description": "${description}",
"url": "${pageUrl}",
"numberOfEpisodes": ${gipfelVideos.length},
"genre": ["Talkshow", "Volksmusik", "Unterhaltung"],
"inLanguage": "de",
"productionCompany": {"@type": "Organization", "name": "FOLX.TV"},
"publisher": {"@type": "Organization", "name": "FOLX.TV", "url": "https://folx.tv"}
}
</script>
</head>
<body>
<h1>${title}</h1>
<p>${description}</p>
<h2>Alle Folgen (${gipfelVideos.length} Videos)</h2>
<ul>${gipfelVideos.map(v => `<li><a href="${baseUrl}/video/${v.id.replace(/-/g, '').substring(0, 8)}">${v.title}</a></li>`).join('')}</ul>
</body>
</html>`;
res.set('Content-Type', 'text/html');
res.send(html);
});
// Sitemap.xml for SEO
app.get("/sitemap.xml", async (req, res) => {
try {
@@ -411,16 +659,6 @@ export async function registerRoutes(app: Express): Promise<Server> {
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>${baseUrl}/live</loc>
<changefreq>always</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>${baseUrl}/player</loc>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>${baseUrl}/folx-stadl</loc>
<changefreq>weekly</changefreq>
@@ -442,9 +680,26 @@ export async function registerRoutes(app: Express): Promise<Server> {
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];
const safeTitle = escapeXml(video.title);
const safeDescription = escapeXml(video.description || video.title);
const safeThumbnail = escapeXml(video.thumbnailUrl || '');
// Extract artist for richer description
const titleStr = video.title || '';
let artist = '';
let song = titleStr;
if (titleStr.includes('–')) {
artist = titleStr.split('–')[0].trim();
song = titleStr.split('–').slice(1).join('–').trim();
} else if (titleStr.includes(' - ')) {
artist = titleStr.split(' - ')[0].trim();
song = titleStr.split(' - ').slice(1).join(' - ').trim();
}
const safeDescription = escapeXml(
video.description ||
(artist ? `${artist} – ${song}. Volksmusik und Schlager auf Folx TV - Nummer 1 in Europa.` : `${titleStr} auf Folx TV ansehen.`)
);
const safeTags = artist ? `<video:tag>${escapeXml(artist)}</video:tag><video:tag>Volksmusik</video:tag><video:tag>Schlager</video:tag><video:tag>Folx TV</video:tag>` : '<video:tag>Volksmusik</video:tag><video:tag>Schlager</video:tag><video:tag>Folx TV</video:tag>';
xml += ` <url>
<loc>${baseUrl}/video/${shortId}</loc>
<lastmod>${lastmod}</lastmod>
@@ -455,6 +710,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
<video:title>${safeTitle}</video:title>
<video:description>${safeDescription}</video:description>
<video:duration>${video.duration || 0}</video:duration>
<video:family_friendly>yes</video:family_friendly>
${safeTags}
</video:video>
</url>
`;