218 lines
7.9 KiB
TypeScript
Raw Normal View History

2025-08-19 14:33:59 +08:00
import { BookTaskDetailService } from '@/define/db/service/book/bookTaskDetailService'
import { BookTaskService } from '@/define/db/service/book/bookTaskService'
import { OptionRealmService } from '@/define/db/service/optionService'
import { BookService } from '@/define/db/service/book/bookService'
import { TaskListService } from '@/define/db/service/book/taskListService'
import { TaskModal } from '@/define/model/task'
import { Book } from '@/define/model/book/book'
import { getProjectPath } from '../../option/optionCommonService'
import path from 'path'
import { isEmpty } from 'lodash'
import axios from 'axios'
import { define } from '@/define/define'
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '@/define/Tools/file'
import { DownloadFile } from '@/define/Tools/common'
import { MappingTaskTypeToVideoModel } from '@/define/enum/video'
import { BookBackTaskType } from '@/define/enum/bookEnum'
import { t } from '@/i18n'
2025-09-25 17:21:45 +08:00
import { PresetRealmService } from '@/define/db/service/presetService'
2025-08-19 14:33:59 +08:00
export class BookBasicHandle {
bookTaskDetailService!: BookTaskDetailService
bookTaskService!: BookTaskService
optionRealmService!: OptionRealmService
bookService!: BookService
taskListService!: TaskListService
2025-09-25 17:21:45 +08:00
presetRealmService!: PresetRealmService
2025-08-19 14:33:59 +08:00
constructor() {
// 初始化
}
async InitBookBasicHandle() {
// 如果 bookTaskDetailService 已经初始化,则直接返回
if (!this.bookTaskDetailService) {
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
}
if (!this.bookTaskService) {
this.bookTaskService = await BookTaskService.getInstance()
}
if (!this.optionRealmService) {
this.optionRealmService = await OptionRealmService.getInstance()
}
if (!this.bookService) {
this.bookService = await BookService.getInstance()
}
if (!this.taskListService) {
this.taskListService = await TaskListService.getInstance()
}
2025-09-25 17:21:45 +08:00
if (!this.presetRealmService) {
this.presetRealmService = await PresetRealmService.getInstance()
}
2025-08-19 14:33:59 +08:00
}
/**
*
* @returns
*/
CheckInit() {
if (this.bookTaskDetailService
&& this.bookTaskService
&& this.optionRealmService
&& this.bookService
&& this.taskListService) {
return true
}
return false
}
/** 执行事务的方法 */
2025-08-19 14:33:59 +08:00
async transaction(callback: (realm: any) => void) {
this.CheckInit() || await this.InitBookBasicHandle()
2025-08-19 14:33:59 +08:00
this.bookService.transaction(() => {
callback(this.bookService.realm)
})
}
/**
*
*
* URL下载视频文件到本地
* MidJourney
* MJ官方CDN和可灵视频外
*
* @param {string[]} videoUrls - URL列表
* @param {TaskModal.Task} task -
* @param {Book.SelectBookTaskDetail} bookTaskDetail -
* @param {string} preffix -
*
* @returns {Promise<{outVideoPath: string, subVideoPath: string[]}>}
* - outVideoPath: 主输出视频的本地路径
* - subVideoPath: 所有子视频的路径信息数组JSON字符串格式
*
* @throws {Error}
* @throws {Error}
* @throws {Error}
*
* @example
* ```typescript
* const result = await this.DownloadVideoUrls(
* ['http://example.com/video1.mp4', 'http://example.com/video2.mp4'],
* task,
* bookTaskDetail,
* 'MJ'
* );
* console.log('主视频路径:', result.outVideoPath);
* console.log('所有视频路径:', result.subVideoPath);
* ```
*
* @description
*
* 1.
* 2. URL进行下载
* 3. 使
* 4.
* 5.
* 6.
*
* @note
* - MidJourney官方CDN (cdn.midjourney.com)
* - (KLING_VIDEO, KLING_VIDEO_EXTEND) 使
* - machineId配置
* -
*/
async DownloadVideoUrls(videoUrls: string[], task: TaskModal.Task, bookTaskDetail: Book.SelectBookTaskDetail, preffix: string, videoIds?: string[]): Promise<{ outVideoPath: string, subVideoPath: string[] }> {
this.CheckInit() || await this.InitBookBasicHandle()
if (videoIds != undefined && videoIds.length != videoUrls.length) {
throw new Error(t("视频ID数量与视频链接数量不匹配"))
}
let bookTask = await this.bookTaskService.GetBookTaskDataById(
bookTaskDetail.bookTaskId as string,
true
)
let tempVideoUrls = bookTaskDetail.subVideoPath || []
let newVideoUrls: string[] = []
let outVideoPath: string = ''
const project_path = await getProjectPath()
// 开始下载所有视频
for (let i = 0; i < videoUrls.length; i++) {
const videoUrl = videoUrls[i]
// 处理文件地址和下载
let videoPath = path.join(
bookTask.imageFolder as string,
`video/subVideo/${bookTaskDetail.name}/${new Date().getTime()}_${i}.mp4`
)
let remoteUrl = videoUrl
// 开始处理下载 mj 官方的图片不支持转存
if (global.machineId
&& !isEmpty(global.machineId)
&& !videoUrl.startsWith('https://cdn.midjourney.com')
&& task.type != BookBackTaskType.KLING_VIDEO
&& task.type != BookBackTaskType.KLING_VIDEO_EXTEND
2025-09-25 17:21:45 +08:00
&& task.type != BookBackTaskType.HAILUO_TEXT_TO_VIDEO
&& task.type != BookBackTaskType.HAILUO_IMAGE_TO_VIDEO
&& task.type != BookBackTaskType.HAILUO_FIRST_LAST_FRAME
) {
// 转存一下视频文件
// 获取当前url的文件名
let fileName = preffix + "_" + path.basename(videoUrl)
let transferRes = await axios.post(define.lms_url + `/lms/FileUpload/UrlUpload/${global.machineId}`, {
url: videoUrl,
fileName: fileName
})
if (transferRes.status == 200 && transferRes.data.code == 1) {
remoteUrl = transferRes.data.data.url
}
}
if (isEmpty(remoteUrl)) {
remoteUrl = videoUrl
}
await CheckFolderExistsOrCreate(path.dirname(videoPath))
await DownloadFile(remoteUrl, videoPath)
// 处理返回数据信息
// 开始修改信息
// 将信息添加到里面
let a = {
localPath: path.relative(project_path, videoPath),
remotePath: remoteUrl,
taskId: bookTaskDetail.videoMessage?.taskId,
videoId: videoIds != undefined && videoIds[i] ? videoIds[i] : "",
index: i,
type: MappingTaskTypeToVideoModel(task.type as string)
}
newVideoUrls.push(JSON.stringify(a))
if (i == 0) {
outVideoPath = path.join(
bookTask.imageFolder as string,
'video',
bookTaskDetail.name + path.extname(videoPath)
)
await CopyFileOrFolder(videoPath, outVideoPath as string)
}
}
// 开始处理数据
// 将原有的视频路径合并到新数组中
newVideoUrls.push(...tempVideoUrls)
await this.bookTaskDetailService.ModifyBookTaskDetailById(bookTaskDetail.id as string, {
subVideoPath: newVideoUrls,
generateVideoPath: outVideoPath != '' ? outVideoPath : ''
})
return {
outVideoPath: outVideoPath,
subVideoPath: newVideoUrls
}
}
2025-08-19 14:33:59 +08:00
}