loreal-video-optimizer/backend/platform_specs.py
DJP 129ea3ec1e Initial commit: Video Optimizer for L'Oréal
Complete video optimization tool with:
- 21 platform configurations (Meta, TikTok, YouTube, Pinterest, Snapchat, Amazon)
- FFmpeg-powered video conversion with H264, H265, and VP9 codecs
- Python Flask backend with REST API
- HTML/JS frontend with drag-drop interface
- Black + #FFC407 color scheme with Montserrat font
- Side-by-side video comparison player
- Filename auto-detection for platform and aspect ratio
- MAMP-compatible setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 16:52:11 -04:00

306 lines
8.5 KiB
Python

"""
Platform specifications for video optimization
Based on L'Oreal CDMO Creative Optimization Documentation v1.1
"""
PLATFORM_SPECS = {
"meta": {
"name": "Meta (Facebook/Instagram)",
"codec": "libx264",
"container": "mp4",
"formats": [
{
"ratio": "1:1",
"size": "720x720",
"bitrate": "1000k",
"bitrate_min": "840k",
"bitrate_max": "1200k",
"audio": "128k"
},
{
"ratio": "16:9",
"size": "1280x720",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
},
{
"ratio": "4:5",
"size": "720x900",
"bitrate": "1000k",
"bitrate_min": "840k",
"bitrate_max": "1200k",
"audio": "128k"
},
{
"ratio": "9:16",
"size": "720x1280",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
}
]
},
"pinterest": {
"name": "Pinterest",
"codec": "libx264",
"container": "mp4",
"formats": [
{
"ratio": "1:1",
"size": "720x720",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
},
{
"ratio": "16:9",
"size": "1280x720",
"bitrate": "1495k",
"bitrate_min": "1300k",
"bitrate_max": "1690k",
"audio": "128k"
},
{
"ratio": "2:3",
"size": "1000x1500",
"bitrate": "1495k",
"bitrate_min": "1300k",
"bitrate_max": "1690k",
"audio": "128k",
"note": "Not tested - Reduce bitrate if possible + smaller size"
},
{
"ratio": "4:5",
"size": "720x900",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
},
{
"ratio": "9:16",
"size": "720x1280",
"bitrate": "1495k",
"bitrate_min": "1300k",
"bitrate_max": "1690k",
"audio": "128k"
}
]
},
"snapchat": {
"name": "Snapchat",
"codec": "libx264",
"container": "mp4",
"formats": [
{
"ratio": "16:9",
"size": "1280x720",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
},
{
"ratio": "9:16",
"size": "720x1280",
"bitrate": "1250k",
"bitrate_min": "1100k",
"bitrate_max": "1400k",
"audio": "128k"
}
]
},
"tiktok": {
"name": "TikTok",
"codec": "libx265",
"container": "mp4",
"formats": [
{
"ratio": "1:1",
"size": "640x640",
"bitrate": "1000k",
"bitrate_min": "840k",
"bitrate_max": "1200k",
"audio": "128k"
},
{
"ratio": "16:9",
"size": "960x540",
"bitrate": "1050k",
"bitrate_min": "840k",
"bitrate_max": "1300k",
"audio": "128k"
},
{
"ratio": "9:16",
"size": "540x960",
"bitrate": "1050k",
"bitrate_min": "840k",
"bitrate_max": "1300k",
"audio": "128k"
}
]
},
"youtube": {
"name": "YouTube & DV360 - All Devices",
"codec": "libvpx-vp9",
"container": "webm",
"formats": [
{
"ratio": "1:1",
"size": "720x720",
"bitrate": "1495k",
"bitrate_min": "1300k",
"bitrate_max": "1690k",
"audio": "128k",
"audio_codec": "libopus"
},
{
"ratio": "16:9",
"size": "1280x720",
"bitrate": "1650k",
"bitrate_min": "1300k",
"bitrate_max": "2000k",
"audio": "128k",
"audio_codec": "libopus"
},
{
"ratio": "4:5",
"size": "720x900",
"bitrate": "1495k",
"bitrate_min": "1300k",
"bitrate_max": "1690k",
"audio": "128k",
"audio_codec": "libopus"
},
{
"ratio": "9:16",
"size": "720x1280",
"bitrate": "1650k",
"bitrate_min": "1300k",
"bitrate_max": "2000k",
"audio": "128k",
"audio_codec": "libopus"
}
]
},
"youtube_ctv": {
"name": "YouTube - CTV Specific",
"codec": "libvpx-vp9",
"container": "webm",
"formats": [
{
"ratio": "16:9",
"size": "1920x1080",
"bitrate": "5150k",
"bitrate_min": "3300k",
"bitrate_max": "7000k",
"audio": "192k",
"audio_codec": "libopus"
}
]
},
"amazon_prime": {
"name": "Amazon Prime - CTV Specific",
"codec": "libx264",
"container": "mp4",
"formats": [
{
"ratio": "16:9",
"size": "1920x1080",
"bitrate": "15000k",
"bitrate_min": "15000k",
"bitrate_max": "15000k",
"audio": "192k",
"note": "Minimum Video Bitrate accepted by Prime is 15Mbit/s"
}
]
},
"amazon_freevee": {
"name": "Amazon Freevee - CTV Specific",
"codec": "libx264",
"container": "mp4",
"formats": [
{
"ratio": "16:9",
"size": "1920x1080",
"bitrate": "5750k",
"bitrate_min": "4500k",
"bitrate_max": "7000k",
"audio": "192k"
}
]
}
}
# Filename pattern detection
FILENAME_PATTERNS = {
'meta': ['_meta_', '_fb_', '_ig_', '_facebook_', '_instagram_'],
'pinterest': ['_pinterest_', '_pin_'],
'snapchat': ['_snapchat_', '_snap_'],
'tiktok': ['_tiktok_', '_tt_'],
'youtube': ['_youtube_', '_yt_'],
'youtube_ctv': ['_youtube_ctv_', '_yt_ctv_', '_ctv_'],
'amazon_prime': ['_prime_', '_amazon_prime_'],
'amazon_freevee': ['_freevee_', '_amazon_freevee_']
}
# Aspect ratio patterns
ASPECT_RATIO_PATTERNS = {
'1:1': ['_1x1_', '_square_', '_1-1_'],
'16:9': ['_16x9_', '_landscape_', '_16-9_'],
'4:5': ['_4x5_', '_4-5_'],
'9:16': ['_9x16_', '_vertical_', '_9-16_', '_portrait_'],
'2:3': ['_2x3_', '_2-3_']
}
def detect_platform_from_filename(filename):
"""
Detect platform from filename patterns
Returns platform key or None
"""
filename_lower = filename.lower()
for platform, patterns in FILENAME_PATTERNS.items():
for pattern in patterns:
if pattern in filename_lower:
return platform
return None
def detect_aspect_ratio_from_filename(filename):
"""
Detect aspect ratio from filename patterns
Returns aspect ratio string or None
"""
filename_lower = filename.lower()
for ratio, patterns in ASPECT_RATIO_PATTERNS.items():
for pattern in patterns:
if pattern in filename_lower:
return ratio
return None
def get_all_platforms():
"""Return list of all platform keys"""
return list(PLATFORM_SPECS.keys())
def get_platform_formats(platform):
"""Get all available formats for a platform"""
if platform in PLATFORM_SPECS:
return PLATFORM_SPECS[platform]['formats']
return []
def get_platform_info(platform):
"""Get complete platform information"""
return PLATFORM_SPECS.get(platform, None)