1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-03 09:49:28 +02:00
This commit is contained in:
Daniel Neto 2024-09-06 21:07:27 -03:00
parent 85a6a85967
commit d246ee5013
10 changed files with 260 additions and 24 deletions

3
.gitignore vendored
View file

@ -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*

View file

@ -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();
}
}

View file

@ -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)) {
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);
}
}

View file

@ -4059,7 +4059,7 @@ if (!class_exists('Video')) {
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 @@ if (!class_exists('Video')) {
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 @@ if (!class_exists('Video')) {
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 @@ if (!class_exists('Video')) {
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 @@ if (!class_exists('Video')) {
$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}";
}

View file

@ -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 @@ class AI extends PluginAbstract
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 @@ class AI extends PluginAbstract
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 @@ class AI extends PluginAbstract
$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 @@ class AI extends PluginAbstract
$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 @@ class AI extends PluginAbstract
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 @@ class AI extends PluginAbstract
_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();

View file

@ -34,6 +34,7 @@ $priceForBasic = $objAI->priceForBasic;
$priceForTranscription = $objAI->priceForTranscription;
$priceForTranslation = $objAI->priceForTranslation;
$priceForShorts = $objAI->priceForShorts;
$priceForDubbing = $objAI->priceForDubbing;
$priceForAll = $priceForTranscription + $priceForBasic + $priceForShorts;
$priceForBasicText = YPTWallet::formatCurrency($priceForBasic);
@ -41,6 +42,7 @@ $priceForTranscriptionText = YPTWallet::formatCurrency($priceForTranscription);
$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 @@ $_page = new Page(['Video Metatags']);
<?php echo __("Shorts"); ?>
</a>
</li>
<li>
<a data-toggle="tab" href="#pDubbing">
<i class="fa-solid fa-headphones"></i>
<?php echo __("Dubbing"); ?>
</a>
</li>
<?php
if (User::isAdmin()) {
?>
@ -205,6 +213,11 @@ $_page = new Page(['Video Metatags']);
include $global['systemRootPath'] . 'plugin/AI/tabs/shorts.php';
?>
</div>
<div id="pDubbing" class="tab-pane fade">
<?php
include $global['systemRootPath'] . 'plugin/AI/tabs/Dubbing.php';
?>
</div>
<?php
if (User::isAdmin()) {
?>

View file

@ -4,7 +4,7 @@ require_once '../../videos/configuration.php';
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 @@ switch ($_REQUEST['type']) {
$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__);

103
plugin/AI/tabs/dubbing.php Normal file
View file

@ -0,0 +1,103 @@
<?php
$paths = AI::getMP3Path($videos_id);
$mp3Exists = !empty($paths['path']) && file_exists($paths['path']);
$hlsIsEnabled = AVideoPlugin::loadPluginIfEnabled('VideoHLS');
?>
<div class="panel panel-default">
<div class="panel-heading">
<!-- This feature works with HLS plugin and requires an HLS video -->
<h4>Generate Dubbing for HLS Video</h4>
</div>
<div class="panel-body">
<?php if (!$mp3Exists): ?>
<div class="alert alert-danger">
<strong>Error:</strong> MP3 file is missing. Please ensure that the video has an MP3 version available for dubbing.
</div>
<?php elseif (!$hlsIsEnabled): ?>
<div class="alert alert-danger">
<strong>Error:</strong> The HLS plugin is not enabled. Please enable the HLS plugin to use this feature.
</div>
<?php else: ?>
<div class="row">
<div class="col-sm-12">
<p>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.</p>
</div>
<div class="col-sm-3">
<label for="transcribeLang">Select Language for Dubbing:</label>
<select class="form-control" name="transcribeLang" id="transcribeLang" required>
<?php
foreach (AI::DubbingLANGS as $key => $value) {
echo "<option value=\"{$value['code']}\">{$value['name']}</option>";
}
?>
</select>
</div>
<div class="col-sm-9">
<label>&nbsp;</label>
<button class="btn btn-success btn-block" onclick="generateDubbing()">
<i class="fas fa-microphone-alt"></i> <?php echo __('Generate Dubbing') ?>
<?php
if (!empty($priceForDubbing)) {
echo "<br><span class=\"label label-success\">{$priceForDubbingText}</span>";
}
?>
</button>
<p class="help-block">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.</p>
</div>
<hr class="col-sm-12">
<small class="col-sm-12 text-muted">
<strong>Note:</strong> 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.
</small>
</div>
<?php endif; ?>
</div>
<div class="panel-footer" id="transcriptionFooter">
<!-- Status messages and results will appear here -->
<p id="dubbingStatus" class="text-info">Dubbing status and results will be displayed here once the process begins.</p>
</div>
</div>
<script>
var hasTranscriptionRecord = false;
async function generateDubbing() {
await createAIDubbing();
loadAIUsage();
}
async function createAIDubbing() {
return new Promise((resolve, reject) => {
modalContinueAISuggestions.showPleaseWait();
$.ajax({
url: webSiteRootURL + 'plugin/AI/async.json.php',
data: {
videos_id: <?php echo $videos_id; ?>,
type: '<?php echo AI::$typeDubbing; ?>',
language: $('#transcribeLang').val()
},
type: 'post',
success: function(response) {
modalContinueAISuggestions.hidePleaseWait();
if (response.error) {
avideoAlertError(response.msg);
reject(response.msg);
} else {
avideoToast(response.msg);
resolve();
}
},
complete: function(resp) {
const response = resp.responseJSON;
console.log(response);
modalContinueAISuggestions.hidePleaseWait();
if (response.error) {
avideoAlertError(response.msg);
reject(response.msg);
}
}
});
});
}
</script>

View file

@ -143,4 +143,5 @@ echo AVideoPlugin::afterVideoJS();
$(document).ready(function() {
loadAIShorts();
});
var autoplay = false;var forceautoplay = false;var forceNotautoplay = true;
</script>

View file

@ -36,7 +36,7 @@ $columnCallbackFunctions = ['text'];
</div>
<?php
echo AI::getProgressBarHTML("transcription_{$videos_id}", __('Automatic'));
foreach (AI::$languages as $key => $value) {
foreach (AI::LANGS as $key => $value) {
echo AI::getProgressBarHTML("transcription_{$key}_{$videos_id}", $value);
}
?>
@ -83,7 +83,7 @@ $columnCallbackFunctions = ['text'];
<select class="form-control" name="transcribeLang" id="transcribeLang">
<option value=""><?php echo __("Automatic"); ?></option>
<?php
foreach (AI::$languages as $key => $value) {
foreach (AI::LANGS as $key => $value) {
echo "<option value=\"{$key}\">{$value}</option>";
}
?>