mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-03 01:39:24 +02:00
Implement AI image generation feature and enhance image handling in video library
This commit is contained in:
parent
0f6b38e7c7
commit
9b438e96e5
17 changed files with 403 additions and 79 deletions
|
@ -154,7 +154,11 @@ $croppieFilesAdded = 1;
|
||||||
|
|
||||||
$('#library-btn<?php echo $uid; ?>').off('click');
|
$('#library-btn<?php echo $uid; ?>').off('click');
|
||||||
$('#library-btn<?php echo $uid; ?>').on('click', function(ev) {
|
$('#library-btn<?php echo $uid; ?>').on('click', function(ev) {
|
||||||
avideoModalIframe(webSiteRootURL + 'view/list-images.php?uid=<?php echo $uid; ?>');
|
var url = webSiteRootURL + 'view/list-images.php?uid=<?php echo $uid; ?>';
|
||||||
|
if (typeof mediaId == 'number' && !empty(mediaId)) {
|
||||||
|
url = addQueryStringParameter(url, 'videos_id', mediaId);
|
||||||
|
}
|
||||||
|
avideoModalIframe(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7485,6 +7485,80 @@ if (!class_exists('Video')) {
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function saveImageInVideoLib($videos_id, $imageContent, $imageExt = 'png', $prefix = '')
|
||||||
|
{
|
||||||
|
global $global;
|
||||||
|
if (empty($videos_id) || empty($imageContent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$video = Video::getVideoLight($videos_id);
|
||||||
|
if (empty($video)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$imageExt = preg_replace('/[^a-zA-Z0-9]/', '', $imageExt);
|
||||||
|
$imageName = $prefix .'_'. uniqid() . ".{$imageExt}";
|
||||||
|
$relativeDir = Video::getVideoLibRelativePath($videos_id);
|
||||||
|
$path = "{$global['systemRootPath']}{$relativeDir}{$imageName}";
|
||||||
|
|
||||||
|
if (_file_put_contents($path, $imageContent)) {
|
||||||
|
_error_log("Video::saveImageInVideoLib({$videos_id}, {$imageExt}) saved in {$path}");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
_error_log("Video::saveImageInVideoLib({$videos_id}, {$imageExt}) could not save in {$path}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getVideoLibRelativePath($videos_id)
|
||||||
|
{
|
||||||
|
if (empty($videos_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$video = Video::getVideoLight($videos_id);
|
||||||
|
if (empty($video)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$relativeDir = "videos/{$video['filename']}/images/";
|
||||||
|
return $relativeDir;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static function listAllImagesInVideoLib($videos_id)
|
||||||
|
{
|
||||||
|
global $global;
|
||||||
|
if (empty($videos_id)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$video = Video::getVideoLight($videos_id);
|
||||||
|
if (empty($video)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$relativeDir = Video::getVideoLibRelativePath($videos_id);
|
||||||
|
$path = "{$global['systemRootPath']}{$relativeDir}";
|
||||||
|
if (!is_dir($path)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$images = [];
|
||||||
|
$files = scandir($path);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (preg_match('/\.(jpg|jpeg|png|gif)$/i', $file)) {
|
||||||
|
$images[] = [
|
||||||
|
'name' => $file,
|
||||||
|
'url' => "{$global['webSiteRootURL']}{$relativeDir}{$file}",
|
||||||
|
'path' => "{$path}{$file}"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $images;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Just to convert permalink into clean_title
|
// Just to convert permalink into clean_title
|
||||||
|
|
|
@ -16,6 +16,7 @@ class AI extends PluginAbstract
|
||||||
static $typeTranslation = 'translation';
|
static $typeTranslation = 'translation';
|
||||||
static $typeTranscription = 'transcription';
|
static $typeTranscription = 'transcription';
|
||||||
static $typeBasic = 'basic';
|
static $typeBasic = 'basic';
|
||||||
|
static $typeImage = 'image';
|
||||||
static $typeShorts = 'shorts';
|
static $typeShorts = 'shorts';
|
||||||
static $typeDubbing = 'dubbing';
|
static $typeDubbing = 'dubbing';
|
||||||
|
|
||||||
|
@ -845,6 +846,10 @@ class AI extends PluginAbstract
|
||||||
_error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__);
|
_error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__);
|
||||||
$obj = AI::getVideoDubbingMetadata($videos_id, @$_REQUEST['language']);
|
$obj = AI::getVideoDubbingMetadata($videos_id, @$_REQUEST['language']);
|
||||||
break;
|
break;
|
||||||
|
case AI::$typeImage:
|
||||||
|
_error_log('AI:asyncVideosId typeImage ' . basename(__FILE__) . ' line=' . __LINE__);
|
||||||
|
$obj = AI::getVideoBasicMetadata($videos_id);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__);
|
_error_log('AI:asyncVideosId ' . basename(__FILE__) . ' line=' . __LINE__);
|
||||||
$obj = new stdClass();
|
$obj = new stdClass();
|
||||||
|
|
|
@ -75,14 +75,55 @@ class Ai_responses extends ObjectYPT
|
||||||
return intval($this->videos_id);
|
return intval($this->videos_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPrice($price) {
|
function setPrice($price)
|
||||||
|
{
|
||||||
$this->price = floatval($price);
|
$this->price = floatval($price);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrice() {
|
function getPrice()
|
||||||
|
{
|
||||||
return floatval($this->price);
|
return floatval($this->price);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function getAllImageFromVideo($videos_id)
|
||||||
|
{
|
||||||
|
global $global;
|
||||||
|
$sql = "SELECT *
|
||||||
|
FROM ai_responses_json as arj
|
||||||
|
LEFT JOIN ai_responses as ar ON ar.id = arj.ai_responses_id
|
||||||
|
WHERE ar.videos_id = ? AND arj.ai_type = ?";
|
||||||
|
|
||||||
|
$sql .= self::getSqlFromPost('arj.');
|
||||||
|
// var_dump($sql, [$videos_id, AI::$typeImage]);
|
||||||
|
$res = sqlDAL::readSql($sql, 'is', [$videos_id, AI::$typeImage]);
|
||||||
|
$fullData = sqlDAL::fetchAllAssoc($res);
|
||||||
|
//var_dump($sql, $fullData);exit;
|
||||||
|
sqlDAL::close($res);
|
||||||
|
$rows = array();
|
||||||
|
if ($res != false) {
|
||||||
|
foreach ($fullData as $row) {
|
||||||
|
if (!empty($row['response'])) {
|
||||||
|
$row['response'] = _json_decode($row['response']);
|
||||||
|
}
|
||||||
|
//var_dump($row['response']->data[0]->url);
|
||||||
|
$row['url'] = '';
|
||||||
|
if (!empty($row['response']) && !empty($row['response']->data[0]->url)) {
|
||||||
|
$row['url'] = $row['response']->data[0]->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var array $global
|
||||||
|
* @var object $global['mysqli']
|
||||||
|
*/
|
||||||
|
_error_log($sql . ' Error : (' . $global['mysqli']->errno . ') ' . $global['mysqli']->error);
|
||||||
|
}
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
static function getAllBasicFromVideo($videos_id)
|
static function getAllBasicFromVideo($videos_id)
|
||||||
{
|
{
|
||||||
global $global;
|
global $global;
|
||||||
|
@ -100,14 +141,14 @@ class Ai_responses extends ObjectYPT
|
||||||
$rows = array();
|
$rows = array();
|
||||||
if ($res != false) {
|
if ($res != false) {
|
||||||
foreach ($fullData as $row) {
|
foreach ($fullData as $row) {
|
||||||
if(empty($row['videoTitles'])){
|
if (empty($row['videoTitles'])) {
|
||||||
$row['videoTitles'] = array();
|
$row['videoTitles'] = array();
|
||||||
}else if(is_string($row['videoTitles'])){
|
} else if (is_string($row['videoTitles'])) {
|
||||||
$row['videoTitles'] = json_decode($row['videoTitles']);
|
$row['videoTitles'] = json_decode($row['videoTitles']);
|
||||||
}
|
}
|
||||||
if(empty($row['keywords'])){
|
if (empty($row['keywords'])) {
|
||||||
$row['keywords'] = array();
|
$row['keywords'] = array();
|
||||||
}else if(is_string($row['keywords'])){
|
} else if (is_string($row['keywords'])) {
|
||||||
$row['keywords'] = json_decode($row['keywords']);
|
$row['keywords'] = json_decode($row['keywords']);
|
||||||
}
|
}
|
||||||
$rows[] = $row;
|
$rows[] = $row;
|
||||||
|
@ -211,14 +252,14 @@ class Ai_responses extends ObjectYPT
|
||||||
'text');
|
'text');
|
||||||
*/
|
*/
|
||||||
foreach ($fullData as $row) {
|
foreach ($fullData as $row) {
|
||||||
if(empty($row['videoTitles'])){
|
if (empty($row['videoTitles'])) {
|
||||||
$row['videoTitles'] = array();
|
$row['videoTitles'] = array();
|
||||||
}else if(is_string($row['videoTitles'])){
|
} else if (is_string($row['videoTitles'])) {
|
||||||
$row['videoTitles'] = json_decode($row['videoTitles']);
|
$row['videoTitles'] = json_decode($row['videoTitles']);
|
||||||
}
|
}
|
||||||
if(empty($row['keywords'])){
|
if (empty($row['keywords'])) {
|
||||||
$row['keywords'] = array();
|
$row['keywords'] = array();
|
||||||
}else if(is_string($row['keywords'])){
|
} else if (is_string($row['keywords'])) {
|
||||||
$row['keywords'] = json_decode($row['keywords']);
|
$row['keywords'] = json_decode($row['keywords']);
|
||||||
}
|
}
|
||||||
foreach ($cleanKeys as $value) {
|
foreach ($cleanKeys as $value) {
|
||||||
|
@ -265,20 +306,18 @@ class Ai_responses extends ObjectYPT
|
||||||
$fullData = sqlDAL::fetchAllAssoc($res);
|
$fullData = sqlDAL::fetchAllAssoc($res);
|
||||||
sqlDAL::close($res);
|
sqlDAL::close($res);
|
||||||
|
|
||||||
return $fullData ;
|
return $fullData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static function getValidTranscriptions($videos_id)
|
static function getValidTranscriptions($videos_id)
|
||||||
{
|
{
|
||||||
$rows = self::getTranscriptions($videos_id);
|
$rows = self::getTranscriptions($videos_id);
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
if(!empty($row['text'])){
|
if (!empty($row['text'])) {
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,8 +335,7 @@ class Ai_responses extends ObjectYPT
|
||||||
$fullData = sqlDAL::fetchAllAssoc($res);
|
$fullData = sqlDAL::fetchAllAssoc($res);
|
||||||
sqlDAL::close($res);
|
sqlDAL::close($res);
|
||||||
|
|
||||||
return $fullData ;
|
return $fullData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hasTranscriptions($videos_id)
|
static function hasTranscriptions($videos_id)
|
||||||
|
@ -309,7 +347,7 @@ class Ai_responses extends ObjectYPT
|
||||||
static function getTranscriptionText($videos_id)
|
static function getTranscriptionText($videos_id)
|
||||||
{
|
{
|
||||||
$rows = self::getValidTranscriptions($videos_id);
|
$rows = self::getValidTranscriptions($videos_id);
|
||||||
if(!empty($rows)){
|
if (!empty($rows)) {
|
||||||
return $rows['text'];
|
return $rows['text'];
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -318,14 +356,15 @@ class Ai_responses extends ObjectYPT
|
||||||
static function getTranscriptionVtt($videos_id)
|
static function getTranscriptionVtt($videos_id)
|
||||||
{
|
{
|
||||||
$rows = self::getValidTranscriptions($videos_id);
|
$rows = self::getValidTranscriptions($videos_id);
|
||||||
if(!empty($rows)){
|
if (!empty($rows)) {
|
||||||
//_error_log("AI::getTranscriptionVtt($videos_id) ".json_encode($rows['vtt']));
|
//_error_log("AI::getTranscriptionVtt($videos_id) ".json_encode($rows['vtt']));
|
||||||
return $rows['vtt'];
|
return $rows['vtt'];
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static function getLatest($videos_id) {
|
static function getLatest($videos_id)
|
||||||
|
{
|
||||||
global $global;
|
global $global;
|
||||||
$sql = "SELECT tr.*, mr.*, r.* FROM ai_responses r
|
$sql = "SELECT tr.*, mr.*, r.* FROM ai_responses r
|
||||||
LEFT JOIN ai_transcribe_responses tr ON tr.ai_responses_id = r.id
|
LEFT JOIN ai_transcribe_responses tr ON tr.ai_responses_id = r.id
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
loadAIShorts();
|
loadAIShorts();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '<?php echo AI::$typeImage; ?>':
|
||||||
|
if (typeof loadAIImage == 'function') {
|
||||||
|
loadAIImage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,12 @@ $_page = new Page(['Video Metatags']);
|
||||||
<?php echo __("Basic"); ?>
|
<?php echo __("Basic"); ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a data-toggle="tab" href="#pimage">
|
||||||
|
<i class="fa-solid fa-image"></i>
|
||||||
|
<?php echo __("Image"); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a data-toggle="tab" href="#pShorts">
|
<a data-toggle="tab" href="#pShorts">
|
||||||
<i class="fa-solid fa-scissors"></i>
|
<i class="fa-solid fa-scissors"></i>
|
||||||
|
@ -208,6 +214,11 @@ $_page = new Page(['Video Metatags']);
|
||||||
include $global['systemRootPath'] . 'plugin/AI/tabs/basic.php';
|
include $global['systemRootPath'] . 'plugin/AI/tabs/basic.php';
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="pimage" class="tab-pane fade">
|
||||||
|
<?php
|
||||||
|
include $global['systemRootPath'] . 'plugin/AI/tabs/image.php';
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
<div id="pShorts" class="tab-pane fade">
|
<div id="pShorts" class="tab-pane fade">
|
||||||
<?php
|
<?php
|
||||||
include $global['systemRootPath'] . 'plugin/AI/tabs/shorts.php';
|
include $global['systemRootPath'] . 'plugin/AI/tabs/shorts.php';
|
||||||
|
|
|
@ -164,6 +164,26 @@ switch ($_REQUEST['type']) {
|
||||||
//$jsonDecoded->lines[] = __LINE__;
|
//$jsonDecoded->lines[] = __LINE__;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AI::$typeImage:
|
||||||
|
error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__);
|
||||||
|
if (!empty($_REQUEST['response'])) {
|
||||||
|
$o = new Ai_responses_json(0);
|
||||||
|
$o->setResponse($_REQUEST['response']);
|
||||||
|
$o->setAi_type(AI::$typeImage);
|
||||||
|
$o->setAi_responses_id($token->ai_responses_id);
|
||||||
|
if (!empty($_REQUEST['response']['data'][0]['url'])) {
|
||||||
|
$imageContent = file_get_contents($_REQUEST['response']['data'][0]['url']);
|
||||||
|
if (empty($imageContent)) {
|
||||||
|
_error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__ . ' Error fetching image content');
|
||||||
|
} else {
|
||||||
|
Video::saveImageInVideoLib($token->videos_id, $imageContent, 'png', 'ai');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$jsonDecoded->msg = $_REQUEST['msg'];
|
||||||
|
$jsonDecoded->Ai_responses_json = $o->save();
|
||||||
|
$jsonDecoded->error = empty($jsonDecoded->Ai_responses_json);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__);
|
_error_log('AI: ' . basename(__FILE__) . ' line=' . __LINE__);
|
||||||
|
|
|
@ -1,11 +1,24 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info" style="border-left: 5px solid #31708f; padding-left: 20px;">
|
||||||
<h4><strong>Enhance Your Video SEO with AI</strong></h4>
|
<h4 class="text-primary" style="margin-top: 0;">
|
||||||
<p>We're excited to announce a new AI-driven feature to enhance your video SEO! This tool will automatically suggest optimized <strong>Titles, Casual Descriptions, Professional Descriptions, Meta Descriptions, Keywords, Summaries, Ratings, and Rating Justifications</strong> for your videos.</p>
|
<strong><i class="fas fa-rocket"></i> Boost Your Video SEO with AI</strong>
|
||||||
<p>Our AI analyzes your video's existing title and description to generate these SEO elements. For even more precise and tailored suggestions, we recommend providing a <i class="fas fa-microphone-alt"></i> <?php echo __("Transcription"); ?> of your video. This additional information allows our AI to better understand and optimize your content for search engines, boosting your video's visibility and reach.</p>
|
</h4>
|
||||||
<p>Start leveraging the power of AI to make your videos stand out in search results!</p>
|
<p>
|
||||||
|
We're pleased to introduce an <strong>AI-powered SEO enhancement tool</strong> for your videos.
|
||||||
|
This new feature intelligently generates optimized:
|
||||||
|
<em>Titles, Descriptions (Casual & Professional), Meta Descriptions, Keywords, Summaries, Ratings, and Justifications</em>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
By analyzing your video's current title and description, our AI delivers tailored SEO suggestions
|
||||||
|
to maximize discoverability. For the most accurate results, we recommend including a
|
||||||
|
<i class="fas fa-microphone-alt"></i> <strong><?php echo __("Transcription"); ?></strong> of your video — enabling deeper content understanding.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Start using AI to elevate your content and stand out in search results.</strong>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
echo AI::getProgressBarHTML("basic_{$videos_id}", '');
|
echo AI::getProgressBarHTML("basic_{$videos_id}", '');
|
||||||
?>
|
?>
|
||||||
|
@ -24,7 +37,7 @@
|
||||||
<button class="btn btn-success btn-block" onclick="generateAIIdeas()">
|
<button class="btn btn-success btn-block" onclick="generateAIIdeas()">
|
||||||
<i class="fa-solid fa-lightbulb"></i> <?php echo __('Generate Basic Ideas') ?>
|
<i class="fa-solid fa-lightbulb"></i> <?php echo __('Generate Basic Ideas') ?>
|
||||||
<?php
|
<?php
|
||||||
if(!empty($priceForBasic)){
|
if (!empty($priceForBasic)) {
|
||||||
echo "<br><span class=\"label label-success\">{$priceForBasicText}</span>";
|
echo "<br><span class=\"label label-success\">{$priceForBasicText}</span>";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
32
plugin/AI/tabs/image.json.php
Normal file
32
plugin/AI/tabs/image.json.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
require_once '../../../videos/configuration.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$videos_id = getVideos_id();
|
||||||
|
if (empty($videos_id)) {
|
||||||
|
forbiddenPage('Videos ID is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AVideoPlugin::isEnabledByName('AI')) {
|
||||||
|
forbiddenPage('AI plugin is disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!AI::canUseAI()){
|
||||||
|
forbiddenPage('You cannot use AI');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Video::canEdit($videos_id)) {
|
||||||
|
forbiddenPage('You cannot edit this video');
|
||||||
|
}
|
||||||
|
setRowCount(100);
|
||||||
|
$video = new Video('', '', $videos_id);
|
||||||
|
setDefaultSort('created', 'DESC');
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->msg = '';
|
||||||
|
$obj->videos_id = $videos_id;
|
||||||
|
$obj->response = Ai_responses::getAllImageFromVideo($videos_id);
|
||||||
|
$obj->error = empty($obj->response) && !is_array($obj->response);
|
||||||
|
$obj->images = Video::listAllImagesInVideoLib($videos_id);
|
||||||
|
|
||||||
|
echo _json_encode($obj);
|
79
plugin/AI/tabs/image.php
Normal file
79
plugin/AI/tabs/image.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div class="alert alert-info" style="border-left: 5px solid #31708f; padding-left: 20px;">
|
||||||
|
<p>
|
||||||
|
<strong><i class="fas fa-image"></i> AI-Generated Image Preview:</strong> We use your video's <strong>title</strong> and <strong>description</strong> to create a unique and visually engaging AI-generated image.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
These images are designed to enhance your content’s visual appeal — ideal for use as thumbnails, background posters, or video covers.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
For the best results, ensure your title and description clearly reflect the main subject or mood of the video.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php echo AI::getProgressBarHTML("image_{$videos_id}", ''); ?>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="ai-images" class="row">
|
||||||
|
<!-- As imagens serão carregadas aqui -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<button class="btn btn-success btn-block" onclick="generateAIImages()">
|
||||||
|
<i class="fa fa-images"></i> <?php echo __('Generate Image') ?>
|
||||||
|
<?php
|
||||||
|
if (!empty($priceForBasic)) {
|
||||||
|
echo "<br><span class=\"label label-success\">{$priceForBasicText}</span>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function generateAIImages() {
|
||||||
|
await createAISuggestions('<?php echo AI::$typeImage; ?>');
|
||||||
|
loadAIImage();
|
||||||
|
loadAIUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAIImage() {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AI/tabs/image.json.php',
|
||||||
|
data: {
|
||||||
|
videos_id: <?php echo $videos_id; ?>
|
||||||
|
},
|
||||||
|
type: 'post',
|
||||||
|
success: function(response) {
|
||||||
|
if (response.error) {
|
||||||
|
avideoAlertError(response.msg);
|
||||||
|
} else {
|
||||||
|
const container = $('#ai-images');
|
||||||
|
container.empty();
|
||||||
|
|
||||||
|
response.images.forEach(function(item) {
|
||||||
|
const imgURL = item.url;
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<div class="col-xs-12 col-sm-6 col-md-4 text-center" style="margin-bottom: 15px;">
|
||||||
|
<a href="${imgURL}" target="_blank">
|
||||||
|
<img src="${imgURL}" class="img img-responsive img-thumbnail" style="margin: 0 auto;"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
container.append(html);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
loadAIImage();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -31,9 +31,16 @@ $columnCallbackFunctions = ['text'];
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info" style="border-left: 5px solid #31708f; padding-left: 20px;">
|
||||||
<p><strong>Note:</strong> To ensure accurate transcription, your videos should contain clear speech. Please be aware that videos without any spoken words, or those containing only sounds and instrumental music, cannot be transcribed by our AI system. Make sure your videos have audible and clear speech to take full advantage of this feature.</p>
|
<p>
|
||||||
|
<strong><i class="fas fa-info-circle"></i> Important:</strong> For accurate transcriptions, your videos must contain clear, audible speech.
|
||||||
|
Please note that videos with no spoken words — or only instrumental music or sound effects — cannot be processed by our AI transcription system.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Ensure that speech is present and understandable in your content to fully benefit from this feature.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
echo AI::getProgressBarHTML("transcription_{$videos_id}", __('Automatic'));
|
echo AI::getProgressBarHTML("transcription_{$videos_id}", __('Automatic'));
|
||||||
foreach (AI::LANGS as $key => $value) {
|
foreach (AI::LANGS as $key => $value) {
|
||||||
|
|
|
@ -40,6 +40,8 @@ foreach ($obj->response as $key => $value) {
|
||||||
}else if(!empty($value['ai_type'])){
|
}else if(!empty($value['ai_type'])){
|
||||||
if($value['ai_type'] === AI::$typeShorts){
|
if($value['ai_type'] === AI::$typeShorts){
|
||||||
$obj->response[$key]['type'] = __('Shorts');
|
$obj->response[$key]['type'] = __('Shorts');
|
||||||
|
}else if($value['ai_type'] === AI::$typeImage){
|
||||||
|
$obj->response[$key]['type'] = __('Image');
|
||||||
}else{
|
}else{
|
||||||
$obj->response[$key]['type'] = "ERROR: {$value['ai_type']} ";
|
$obj->response[$key]['type'] = "ERROR: {$value['ai_type']} ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ $bodyClass = '';
|
||||||
if (!empty($_REQUEST['isClosed'])) {
|
if (!empty($_REQUEST['isClosed'])) {
|
||||||
$bodyClass = 'is-closed';
|
$bodyClass = 'is-closed';
|
||||||
}
|
}
|
||||||
|
// this is to make sure will not play in fullscreen on ios
|
||||||
$global['overrideNative'] = 1;
|
$global['overrideNative'] = 1;
|
||||||
//var_dump($liveVideo, $video['id'], $poster, $sources);exit;
|
//var_dump($liveVideo, $video['id'], $poster, $sources);exit;
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -10,7 +10,13 @@ if (!User::isLogged()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$userId = User::getId();
|
$userId = User::getId();
|
||||||
$relativeDir = "videos/userPhoto/Live/user_{$userId}/";
|
|
||||||
|
if (!empty($_REQUEST['videos_id'])) {
|
||||||
|
$relativeDir = Video::getVideoLibRelativePath($_REQUEST['videos_id']);
|
||||||
|
} else {
|
||||||
|
$relativeDir = "videos/userPhoto/Live/user_{$userId}/";
|
||||||
|
}
|
||||||
|
|
||||||
$absoluteDir = realpath(__DIR__ . "/../{$relativeDir}");
|
$absoluteDir = realpath(__DIR__ . "/../{$relativeDir}");
|
||||||
|
|
||||||
if (!is_dir($absoluteDir)) {
|
if (!is_dir($absoluteDir)) {
|
||||||
|
|
|
@ -6,11 +6,18 @@ if (!User::isLogged()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$userId = User::getId();
|
$userId = User::getId();
|
||||||
|
$videos_id = getVideos_id();
|
||||||
|
|
||||||
// List of relative directories (must end with slash)
|
// List of relative directories (must end with slash)
|
||||||
$relativeDirs = [
|
if($videos_id){
|
||||||
"videos/userPhoto/Live/user_{$userId}/",
|
$relativeDirs = [
|
||||||
];
|
Video::getVideoLibRelativePath($videos_id),
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
$relativeDirs = [
|
||||||
|
"videos/userPhoto/Live/user_{$userId}/",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||||
$images = [];
|
$images = [];
|
||||||
|
@ -19,7 +26,7 @@ foreach ($relativeDirs as $relativeDir) {
|
||||||
$absoluteDir = realpath(__DIR__ . "/../{$relativeDir}");
|
$absoluteDir = realpath(__DIR__ . "/../{$relativeDir}");
|
||||||
|
|
||||||
// Security check: must be valid and inside videos folder
|
// Security check: must be valid and inside videos folder
|
||||||
if (!$absoluteDir || strpos($absoluteDir, realpath(__DIR__ . '/../videos/userPhoto/Live/')) !== 0) {
|
if (!$absoluteDir || strpos($absoluteDir, realpath(__DIR__ . '/../videos/')) !== 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
global $global, $config;
|
global $global, $config;
|
||||||
require_once __DIR__ . '/../videos/configuration.php';
|
require_once __DIR__ . '/../videos/configuration.php';
|
||||||
|
$videos_id = getVideos_id();
|
||||||
$_page = new Page(array('List Categories'));
|
$_page = new Page(array('List Categories'));
|
||||||
?>
|
?>
|
||||||
<link href="<?php echo getURL('view/mini-upload-form/assets/css/style.css'); ?>" rel="stylesheet" />
|
<link href="<?php echo getURL('view/mini-upload-form/assets/css/style.css'); ?>" rel="stylesheet" />
|
||||||
|
@ -9,6 +10,7 @@ $_page = new Page(array('List Categories'));
|
||||||
.image-col {
|
.image-col {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-col img {
|
.image-col img {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +33,7 @@ $_page = new Page(array('List Categories'));
|
||||||
<div id="drop">
|
<div id="drop">
|
||||||
<a><?php echo __("Browse files"); ?></a>
|
<a><?php echo __("Browse files"); ?></a>
|
||||||
<input type="file" name="upl" id="fileInput" multiple accept="image/*" />
|
<input type="file" name="upl" id="fileInput" multiple accept="image/*" />
|
||||||
|
<input type="hidden" name="videos_id" value="<?php echo $videos_id; ?>" />
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<!-- Upload progress shown here -->
|
<!-- Upload progress shown here -->
|
||||||
|
@ -49,8 +52,15 @@ $_page = new Page(array('List Categories'));
|
||||||
<script src="<?php echo getURL('view/mini-upload-form/assets/js/jquery.fileupload.js'); ?>"></script>
|
<script src="<?php echo getURL('view/mini-upload-form/assets/js/jquery.fileupload.js'); ?>"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var videos_id = <?php echo json_encode($videos_id ?: null); ?>;
|
||||||
|
|
||||||
function loadImages() {
|
function loadImages() {
|
||||||
$.getJSON(webSiteRootURL + 'view/list-images.json.php', function(images) {
|
const url = webSiteRootURL + 'view/list-images.json.php';
|
||||||
|
const query = videos_id ? {
|
||||||
|
videos_id: videos_id
|
||||||
|
} : {};
|
||||||
|
|
||||||
|
$.getJSON(url, query, function(images) {
|
||||||
$('#imageGrid').empty();
|
$('#imageGrid').empty();
|
||||||
images.forEach(function(img) {
|
images.forEach(function(img) {
|
||||||
const col = $('<div class="col-xs-6 col-sm-4 col-md-3 text-center image-col"></div>');
|
const col = $('<div class="col-xs-6 col-sm-4 col-md-3 text-center image-col"></div>');
|
||||||
|
@ -62,7 +72,8 @@ $_page = new Page(array('List Categories'));
|
||||||
avideoConfirm(__('Are you sure you want to delete this image?')).then(function(response) {
|
avideoConfirm(__('Are you sure you want to delete this image?')).then(function(response) {
|
||||||
if (response) {
|
if (response) {
|
||||||
$.post(webSiteRootURL + 'view/list-images.delete.json.php', {
|
$.post(webSiteRootURL + 'view/list-images.delete.json.php', {
|
||||||
filename: img.filename
|
filename: img.filename,
|
||||||
|
videos_id: videos_id
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
if (!response.error) {
|
if (!response.error) {
|
||||||
col.remove();
|
col.remove();
|
||||||
|
@ -81,7 +92,8 @@ $_page = new Page(array('List Categories'));
|
||||||
const uid = new URLSearchParams(window.location.search).get('uid');
|
const uid = new URLSearchParams(window.location.search).get('uid');
|
||||||
window.parent.postMessage({
|
window.parent.postMessage({
|
||||||
selectedImageURL: image.data('src'),
|
selectedImageURL: image.data('src'),
|
||||||
croppieUID: uid
|
croppieUID: uid,
|
||||||
|
videos_id: videos_id
|
||||||
}, '*');
|
}, '*');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -91,6 +103,7 @@ $_page = new Page(array('List Categories'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#drop a').click(function() {
|
$('#drop a').click(function() {
|
||||||
$(this).parent().find('input').click();
|
$(this).parent().find('input').click();
|
||||||
|
|
|
@ -13,7 +13,14 @@ if (!User::isLogged()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$userId = User::getId();
|
$userId = User::getId();
|
||||||
$relativeDir = "videos/userPhoto/Live/user_{$userId}/";
|
|
||||||
|
if (!empty($_REQUEST['videos_id'])) {
|
||||||
|
$relativeDir = Video::getVideoLibRelativePath($_REQUEST['videos_id']);
|
||||||
|
} else {
|
||||||
|
$relativeDir = "videos/userPhoto/Live/user_{$userId}/";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$absoluteDir = __DIR__ . '/../' . $relativeDir;
|
$absoluteDir = __DIR__ . '/../' . $relativeDir;
|
||||||
|
|
||||||
make_path($relativeDir);
|
make_path($relativeDir);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue