diff --git a/objects/Object.php b/objects/Object.php index 180d09f678..ddf7734b83 100644 --- a/objects/Object.php +++ b/objects/Object.php @@ -107,13 +107,7 @@ abstract class ObjectYPT implements ObjectInterface $res = sqlDAL::readSql($sql); $fullData = sqlDAL::fetchAllAssoc($res); sqlDAL::close($res); - $rows = []; - if ($res !== false) { - foreach ($fullData as $row) { - $rows[] = $row; - } - } - return $rows; + return $fullData; } public static function getAllActive() @@ -128,13 +122,7 @@ abstract class ObjectYPT implements ObjectInterface $res = sqlDAL::readSql($sql); $fullData = sqlDAL::fetchAllAssoc($res); sqlDAL::close($res); - $rows = []; - if ($res !== false) { - foreach ($fullData as $row) { - $rows[] = $row; - } - } - return $rows; + return $fullData; } public static function getTotal() @@ -299,6 +287,7 @@ abstract class ObjectYPT implements ObjectInterface _error_log("Save error, table " . static::getTableName() . " MySQL Error", AVideoLog::$ERROR); return false; } + //_error_log("Save ".static::getTableName().' '.json_encode($fieldsName)); $formats = ''; $values = []; if (!empty($this->id)) { @@ -475,6 +464,7 @@ abstract class ObjectYPT implements ObjectInterface 'ai_responses', 'ai_metatags_responses', 'ai_transcribe_responses', + 'ai_responses_json', 'playlists_schedules' ]; return in_array(static::getTableName(), $ignoreArray); diff --git a/objects/functionExec.php b/objects/functionExec.php new file mode 100644 index 0000000000..70c01c5564 --- /dev/null +++ b/objects/functionExec.php @@ -0,0 +1,390 @@ +&1', $output, $return_val); + if ($return_val !== 0) { + error_log('{"status":"error", "msg":' . json_encode($output) . ' ,"return_val":' . json_encode($return_val) . ', "where":"getDuration", "cmd":"' . $cmd . '"}'); + // fix ffprobe + $duration = "EE:EE:EE"; + } else { + preg_match("/([0-9]+:[0-9]+:[0-9]{2})/", $output[0], $match); + if (!empty($match[1])) { + $duration = $match[1]; + } else { + error_log('{"status":"error", "msg":' . json_encode($output) . ' ,"match_not_found":' . json_encode($match) . ' ,"return_val":' . json_encode($return_val) . ', "where":"getDuration", "cmd":"' . $cmd . '"}'); + $duration = "EE:EE:EE"; + } + } + error_log("Duration found: {$duration}"); + if ($duration !== 'EE:EE:EE') { + $getDurationFromFile[$file] = $duration; + } + return $duration; +} + +function wget($url, $filename, $debug = false) +{ + if (empty($url) || $url == "php://input" || !isValidURL($url)) { + return false; + } + if ($lockfilename = wgetIsLocked($url)) { + if ($debug) { + _error_log("wget: ERROR the url is already downloading {$lockfilename} $url, $filename"); + } + return false; + } + wgetLock($url); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $content = @file_get_contents($url); + if (!empty($content) && file_put_contents($filename, $content) > 100) { + wgetRemoveLock($url); + return true; + } + wgetRemoveLock($url); + return false; + } + + $filename = escapeshellarg($filename); + $url = escapeshellarg($url); + $cmd = "wget --tries=1 {$url} -O {$filename} --no-check-certificate"; + if ($debug) { + _error_log("wget Start ({$cmd}) "); + } + //echo $cmd; + exec($cmd); + wgetRemoveLock($url); + if (!file_exists($filename)) { + _error_log("wget: ERROR the url does not download $url, $filename"); + return false; + } + if ($_SERVER['SCRIPT_NAME'] !== '/plugin/Live/m3u8.php' && empty(filesize($filename))) { + _error_log("wget: ERROR the url download but is empty $url, $filename"); + return true; + } + return false; +} + +function getDirSize($dir, $forceNew = false) +{ + global $_getDirSize; + + if (!isset($_getDirSize)) { + $_getDirSize = []; + } + if (empty($forceNew) && isset($_getDirSize[$dir])) { + return $_getDirSize[$dir]; + } + + _error_log("getDirSize: start {$dir}"); + + if (isWindows()) { + $return = foldersize($dir); + $_getDirSize[$dir] = $return; + return $return; + } else { + $command = "du -sb {$dir}"; + exec($command . " < /dev/null 2>&1", $output, $return_val); + if ($return_val !== 0) { + _error_log("getDirSize: ERROR ON Command {$command}"); + $return = 0; + $_getDirSize[$dir] = $return; + return $return; + } else { + if (!empty($output[0])) { + preg_match("/^([0-9]+).*/", $output[0], $matches); + } + if (!empty($matches[1])) { + _error_log("getDirSize: found {$matches[1]} from - {$output[0]}"); + $return = intval($matches[1]); + $_getDirSize[$dir] = $return; + return $return; + } + + _error_log("getDirSize: ERROR on pregmatch {$output[0]}"); + $return = 0; + $_getDirSize[$dir] = $return; + return $return; + } + } +} + +function convertVideoFileWithFFMPEG($fromFileLocation, $toFileLocation, $logFile = '', $try = 0) +{ + $parts = explode('?', $fromFileLocation); + $localFileLock = getCacheDir() . 'convertVideoFileWithFFMPEG_' . md5($parts[0]) . ".lock"; + $ageInSeconds = time() - @filemtime($localFileLock); + if ($ageInSeconds > 60) { + _error_log("convertVideoFileWithFFMPEG: age: {$ageInSeconds} too long without change, unlock it " . $fromFileLocation); + @unlink($localFileLock); + } elseif (file_exists($localFileLock)) { + _error_log("convertVideoFileWithFFMPEG: age: {$ageInSeconds} download from CDN There is a process running for " . $fromFileLocation); + return false; + } else { + _error_log("convertVideoFileWithFFMPEG: creating file: localFileLock: {$localFileLock} toFileLocation: {$toFileLocation}"); + } + make_path($toFileLocation); + file_put_contents($localFileLock, time()); + $fromFileLocationEscaped = escapeshellarg($fromFileLocation); + $toFileLocationEscaped = escapeshellarg($toFileLocation); + + $format = pathinfo($toFileLocation, PATHINFO_EXTENSION); + + if ($format == 'mp3') { + switch ($try) { + case 0: + $command = get_ffmpeg() . " -i \"{$fromFileLocation}\" -c:a libmp3lame \"{$toFileLocation}\""; + break; + default: + return false; + break; + } + } else { + if ($try === 0 && preg_match('/_offline\.mp4/', $toFileLocation)) { + $try = 'offline'; + $fromFileLocationEscaped = "\"$fromFileLocation\""; + $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -crf 30 {$toFileLocationEscaped}"; + } else { + switch ($try) { + case 0: + $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 128k {$toFileLocationEscaped}"; + break; + case 1: + $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -c copy {$toFileLocationEscaped}"; + break; + case 2: + $command = get_ffmpeg() . " -allowed_extensions ALL -y -i {$fromFileLocationEscaped} -c:v copy -c:a copy -bsf:a aac_adtstoasc -strict -2 {$toFileLocationEscaped}"; + break; + case 3: + $command = get_ffmpeg() . " -y -i {$fromFileLocationEscaped} -c:v copy -c:a copy -bsf:a aac_adtstoasc -strict -2 {$toFileLocationEscaped}"; + break; + default: + return false; + break; + } + } + } + if (!empty($logFile)) { + $progressFile = getConvertVideoFileWithFFMPEGProgressFilename($toFileLocation); + } else { + $progressFile = $logFile; + } + $progressFileEscaped = escapeshellarg($progressFile); + $command .= " 1> {$progressFileEscaped} 2>&1"; + $command = removeUserAgentIfNotURL($command); + _error_log("convertVideoFileWithFFMPEG try[{$try}]: " . $command . ' ' . json_encode(debug_backtrace())); + _session_write_close(); + _mysql_close(); + exec($command, $output, $return); + _session_start(); + _mysql_connect(); + _error_log("convertVideoFileWithFFMPEG try[{$try}] output: " . json_encode($output)); + + unlink($localFileLock); + + return ['return' => $return, 'output' => $output, 'command' => $command, 'fromFileLocation' => $fromFileLocation, 'toFileLocation' => $toFileLocation, 'progressFile' => $progressFile]; +} + +function rrmdirCommandLine($dir, $async = false) +{ + if (is_dir($dir)) { + $dir = escapeshellarg($dir); + if (isWindows()) { + $command = ('rd /s /q ' . $dir); + } else { + $command = ('rm -fR ' . $dir); + } + + if ($async) { + return execAsync($command); + } else { + return exec($command); + } + } +} + +function unzipDirectory($filename, $destination) +{ + // Set memory limit and execution time to avoid issues with large files + ini_set('memory_limit', '-1'); + set_time_limit(0); + + // Escape the input parameters to prevent command injection attacks + $filename = escapeshellarg($filename); + $destination = escapeshellarg($destination); + + // Build the command for unzipping the file + $cmd = "unzip -q -o {$filename} -d {$destination} 2>&1"; + + // Log the command for debugging purposes + _error_log("unzipDirectory: {$cmd}"); + + // Execute the command and check the return value + exec($cmd, $output, $return_val); + + if ($return_val !== 0) { + // If the unzip command fails, try using PHP's ZipArchive class as a fallback + if (class_exists('ZipArchive')) { + $zip = new ZipArchive(); + if ($zip->open($filename) === true) { + $zip->extractTo($destination); + $zip->close(); + _error_log("unzipDirectory: Success {$destination}"); + } else { + _error_log("unzipDirectory: Error opening zip archive: {$filename}"); + } + } else { + _error_log("unzipDirectory: Error: ZipArchive class is not available"); + } + } else { + _error_log("unzipDirectory: Success {$destination}"); + } + + // Delete the original zip file + _error_log("unzipDirectory($filename) unlink line=" . __LINE__); + @unlink($filename); +} + +function getPIDUsingPort($port) +{ + $port = intval($port); + if (empty($port)) { + return false; + } + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $command = 'netstat -ano | findstr ' . $port; + exec($command, $output, $retval); + $pid = 0; + foreach ($output as $value) { + if (preg_match('/LISTENING[^0-9]+([0-9]+)/i', $value, $matches)) { + if (!empty($matches[1])) { + $pid = intval($matches[1]); + return $pid; + } + } + } + } else { + $command = 'lsof -n -i :' . $port . ' | grep LISTEN'; + exec($command, $output, $retval); + $pid = 0; + foreach ($output as $value) { + if (preg_match('/[^ ] +([0-9]+).*/i', $value, $matches)) { + if (!empty($matches[1])) { + $pid = intval($matches[1]); + return $pid; + } + } elseif (preg_match('/lsof: not found/i', $value)) { + die('Please install lsof running this command: "sudo apt-get install lsof"'); + } + } + } + return false; +} + +function execAsync($command) +{ + //$command = escapeshellarg($command); + // If windows, else + if (isWindows()) { + //echo $command; + //$pid = system("start /min ".$command. " > NUL"); + //$commandString = "start /B " . $command; + //pclose($pid = popen($commandString, "r")); + _error_log($command); + $pid = exec($command, $output, $retval); + _error_log('execAsync Win: ' . json_encode($output) . ' ' . $retval); + } else { + $newCommand = $command . " > /dev/null 2>&1 & echo $!; "; + _error_log('execAsync Linux: ' . $newCommand); + $pid = exec($newCommand); + } + return $pid; +} + +function killProcess($pid) +{ + $pid = intval($pid); + if (empty($pid)) { + return false; + } + if (isWindows()) { + exec("taskkill /F /PID $pid"); + } else { + exec("kill -9 $pid"); + } + return true; +} diff --git a/objects/functions.php b/objects/functions.php index be77dde86c..e6682c1e61 100644 --- a/objects/functions.php +++ b/objects/functions.php @@ -1896,48 +1896,6 @@ function decideMoveUploadedToVideos($tmp_name, $filename, $type = "video") return $destinationFile; } -function unzipDirectory($filename, $destination) -{ - // Set memory limit and execution time to avoid issues with large files - ini_set('memory_limit', '-1'); - set_time_limit(0); - - // Escape the input parameters to prevent command injection attacks - $filename = escapeshellarg($filename); - $destination = escapeshellarg($destination); - - // Build the command for unzipping the file - $cmd = "unzip -q -o {$filename} -d {$destination} 2>&1"; - - // Log the command for debugging purposes - _error_log("unzipDirectory: {$cmd}"); - - // Execute the command and check the return value - exec($cmd, $output, $return_val); - - if ($return_val !== 0) { - // If the unzip command fails, try using PHP's ZipArchive class as a fallback - if (class_exists('ZipArchive')) { - $zip = new ZipArchive(); - if ($zip->open($filename) === true) { - $zip->extractTo($destination); - $zip->close(); - _error_log("unzipDirectory: Success {$destination}"); - } else { - _error_log("unzipDirectory: Error opening zip archive: {$filename}"); - } - } else { - _error_log("unzipDirectory: Error: ZipArchive class is not available"); - } - } else { - _error_log("unzipDirectory: Success {$destination}"); - } - - // Delete the original zip file - _error_log("unzipDirectory($filename) unlink line=".__LINE__); - @unlink($filename); -} - function make_path($path) { $created = false; @@ -3485,23 +3443,6 @@ function rrmdir($dir) } } -function rrmdirCommandLine($dir, $async = false) -{ - if (is_dir($dir)) { - $dir = escapeshellarg($dir); - if (isWindows()) { - $command = ('rd /s /q ' . $dir); - } else { - $command = ('rm -fR ' . $dir); - } - - if ($async) { - return execAsync($command); - } else { - return exec($command); - } - } -} /** * You can now configure it on the configuration.php @@ -4587,50 +4528,6 @@ function getUsageFromURL($url) return (int) $result; } -function getDirSize($dir, $forceNew = false) -{ - global $_getDirSize; - - if (!isset($_getDirSize)) { - $_getDirSize = []; - } - if (empty($forceNew) && isset($_getDirSize[$dir])) { - return $_getDirSize[$dir]; - } - - _error_log("getDirSize: start {$dir}"); - - if (isWindows()) { - $return = foldersize($dir); - $_getDirSize[$dir] = $return; - return $return; - } else { - $command = "du -sb {$dir}"; - exec($command . " < /dev/null 2>&1", $output, $return_val); - if ($return_val !== 0) { - _error_log("getDirSize: ERROR ON Command {$command}"); - $return = 0; - $_getDirSize[$dir] = $return; - return $return; - } else { - if (!empty($output[0])) { - preg_match("/^([0-9]+).*/", $output[0], $matches); - } - if (!empty($matches[1])) { - _error_log("getDirSize: found {$matches[1]} from - {$output[0]}"); - $return = intval($matches[1]); - $_getDirSize[$dir] = $return; - return $return; - } - - _error_log("getDirSize: ERROR on pregmatch {$output[0]}"); - $return = 0; - $_getDirSize[$dir] = $return; - return $return; - } - } -} - function foldersize($path) { $total_size = 0; @@ -5784,48 +5681,6 @@ function reloadSearchVar() } } -function wget($url, $filename, $debug = false) -{ - if (empty($url) || $url == "php://input" || !isValidURL($url)) { - return false; - } - if ($lockfilename = wgetIsLocked($url)) { - if ($debug) { - _error_log("wget: ERROR the url is already downloading {$lockfilename} $url, $filename"); - } - return false; - } - wgetLock($url); - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - $content = @file_get_contents($url); - if (!empty($content) && file_put_contents($filename, $content) > 100) { - wgetRemoveLock($url); - return true; - } - wgetRemoveLock($url); - return false; - } - - $filename = escapeshellarg($filename); - $url = escapeshellarg($url); - $cmd = "wget --tries=1 {$url} -O {$filename} --no-check-certificate"; - if ($debug) { - _error_log("wget Start ({$cmd}) "); - } - //echo $cmd; - exec($cmd); - wgetRemoveLock($url); - if (!file_exists($filename)) { - _error_log("wget: ERROR the url does not download $url, $filename"); - return false; - } - if ($_SERVER['SCRIPT_NAME'] !== '/plugin/Live/m3u8.php' && empty(filesize($filename))) { - _error_log("wget: ERROR the url download but is empty $url, $filename"); - return true; - } - return false; -} - /** * Copy remote file over HTTP one small chunk at a time. * @@ -7250,73 +7105,7 @@ function get_ffprobe() { return $ffprobe.$complement; } -function getDurationFromFile($file) - { - global $config, $getDurationFromFile; - if (empty($file)) { - return "EE:EE:EE"; - } - - if (!isset($getDurationFromFile)) { - $getDurationFromFile = []; - } - - if (!empty($getDurationFromFile[$file])) { - // I need to check again because I am recreating the file on the AI - //return $getDurationFromFile[$file]; - } - - $hls = str_replace(".zip", "/index.m3u8", $file); - $file = str_replace(".zip", ".mp4", $file); - - // get movie duration HOURS:MM:SS.MICROSECONDS - $videoFile = $file; - if (!file_exists($videoFile)) { - $file_headers = @get_headers($videoFile); - if (!$file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found') { - error_log('getDurationFromFile try 1, File (' . $videoFile . ') Not Found'); - $videoFile = $hls; - } - } - if (!file_exists($videoFile)) { - $file_headers = @get_headers($videoFile); - if (!$file_headers || $file_headers[0] == 'HTTP/1.1 404 Not Found') { - error_log('getDurationFromFile try 2, File (' . $videoFile . ') Not Found'); - $videoFile = ''; - } - } - if (empty($videoFile)) { - return "EE:EE:EE"; - } - $videoFile = escapeshellarg($videoFile); - /** - * @var string $cmd - */ - //$cmd = 'ffprobe -i ' . $file . ' -sexagesimal -show_entries format=duration -v quiet -of csv="p=0"'; - eval('$cmd=get_ffprobe()." -i {$videoFile} -sexagesimal -show_entries format=duration -v quiet -of csv=\\"p=0\\"";'); - $cmd = removeUserAgentIfNotURL($cmd); - exec($cmd . ' 2>&1', $output, $return_val); - if ($return_val !== 0) { - error_log('{"status":"error", "msg":' . json_encode($output) . ' ,"return_val":' . json_encode($return_val) . ', "where":"getDuration", "cmd":"' . $cmd . '"}'); - // fix ffprobe - $duration = "EE:EE:EE"; - } else { - preg_match("/([0-9]+:[0-9]+:[0-9]{2})/", $output[0], $match); - if (!empty($match[1])) { - $duration = $match[1]; - } else { - error_log('{"status":"error", "msg":' . json_encode($output) . ' ,"match_not_found":' . json_encode($match) . ' ,"return_val":' . json_encode($return_val) . ', "where":"getDuration", "cmd":"' . $cmd . '"}'); - $duration = "EE:EE:EE"; - } - } - error_log("Duration found: {$duration}"); - if ($duration !== 'EE:EE:EE') { - $getDurationFromFile[$file] = $duration; - } - return $duration; - } - -function removeUserAgentIfNotURL($cmd) + function removeUserAgentIfNotURL($cmd) { if (!preg_match('/ -i [\'"]?https?:/', $cmd)) { $cmd = preg_replace('/-user_agent "[^"]+"/', '', $cmd); @@ -7360,82 +7149,6 @@ function convertVideoToMP3FileIfNotExists($videos_id) } } -function convertVideoFileWithFFMPEG($fromFileLocation, $toFileLocation, $logFile = '', $try = 0) -{ - $parts = explode('?', $fromFileLocation); - $localFileLock = getCacheDir() . 'convertVideoFileWithFFMPEG_' . md5($parts[0]) . ".lock"; - $ageInSeconds = time() - @filemtime($localFileLock); - if ($ageInSeconds > 60) { - _error_log("convertVideoFileWithFFMPEG: age: {$ageInSeconds} too long without change, unlock it " . $fromFileLocation); - @unlink($localFileLock); - } elseif (file_exists($localFileLock)) { - _error_log("convertVideoFileWithFFMPEG: age: {$ageInSeconds} download from CDN There is a process running for " . $fromFileLocation); - return false; - } else { - _error_log("convertVideoFileWithFFMPEG: creating file: localFileLock: {$localFileLock} toFileLocation: {$toFileLocation}"); - } - make_path($toFileLocation); - file_put_contents($localFileLock, time()); - $fromFileLocationEscaped = escapeshellarg($fromFileLocation); - $toFileLocationEscaped = escapeshellarg($toFileLocation); - - $format = pathinfo($toFileLocation, PATHINFO_EXTENSION); - - if ($format == 'mp3') { - switch ($try) { - case 0: - $command = get_ffmpeg() . " -i \"{$fromFileLocation}\" -c:a libmp3lame \"{$toFileLocation}\""; - break; - default: - return false; - break; - } - } else { - if ($try === 0 && preg_match('/_offline\.mp4/', $toFileLocation)) { - $try = 'offline'; - $fromFileLocationEscaped = "\"$fromFileLocation\""; - $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -crf 30 {$toFileLocationEscaped}"; - } else { - switch ($try) { - case 0: - $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 128k {$toFileLocationEscaped}"; - break; - case 1: - $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -c copy {$toFileLocationEscaped}"; - break; - case 2: - $command = get_ffmpeg() . " -allowed_extensions ALL -y -i {$fromFileLocationEscaped} -c:v copy -c:a copy -bsf:a aac_adtstoasc -strict -2 {$toFileLocationEscaped}"; - break; - case 3: - $command = get_ffmpeg() . " -y -i {$fromFileLocationEscaped} -c:v copy -c:a copy -bsf:a aac_adtstoasc -strict -2 {$toFileLocationEscaped}"; - break; - default: - return false; - break; - } - } - } - if(!empty($logFile)){ - $progressFile = getConvertVideoFileWithFFMPEGProgressFilename($toFileLocation); - }else{ - $progressFile = $logFile; - } - $progressFileEscaped = escapeshellarg($progressFile); - $command .= " 1> {$progressFileEscaped} 2>&1"; - $command = removeUserAgentIfNotURL($command); - _error_log("convertVideoFileWithFFMPEG try[{$try}]: " . $command . ' '.json_encode(debug_backtrace())); - _session_write_close(); - _mysql_close(); - exec($command, $output, $return); - _session_start(); - _mysql_connect(); - _error_log("convertVideoFileWithFFMPEG try[{$try}] output: " . json_encode($output)); - - unlink($localFileLock); - - return ['return' => $return, 'output' => $output, 'command' => $command, 'fromFileLocation' => $fromFileLocation, 'toFileLocation' => $toFileLocation, 'progressFile' => $progressFile]; -} - function m3u8ToMP4($input) { $videosDir = getVideosDir(); @@ -7806,81 +7519,11 @@ function sendSocketMessageToNone($msg, $callbackJSFunction = "") return sendSocketMessage($msg, $callbackJSFunction, -1); } -function execAsync($command) -{ - //$command = escapeshellarg($command); - // If windows, else - if (isWindows()) { - //echo $command; - //$pid = system("start /min ".$command. " > NUL"); - //$commandString = "start /B " . $command; - //pclose($pid = popen($commandString, "r")); - _error_log($command); - $pid = exec($command, $output, $retval); - _error_log('execAsync Win: ' . json_encode($output) . ' ' . $retval); - } else { - $newCommand = $command . " > /dev/null 2>&1 & echo $!; "; - _error_log('execAsync Linux: ' . $newCommand); - $pid = exec($newCommand); - } - return $pid; -} - -function killProcess($pid) -{ - $pid = intval($pid); - if (empty($pid)) { - return false; - } - if (isWindows()) { - exec("taskkill /F /PID $pid"); - } else { - exec("kill -9 $pid"); - } - return true; -} - function isWindows() { return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } -function getPIDUsingPort($port) -{ - $port = intval($port); - if (empty($port)) { - return false; - } - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - $command = 'netstat -ano | findstr ' . $port; - exec($command, $output, $retval); - $pid = 0; - foreach ($output as $value) { - if (preg_match('/LISTENING[^0-9]+([0-9]+)/i', $value, $matches)) { - if (!empty($matches[1])) { - $pid = intval($matches[1]); - return $pid; - } - } - } - } else { - $command = 'lsof -n -i :' . $port . ' | grep LISTEN'; - exec($command, $output, $retval); - $pid = 0; - foreach ($output as $value) { - if (preg_match('/[^ ] +([0-9]+).*/i', $value, $matches)) { - if (!empty($matches[1])) { - $pid = intval($matches[1]); - return $pid; - } - } elseif (preg_match('/lsof: not found/i', $value)) { - die('Please install lsof running this command: "sudo apt-get install lsof"'); - } - } - } - return false; -} - function isURL200($url, $forceRecheck = false) { global $_isURL200; @@ -10572,4 +10215,5 @@ function checkFileModified($filePath) { require_once __DIR__.'/functionSecurity.php'; require_once __DIR__.'/functionMySQL.php'; require_once __DIR__.'/functionDocker.php'; -require_once __DIR__.'/functionImages.php'; \ No newline at end of file +require_once __DIR__.'/functionImages.php'; +require_once __DIR__.'/functionExec.php'; \ No newline at end of file diff --git a/objects/video.php b/objects/video.php index 98a37bfa72..26045e1a5d 100644 --- a/objects/video.php +++ b/objects/video.php @@ -4147,6 +4147,7 @@ if (!class_exists('Video')) { return $__getPaths[$videoFilename]; } $cleanVideoFilename = self::getCleanFilenameFromFile($videoFilename); + //var_dump('--'.$cleanVideoFilename, '++'.$videoFilename); $videosDir = self::getStoragePath(); $path = addLastSlash("{$videosDir}{$cleanVideoFilename}"); @@ -4193,6 +4194,7 @@ if (!class_exists('Video')) { if (!empty($parts[1]) && $parts[1] == 'index.m3u8') { $videoFilename = $parts[1]; } + //var_dump('--'.$videoFilename, $paths); return "{$paths['url']}{$videoFilename}"; } @@ -4336,6 +4338,10 @@ if (!class_exists('Video')) { $path_parts = pathinfo($filename); if (!empty($path_parts['extension'])) { if ($path_parts['extension'] == 'vtt' || $path_parts['extension'] == 'srt') { + $search = ['.Chapters']; + foreach ($search as $value) { + $path_parts['filename'] = str_ireplace($value, '', $path_parts['filename']); + } $p = explode('.', $path_parts['filename']); if (count($p) > 1) { array_pop($p); diff --git a/plugin/AI/AI.php b/plugin/AI/AI.php index 2f3c6a4d6a..809a5f4652 100644 --- a/plugin/AI/AI.php +++ b/plugin/AI/AI.php @@ -5,11 +5,12 @@ require_once $global['systemRootPath'] . 'plugin/Plugin.abstract.php'; require_once $global['systemRootPath'] . 'plugin/AI/Objects/Ai_responses.php'; require_once $global['systemRootPath'] . 'plugin/AI/Objects/Ai_metatags_responses.php'; require_once $global['systemRootPath'] . 'plugin/AI/Objects/Ai_transcribe_responses.php'; +require_once $global['systemRootPath'] . 'plugin/AI/Objects/Ai_responses_json.php'; +require_once $global['systemRootPath'] . 'plugin/AI/Objects/Ai_scheduler.php'; +class AI extends PluginAbstract +{ - -class AI extends PluginAbstract { - static $typeTranslation = 'translation'; static $typeTranscription = 'transcription'; static $typeBasic = 'basic'; @@ -47,41 +48,48 @@ class AI extends PluginAbstract { 'uk' => 'Ukrainian', 'vi' => 'Vietnamese' ]; - + static $isTest = 0; static $url = 'https://ai.ypt.me/'; static $url_test = 'http://192.168.0.2:81/AI/'; - static function getMetadataURL(){ + static function getMetadataURL() + { self::$isTest = ($_SERVER["SERVER_NAME"] == "vlu.me"); - return self::$isTest?self::$url_test:self::$url; + return self::$isTest ? self::$url_test : self::$url; } - static function getPricesURL(){ - return self::$url.'prices.json.php'; + static function getPricesURL() + { + return self::$url . 'prices.json.php'; } - public function getDescription() { + public function getDescription() + { $desc = "Optimize video visibility with AI-driven meta-tag suggestions and automatic transcription for enhanced SEO performance."; $help = "
Help"; - + //$desc .= $this->isReadyLabel(array('YPTWallet')); - return $desc.$help; + return $desc . $help; } - public function getName() { + public function getName() + { return "AI"; } - public function getUUID() { + public function getUUID() + { return "AI-5ee8405eaaa16"; } - public function getPluginVersion() { - return "4.0"; + public function getPluginVersion() + { + return "6.0"; } - public function getEmptyDataObject() { + public function getEmptyDataObject() + { $obj = new stdClass(); $obj->AccessToken = ""; /* @@ -102,7 +110,8 @@ class AI extends PluginAbstract { return $obj; } - static function getVideoTranslationMetadata($videos_id, $lang, $langName){ + static function getVideoShortsMetadata($videos_id) + { global $global; $obj = new stdClass(); $obj->error = true; @@ -114,7 +123,42 @@ class AI extends PluginAbstract { return $obj; } - if(!Video::canEdit($videos_id)){ + if (!Video::canEdit($videos_id)) { + $obj->msg = 'you cannot edit this video'; + return $obj; + } + + $trascription = Ai_responses::getTranscriptionVtt($videos_id); + + if (empty($trascription)) { + $obj->msg = 'empty transcription'; + return $obj; + } + + //var_dump($paths);exit; + $obj->response = array( + 'type' => AI::$typeShorts, + 'transcription' => $trascription, + ); + + $obj->error = false; + return $obj; + } + + static function getVideoTranslationMetadata($videos_id, $lang, $langName) + { + global $global; + $obj = new stdClass(); + $obj->error = true; + $obj->msg = ''; + $obj->response = array(); + + if (empty($videos_id)) { + $obj->msg = 'empty videos id'; + return $obj; + } + + if (!Video::canEdit($videos_id)) { $obj->msg = 'you cannot edit this video'; return $obj; } @@ -122,12 +166,12 @@ class AI extends PluginAbstract { $video = new Video('', '', $videos_id); $filename = $video->getFilename(); - if(AVideoPlugin::isEnabledByName('SubtitleSwitcher')){ + if (AVideoPlugin::isEnabledByName('SubtitleSwitcher')) { SubtitleSwitcher::transcribe($videos_id, false); } $firstVTTPath = AI::getFirstVTTFile($videos_id); - $vttURL = str_replace($global['systemRootPath'], $global['webSiteRootURL'],$firstVTTPath); + $vttURL = str_replace($global['systemRootPath'], $global['webSiteRootURL'], $firstVTTPath); //var_dump($paths);exit; $obj->response = array( @@ -142,7 +186,8 @@ class AI extends PluginAbstract { return $obj; } - static function getVideoBasicMetadata($videos_id){ + static function getVideoBasicMetadata($videos_id) + { global $global; $obj = new stdClass(); $obj->error = true; @@ -154,7 +199,7 @@ class AI extends PluginAbstract { return $obj; } - if(!Video::canEdit($videos_id)){ + if (!Video::canEdit($videos_id)) { $obj->msg = 'you cannot edit this video'; return $obj; } @@ -162,13 +207,13 @@ class AI extends PluginAbstract { $video = new Video('', '', $videos_id); $filename = $video->getFilename(); - if(AVideoPlugin::isEnabledByName('SubtitleSwitcher')){ + if (AVideoPlugin::isEnabledByName('SubtitleSwitcher')) { SubtitleSwitcher::transcribe($videos_id, false); } /* */ $firstVTTPath = AI::getFirstVTTFile($videos_id); - $vttURL = str_replace(getVideosDir(), $global['webSiteRootURL'],$firstVTTPath); + $vttURL = str_replace(getVideosDir(), $global['webSiteRootURL'], $firstVTTPath); //var_dump($paths);exit; $obj->response = array( 'type' => AI::$typeBasic, @@ -185,7 +230,8 @@ class AI extends PluginAbstract { return $obj; } - static function getVideoTranscriptionMetadata($videos_id, $lang){ + static function getVideoTranscriptionMetadata($videos_id, $lang) + { $obj = new stdClass(); $obj->error = true; $obj->msg = ''; @@ -196,7 +242,7 @@ class AI extends PluginAbstract { return $obj; } - if(!Video::canEdit($videos_id)){ + if (!Video::canEdit($videos_id)) { $obj->msg = 'you cannot edit this video'; return $obj; } @@ -205,7 +251,7 @@ class AI extends PluginAbstract { $mp3 = false; $mp3s = self::getLowerMP3($videos_id); $fsize = 0; - if($mp3s['isValid']){ + if ($mp3s['isValid']) { $mp3 = $mp3s['lower']['paths']['url']; $fsize = filesize($mp3s['lower']['paths']['path']); } @@ -225,7 +271,8 @@ class AI extends PluginAbstract { return $obj; } - static function getTokenForVideo($videos_id, $ai_responses_id, $param){ + static function getTokenForVideo($videos_id, $ai_responses_id, $param) + { global $global; $obj = new stdClass(); $obj->videos_id = $videos_id; @@ -237,47 +284,51 @@ class AI extends PluginAbstract { return encryptString(_json_encode($obj)); } - - static function getTokenFromRequest(){ - if(empty($_REQUEST['token'])){ + static function getTokenFromRequest() + { + + if (empty($_REQUEST['token'])) { return false; } $string = decryptString($_REQUEST['token']); - - if(empty($string)){ + + if (empty($string)) { return false; } $json = _json_decode($string); - if(empty($json)){ + if (empty($json)) { return false; } - + return $json; } - static function getMP3Path($videos_id){ + static function getMP3Path($videos_id) + { $convert = convertVideoToMP3FileIfNotExists($videos_id); - if(empty($convert) || empty($convert['url'])){ + if (empty($convert) || empty($convert['url'])) { return false; } return $convert; } - static function getMP3LowerPath($videos_id){ + static function getMP3LowerPath($videos_id) + { $convert = self::getMP3Path($videos_id); - if(empty($convert) || empty($convert['url'])){ + if (empty($convert) || empty($convert['url'])) { return false; } $convert['path'] = str_replace('.mp3', '_Low.mp3', $convert['path']); $convert['url'] = str_replace('.mp3', '_Low.mp3', $convert['url']); return $convert; } - - static function getMP3RegularAndLower($videos_id){ + + static function getMP3RegularAndLower($videos_id) + { $arrayRegular = array( 'paths' => false, 'duration' => false, @@ -292,7 +343,7 @@ class AI extends PluginAbstract { ); $paths = self::getMP3Path($videos_id); - if(!empty($paths)){ + if (!empty($paths)) { $duration = getDurationFromFile($paths['path']); $durationInSeconds = durationToSeconds($duration); $video = new Video('', '', $videos_id); @@ -306,7 +357,7 @@ class AI extends PluginAbstract { 'isValid' => false, 'msg' => "Length does not match (Video/MP3) video = {$videoDuration} seconds MP3 = $durationInSeconds seconds", ); - return $response; + return $response; } $arrayRegular = array( @@ -315,9 +366,9 @@ class AI extends PluginAbstract { 'durationInSeconds' => $durationInSeconds, 'isValid' => !empty($durationInSeconds), ); - - $pathsLower = self::getMP3LowerPath($videos_id); - if(!empty($pathsLower )){ + + $pathsLower = self::getMP3LowerPath($videos_id); + if (!empty($pathsLower)) { $duration = getDurationFromFile($pathsLower['path']); $durationInSeconds = durationToSeconds($duration); $arrayLower = array( @@ -326,24 +377,24 @@ class AI extends PluginAbstract { 'durationInSeconds' => $durationInSeconds, 'isValid' => !empty($durationInSeconds), ); - - $pathsLower = self::getMP3LowerPath($videos_id); + + $pathsLower = self::getMP3LowerPath($videos_id); } } $msg = ''; $isValid = false; - if($arrayRegular['isValid'] && $arrayLower['isValid']){ + if ($arrayRegular['isValid'] && $arrayLower['isValid']) { $diff = abs($arrayRegular['durationInSeconds'] - $arrayLower['durationInSeconds']); if ($diff <= 2) { $isValid = true; - }else{ + } else { $msg = "durationInSeconds are not the same regular={$arrayRegular['durationInSeconds']} lower={$arrayLower['durationInSeconds']}"; } - }else{ - if(!$arrayRegular['isValid']){ + } else { + if (!$arrayRegular['isValid']) { $msg = 'Regular MP3 is invalid'; } - if(!$arrayRegular['isValid']){ + if (!$arrayRegular['isValid']) { $msg .= ' Lower MP3 is invalid'; } } @@ -357,33 +408,35 @@ class AI extends PluginAbstract { return $response; } - static function getLowerMP3($videos_id, $try = 0){ + static function getLowerMP3($videos_id, $try = 0) + { $mp3s = self::getMP3RegularAndLower($videos_id); - if($mp3s['regular']['isValid']){ - if(!$mp3s['isValid']){ - ini_set('max_execution_time', 300); + if ($mp3s['regular']['isValid']) { + if (!$mp3s['isValid']) { + ini_set('max_execution_time', 300); set_time_limit(300); - if(file_exists($mp3s['lower']['paths']['path'])){ + if (file_exists($mp3s['lower']['paths']['path'])) { unlink($mp3s['lower']['paths']['path']); } $fromFileLocationEscaped = escapeshellarg($mp3s['regular']['paths']['path']); $toFileLocationEscaped = escapeshellarg($mp3s['lower']['paths']['path']); - $command = get_ffmpeg()." -i {$fromFileLocationEscaped} -ar 16000 -ac 1 -b:a 16k {$toFileLocationEscaped}"; + $command = get_ffmpeg() . " -i {$fromFileLocationEscaped} -ar 16000 -ac 1 -b:a 16k {$toFileLocationEscaped}"; $command = removeUserAgentIfNotURL($command); exec($command, $output); - _error_log('getLowerMP3: '.json_encode($output)); + _error_log('getLowerMP3: ' . json_encode($output)); return self::getMP3RegularAndLower($videos_id); } - }else{ + } else { return $mp3s; } return $mp3s; } - - - public function getPluginMenu() { + + + public function getPluginMenu() + { global $global; - return ''; + return ''; } public function getVideosManagerListButton() @@ -398,18 +451,19 @@ class AI extends PluginAbstract { return $btn; } - public static function getTagTypeId() { + public static function getTagTypeId() + { $VideoTags = AVideoPlugin::isEnabledByName('VideoTags'); - if(empty($VideoTags)){ + if (empty($VideoTags)) { return false; - } + } $typeName = 'Keywords'; $row = TagsTypes::getFromName($typeName); - if(empty($row)){ + if (empty($row)) { $tagType = new TagsTypes(0); - $tagType->setName($typeName ); + $tagType->setName($typeName); return $tagType->save(); - }else{ + } else { return $row['id']; } } @@ -424,16 +478,17 @@ class AI extends PluginAbstract { $global['lastQuery'] = $sql; sqlDAL::writeSql($sql); } - + return true; } - static function getVTTLanguageCodes($videos_id) { + static function getVTTLanguageCodes($videos_id) + { $video = new Video('', '', $videos_id); - $dir = getVideosDir().DIRECTORY_SEPARATOR.$video->getFilename(); + $dir = getVideosDir() . DIRECTORY_SEPARATOR . $video->getFilename(); $languageCodes = []; $filePattern = '/video_[\w\d]+\.([\w\d_]+)\.vtt$/'; - + if (is_dir($dir) && ($handle = opendir($dir))) { while (false !== ($entry = readdir($handle))) { if (is_file($dir . '/' . $entry) && preg_match($filePattern, $entry, $matches)) { @@ -442,46 +497,98 @@ class AI extends PluginAbstract { } closedir($handle); } - + return array_unique($languageCodes); // Return unique language codes } - public function getFooterCode() { + public function getFooterCode() + { global $global; include $global['systemRootPath'] . 'plugin/AI/footer.php'; } - static function getVTTFiles($videos_id) { + static function getVTTFiles($videos_id) + { $video = new Video('', '', $videos_id); $filename = $video->getFilename(); $dir = getVideosDir() . "{$filename}/"; - + // Find all .vtt files in the directory $vttFiles = glob($dir . "*.vtt"); - + // Return the array of .vtt files return $vttFiles; } - - static function getFirstVTTFile($videos_id){ + + static function getFirstVTTFile($videos_id) + { $vttFiles = self::getVTTFiles($videos_id); - if(empty($vttFiles)){ + if (empty($vttFiles)) { return false; } return $vttFiles[0]; } - static function getProgressBarHTML($classname, $text){ + static function getProgressBarHTML($classname, $text) + { return ' -