xiaoai/php_server/app/api/logic/sv/PublishLogic.php

567 lines
22 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\api\logic\sv;
use think\facade\Db;
use app\common\model\sv\SvPublishSetting;
use app\common\model\sv\SvPublishSettingAccount;
use app\common\model\sv\SvAccount;
use app\common\model\sv\SvDevice;
use app\common\model\sv\SvVideoSetting;
use app\common\model\sv\SvVideoTask;
use app\common\model\sv\SvPublishSettingDetail;
use app\common\service\FileService;
/**
* PublishLogic
* @desc 机器人
* @author Qasim
*/
class PublishLogic extends SvBaseLogic
{
protected static $interval = 3600; //视频发布间隔时间(秒)
/**
* @desc 添加机器人
* @param array $params
* @return bool
*/
public static function add(array $params)
{
// 启动事务
Db::startTrans();
try {
$params['user_id'] = self::$uid;
if (is_array($params['accounts'])) {
$params['accounts'] = implode(',', $params['accounts']);
}
if (is_array($params['time_config'])) {
$params['time_config'] = json_encode($params['time_config'], JSON_UNESCAPED_UNICODE);
}
// 添加
$publish = SvPublishSetting::create($params);
if (!$publish->isEmpty()) {
self::batchPushlishAccount($publish, $params);
}
// 提交事务
Db::commit();
self::$returnData = $publish->toArray();
return true;
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
// clogger($e);
self::setError($e->getMessage());
return false;
}
}
/**
* @desc 更新机器人
* @param array $params
* @return bool
*/
public static function update(array $params)
{
Db::startTrans();
try {
// 检查机器人是否存在
$publish = SvPublishSetting::where('id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
if ($publish->isEmpty()) {
self::setError('任务不存在');
return false;
}
//查询任务明细是否存在
$publishDetial = SvPublishSettingDetail::where('publish_id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
if (!$publishDetial->isEmpty()) {
self::setError('任务正在执行中,不能修改');
return false;
}
if (is_array($params['accounts'])) {
$params['accounts'] = implode(',', $params['accounts']);
}
if (is_array($params['time_config'])) {
$params['time_config'] = json_encode($params['time_config'], JSON_UNESCAPED_UNICODE);
}
// 更新
SvPublishSetting::where('id', $publish->id)->update($params);
SvPublishSettingAccount::where('publish_id', $publish->id)->delete();
self::batchPushlishAccount($publish, $params);
Db::commit();
self::$returnData = $publish->refresh()->toArray();
return true;
} catch (\Exception $e) {
Db::rollback();
// clogger($e);
self::setError($e->getMessage());
return false;
}
}
private static function batchPushlishAccount($publish, $params)
{
$insertData = [];
$accounts = explode(',', $params['accounts']);
foreach ($accounts as $key => $account) {
$account = SvAccount::where('account', $account)->limit(1)->find();
$videoSetting = SvVideoSetting::where('id', $params['video_setting_id'])->limit(1)->find();
array_push($insertData, [
'publish_id' => $publish->id,
'user_id' => self::$uid,
'name' => $params['name'],
'account' => $account['account'],
'account_type' => $account['type'],
'device_code' => $account['device_code'],
'video_setting_id' => $params['video_setting_id'],
'publish_start' => $params['publish_start'],
'publish_end' => $params['publish_end'],
'next_publish_time' => self::_getPublishTime($account, $videoSetting['video_count'], 0), //视频发布时间
'count' => $videoSetting['video_count'],
'published_count' => 0,
'status' => 1,
'created_time' => time(),
]);
}
$model = new SvPublishSettingAccount();
$model->saveAll($insertData);
}
public static function change(array $params)
{
$find = SvPublishSettingAccount::where('id', $params['id'])->findOrEmpty();
if ($find->isEmpty()) {
self::setError('任务不存在');
return false;
}
$find->status = $params['status'];
$find->updated_time = time();
$find->save();
self::$returnData = $find->refresh()->toArray();
return true;
}
/**
* @desc 获取机器人详情
* @param array $params
* @return bool
*/
public static function detail(array $params)
{
try {
// 检查机器人是否存在
$publish = SvPublishSetting::field('*')
->where('id', $params['id'])
->where('user_id', self::$uid)
->findOrEmpty();
if ($publish->isEmpty()) {
self::setError('任务不存在');
return false;
}
$publish['accounts'] = explode(',', $publish['accounts']);
$publish['time_config'] = json_decode($publish['time_config'], true);
self::$returnData = $publish->toArray();
return true;
} catch (\Exception $e) {
self::setError($e->getMessage());
return false;
}
}
/**
* @desc 删除机器人
* @param array $params
* @return bool
*/
public static function delete(array $params)
{
Db::startTrans();
try {
// 检查机器人是否存在
$publish = SvPublishSettingAccount::where('id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
if ($publish->isEmpty()) {
self::setError('任务不存在');
return false;
}
//查询任务明细是否存在
// $publishDetial = SvPublishSettingDetail::where('publish_id', $params['id'])->where('user_id', self::$uid)->findOrEmpty();
// if (!$publishDetial->isEmpty()) {
// self::setError('任务正在执行中,不能删除');
// return false;
// }
$publish->delete();
//SvPublishSettingAccount::where('publish_id', $publish->id)->delete();
Db::commit();
return true;
} catch (\Exception $e) {
Db::rollback();
// clogger($e);
self::setError($e->getMessage());
return false;
}
}
public static function recordDetail(array $params)
{
try {
// 检查机器人是否存在
$record = SvPublishSettingDetail::field('*')
->where('id', $params['id'])
->where('user_id', self::$uid)
->findOrEmpty();
if ($record->isEmpty()) {
self::setError('任务记录不存在');
return false;
}
self::$returnData = $record->toArray();
return true;
} catch (\Exception $e) {
self::setError($e->getMessage());
return false;
}
}
public static function recordDelete(array $params)
{
$record = SvPublishSettingDetail::field('*')
->where('id', $params['id'])
->where('user_id', self::$uid)
->findOrEmpty();
if ($record->isEmpty()) {
self::setError('任务记录不存在');
return false;
}
$record->delete();
return true;
}
public static function recordRetry(array $params)
{
try {
if (time() > strtotime($params['retry_time'])) {
self::setError('重试时间不能小于当前时间');
return false;
}
// 检查机器人是否存在
$record = SvPublishSettingDetail::field('*')
->where('id', $params['id'])
->where('user_id', self::$uid)
->findOrEmpty();
if ($record->isEmpty()) {
self::setError('任务记录不存在');
return false;
}
$setting = SvPublishSetting::where('id', $record['publish_id'])->limit(1)->find();
if (empty($setting)) {
self::setError('任务配置不存在');
return false;
}
$time_config = json_decode($setting['time_config'], true);
if (empty($time_config)) {
$time_config = [
[
'start_time' => date('H:i', time() + 600), // 开始时间
'end_time' => '23:59' // 结束时间
]
];
}
$periods = array_map(function ($item) use ($setting) {
return [
'start' => strtotime("{$setting['publish_start']} {$item['start_time']}:00"),
'end' => strtotime("{$setting['publish_end']} {$item['end_time']}:00")
];
}, $time_config);
//print_r($periods);die;
if (strtotime($params['retry_time']) > $periods[0]['end']) {
self::setError('重试时间不在任务时间段内');
return false;
}
$record->status = 0;
$record->publish_time = $params['retry_time'];
$record->save();
self::$returnData = $record->toArray();
return true;
} catch (\Exception $e) {
self::setError($e->getMessage());
return false;
}
}
public static function testAdd(array $params)
{
Db::startTrans();
try {
$device = SvDevice::where('status', 1)->where('user_id', self::$uid)->order('id asc')->limit(1)->findOrEmpty();
if ($device->isEmpty()) {
self::setError('没有在线设备');
return false;
}
if(mb_strlen($params['title'], 'utf-8') > 150){
self::setError('标题不能超过150个字');
return false;
}
if(mb_strlen($params['subtitle'], 'utf-8') > 150){
self::setError('正文不能超过150个字');
return false;
}
$publish = SvPublishSetting::create([
'user_id' => self::$uid,
'name' => empty($params['title']) ? '模拟发布' : $params['title'],
'accounts' => implode(',', $params['accounts']),
'video_setting_id' => 0,
'type' => 3,
'publish_start' => date('Y-m-d', time()),
'publish_end' => date('Y-m-d', time()),
'time_config' => '[]',
'data_type' => 1,
'create_time' => time(),
'update_time' => time()
]);
$url = $params['url'] ?? config('app.app_host') . '/uploads/video/20250517/7b300711-d826-4b46-8b1a-c6eaaa58cbce.mp4';
$insertData = array();
$count = count($params['accounts']);
foreach ($params['accounts'] as $key => $account) {
$account = SvAccount::where('account', $account)->where('user_id', self::$uid)->limit(1)->findOrEmpty();
if($account->isEmpty()){
self::setError("{$account}该账号信息不存在");
return false;
}
$publishAccount = SvPublishSettingAccount::create([
'publish_id' => $publish->id,
'user_id' => self::$uid,
'name' => empty($params['title']) ? '模拟发布' : $params['title'],
'account' => $account['account'],
'account_type' => $account['type'],
'device_code' => $account['device_code'],
'video_setting_id' => 0,
'publish_start' => date('Y-m-d', time()),
'publish_end' => date('Y-m-d', time()),
'next_publish_time' => date('Y-m-d H:i:s', time()), //视频发布时间
'count' => $count,
'published_count' => 0,
'status' => 1,
'data_type' => 1,
'created_time' => time(),
]);
array_push($insertData, [
'publish_id' => $publish->id,
'publish_account_id' => $publishAccount->id,
'video_task_id' => 0, //视频任务id关联sv_video_tas
'user_id' => self::$uid,
'account' => $account['account'],
'account_type' => $account['type'],
'device_code' => $account['device_code'],
'material_id' => 0,
'material_type' => $params['material_type'],
'material_url' => $url,
'material_title' => empty($params['title']) ? ' ' : $params['title'],
'material_tag' => $params['topic'],
'poi' => $params['poi'],
'material_subtitle' => empty($params['subtitle']) ? ' ' : $params['subtitle'],
'task_id' => generate_unique_task_id(),
'platform' => $account['type'],
'status' => 0,
'publish_time' => date('Y-m-d H:i:s', time()), //视频发布时间
'create_time' => time(),
'data_type' => 1
]);
}
//print_r($insertData);die;
if (!empty($insertData)) {
$model = new SvPublishSettingDetail();
$model->saveAll($insertData);
}
Db::commit();
self::$returnData = [];
return true;
} catch (\Exception $e) {
Db::rollback();
self::setError($e->getMessage());
return false;
}
}
public static function setPublishDetail()
{
print_r('执行发布记录拉取任务');
try {
$accounts = SvPublishSettingAccount::alias('pa')
->field('pa.*, ps.publish_start, ps.publish_end, ps.time_config, a.device_code as devicecode')
->join('sv_video_setting vs', 'vs.id = pa.video_setting_id and vs.user_id = pa.user_id')
->join('sv_publish_setting ps', 'ps.id = pa.publish_id and ps.user_id = pa.user_id')
->join('sv_account a', 'a.account = pa.account and a.user_id = pa.user_id')
//->join('sv_device d', 'd.device_code = pa.device_code and d.user_id = pa.user_id')
->where('pa.status', 1)
->where('vs.status', 'in', [3, 5])
//->order('ps.id desc')
->select()->toArray();
print_r(Db::getLastSql());
print_r("count: " . count($accounts));
$insertData = [];
$videoIds = [];
foreach ($accounts as $key => $account) {
$videos = SvVideoTask::alias('vs')
->field('vs.*')
->where('vs.video_setting_id', $account['video_setting_id'])
->where('vs.user_id', $account['user_id'])
->where('vs.status', 6)
// ->where('vs.id', 'not in', function($query) use($account){
// $query->name('sv_publish_setting_detail')->field('video_task_id')->where('user_id', $account['user_id'])->select();
// })
//->fetchSql(true)
->select()
->toArray();
//print_r($videos);die;
$videoCount = count($videos);
foreach ($videos as $key => $video) {
$detail = SvPublishSettingDetail::where('publish_id', $account['publish_id'])
->where('publish_account_id', $account['id'])
->where('video_task_id', $video['id'])
->where('user_id', $account['user_id'])
->where('account', $account['account'])
->find();
if (empty($detail)) {
array_push($insertData, [
'publish_id' => $account['publish_id'],
'publish_account_id' => $account['id'],
'video_task_id' => $video['id'], //视频任务id关联sv_video_tas
'user_id' => $account['user_id'],
'account' => $account['account'],
'account_type' => $account['account_type'],
'device_code' => $account['devicecode'],
'material_id' => $video['id'],
'material_type' => 1,
'material_url' => FileService::getFileUrl($video['video_result_url']),
'material_title' => $video['name'],
'material_tag' => $video['topic'],
'poi' => $video['poi'],
'material_subtitle' => $video['name'],
'task_id' => generate_unique_task_id(),
'platform' => $account['account_type'],
'status' => 0,
'publish_time' => self::_getPublishTime($account, $videoCount, $key),
'create_time' => time()
]);
array_push($videoIds, $video['id']);
}
}
//print_r($insertData);die;
}
//print_r($insertData);die;
if (!empty($insertData)) {
$model = new SvPublishSettingDetail();
$model->saveAll($insertData);
}
self::$returnData = $insertData;
return true;
} catch (\Exception $e) {
print_r($e);
die;
return false;
}
}
/**
* 计算发布时间
* @param array $account 机器人账号信息
* @param int $videoCount 视频数量
* @param int $num 视频序号
* @param int $type 视频发布时间分配方式 1:循环分配 2:平均分配
* @return string 发布时间
*/
private static function _getPublishTime($account, int $videoCount, int $num, int $type = 1)
{
$account['time_config'] = json_decode($account['time_config'], true);
try {
if (empty($account['time_config'])) {
$account['time_config'] = [
[
'start_time' => date('H:i', time() + 600), // 开始时间
'end_time' => '23:59' // 结束时间
]
];
}
$timeConfig = $account['time_config'];
// 时间配置解析
$periods = array_map(function ($item) use ($account) {
return [
'start' => strtotime("{$account['publish_start']} {$item['start_time']}:00"),
'end' => strtotime("{$account['publish_end']} {$item['end_time']}:00")
];
}, $timeConfig);
if ($type == 1) {
$periodCount = count($periods);
$currentPeriod = $num % $periodCount; // 当前视频所属时段索引
// 计算当前时段内的视频序号从0开始
$periodVideoNum = (int)($num / $periodCount);
// 每个时段的总视频数(向上取整)
$videosPerPeriod = ceil($videoCount / $periodCount);
// 计算时间间隔(+1保证首尾留空
$interval = ($periods[$currentPeriod]['end'] - $periods[$currentPeriod]['start']) / ($videosPerPeriod + 1);
// 生成精确时间戳(秒级精度)
$timestamp = $periods[$currentPeriod]['start'] + ($periodVideoNum + 1) * $interval;
// 确保时间不超过当前时段
$timestamp = min($timestamp, $periods[$currentPeriod]['end'] - 1);
return date('Y-m-d H:i:s', $timestamp);
} else if ($type == 2) {
// 计算各时间段分配数量
$periodCount = count($periods);
$baseCount = floor($videoCount / $periodCount);
$extra = $videoCount % $periodCount;
// 生成时间点
$timestamps = [];
foreach ($periods as $index => $period) {
$count = $baseCount + ($index < $extra ? 1 : 0);
$duration = $period['end'] - $period['start'];
$interval = $duration / ($count + 1);
for ($i = 1; $i <= $count; $i++) {
$timestamps[] = $period['start'] + $interval * $i;
}
}
// 获取当前视频序号对应的时间
return isset($timestamps[$num]) ? date('Y-m-d H:i:s', $timestamps[$num]) : date('Y-m-d H:i:s', $periods[0]['start'] + 60); // 默认值
}
} catch (\Exception $e) {
print_r($e);
die;
}
}
}