diff --git a/client/src/pages/VideoPage.tsx b/client/src/pages/VideoPage.tsx
index ce3ccc8..be986b0 100644
--- a/client/src/pages/VideoPage.tsx
+++ b/client/src/pages/VideoPage.tsx
@@ -308,23 +308,24 @@ export default function VideoPage() {
};
+ // Share URL uses special endpoint with proper OG meta tags for social media previews
+ // This URL shows thumbnail, title, and description when shared on Facebook, Viber, WhatsApp, etc.
const getShareUrl = () => {
- if (!currentVideo?.id) return window.location.origin;
- // Use custom domain if set, otherwise current domain
- const baseUrl = import.meta.env.VITE_SHARE_DOMAIN || window.location.origin;
- return `${baseUrl}/video/${currentVideo.id}`;
- };
-
- // Facebook share URL uses special endpoint with proper OG meta tags
- const getFacebookShareUrl = () => {
if (!currentVideo?.id) return window.location.origin;
const baseUrl = 'https://video.folx.tv';
return `${baseUrl}/share/video/${currentVideo.id}`;
};
+ // Direct video URL (for display purposes)
+ const getVideoUrl = () => {
+ if (!currentVideo?.id) return window.location.origin;
+ const baseUrl = 'https://video.folx.tv';
+ return `${baseUrl}/video/${currentVideo.id}`;
+ };
+
const copyToClipboard = async () => {
try {
- await navigator.clipboard.writeText(getFacebookShareUrl());
+ await navigator.clipboard.writeText(getShareUrl());
const notification = document.createElement('div');
notification.textContent = 'Link kopiert!';
notification.className = 'fixed top-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg z-50 transition-opacity duration-300';
@@ -739,19 +740,19 @@ export default function VideoPage() {
{showShareMenu && (
-
+
Facebook
-
+
Twitter
-
+
WhatsApp
diff --git a/server/routes.ts b/server/routes.ts
index 1c69c94..26a31a2 100644
--- a/server/routes.ts
+++ b/server/routes.ts
@@ -83,6 +83,115 @@ export async function registerRoutes(app: Express): Promise
{
// Setup Replit Auth first
await setupAuth(app);
+ // Social media crawler detection middleware for /video/:id routes
+ // This serves proper OG meta tags to crawlers while letting regular users get the SPA
+ app.get('/video/:id', async (req, res, next) => {
+ const userAgent = req.headers['user-agent']?.toLowerCase() || '';
+
+ // List of social media crawler user agents
+ 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) {
+ // Not a crawler, let the SPA handle it
+ return next();
+ }
+
+ try {
+ const { id } = req.params;
+
+ // Find video from cache
+ const allVideos = await storage.getVideos(600, 0);
+ let video;
+
+ if (id.length === 36 && id.includes('-')) {
+ video = allVideos.find(v => v.id === id);
+ } else if (id.length === 8) {
+ video = allVideos.find(v => v.id.replace(/-/g, '').substring(0, 8) === id);
+ } else {
+ video = allVideos.find(v => v.id.includes(id));
+ }
+
+ if (!video) {
+ return next(); // Let SPA handle 404
+ }
+
+ const baseUrl = 'https://video.folx.tv';
+ const videoUrl = `${baseUrl}/video/${video.id}`;
+
+ // Get high-quality thumbnail for sharing (1200x630 is ideal for Facebook)
+ const thumbnailUrl = video.thumbnailUrl
+ ? video.thumbnailUrl.replace('width=400&height=225', 'width=1200&height=630').replace('format=webp', 'format=jpg')
+ : `${baseUrl}/api/social-image`;
+
+ // 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`;
+
+ const title = video.title || 'video.folx.tv';
+
+ // Return HTML page with OG tags for crawlers
+ const html = `
+
+
+
+
+ ${title} - video.folx.tv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${title}
+ ${description}
+ Watch on video.folx.tv
+
+`;
+
+ res.set('Content-Type', 'text/html');
+ res.send(html);
+ } catch (error) {
+ console.error('Error generating OG tags for crawler:', error);
+ next(); // Let SPA handle errors
+ }
+ });
+
// Add compression middleware for better performance
app.use(compression({
level: 6,