cinema-studio-pro/stream_video.php
Simeon.Schecter c8326e6ddd Rebrand to Lux Studio + Video Gen + Project Management
Major Features:
- Rebrand from Cinema Studio Pro to Lux Studio
- New logo and branding (orange/gold theme)
- Video generation with Veo 3.1 (I2V and T2V)
- Project-first workflow with IndexedDB storage
- AI prompt optimizer with intelligent inference

Video Gen:
- Duration (4s/6s/8s), aspect ratio (16:9/9:16), resolution
- Reference image support for I2V
- Aspect ratio mismatch warnings
- Frame extraction from generated videos
- Video streaming with HTTP Range support

UI/UX:
- Tab navigation with underline style
- Portrait format adaptive display
- Editable optimized prompts with [AI suggestions]
- Auto-save to active project

Security:
- Remove config.php from tracking (contains API key)
- Add comprehensive .gitignore
- Remove uploaded session files from repo

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 21:02:28 -05:00

98 lines
2.5 KiB
PHP

<?php
/**
* Video Streaming with Range Request Support
* Enables proper video seeking in browsers
*/
$videoDir = __DIR__ . '/generated_videos';
// Get the requested video file
$file = isset($_GET['file']) ? basename($_GET['file']) : null;
if (!$file) {
http_response_code(400);
die('No file specified');
}
$filePath = $videoDir . '/' . $file;
// Security: ensure file is within video directory
$realPath = realpath($filePath);
$realVideoDir = realpath($videoDir);
if ($realPath === false || strpos($realPath, $realVideoDir) !== 0) {
http_response_code(404);
die('File not found');
}
if (!file_exists($filePath)) {
http_response_code(404);
die('File not found');
}
$fileSize = filesize($filePath);
$mimeType = 'video/mp4';
// Check for Range header
$range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : null;
if ($range) {
// Parse Range header
list($unit, $rangeSpec) = explode('=', $range, 2);
if ($unit !== 'bytes') {
http_response_code(416);
header("Content-Range: bytes */$fileSize");
die('Invalid range unit');
}
// Parse the range values
$ranges = explode(',', $rangeSpec);
$rangeSpec = trim($ranges[0]); // Only handle first range
list($start, $end) = explode('-', $rangeSpec);
$start = $start === '' ? 0 : intval($start);
$end = $end === '' ? $fileSize - 1 : intval($end);
// Validate range
if ($start < 0 || $start >= $fileSize || $end >= $fileSize || $start > $end) {
http_response_code(416);
header("Content-Range: bytes */$fileSize");
die('Invalid range');
}
$length = $end - $start + 1;
// Send partial content headers
http_response_code(206);
header('Content-Type: ' . $mimeType);
header('Accept-Ranges: bytes');
header("Content-Range: bytes $start-$end/$fileSize");
header("Content-Length: $length");
header('Cache-Control: public, max-age=86400');
// Output the requested range
$fp = fopen($filePath, 'rb');
fseek($fp, $start);
$bytesRemaining = $length;
$bufferSize = 8192;
while ($bytesRemaining > 0 && !feof($fp)) {
$readSize = min($bufferSize, $bytesRemaining);
echo fread($fp, $readSize);
$bytesRemaining -= $readSize;
flush();
}
fclose($fp);
} else {
// No range requested - send full file
header('Content-Type: ' . $mimeType);
header('Accept-Ranges: bytes');
header("Content-Length: $fileSize");
header('Cache-Control: public, max-age=86400');
readfile($filePath);
}