'English',
'es' => 'Spanish',
'fr' => 'French',
'de' => 'German',
'it' => 'Italian',
'pt' => 'Portuguese',
'ru' => 'Russian',
'zh' => 'Chinese',
'ja' => 'Japanese',
'ko' => 'Korean',
'ar' => 'Arabic',
'hi' => 'Hindi',
'bn' => 'Bengali',
'pl' => 'Polish',
'tr' => 'Turkish',
'nl' => 'Dutch',
'sv' => 'Swedish',
'da' => 'Danish',
'fi' => 'Finnish',
'no' => 'Norwegian',
'cs' => 'Czech',
'el' => 'Greek',
'he' => 'Hebrew',
'th' => 'Thai',
'hu' => 'Hungarian',
'id' => 'Indonesian',
'ms' => 'Malay',
'fa' => 'Persian',
'uk' => 'Ukrainian',
'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/';
public function getTags()
{
return [
PluginTags::$MONETIZATION,
PluginTags::$FREE,
PluginTags::$RECOMMENDED,
PluginTags::$PLAYER,
];
}
static function getMetadataURL()
{
global $global;
if (!empty($_SERVER["SERVER_NAME"])) {
$domain = $_SERVER["SERVER_NAME"];
} else {
$domain = parse_url($global['webSiteRootURL'], PHP_URL_HOST);
}
self::$isTest = ($domain == "vlu.me");
//return self::$url;
return self::$isTest ? self::$url_test : self::$url;
}
static function getPricesURL()
{
return self::$url . 'prices.json.php';
}
public function getDescription()
{
$desc = "Optimize video visibility with AI-driven meta-tag suggestions and automatic transcription for enhanced SEO performance.";
$desc .= "
You can overprice AI request prices and generate income from users who utilize these AI services.";
$help = "
Help";
$help .= "
AI Services Pricing";
//$desc .= $this->isReadyLabel(array('YPTWallet'));
return $desc . $help;
}
public function getName()
{
return "AI";
}
public function getUUID()
{
return "AI-5ee8405eaaa16";
}
public function getPluginVersion()
{
return "6.0";
}
public function getEmptyDataObject()
{
$obj = new stdClass();
$obj->AccessToken = "";
$obj->priceForBasic = 0;
self::addDataObjectHelper('priceForBasic', 'Price for Basic 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->priceForTranscription = 0;
self::addDataObjectHelper('priceForTranscription', 'Price for Transcription 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->priceForTranslation = 0;
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 per second 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;
self::addDataObjectHelper('autoProcessAll', 'Auto Process All', "This will create the transcription + basic + shorts automatically for all new videos");
/*
$obj->textSample = "text";
$obj->checkboxSample = true;
$obj->numberSample = 5;
$o = new stdClass();
$o->type = array(0=>__("Default"))+array(1,2,3);
$o->value = 0;
$obj->selectBoxSample = $o;
$o = new stdClass();
$o->type = "textarea";
$o->value = "";
$obj->textareaSample = $o;
*/
return $obj;
}
static function getVideoShortsMetadata($videos_id)
{
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 (!isCommandLineInterface() && !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;
}
$video = new Video('', '', $videos_id);
$filename = $video->getFilename();
if (AVideoPlugin::isEnabledByName('SubtitleSwitcher')) {
SubtitleSwitcher::transcribe($videos_id, false);
}
$firstVTTPath = AI::getFirstVTTFile($videos_id);
$vttURL = str_replace($global['systemRootPath'], $global['webSiteRootURL'], $firstVTTPath);
//var_dump($paths);exit;
$obj->response = array(
'type' => AI::$typeTranslation,
'vtt' => $vttURL,
//'firstVTTPath' => $firstVTTPath,
'lang' => $lang,
'langName' => $langName
);
$obj->error = false;
return $obj;
}
static function getVideoBasicMetadata($videos_id)
{
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 (!isCommandLineInterface() && !Video::canEdit($videos_id)) {
$obj->msg = 'you cannot edit this video';
return $obj;
}
$video = new Video('', '', $videos_id);
$filename = $video->getFilename();
if (AVideoPlugin::isEnabledByName('SubtitleSwitcher')) {
SubtitleSwitcher::transcribe($videos_id, false);
}
/*
*/
$firstVTTPath = AI::getFirstVTTFile($videos_id);
$vttURL = str_replace(getVideosDir(), $global['webSiteRootURL'], $firstVTTPath);
//var_dump($paths);exit;
$obj->response = array(
'type' => AI::$typeBasic,
'filename' => $filename,
'videos_id' => $videos_id,
'title' => strip_tags($video->getTitle()),
'description' => strip_tags($video->getDescription()),
'duration_in_seconds' => $video->getDuration_in_seconds(),
'vtt' => $vttURL,
'text' => Ai_responses::getTranscriptionText($videos_id)
);
$obj->error = false;
return $obj;
}
static function getVideoTranscriptionMetadata($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;
$mp3s = self::getLowerMP3($videos_id);
$fsize = 0;
if ($mp3s['isValid']) {
$mp3 = $mp3s['lower']['paths']['url'];
$fsize = filesize($mp3s['lower']['paths']['path']);
}
//var_dump($paths);exit;
$obj->response = array(
'type' => AI::$typeTranscription,
'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 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;
$obj = new stdClass();
$obj->videos_id = $videos_id;
$obj->users_id = User::getId();
$obj->ai_responses_id = $ai_responses_id;
$obj->param = $param;
$obj->created = time();
return encryptString(_json_encode($obj));
}
static function getTokenFromRequest()
{
if (empty($_REQUEST['token'])) {
return false;
}
$string = decryptString($_REQUEST['token']);
if (empty($string)) {
return false;
}
$json = _json_decode($string);
if (empty($json)) {
return false;
}
return $json;
}
static function getMP3Path($videos_id)
{
$convert = convertVideoToMP3FileIfNotExists($videos_id);
if (empty($convert) || empty($convert['url'])) {
return false;
}
return $convert;
}
static function getMP3LowerPath($videos_id)
{
$convert = self::getMP3Path($videos_id);
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)
{
$arrayRegular = array(
'paths' => false,
'duration' => false,
'durationInSeconds' => 0,
'isValid' => false,
);
$arrayLower = array(
'paths' => false,
'duration' => false,
'durationInSeconds' => 0,
'isValid' => false,
);
$paths = self::getMP3Path($videos_id);
if (!empty($paths)) {
if (filesize($paths['path']) < 20) {
// it is a dummy file, try the Storage URL
$duration = getDurationFromFile($paths['url']);
} else {
$duration = getDurationFromFile($paths['path']);
}
$durationInSeconds = durationToSeconds($duration);
$video = new Video('', '', $videos_id);
$videoDuration = $video->getDuration_in_seconds();
$diff = abs($videoDuration - $durationInSeconds);
$tenPercentOfVideoDuration = $videoDuration * 0.1; // 10% of $videoDuration
if ($diff > $tenPercentOfVideoDuration) {
$f = convertVideoFileWithFFMPEGIsLockedInfo($paths['path']);
if ($f['isUnlocked']) {
_error_log('getMP3RegularAndLower: unlink line=' . __LINE__);
unlink($paths['path']);
$response = array(
'regular' => $arrayRegular,
'lower' => $arrayLower,
'isValid' => false,
'msg' => "Length does not match (Video/MP3) video = {$videoDuration} seconds MP3 = $durationInSeconds seconds",
);
} else {
$response = array(
'regular' => $arrayRegular,
'lower' => $arrayLower,
'isValid' => true,
'msg' => "The MP3 file is processing",
);
}
return $response;
}
$arrayRegular = array(
'paths' => $paths,
'duration' => $duration,
'durationInSeconds' => $durationInSeconds,
'isValid' => !empty($durationInSeconds),
);
$pathsLower = self::getMP3LowerPath($videos_id);
if (!empty($pathsLower)) {
$duration = getDurationFromFile($pathsLower['path']);
if ($duration == "EE:EE:EE" && !empty($pathsLower['url'])) {
$duration = getDurationFromFile($pathsLower['url']);
if ($duration == "EE:EE:EE") {
$pathsLower['url'] = str_replace('_Low.mp3', '.mp3', $pathsLower['url']);
$duration = getDurationFromFile($pathsLower['url']);
}
}
$durationInSeconds = durationToSeconds($duration);
$arrayLower = array(
'paths' => $pathsLower,
'duration' => $duration,
'durationInSeconds' => $durationInSeconds,
'isValid' => !empty($durationInSeconds),
);
$pathsLower = self::getMP3LowerPath($videos_id);
}
}
$msg = '';
$isValid = false;
if ($arrayRegular['isValid'] && $arrayLower['isValid']) {
$f = convertVideoFileWithFFMPEGIsLockedInfo($arrayRegular['paths']['path']);
_error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayRegular['paths']['path']}) arrayRegular " . json_encode($f));
if (!$f['isUnlocked']) {
$msg = "The original audio is processing";
} else {
$f = convertVideoFileWithFFMPEGIsLockedInfo($arrayLower['paths']['path']);
_error_log("convertVideoFileWithFFMPEGIsLockedInfo({$arrayLower['paths']['path']}) arrayLower " . json_encode($f));
if (!$f['isUnlocked']) {
$msg = "The audio is processing";
} else {
$diff = abs($arrayRegular['durationInSeconds'] - $arrayLower['durationInSeconds']);
if ($diff <= 2) {
$isValid = true;
} else {
$msg = "durationInSeconds are not the same regular={$arrayRegular['durationInSeconds']} lower={$arrayLower['durationInSeconds']}";
}
}
}
} else {
if (!$arrayRegular['isValid']) {
$msg = 'Regular MP3 is invalid';
}
if (!$arrayRegular['isValid']) {
$msg .= ' Lower MP3 is invalid';
}
}
$response = array(
'regular' => $arrayRegular,
'lower' => $arrayLower,
'isValid' => $isValid,
'msg' => $msg,
);
return $response;
}
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);
set_time_limit(300);
if (file_exists($mp3s['lower']['paths']['path']) && filesize($mp3s['lower']['paths']['path']) > 20) {
_error_log('getLowerMP3: unlink line=' . __LINE__);
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 64k {$toFileLocationEscaped}";
$command = removeUserAgentIfNotURL($command);
exec($command, $output);
_error_log('getLowerMP3: ' . json_encode($output));
return self::getMP3RegularAndLower($videos_id);
}
} else {
return $mp3s;
}
return $mp3s;
}
public function getPluginMenu()
{
global $global;
return '';
}
public function getVideosManagerListButton()
{
$obj = $this->getDataObject();
$btn = '';
if (AI::canUseAI()) {
$btn .= '';
}
return $btn;
}
public static function getTagTypeId()
{
$VideoTags = AVideoPlugin::isEnabledByName('VideoTags');
if (empty($VideoTags)) {
return false;
}
$typeName = 'Keywords';
$row = TagsTypes::getFromName($typeName);
if (empty($row)) {
$tagType = new TagsTypes(0);
$tagType->setName($typeName);
return $tagType->save();
} else {
return $row['id'];
}
}
static function deleteAllRecords()
{
$tables = array('ai_transcribe_responses', 'ai_metatags_responses', 'ai_responses');
foreach ($tables as $key => $value) {
$sql = "DELETE FROM {$value} ";
$sql .= " WHERE id > 0 ";
$global['lastQuery'] = $sql;
sqlDAL::writeSql($sql);
}
return true;
}
static function getVTTLanguageCodes($videos_id)
{
$video = new Video('', '', $videos_id);
$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)) {
$languageCodes[] = $matches[1]; // Add the language code to the array
}
}
closedir($handle);
}
return array_unique($languageCodes); // Return unique language codes
}
public function getFooterCode()
{
global $global;
include $global['systemRootPath'] . 'plugin/AI/footer.php';
}
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)
{
$vttFiles = self::getVTTFiles($videos_id);
if (empty($vttFiles)) {
return false;
}
return $vttFiles[0];
}
static function getProgressBarHTML($classname, $text)
{
return '