From d246ee5013da40d9c5f3f7564d43efc5625e42ff Mon Sep 17 00:00:00 2001 From: Daniel Neto Date: Fri, 6 Sep 2024 21:07:27 -0300 Subject: [PATCH] Update --- .gitignore | 3 +- objects/functions.php | 2 + objects/functionsFFMPEG.php | 14 +++-- objects/video.php | 20 ++++-- plugin/AI/AI.php | 99 ++++++++++++++++++++++++++--- plugin/AI/page.php | 13 ++++ plugin/AI/receiveAsync.json.php | 25 +++++++- plugin/AI/tabs/dubbing.php | 103 +++++++++++++++++++++++++++++++ plugin/AI/tabs/shorts.php | 1 + plugin/AI/tabs/transcription.php | 4 +- 10 files changed, 260 insertions(+), 24 deletions(-) create mode 100644 plugin/AI/tabs/dubbing.php diff --git a/.gitignore b/.gitignore index e831e143e628..27f041a9b2e9 100644 --- a/.gitignore +++ b/.gitignore @@ -86,7 +86,6 @@ objects/ezyang/ /plugin/TestOnly/ view/videoComments_bkp.php /.compose/ -test.php /plugin/JosephZ/ /Encoder/ /.env @@ -105,4 +104,4 @@ install/bulkCreateUser.php /plugin/CertifyComplete/ plugin/WebAuthnLogin/ plugin/UserOTPLogin/ -test2.php +test* diff --git a/objects/functions.php b/objects/functions.php index d27a84651ff3..213e15a3b0e1 100644 --- a/objects/functions.php +++ b/objects/functions.php @@ -3672,6 +3672,7 @@ function getPlayListCurrentVideosId($setVideos_id = true) $playListData = getPlayListData(); $playlist_index = getPlayListIndex(); if (empty($playListData) && !empty($_REQUEST['playlist_id']) && class_exists('PlayList')) { + _error_log('line='.__LINE__." playlist_id={$_REQUEST['playlist_id']} playlist_index={$playlist_index}"); $videosArrayId = PlayList::getVideosIdFromPlaylist($_REQUEST['playlist_id']); $videos_id = $videosArrayId[$playlist_index]; } else { @@ -3679,6 +3680,7 @@ function getPlayListCurrentVideosId($setVideos_id = true) //var_dump($playlist_index, $playListData); return false; } else { + _error_log('line='.__LINE__." playlist_id={$_REQUEST['playlist_id']} playlist_index={$playlist_index}"); $videos_id = $playListData[$playlist_index]->getVideos_id(); } } diff --git a/objects/functionsFFMPEG.php b/objects/functionsFFMPEG.php index 5bc7d3c883dc..d39da86c98e7 100644 --- a/objects/functionsFFMPEG.php +++ b/objects/functionsFFMPEG.php @@ -55,14 +55,20 @@ function convertVideoToMP3FileIfNotExists($videos_id, $forceTry = 0) } $paths = Video::getPaths($video['filename']); + $mp3HLSFile = "{$paths['path']}index.mp3"; $mp3File = "{$paths['path']}{$video['filename']}.mp3"; - if (!file_exists($mp3File)) { + if(file_exists($mp3HLSFile) || file_exists($mp3File)){ + return Video::getSourceFile($video['filename'], ".mp3", true); + }else { $f = convertVideoFileWithFFMPEGIsLockedInfo($mp3File); if ($f['isUnlocked']) { $sources = getVideosURLOnly($video['filename'], false); - if (!empty($sources)) { - $source = end($sources); + if(!empty($sources['m3u8'])){ + $source = $sources['m3u8']; + }else{ + $source = end($sources); + } convertVideoFileWithFFMPEG($source['url'], $mp3File, '', $forceTry); if (file_exists($mp3File)) { return Video::getSourceFile($video['filename'], ".mp3", true); @@ -76,8 +82,6 @@ function convertVideoToMP3FileIfNotExists($videos_id, $forceTry = 0) _error_log("convertVideoToMP3FileIfNotExists: is locked"); } return false; - } else { - return Video::getSourceFile($video['filename'], ".mp3", true); } } diff --git a/objects/video.php b/objects/video.php index 949e96d0f596..271b3ebf48c5 100644 --- a/objects/video.php +++ b/objects/video.php @@ -4059,7 +4059,7 @@ public static function getSourceFile($filename, $type = ".jpg", $includeS3 = fal TimeLogEnd($timeLog1, __LINE__, $timeLog1Limit); $cacheName = md5($filename . $type . $includeS3); - if (isset($VideoGetSourceFile[$cacheName]) && is_array($VideoGetSourceFile[$cacheName])) { + if (isset($VideoGetSourceFile[$cacheName]) && is_array($VideoGetSourceFile[$cacheName]) ) { if (!preg_match("/token=/", $VideoGetSourceFile[$cacheName]['url'])) { return $VideoGetSourceFile[$cacheName]; } @@ -4110,6 +4110,14 @@ public static function getSourceFile($filename, $type = ".jpg", $includeS3 = fal if ($type == ".m3u8") { $source['path'] = self::getStoragePath() . "{$filename}/index{$type}"; } + $indexMP3Exits = false; + if ($type == ".mp3") { + $exits = self::getStoragePath() . "{$filename}/index{$type}"; + $indexMP3Exits = file_exists($exits); + if($indexMP3Exits){ + $source['path'] = $exits; + } + } TimeLogEnd($timeLog1, __LINE__, $timeLog1Limit); $cleanFileName = self::getCleanFilenameFromFile($filename); TimeLogEnd($timeLog1, __LINE__, $timeLog1Limit); @@ -4133,7 +4141,9 @@ public static function getSourceFile($filename, $type = ".jpg", $includeS3 = fal if (!empty($cdn_obj->enable_storage) && $isValidType && $fsize < 20 && !empty($site) && (empty($yptStorage) || $site->getUrl() == 'url/')) { if ($type == ".m3u8") { $f = "{$filename}/index{$type}"; - } else { + } else if($indexMP3Exits){ + $f = "{$filename}/index{$type}"; + }else { $f = "{$paths['relative']}{$filename}{$type}"; } TimeLogEnd($timeLog1, __LINE__, $timeLog1Limit); @@ -4146,7 +4156,7 @@ public static function getSourceFile($filename, $type = ".jpg", $includeS3 = fal TimeLogEnd($timeLog1, __LINE__, $timeLog1Limit); $source['url'] = "{$siteURL}{$paths['relative']}{$filename}{$type}"; $source['url_noCDN'] = $site->getUrl() . "{$paths['relative']}{$filename}{$type}"; - if ($type == ".m3u8") { + if ($type == ".m3u8" || $indexMP3Exits) { $source['url'] = "{$siteURL}videos/{$filename}/index{$type}"; $source['url_noCDN'] = "{$global['webSiteRootURL']}videos/{$filename}/index{$type}"; } @@ -4154,14 +4164,14 @@ public static function getSourceFile($filename, $type = ".jpg", $includeS3 = fal $advancedCustom->videosCDN = addLastSlash($advancedCustom->videosCDN); $source['url'] = "{$advancedCustom->videosCDN}{$paths['relative']}{$filename}{$type}"; $source['url_noCDN'] = "{$global['webSiteRootURL']}{$paths['relative']}{$filename}{$type}"; - if ($type == ".m3u8") { + if ($type == ".m3u8" || $indexMP3Exits) { $source['url'] = "{$advancedCustom->videosCDN}videos/{$filename}/index{$type}"; $source['url_noCDN'] = "{$global['webSiteRootURL']}videos/{$filename}/index{$type}"; } } else { $source['url'] = getCDN() . "{$paths['relative']}{$filename}{$type}"; $source['url_noCDN'] = "{$global['webSiteRootURL']}{$paths['relative']}{$filename}{$type}"; - if ($type == ".m3u8") { + if ($type == ".m3u8" || $indexMP3Exits) { $source['url'] = getCDN() . "videos/{$filename}/index{$type}"; $source['url_noCDN'] = "{$global['webSiteRootURL']}videos/{$filename}/index{$type}"; } diff --git a/plugin/AI/AI.php b/plugin/AI/AI.php index a6218a581700..6d6d268948ba 100644 --- a/plugin/AI/AI.php +++ b/plugin/AI/AI.php @@ -17,8 +17,9 @@ class AI extends PluginAbstract static $typeTranscription = 'transcription'; static $typeBasic = 'basic'; static $typeShorts = 'shorts'; + static $typeDubbing = 'dubbing'; - static $languages = [ + const LANGS = [ 'en' => 'English', 'es' => 'Spanish', 'fr' => 'French', @@ -51,6 +52,39 @@ class AI extends PluginAbstract 'vi' => 'Vietnamese' ]; + + const DubbingLANGS = [ + ['name' => 'English', 'code' => 'en'], + ['name' => 'Hindi', 'code' => 'hi'], + ['name' => 'Portuguese', 'code' => 'pt'], + ['name' => 'Chinese', 'code' => 'zh'], + ['name' => 'Spanish', 'code' => 'es'], + ['name' => 'French', 'code' => 'fr'], + ['name' => 'German', 'code' => 'de'], + ['name' => 'Japanese', 'code' => 'ja'], + ['name' => 'Arabic', 'code' => 'ar'], + ['name' => 'Russian', 'code' => 'ru'], + ['name' => 'Korean', 'code' => 'ko'], + ['name' => 'Indonesian', 'code' => 'id'], + ['name' => 'Italian', 'code' => 'it'], + ['name' => 'Dutch', 'code' => 'nl'], + ['name' => 'Turkish', 'code' => 'tr'], + ['name' => 'Polish', 'code' => 'pl'], + ['name' => 'Swedish', 'code' => 'sv'], + ['name' => 'Filipino', 'code' => 'fil'], + ['name' => 'Malay', 'code' => 'ms'], + ['name' => 'Romanian', 'code' => 'ro'], + ['name' => 'Ukrainian', 'code' => 'uk'], + ['name' => 'Greek', 'code' => 'el'], + ['name' => 'Czech', 'code' => 'cs'], + ['name' => 'Danish', 'code' => 'da'], + ['name' => 'Finnish', 'code' => 'fi'], + ['name' => 'Bulgarian', 'code' => 'bg'], + ['name' => 'Croatian', 'code' => 'hr'], + ['name' => 'Slovak', 'code' => 'sk'], + ['name' => 'Tamil', 'code' => 'ta'], + ]; + static $isTest = 0; static $url = 'https://ai.ypt.me/'; static $url_test = 'http://192.168.0.2:81/AI/'; @@ -120,6 +154,8 @@ public function getEmptyDataObject() self::addDataObjectHelper('priceForTranslation', 'Price for Translation Service', "Enter the charge amount for AI processing. Insufficient wallet balance will prevent processing. Successful charges apply to both your and the admin's CDN wallet on the marketplace."); $obj->priceForShorts = 0; self::addDataObjectHelper('priceForShorts', 'Price for Shorts Service', "Enter the charge amount for AI processing. Insufficient wallet balance will prevent processing. Successful charges apply to both your and the admin's CDN wallet on the marketplace."); + $obj->priceForDubbing = 0; + self::addDataObjectHelper('priceForDubbing', 'Price for Dubbing Service', "Enter the charge amount for AI processing. Insufficient wallet balance will prevent processing. Successful charges apply to both your and the admin's CDN wallet on the marketplace."); $obj->autoProcessAll = false; @@ -304,6 +340,48 @@ static function getVideoTranscriptionMetadata($videos_id, $lang) return $obj; } + static function getVideoDubbingMetadata($videos_id, $lang) + { + $obj = new stdClass(); + $obj->error = true; + $obj->msg = ''; + $obj->response = array(); + + if (empty($videos_id)) { + $obj->msg = 'empty videos id'; + return $obj; + } + + if (!isCommandLineInterface() && !Video::canEdit($videos_id)) { + $obj->msg = 'you cannot edit this video'; + return $obj; + } + + $video = new Video('', '', $videos_id); + $mp3 = false; + + $paths = AI::getMP3Path($videos_id); + $fsize = 0; + if ($paths['url']) { + $mp3 = $paths['url']; + $fsize = filesize($paths['path']); + } + + //var_dump($paths);exit; + $obj->response = array( + 'type' => AI::$typeDubbing, + 'videos_id' => $videos_id, + 'mp3' => $mp3, + 'filesize' => $fsize, + 'language' => $lang, + 'filesizeHuman' => humanFileSize($fsize), + 'duration_in_seconds' => $video->getDuration_in_seconds(), + ); + + $obj->error = false; + return $obj; + } + static function getTokenForVideo($videos_id, $ai_responses_id, $param) { global $global; @@ -422,9 +500,9 @@ static function getMP3RegularAndLower($videos_id) $pathsLower = self::getMP3LowerPath($videos_id); if (!empty($pathsLower)) { $duration = getDurationFromFile($pathsLower['path']); - if($duration == "EE:EE:EE" && !empty($pathsLower['url'])){ + if ($duration == "EE:EE:EE" && !empty($pathsLower['url'])) { $duration = getDurationFromFile($pathsLower['url']); - if($duration == "EE:EE:EE"){ + if ($duration == "EE:EE:EE") { $pathsLower['url'] = str_replace('_Low.mp3', '.mp3', $pathsLower['url']); $duration = getDurationFromFile($pathsLower['url']); } @@ -445,15 +523,15 @@ static function getMP3RegularAndLower($videos_id) $isValid = false; if ($arrayRegular['isValid'] && $arrayLower['isValid']) { $f = convertVideoFileWithFFMPEGIsLockedInfo($arrayRegular['paths']['path']); - _error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayRegular['paths']['path']}) arrayRegular ".json_encode($f)); + _error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayRegular['paths']['path']}) arrayRegular " . json_encode($f)); if (!$f['isUnlocked']) { $msg = "The original audio is processing"; - }else{ + } else { $f = convertVideoFileWithFFMPEGIsLockedInfo($arrayLower['paths']['path']); - _error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayLower['paths']['path']}) arrayLower ".json_encode($f)); + _error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayLower['paths']['path']}) arrayLower " . json_encode($f)); if (!$f['isUnlocked']) { $msg = "The audio is processing"; - }else{ + } else { $diff = abs($arrayRegular['durationInSeconds'] - $arrayLower['durationInSeconds']); if ($diff <= 2) { $isValid = true; @@ -688,6 +766,9 @@ static function chargeUser($type, $users_id, $videos_id) case AI::$typeShorts: $price = $obj->priceForShorts; break; + case AI::$typeDubbing: + $price = $obj->priceForDubbing; + break; } if (empty($price)) { _error_log("AI:asyncVideosId there is no price set for it"); @@ -749,6 +830,10 @@ static function asyncVideosId($videos_id, $type, $users_id) _error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__); $obj = AI::getVideoShortsMetadata($videos_id); break; + case AI::$typeDubbing: + _error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__); + $obj = AI::getVideoDubbingMetadata($videos_id, @$_REQUEST['language']); + break; default: _error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__); $obj = new stdClass(); diff --git a/plugin/AI/page.php b/plugin/AI/page.php index 2f1fdb57ff79..119bdb298a6d 100644 --- a/plugin/AI/page.php +++ b/plugin/AI/page.php @@ -34,6 +34,7 @@ $priceForTranscription = $objAI->priceForTranscription; $priceForTranslation = $objAI->priceForTranslation; $priceForShorts = $objAI->priceForShorts; +$priceForDubbing = $objAI->priceForDubbing; $priceForAll = $priceForTranscription + $priceForBasic + $priceForShorts; $priceForBasicText = YPTWallet::formatCurrency($priceForBasic); @@ -41,6 +42,7 @@ $priceForTranslationText = YPTWallet::formatCurrency($priceForTranslation); $priceForShortsText = YPTWallet::formatCurrency($priceForShorts); $priceForAllText = YPTWallet::formatCurrency($priceForAll); +$priceForDubbingText = YPTWallet::formatCurrency($priceForDubbing); /* if (User::isAdmin()) { $_1hour = 60 * 60; @@ -168,6 +170,12 @@ +
  • + + + + +
  • @@ -205,6 +213,11 @@ include $global['systemRootPath'] . 'plugin/AI/tabs/shorts.php'; ?> +
    + +
    diff --git a/plugin/AI/receiveAsync.json.php b/plugin/AI/receiveAsync.json.php index d94f4164a1ff..d2b9189d361f 100644 --- a/plugin/AI/receiveAsync.json.php +++ b/plugin/AI/receiveAsync.json.php @@ -4,7 +4,7 @@ header('Content-Type: application/json'); if (empty($_REQUEST['response'])) { - _error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__); + _error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__ . ' ' . json_encode($_REQUEST)); forbiddenPage('Response is empty'); } @@ -130,13 +130,32 @@ $jsonDecoded->shorts = $shorts; $jsonDecoded->Ai_responses_json = $o->save(); $jsonDecoded->error = empty($jsonDecoded->Ai_responses_json); - }else{ + } else { _error_log('AI: shorts ERROR' . basename(__FILE__) . ' line=' . __LINE__); } - }else{ + } else { _error_log('AI: ERROR ' . basename(__FILE__) . ' line=' . __LINE__ . json_encode($_REQUEST)); } break; + case AI::$typeDubbing: + _error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__); + if (!empty($_REQUEST['response']['relativeFile'])) { + _error_log('Start line=' . __LINE__); + require_once __DIR__ . '/../../plugin/VideoHLS/HLSAudioManager.php'; + $mp3URL = AI::getMetadataURL() . $_REQUEST['response']['relativeFile']; + + $language = 'Default'; + foreach (AI::DubbingLANGS as $key => $value) { + if ($value['code'] == $_REQUEST['response']['language']) { + $language = $value['name']; + } + } + + $jsonDecoded->addAudioTrack = HLSAudioManager::addAudioTrack($token->videos_id, $mp3URL, $language); + _error_log('End line=' . __LINE__.' '.json_encode($jsonDecoded->addAudioTrack)); + //$jsonDecoded->lines[] = __LINE__; + } + break; default: _error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__); diff --git a/plugin/AI/tabs/dubbing.php b/plugin/AI/tabs/dubbing.php new file mode 100644 index 000000000000..c5a0f75fcc78 --- /dev/null +++ b/plugin/AI/tabs/dubbing.php @@ -0,0 +1,103 @@ + + +
    +
    + +

    Generate Dubbing for HLS Video

    +
    +
    + +
    + Error: MP3 file is missing. Please ensure that the video has an MP3 version available for dubbing. +
    + +
    + Error: The HLS plugin is not enabled. Please enable the HLS plugin to use this feature. +
    + +
    +
    +

    Use this tool to generate dubbing for your HLS video in the language of your choice. Please note that the video must be in HLS format.

    +
    +
    + + +
    +
    + + +

    Click the button above to begin generating the dubbing for your selected language. This process may take a few minutes depending on the length of the video.

    +
    +
    + + Note: Ensure that your video is in HLS format and the HLS plugin is properly installed. If you're not familiar with these requirements, please contact support for assistance. + +
    + +
    + +
    + + diff --git a/plugin/AI/tabs/shorts.php b/plugin/AI/tabs/shorts.php index 33e349f916c9..69820dca7bcc 100644 --- a/plugin/AI/tabs/shorts.php +++ b/plugin/AI/tabs/shorts.php @@ -143,4 +143,5 @@ function loadAIShorts() { $(document).ready(function() { loadAIShorts(); }); + var autoplay = false;var forceautoplay = false;var forceNotautoplay = true; \ No newline at end of file diff --git a/plugin/AI/tabs/transcription.php b/plugin/AI/tabs/transcription.php index 408e05848ba1..dcc024bc39f3 100644 --- a/plugin/AI/tabs/transcription.php +++ b/plugin/AI/tabs/transcription.php @@ -36,7 +36,7 @@ $value) { + foreach (AI::LANGS as $key => $value) { echo AI::getProgressBarHTML("transcription_{$key}_{$videos_id}", $value); } ?> @@ -83,7 +83,7 @@