diff --git a/attached_assets/image_1763470344354.png b/attached_assets/image_1763470344354.png new file mode 100644 index 0000000..d7d5cd4 Binary files /dev/null and b/attached_assets/image_1763470344354.png differ diff --git a/replit.md b/replit.md index 412402c..2e0fa94 100644 --- a/replit.md +++ b/replit.md @@ -6,6 +6,11 @@ Social Flow is an AI-powered social media automation platform designed to stream ## User Preferences Preferred communication style: Simple, everyday language. +## Recent Changes + +### November 18, 2025 +- **Facebook Video Codec Compatibility Fix**: Fixed issue where MP4 videos uploaded to Facebook would not play correctly due to codec incompatibility. Facebook requires strict video format: H.264 video codec, AAC audio codec, and MP4 container. Solution: Added automatic video transcoding via Cloudinary transformations. When publishing a video to Facebook, the system now transforms the Cloudinary URL to include `vc_h264,ac_aac,f_mp4,q_auto` parameters, ensuring all videos are automatically re-encoded to Facebook-compatible format before publication. The getFacebookCompatibleVideoUrl() method detects Cloudinary video URLs and applies the necessary transformations transparently. Non-Cloudinary URLs are passed through unchanged with a warning. This ensures reliable video playback on Facebook without requiring users to manually re-encode their videos. Files modified: `server/services/facebook.ts`. + ## System Architecture ### Frontend Architecture diff --git a/server/services/facebook.ts b/server/services/facebook.ts index 7363932..5a59815 100644 --- a/server/services/facebook.ts +++ b/server/services/facebook.ts @@ -127,9 +127,43 @@ export class FacebookService { return data.post_id || data.id; } + /** + * Generates a Facebook-compatible video URL with Cloudinary transformations + * Facebook requires: H.264 video codec, AAC audio codec, MP4 container + */ + private getFacebookCompatibleVideoUrl(originalUrl: string): string { + // Check if this is a Cloudinary URL + const cloudinaryPattern = /https:\/\/res\.cloudinary\.com\/([^\/]+)\/video\/upload\//; + const match = originalUrl.match(cloudinaryPattern); + + if (!match) { + // Not a Cloudinary URL, return as-is (may fail on Facebook) + console.warn('Video URL is not from Cloudinary, cannot apply transformations:', originalUrl); + return originalUrl; + } + + const [fullMatch, cloudName] = match; + const videoPath = originalUrl.replace(fullMatch, ''); + + // Apply transformations for Facebook compatibility: + // - vc_h264: Video codec H.264 + // - ac_aac: Audio codec AAC + // - f_mp4: Force MP4 format + // - q_auto: Automatic quality optimization + const transformations = 'vc_h264,ac_aac,f_mp4,q_auto'; + + const transformedUrl = `https://res.cloudinary.com/${cloudName}/video/upload/${transformations}/${videoPath}`; + + console.log('🎬 Transforming video for Facebook compatibility:'); + console.log(' Original:', originalUrl); + console.log(' Transformed:', transformedUrl); + + return transformedUrl; + } + private async publishVideoPost(post: Post, page: SocialPage, media: Media): Promise { - // Use original URL for video - const videoUrl = media.originalUrl; + // Transform video URL to ensure Facebook compatibility (H.264/AAC/MP4) + const videoUrl = this.getFacebookCompatibleVideoUrl(media.originalUrl); const params = new URLSearchParams({ access_token: page.accessToken!,