- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
304 lines
9.1 KiB
PHP
304 lines
9.1 KiB
PHP
<?php
|
|
/*******************************************************************************************************************
|
|
| Video Processing Helper Functions
|
|
| Convenience functions for video processing integration
|
|
|*******************************************************************************************************************/
|
|
|
|
defined('_ISVALID') or header('Location: /error');
|
|
|
|
/**
|
|
* Queue video for processing
|
|
* @param string $videoKey Video key
|
|
* @param string $inputFile Input file path
|
|
* @param array $options Processing options
|
|
* @return string|false Job ID or false on failure
|
|
*/
|
|
function queue_video_processing($videoKey, $inputFile, $options = [])
|
|
{
|
|
try {
|
|
$processor = new VVideoProcessor();
|
|
return $processor->queueVideoProcessing($inputFile, $videoKey, $options);
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to queue video processing', [
|
|
'video_key' => $videoKey,
|
|
'input_file' => $inputFile,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process video immediately (synchronous)
|
|
* @param string $videoKey Video key
|
|
* @param string $inputFile Input file path
|
|
* @param array $options Processing options
|
|
* @return array Processing result
|
|
*/
|
|
function process_video_sync($videoKey, $inputFile, $options = [])
|
|
{
|
|
try {
|
|
$processor = new VVideoProcessor();
|
|
return $processor->processVideo($inputFile, $videoKey, $options);
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Synchronous video processing failed', [
|
|
'video_key' => $videoKey,
|
|
'input_file' => $inputFile,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage(),
|
|
'video_key' => $videoKey
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get video processing status
|
|
* @param string $videoKey Video key
|
|
* @return array|false Processing status or false if not found
|
|
*/
|
|
function get_video_processing_status($videoKey)
|
|
{
|
|
try {
|
|
$db = VDatabase::getInstance();
|
|
|
|
$query = "SELECT processing_status, processed_at, processing_error,
|
|
available_formats, hls_available, thumbnails_generated
|
|
FROM db_videofiles WHERE file_key = ?";
|
|
$result = $db->doQuery($query, [$videoKey]);
|
|
$row = $db->doFetch($result);
|
|
|
|
if ($row) {
|
|
return [
|
|
'status' => $row['processing_status'],
|
|
'processed_at' => $row['processed_at'],
|
|
'error' => $row['processing_error'],
|
|
'available_formats' => json_decode($row['available_formats'], true) ?: [],
|
|
'hls_available' => (bool)$row['hls_available'],
|
|
'thumbnails_generated' => (bool)$row['thumbnails_generated']
|
|
];
|
|
}
|
|
|
|
return false;
|
|
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to get video processing status', [
|
|
'video_key' => $videoKey,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Queue thumbnail generation
|
|
* @param string $fileKey File key
|
|
* @param string $filePath File path
|
|
* @param string $fileType File type (video, image)
|
|
* @param array $sizes Thumbnail sizes
|
|
* @return string|false Job ID or false on failure
|
|
*/
|
|
function queue_thumbnail_generation($fileKey, $filePath, $fileType, $sizes = [])
|
|
{
|
|
try {
|
|
$queue = new VQueue();
|
|
|
|
$jobData = [
|
|
'file_key' => $fileKey,
|
|
'file_path' => $filePath,
|
|
'file_type' => $fileType,
|
|
'sizes' => $sizes ?: [
|
|
'small' => [160, 120],
|
|
'medium' => [320, 240],
|
|
'large' => [640, 480]
|
|
]
|
|
];
|
|
|
|
return $queue->enqueue('ThumbnailGenerationJob', $jobData, 'thumbnails');
|
|
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to queue thumbnail generation', [
|
|
'file_key' => $fileKey,
|
|
'file_path' => $filePath,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Queue notification
|
|
* @param string $type Notification type (email, push, in_app, sms, webhook)
|
|
* @param string $recipient Recipient (email, user ID, phone, URL)
|
|
* @param string $subject Subject/title
|
|
* @param string $message Message content
|
|
* @param array $templateData Additional template data
|
|
* @param string $priority Priority (low, normal, high, urgent)
|
|
* @return string|false Job ID or false on failure
|
|
*/
|
|
function queue_notification($type, $recipient, $subject, $message, $templateData = [], $priority = 'normal')
|
|
{
|
|
try {
|
|
$queue = new VQueue();
|
|
|
|
$jobData = [
|
|
'type' => $type,
|
|
'recipient' => $recipient,
|
|
'subject' => $subject,
|
|
'message' => $message,
|
|
'template_data' => $templateData,
|
|
'priority' => $priority
|
|
];
|
|
|
|
$queuePriority = $priority === 'urgent' ? 2 : ($priority === 'high' ? 1 : 0);
|
|
|
|
return $queue->enqueue('NotificationJob', $jobData, 'notifications', 0, $queuePriority);
|
|
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to queue notification', [
|
|
'type' => $type,
|
|
'recipient' => $recipient,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get queue statistics
|
|
* @param string $queue Queue name (optional)
|
|
* @return array Queue statistics
|
|
*/
|
|
function get_queue_stats($queue = null)
|
|
{
|
|
try {
|
|
$queueInstance = new VQueue();
|
|
return $queueInstance->getQueueStats($queue);
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to get queue statistics', [
|
|
'queue' => $queue,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if video processing is available
|
|
* @return bool True if FFmpeg is available
|
|
*/
|
|
function is_video_processing_available()
|
|
{
|
|
static $available = null;
|
|
|
|
if ($available === null) {
|
|
// Check if FFmpeg is available
|
|
$output = shell_exec('ffmpeg -version 2>&1');
|
|
$available = $output && strpos($output, 'ffmpeg version') !== false;
|
|
}
|
|
|
|
return $available;
|
|
}
|
|
|
|
/**
|
|
* Get supported video formats
|
|
* @return array Supported formats
|
|
*/
|
|
function get_supported_video_formats()
|
|
{
|
|
return [
|
|
'mp4' => 'MP4 Video',
|
|
'avi' => 'AVI Video',
|
|
'mov' => 'QuickTime Video',
|
|
'wmv' => 'Windows Media Video',
|
|
'flv' => 'Flash Video',
|
|
'webm' => 'WebM Video',
|
|
'mkv' => 'Matroska Video',
|
|
'3gp' => '3GP Video'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get video processing formats
|
|
* @return array Available processing formats
|
|
*/
|
|
function get_video_processing_formats()
|
|
{
|
|
return [
|
|
'1080p' => ['width' => 1920, 'height' => 1080, 'bitrate' => '5000k'],
|
|
'720p' => ['width' => 1280, 'height' => 720, 'bitrate' => '2500k'],
|
|
'480p' => ['width' => 854, 'height' => 480, 'bitrate' => '1000k'],
|
|
'360p' => ['width' => 640, 'height' => 360, 'bitrate' => '750k'],
|
|
'240p' => ['width' => 426, 'height' => 240, 'bitrate' => '400k']
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Estimate video processing time
|
|
* @param string $inputFile Input file path
|
|
* @param array $formats Formats to process
|
|
* @return int Estimated processing time in seconds
|
|
*/
|
|
function estimate_video_processing_time($inputFile, $formats = ['720p', '480p', '360p'])
|
|
{
|
|
if (!file_exists($inputFile)) {
|
|
return 0;
|
|
}
|
|
|
|
$fileSize = filesize($inputFile);
|
|
$fileSizeMB = $fileSize / (1024 * 1024);
|
|
|
|
// Rough estimation: 1MB takes about 2-5 seconds per format
|
|
$baseTimePerMB = 3; // seconds
|
|
$timePerFormat = $fileSizeMB * $baseTimePerMB;
|
|
|
|
return (int)($timePerFormat * count($formats));
|
|
}
|
|
|
|
/**
|
|
* Clean up old processed files
|
|
* @param int $daysOld Days old threshold
|
|
* @return int Number of files cleaned
|
|
*/
|
|
function cleanup_old_processed_files($daysOld = 30)
|
|
{
|
|
try {
|
|
$processedDir = _FPATH . 'f_data/processed/';
|
|
$cutoffTime = time() - ($daysOld * 24 * 60 * 60);
|
|
$cleanedCount = 0;
|
|
|
|
if (!is_dir($processedDir)) {
|
|
return 0;
|
|
}
|
|
|
|
$iterator = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator($processedDir),
|
|
RecursiveIteratorIterator::CHILD_FIRST
|
|
);
|
|
|
|
foreach ($iterator as $file) {
|
|
if ($file->isFile() && $file->getMTime() < $cutoffTime) {
|
|
if (unlink($file->getPathname())) {
|
|
$cleanedCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
VLogger::getInstance()->info('Cleaned up old processed files', [
|
|
'days_old' => $daysOld,
|
|
'files_cleaned' => $cleanedCount
|
|
]);
|
|
|
|
return $cleanedCount;
|
|
|
|
} catch (Exception $e) {
|
|
VLogger::getInstance()->error('Failed to cleanup old processed files', [
|
|
'days_old' => $daysOld,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return 0;
|
|
}
|
|
} |