diff --git a/client/src/components/adsense-ad.tsx b/client/src/components/adsense-ad.tsx index 6abd647..961ba7e 100644 --- a/client/src/components/adsense-ad.tsx +++ b/client/src/components/adsense-ad.tsx @@ -19,26 +19,13 @@ export default function AdSenseAd({ useEffect(() => { try { - // Only initialize if the ad container has proper dimensions - if (typeof window !== 'undefined' && adRef.current) { - const adContainer = adRef.current; - const rect = adContainer.getBoundingClientRect(); - - // Wait for proper dimensions before initializing - if (rect.width > 0 && rect.height > 0) { - // Small delay to ensure DOM is fully ready - setTimeout(() => { - try { - // @ts-ignore - (window.adsbygoogle = window.adsbygoogle || []).push({}); - } catch (error) { - console.warn('AdSense initialization skipped:', error); - } - }, 100); - } + // Ensure adsbygoogle is loaded + if (typeof window !== 'undefined') { + // @ts-ignore + (window.adsbygoogle = window.adsbygoogle || []).push({}); } } catch (error) { - console.warn('AdSense initialization error:', error); + console.error('AdSense initialization error:', error); } }, []); diff --git a/client/src/components/netflix-grid.tsx b/client/src/components/netflix-grid.tsx index d4c1523..1295e59 100644 --- a/client/src/components/netflix-grid.tsx +++ b/client/src/components/netflix-grid.tsx @@ -49,35 +49,24 @@ export default function NetflixGrid({ videos, isLoading }: NetflixGridProps) { new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); - // FOLX STADL videos - match the actual show format - const folxStadlVideos = videos.filter(video => { - const title = video.title.toLowerCase(); - return title.includes("folx stadl s4") || - title.includes("folx stadl s3") || - title.includes("folx stadl s2") || - title.includes("folx stadl s1") || - title.includes("folx stadl") || - title.includes("folxstadl"); - }); + // FOLX STADL videos + const folxStadlVideos = videos.filter(video => + video.title.includes("FOLX STADL") || video.title.includes("FOLXSTADL") + ); return [ { title: "Meist Angesehen", videos: sortedByViews.slice(0, 10) }, - { + ...(folxStadlVideos.length > 0 ? [{ title: "FOLX STADL", videos: (() => { - // Show FOLX STADL episodes in order (newest first) - const sortedFolxStadl = [...folxStadlVideos].sort((a, b) => { - // Extract episode numbers for proper sorting - const aEp = parseInt(a.title.match(/\d+/)?.[0] || '0'); - const bEp = parseInt(b.title.match(/\d+/)?.[0] || '0'); - return bEp - aEp; // Newest episodes first - }); - return sortedFolxStadl.slice(0, 10); + // Shuffle FOLX STADL videos randomly + const shuffled = [...folxStadlVideos].sort(() => Math.random() - 0.5); + return shuffled.slice(0, 10); })() - }, + }] : []), { title: "VIDEO", videos: (() => { @@ -111,37 +100,44 @@ export default function NetflixGrid({ videos, isLoading }: NetflixGridProps) { { title: "GIPFELSTAMMTISCH", videos: (() => { - // Filter actual Gipfelstammtisch show episodes - const gipfelVideos = videos.filter(video => { - const title = video.title.toLowerCase(); - return title.includes("gipfelstammtisch") && - !title.includes("folx stadl"); // Exclude if it's part of Folx Stadl - }); + // Filter videos that specifically contain "Gipfelstammtisch" in title + const gipfelVideos = videos.filter(video => + video.title.includes("Gipfelstammtisch") + ); - // Shuffle the Gipfelstammtisch videos + // Shuffle the Gipfelstammtisch videos randomly const shuffled = [...gipfelVideos].sort(() => Math.random() - 0.5); - return shuffled.slice(0, 10); - })() - }, - { - title: "DIE GESCHICHTE DES LIEDES", - videos: (() => { - // Filter actual "Die Geschichte des Liedes" episodes - const gdlVideos = videos.filter(video => { - const title = video.title.toLowerCase(); - return title.includes("die geschichte des liedes") && - !title.includes("folx stadl") && - !title.includes("gipfelstammtisch"); - }); - // Shuffle the Geschichte des Liedes videos - const shuffled = [...gdlVideos].sort(() => Math.random() - 0.5); + // Return 10 random videos from the GIPFELSTAMMTISCH collection return shuffled.slice(0, 10); })() }, { - title: "NEUE VIDEOS", - videos: sortedByDate.slice(0, 10) + title: "DIE Geschichte des Liedes", + videos: (() => { + // Filter videos that specifically contain "Geschichte des Liedes" in title or description + const gdlVideos = videos.filter(video => + video.title.toLowerCase().includes("geschichte des liedes") || + video.description?.toLowerCase().includes("geschichte des liedes") + ); + + // If no specific "Geschichte des Liedes" videos found, fallback to general filter + if (gdlVideos.length === 0) { + const fallbackVideos = videos.filter(video => + !video.title.includes("FOLX STADL") && + !video.title.includes("FOLXSTADL") && + !video.title.includes("Gipfelstammtisch") + ); + const shuffled = [...fallbackVideos].sort(() => Math.random() - 0.5); + return shuffled.slice(0, 10); + } + + // Shuffle the Geschichte des Liedes videos randomly + const shuffled = [...gdlVideos].sort(() => Math.random() - 0.5); + + // Return 10 random videos from the collection + return shuffled.slice(0, 10); + })() } ]; }, [videos]); diff --git a/client/src/main.tsx b/client/src/main.tsx index b1ee6d7..d5e5d0f 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -80,8 +80,10 @@ function initApp() { `; - // Remove auto-refresh to prevent loops - console.warn('Auto-refresh disabled to prevent reload loops'); + // Auto-refresh on error + setTimeout(() => { + location.reload(); + }, 3000); } } } diff --git a/server/bunny.ts b/server/bunny.ts index e570be0..7161539 100644 --- a/server/bunny.ts +++ b/server/bunny.ts @@ -103,11 +103,7 @@ export class BunnyService { return { id: bunnyVideo.guid, title: bunnyVideo.title || 'Untitled Video', - artist: null, // Extract from title if needed description: description, - filename: bunnyVideo.title || null, // Use title as filename fallback - episodeNumber: null, // Parse from title if format detected - episodeTitle: null, // Parse from title if format detected thumbnailUrl, customThumbnailUrl: null, videoUrl: hlsUrl, // Signed HLS URL @@ -116,8 +112,6 @@ export class BunnyService { duration: Math.floor(bunnyVideo.length || 0), views: bunnyVideo.views || 0, category: category, - contentType: 'video' as const, - genre: 'other' as const, tags: tags, isPublic: true, uploadStatus: "completed", diff --git a/server/videoSync.ts b/server/videoSync.ts index ba2bb7a..806e1c1 100644 --- a/server/videoSync.ts +++ b/server/videoSync.ts @@ -116,21 +116,20 @@ class VideoSyncService { }; if (existingVideo.rows.length === 0) { - // Insert new video using raw SQL with all required columns including the new ones + // Insert new video using raw SQL to avoid schema issues await db.execute(sql` - INSERT INTO videos (id, title, artist, description, filename, episode_number, episode_title, thumbnail_url, video_url, duration, views, category, custom_thumbnail_url, tags, is_public, content_type, genre, upload_status, created_at, updated_at) - VALUES (${videoData.id}, ${videoData.title}, NULL, ${videoData.description}, ${videoData.title}, NULL, NULL, ${videoData.thumbnailUrl}, ${videoData.videoUrl}, ${videoData.duration}, ${videoData.views}, ${videoData.category}, ${videoData.customThumbnailUrl}, ${'{' + videoData.tags.join(',') + '}'}, ${videoData.isPublic}, 'video', 'other', 'completed', ${videoData.createdAt.toISOString()}, ${videoData.updatedAt.toISOString()}) + INSERT INTO videos (id, title, description, thumbnail_url, video_url, duration, views, category, custom_thumbnail_url, tags, is_public, created_at, updated_at) + VALUES (${videoData.id}, ${videoData.title}, ${videoData.description}, ${videoData.thumbnailUrl}, ${videoData.videoUrl}, ${videoData.duration}, ${videoData.views}, ${videoData.category}, ${videoData.customThumbnailUrl}, ${'{' + videoData.tags.join(',') + '}'}, ${videoData.isPublic}, ${videoData.createdAt.toISOString()}, ${videoData.updatedAt.toISOString()}) `); insertedCount++; } else { - // Update existing video using raw SQL with all fields + // Update existing video using raw SQL await db.execute(sql` UPDATE videos SET title = ${videoData.title}, description = ${videoData.description}, thumbnail_url = ${videoData.thumbnailUrl}, video_url = ${videoData.videoUrl}, duration = ${videoData.duration}, views = ${videoData.views}, category = ${videoData.category}, custom_thumbnail_url = ${videoData.customThumbnailUrl}, - tags = ${'{' + videoData.tags.join(',') + '}'}, is_public = ${videoData.isPublic}, updated_at = ${videoData.updatedAt.toISOString()}, - artist = NULL, filename = ${videoData.title}, episode_number = NULL, episode_title = NULL + tags = ${'{' + videoData.tags.join(',') + '}'}, is_public = ${videoData.isPublic}, updated_at = ${videoData.updatedAt.toISOString()} WHERE id = ${video.id} `); updatedCount++; @@ -167,9 +166,9 @@ class VideoSyncService { try { await this.syncVideos(); - // Add timeout protection for database sync - increased to 2 minutes for large datasets + // Add timeout protection for database sync const syncTimeout = new Promise((_, reject) => - setTimeout(() => reject(new Error('Database sync timeout after 2 minutes')), 120000) + setTimeout(() => reject(new Error('Database sync timeout after 30 seconds')), 30000) ); await Promise.race([