|
|
@@ -127,6 +127,51 @@ class AnimeService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 构建统一的分段数据结构(episodeInfoForAce格式)
|
|
|
+ * @param array $segments 分段数据数组
|
|
|
+ * @return array 返回包含acts和total_duration的数组
|
|
|
+ */
|
|
|
+ public function buildEpisodeSegmentsStructureForAce($segments) {
|
|
|
+ $acts = [];
|
|
|
+ $totalDuration = 0; // 初始化总时长
|
|
|
+
|
|
|
+ foreach($segments as $segment) {
|
|
|
+ // 计算分镜时长,优先级:video_duration > audio_duration > 默认5秒
|
|
|
+ $videoDuration = getProp($segment, 'video_duration');
|
|
|
+ $audioDuration = getProp($segment, 'audio_duration');
|
|
|
+
|
|
|
+ if (!empty($videoDuration) && is_numeric($videoDuration)) {
|
|
|
+ $totalDuration += floatval($videoDuration);
|
|
|
+ } elseif (!empty($audioDuration) && is_numeric($audioDuration)) {
|
|
|
+ $totalDuration += floatval($audioDuration);
|
|
|
+ } else {
|
|
|
+ $totalDuration += 5; // 默认5秒
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建分镜信息
|
|
|
+ $segmentInfo = [
|
|
|
+ 'act_id' => getProp($segment, 'id'),
|
|
|
+ 'act_number' => getProp($segment, 'act_number'),
|
|
|
+ 'act_title' => getProp($segment, 'act_title'),
|
|
|
+ 'act_duration' => getProp($segment, 'act_duration'),
|
|
|
+ 'act_content' => getProp($segment, 'act_content'),
|
|
|
+ 'video_url' => getProp($segment, 'video_url'),
|
|
|
+ 'video_duration' => getProp($segment, 'video_duration', 0),
|
|
|
+ 'video_time_point_start' => getProp($segment, 'video_time_point_start', 0),
|
|
|
+ 'video_time_point_end' => getProp($segment, 'video_time_point_end', getProp($segment, 'video_duration', 0)),
|
|
|
+ 'last_frame_url' => getProp($segment, 'last_frame_url'),
|
|
|
+ 'current_type' => getProp($segment, 'current_type'),
|
|
|
+ ];
|
|
|
+ $acts[] = $segmentInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'acts' => array_values($acts),
|
|
|
+ 'total_duration' => intval(round($totalDuration))
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 验证画面比例是否有效
|
|
|
* @param string $ratio 画面比例
|
|
|
* @return bool
|
|
|
@@ -519,6 +564,38 @@ class AnimeService
|
|
|
return $episode;
|
|
|
}
|
|
|
|
|
|
+ public function episodeInfoForAce($data) {
|
|
|
+ $anime_id = getProp($data, 'anime_id');
|
|
|
+ $episode_id = getProp($data, 'episode_id');
|
|
|
+ if (!$anime_id || !$episode_id) {
|
|
|
+ Utils::throwError('1002:请选择剧集');
|
|
|
+ }
|
|
|
+
|
|
|
+ $episode = DB::table('mp_anime_episodes')->where('anime_id', $anime_id)->where('id', $episode_id)->select('id as episode_id', 'anime_id', 'episode_number', 'title', 'intro', 'art_style', 'roles', 'scenes', 'is_generated')->first();
|
|
|
+ if (!$episode) Utils::throwError('20003:该剧集不存在!');
|
|
|
+ $episode = (array)$episode;
|
|
|
+ $episode['roles'] = json_decode($episode['roles'], true);
|
|
|
+ foreach($episode['roles'] as &$item) {
|
|
|
+ if (isset($item['pic_prompt']) && mb_substr($item['pic_prompt'], 0, 11) != '写实。全景,正面拍摄。') $item['pic_prompt'] = '写实。全景,正面拍摄。'.$item['pic_prompt'];
|
|
|
+ }
|
|
|
+ $episode['scenes'] = json_decode($episode['scenes'], true);
|
|
|
+ foreach($episode['scenes'] as &$item) {
|
|
|
+ if (isset($item['pic_prompt']) && mb_substr($item['pic_prompt'], 0, 3) != '写实。') $item['pic_prompt'] = '写实。'.$item['pic_prompt'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取分镜信息
|
|
|
+ $segments = DB::table('mp_episode_segments')->where('anime_id', $anime_id)->where('episode_id', getProp($episode, 'episode_id'))->orderBy('segment_number')
|
|
|
+ ->select('*')->get()->map(function ($value) {
|
|
|
+ return (array)$value;
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ $segmentsStructure = $this->buildEpisodeSegmentsStructureForAce($segments);
|
|
|
+ $episode['acts'] = $segmentsStructure['acts'];
|
|
|
+ $episode['total_duration'] = $segmentsStructure['total_duration'];
|
|
|
+
|
|
|
+ return $episode;
|
|
|
+ }
|
|
|
+
|
|
|
public function segmentInfo($data) {
|
|
|
$segment_id = getProp($data, 'segment_id');
|
|
|
if (!$segment_id) {
|