LaiTool/src/main/Service/Book/basicReverse.ts

902 lines
29 KiB
TypeScript
Raw Normal View History

2024-06-27 16:24:41 +08:00
import path from 'path'
import fs from 'fs'
const util = require('util')
const { exec } = require('child_process')
const execAsync = util.promisify(exec)
2024-08-03 12:46:12 +08:00
import { define } from '../../../define/define'
import { BookService } from '../../../define/db/service/Book/bookService'
import { TaskScheduler } from '../task/taskScheduler'
2024-08-03 12:46:12 +08:00
import { LoggerStatus, LoggerType, OtherData } from '../../../define/enum/softwareEnum'
import { errorMessage, successMessage } from '../../Public/generalTools'
import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from '../../../define/Tools/file'
import { BookTaskDetailService } from '../../../define/db/service/Book/bookTaskDetailService'
import { BookBackTaskListService } from '../../../define/db/service/Book/bookBackTaskListService'
import { BookTaskService } from '../../../define/db/service/Book/bookTaskService'
2024-06-27 16:24:41 +08:00
import { isEmpty, set } from 'lodash'
2024-08-03 12:46:12 +08:00
import { TimeStringToMilliseconds, MillisecondsToTimeString } from '../../../define/Tools/time'
import { FfmpegOptions } from '../ffmpegOptions'
2024-07-13 15:44:13 +08:00
import {
BookBackTaskType,
BookTaskStatus,
BookType,
TaskExecuteType
2024-08-03 12:46:12 +08:00
} from '../../../define/enum/bookEnum'
import { Book } from '../../../model/book'
import { GeneralResponse } from '../../../model/generalResponse'
2024-06-27 16:24:41 +08:00
const fspromises = fs.promises
/**
*
*/
2024-06-24 13:11:19 +08:00
export class BasicReverse {
2024-08-03 12:46:12 +08:00
bookService: BookService
bookTaskService: BookTaskService
bookTaskDetailService: BookTaskDetailService
bookBackTaskListService: BookBackTaskListService
taskScheduler: TaskScheduler
ffmpegOptions: FfmpegOptions
2024-06-24 13:11:19 +08:00
constructor() {
this.taskScheduler = new TaskScheduler()
2024-07-13 15:44:13 +08:00
this.ffmpegOptions = new FfmpegOptions()
2024-06-24 13:11:19 +08:00
}
2024-06-27 16:24:41 +08:00
/**
2024-07-13 15:44:13 +08:00
*
2024-06-27 16:24:41 +08:00
*/
2024-07-13 15:44:13 +08:00
async InitService() {
if (!this.bookService) {
this.bookService = await BookService.getInstance()
2024-06-27 16:24:41 +08:00
}
2024-07-13 15:44:13 +08:00
if (!this.bookTaskService) {
this.bookTaskService = await BookTaskService.getInstance()
}
if (!this.bookTaskDetailService) {
this.bookTaskDetailService = await BookTaskDetailService.getInstance()
}
if (!this.bookBackTaskListService) {
this.bookBackTaskListService = await BookBackTaskListService.getInstance()
2024-06-27 16:24:41 +08:00
}
}
2024-07-13 15:44:13 +08:00
//#region 计算视频的分镜,操作
2024-06-27 16:24:41 +08:00
2024-06-24 13:11:19 +08:00
/**
2024-07-13 15:44:13 +08:00
*
* @param {*} bookId
2024-06-24 13:11:19 +08:00
*/
2024-07-13 15:44:13 +08:00
async AddFrameDataTask(bookId) {
2024-06-24 13:11:19 +08:00
try {
2024-07-13 15:44:13 +08:00
await this.InitService()
2024-06-27 16:24:41 +08:00
2024-06-24 13:11:19 +08:00
// 获取对应的小说小说数据,找到对应的小说视频地址
let bookQuery = {
bookId: bookId
}
2024-07-13 15:44:13 +08:00
let bookData = this.bookService.GetBookData(bookQuery)
2024-06-24 13:11:19 +08:00
if (bookData.code == 0) {
return bookData
}
if (bookData.data.book_length <= 0 || bookData.data.res_book.length <= 0) {
2024-06-27 16:24:41 +08:00
throw new Error('没有找到对应的小说数据请检查bookId是否正确')
}
// 获取小说对应的批次任务数据,默认初始化为第一个
2024-08-03 12:46:12 +08:00
let bookTaskRes = await this.bookTaskService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
name: 'output_00001'
})
2024-08-03 12:46:12 +08:00
2024-06-27 16:24:41 +08:00
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确')
2024-06-24 13:11:19 +08:00
}
// 获取小说的视频地址
let book = bookData.data.res_book[0]
2024-06-27 16:24:41 +08:00
let bookTask = bookTaskRes.data.bookTasks[0]
2024-07-13 15:44:13 +08:00
// 开始添加任务
let taskRes = await this.bookBackTaskListService.AddBookBackTask(
bookId,
BookBackTaskType.STORYBOARD,
TaskExecuteType.AUTO,
bookTask.id,
null
)
if (taskRes.code == 0) {
throw new Error(taskRes.message)
}
this.taskScheduler.AddLogToDB(
bookId,
book.type,
`添加分镜任务成功`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return successMessage(null, '添加分镜任务成功', 'BasicReverse_AddFrameDataTask')
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
}
}
/**
*
* @param bookId ID
* @param bookTaskId ID
* @returns
*/
async ComputeStoryboardFunc(bookId: string, bookTaskId: string): Promise<string> {
await this.InitService()
let book = this.bookService.GetBookDataById(bookId)
if (book == null) {
throw new Error('没有找到对应的小说数据')
}
this.bookTaskService.UpdateBookTaskStatus(bookTaskId, BookTaskStatus.STORYBOARD)
// 分镜之前,删除之前的老数据
let deleteBookTaskRes = this.bookTaskDetailService.DeleteBookTaskDetail({
bookId: bookId,
bookTaskId: bookTaskId
})
let oldVideoPath = book.oldVideoPath
let frameJson = oldVideoPath + '.json'
let sensitivity = 30
// 开始之前,推送日志
let log_content = `开始进行分镜操作,视频地址:${oldVideoPath},敏感度:${sensitivity},正在调用程序进行处理`
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
log_content,
OtherData.DEFAULT,
LoggerStatus.DOING
)
// 小说进行分镜python进行将结果写道一个json里面
// 使用异步的方法调用一个python程序然后写入到指定的json文件中k
let command = `"${path.join(
define.scripts_path,
'Lai.exe'
)}" "-ka" "${oldVideoPath}" "${frameJson}" "${sensitivity}"`
const output = await execAsync(command, {
maxBuffer: 1024 * 1024 * 10,
encoding: 'utf-8'
})
// 有错误输出
if (output.stderr != '') {
let error_msg = `分镜成功,但有警告提示:${output.stderr}`
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
error_msg,
OtherData.DEFAULT,
LoggerStatus.FAIL
)
}
// 分镜成功,处理输出
let josnIsExist = await CheckFileOrDirExist(frameJson)
if (!josnIsExist) {
let error_message = `分镜失败,没有找到对应的分镜输出文件:${frameJson}`
this.bookTaskService.UpdateBookTaskStatus(
bookTaskId,
BookTaskStatus.STORYBOARD_FAIL,
error_message
)
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
error_message,
OtherData.DEFAULT,
LoggerStatus.FAIL
)
throw new Error(error_message)
}
let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8'))
if (frameJsonData.length <= 0) {
let error_msg = `分镜失败,没有找到对应的分镜数据`
this.bookTaskService.UpdateBookTaskStatus(
bookTaskId,
BookTaskStatus.STORYBOARD_FAIL,
error_msg
)
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
error_msg,
OtherData.DEFAULT,
LoggerStatus.FAIL
2024-07-13 15:44:13 +08:00
)
2024-08-03 12:46:12 +08:00
throw new Error(error_msg)
2024-07-13 15:44:13 +08:00
}
2024-08-03 12:46:12 +08:00
// 循环写入小说人物详细数据
for (let i = 0; i < frameJsonData.length; i++) {
let dataArray = frameJsonData[i]
let bookTaskDetail = {
bookId: bookId,
bookTaskId: bookTaskId,
startTime: 0,
endTime: 0
} as Book.SelectBookTaskDetail
// 将字符串转换为number
bookTaskDetail.startTime = TimeStringToMilliseconds(dataArray[0])
bookTaskDetail.endTime = TimeStringToMilliseconds(dataArray[1])
bookTaskDetail.status = BookTaskStatus.STORYBOARD_DONE // 分镜完成
let res = this.bookTaskDetailService.AddBookTaskDetail(bookTaskDetail)
if (res.code == 0) {
throw new Error(res.message)
}
}
this.bookTaskService.UpdateBookTaskStatus(bookTaskId, BookTaskStatus.STORYBOARD_DONE)
// 分镜成功,推送日志
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`分镜成功,分镜数据如下:${frameJsonData}`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return `分镜成功,分镜信息在 ${frameJson}`
2024-07-13 15:44:13 +08:00
}
/**
* task获取
* @param {*} task
* @returns
*/
async GetFrameData(task) {
try {
// 分镜任务一定有对应的小说ID和对应的小说批次任务ID没有直接报错
if (isEmpty(task.bookId) || isEmpty(task.bookTaskId)) {
throw new Error('分镜任务bookId, bookTaskId不能为空')
}
await this.InitService()
let bookId = task.bookId
let bookTaskId = task.bookTaskId
2024-08-03 12:46:12 +08:00
let frameRes = await this.ComputeStoryboardFunc(bookId, bookTaskId)
return successMessage(frameRes)
2024-06-27 16:24:41 +08:00
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-06-27 16:24:41 +08:00
}
}
2024-06-24 13:11:19 +08:00
2024-07-13 15:44:13 +08:00
//#endregion 计算视频的分镜
//#region 裁剪视频的相关操作
2024-06-27 16:24:41 +08:00
/**
2024-07-13 15:44:13 +08:00
*
2024-06-27 16:24:41 +08:00
* @param {*} bookId ID
* @param {*} frameJson json文件地址
*/
2024-07-13 15:44:13 +08:00
async AddCutVideoDataTask(bookId) {
2024-06-27 16:24:41 +08:00
try {
if (isEmpty(bookId)) {
throw new Error('bookId不能为空')
}
2024-07-13 15:44:13 +08:00
await this.InitService()
2024-06-24 13:11:19 +08:00
2024-06-27 16:24:41 +08:00
// 判断小说是不是存在
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(bookId)
2024-06-24 13:11:19 +08:00
2024-08-03 12:46:12 +08:00
if (book == null) {
2024-06-27 16:24:41 +08:00
throw new Error('没有找到对应的小说数据')
}
// 找到对应的小说ID和对应的小说批次任务ID判断是不是有分镜数据
2024-09-04 19:49:20 +08:00
let bookTaskRes = this.bookTaskService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
name: 'output_00001'
})
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确')
}
let bookTask = bookTaskRes.data.bookTasks[0]
2024-07-13 15:44:13 +08:00
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
bookTaskId: bookTask.id
})
if (bookTaskDetail.data.length <= 0) {
// 传入的分镜数据为空,需要重新获取
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`没有传入分镜数据,开始调用分镜方法`,
OtherData.DEFAULT,
LoggerStatus.DOING
)
2024-08-03 12:46:12 +08:00
let frameRes = await this.GetFrameData(bookId)
2024-06-27 16:24:41 +08:00
if (frameRes.code == 0) {
2024-08-03 12:46:12 +08:00
throw new Error(frameRes.message)
2024-06-27 16:24:41 +08:00
}
}
2024-07-13 15:44:13 +08:00
bookTaskDetail = this.bookTaskDetailService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
bookTaskId: bookTask.id
})
if (bookTaskDetail.data.length <= 0) {
2024-07-13 15:44:13 +08:00
this.bookTaskService.UpdateBookTaskStatus(
2024-06-27 16:24:41 +08:00
bookTask.id,
BookTaskStatus.SPLIT_FAIL,
'重新调用分镜方法还是没有分镜数据,请检查'
)
throw new Error('重新调用分镜方法还是没有分镜数据,请检查')
}
2024-07-13 15:44:13 +08:00
this.bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT)
2024-06-27 16:24:41 +08:00
// 有分镜数据,开始处理
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
2024-07-13 15:44:13 +08:00
`成功获取分镜数据,开始添加裁剪视频任务`,
2024-06-27 16:24:41 +08:00
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
2024-07-13 15:44:13 +08:00
// 添加裁剪视频任务
for (let i = 0; i < bookTaskDetail.data.length; i++) {
const element = bookTaskDetail.data[i]
// 创建后台的视频分割任务
2024-09-04 19:49:20 +08:00
let taskRes = this.bookBackTaskListService.AddBookBackTask(
2024-07-13 15:44:13 +08:00
bookId,
BookBackTaskType.SPLIT,
TaskExecuteType.AUTO,
bookTask.id,
element.id
2024-06-27 16:24:41 +08:00
)
2024-07-13 15:44:13 +08:00
if (taskRes.code == 0) {
throw new Error(taskRes.message)
2024-06-27 16:24:41 +08:00
}
2024-07-13 15:44:13 +08:00
}
// 添加日志
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`添加视频裁剪任务成功`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return successMessage(null, '添加视频裁剪任务成功', 'BasicReverse_AddCutVideoDataTask')
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
}
}
/**
*
* @param bookTaskDetailId ID
* @returns
*/
2024-09-04 19:49:20 +08:00
async FrameDataToCutVideoData(bookTaskDetail: Book.SelectBookTaskDetail, frameShortClipData: Book.BookFrameShortClip): Promise<string> {
2024-08-03 12:46:12 +08:00
await this.InitService()
let startTime = bookTaskDetail.startTime
let endTime = bookTaskDetail.endTime
let book = this.bookService.GetBookDataById(bookTaskDetail.bookId)
if (book == null) {
throw new Error('没有找到对应的小说数据')
}
if (startTime == null || endTime == null) {
this.bookTaskService.UpdateBookTaskStatus(
bookTaskDetail.bookTaskId,
BookTaskStatus.SPLIT_FAIL,
'开始时间和结束时间不能为空'
2024-07-13 15:44:13 +08:00
)
2024-08-03 12:46:12 +08:00
throw new Error('开始时间和结束时间不能为空')
}
let outVideoFile = path.join(book.bookFolderPath, `data/frame/${bookTaskDetail.name}.mp4`)
let res = await this.ffmpegOptions.FfmpegCutVideo(
2024-09-04 19:49:20 +08:00
frameShortClipData.startTime,
frameShortClipData.endTime,
frameShortClipData.videoPath,
2024-08-03 12:46:12 +08:00
outVideoFile
)
if (res.code == 0) {
this.bookTaskService.UpdateBookTaskStatus(
bookTaskDetail.bookTaskId,
BookTaskStatus.SPLIT_FAIL,
res.message
2024-07-13 15:44:13 +08:00
)
2024-08-03 12:46:12 +08:00
throw new Error(res.message)
2024-07-13 15:44:13 +08:00
}
2024-08-03 12:46:12 +08:00
// 视频裁剪完成,要将裁剪后的视频地址写入到数据库中
this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetail.id, {
videoPath: path.relative(define.project_path, outVideoFile)
})
// 小改小说批次的状态
this.bookTaskService.UpdateBookTaskStatus(bookTaskDetail.bookTaskId, BookTaskStatus.SPLIT_DONE)
// 结束,分镜完毕,推送日志,返回成功
await this.taskScheduler.AddLogToDB(
bookTaskDetail.bookId,
book.type,
`${bookTaskDetail.name}_视频裁剪完成`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return `${bookTaskDetail.name}_视频裁剪完成`;
2024-07-13 15:44:13 +08:00
}
2024-06-27 16:24:41 +08:00
2024-07-13 15:44:13 +08:00
/**
*
* @param {*} task
* @returns
*/
2024-08-03 12:46:12 +08:00
async CutVideoData(task: TaskModal.Task): Promise<GeneralResponse.ErrorItem | GeneralResponse.SuccessItem> {
2024-07-13 15:44:13 +08:00
try {
// 视频分割任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID没有直接报错
if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) {
throw new Error('分镜任务bookId, bookTaskId, bookTaskDetailId不能为空')
}
await this.InitService()
2024-08-03 12:46:12 +08:00
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(
2024-07-13 15:44:13 +08:00
task.bookTaskDetailId
)
2024-08-03 12:46:12 +08:00
if (bookTaskDetail == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的分镜数据')
2024-06-27 16:24:41 +08:00
}
2024-09-04 19:49:20 +08:00
// let cur_res = await this.FrameDataToCutVideoData(bookTaskDetail, null);
2024-07-13 15:44:13 +08:00
2024-08-03 12:46:12 +08:00
return successMessage(null, `${task.name}_视频裁剪完成`, "BasicReverse_CutVideoData");
2024-06-24 13:11:19 +08:00
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-06-27 16:24:41 +08:00
}
}
2024-07-13 15:44:13 +08:00
//#endregion
//#region 分离音频的相关操作
2024-06-27 16:24:41 +08:00
/**
2024-07-13 15:44:13 +08:00
*
* @param {*} bookId ID
* @param {*} bookTaskId ID
* @returns
2024-06-27 16:24:41 +08:00
*/
2024-07-13 15:44:13 +08:00
async AddSplitAudioDataTask(bookId, bookTaskId = null) {
2024-06-27 16:24:41 +08:00
try {
2024-07-13 15:44:13 +08:00
await this.InitService()
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(bookId)
if (book == null) {
2024-06-27 16:24:41 +08:00
throw new Error('没有找到对应的小说数据')
}
2024-07-13 15:44:13 +08:00
let bookTaskRes
2024-06-27 16:24:41 +08:00
if (bookTaskId != null) {
2024-08-03 12:46:12 +08:00
bookTaskRes = await this.bookTaskService.GetBookTaskData({ id: bookTaskId })
2024-06-27 16:24:41 +08:00
} else {
2024-08-03 12:46:12 +08:00
bookTaskRes = await this.bookTaskService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
name: 'output_00001'
})
}
2024-07-13 15:44:13 +08:00
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`没有找到对应的小说批次任务数据请检查bookId是否正确`,
OtherData.DEFAULT,
LoggerStatus.FAIL
)
2024-06-27 16:24:41 +08:00
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确')
}
2024-07-13 15:44:13 +08:00
let bookTask = bookTaskRes.data.bookTasks[0]
2024-06-27 16:24:41 +08:00
// 获取对应小说批次任务的分镜信息
2024-07-13 15:44:13 +08:00
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({
2024-06-27 16:24:41 +08:00
bookId: bookId,
bookTaskId: bookTask.id
})
if (bookTaskDetails.data.length <= 0) {
2024-07-13 15:44:13 +08:00
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`没有找到对应的小说批次任务数据请检查bookId是否正确或者手动执行`,
bookTask.id,
LoggerStatus.FAIL
)
2024-06-27 16:24:41 +08:00
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确或者手动执行')
}
2024-07-13 15:44:13 +08:00
// 开始添加任务
for (let i = 0; i < bookTaskDetails.data.length; i++) {
const element = bookTaskDetails.data[i]
let taskRes = await this.bookBackTaskListService.AddBookBackTask(
bookId,
BookBackTaskType.AUDIO,
TaskExecuteType.AUTO,
bookTask.id,
element.id
)
if (taskRes.code == 0) {
throw new Error(taskRes.message)
}
// 添加日志
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`添加音频 ${taskRes.data.name} 分离任务成功`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
}
return successMessage(null, `添加所有音频分离任务成功`, 'BasicReverse_AddSplitAudioDataTask')
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-07-13 15:44:13 +08:00
}
}
/**
*
* @param {*} task
* @returns
*/
async SplitAudioData(task) {
try {
// 执行分离音频任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID没有直接报错
if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) {
throw new Error('分镜任务bookId, bookTaskId, bookTaskDetailId不能为空')
}
await this.InitService()
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(task.bookId)
if (book == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的小说数据')
}
2024-08-03 12:46:12 +08:00
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(
2024-07-13 15:44:13 +08:00
task.bookTaskDetailId
)
2024-08-03 12:46:12 +08:00
if (bookTaskDetail == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的分镜数据')
}
let videoPath = bookTaskDetail.videoPath
let audioPath = path.join(book.bookFolderPath, `data/audio/${bookTaskDetail.name}.wav`)
await CheckFolderExistsOrCreate(path.dirname(audioPath))
// 开始分离音频
let audioRes = await this.ffmpegOptions.FfmpegExtractAudio(videoPath, audioPath)
if (audioRes.code == 0) {
let errorMessage = `分离音频失败,错误信息如下:${audioRes.message}`
this.bookTaskService.UpdateBookTaskStatus(
task.bookTaskId,
BookTaskStatus.AUDIO_FAIL,
errorMessage
)
throw new Error(audioRes.message)
}
this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetail.id, {
audioPath: path.relative(define.project_path, audioPath)
})
2024-06-27 16:24:41 +08:00
2024-07-13 15:44:13 +08:00
// 推送成功消息
2024-06-27 16:24:41 +08:00
await this.taskScheduler.AddLogToDB(
2024-07-13 15:44:13 +08:00
task.bookId,
2024-06-27 16:24:41 +08:00
book.type,
2024-07-13 15:44:13 +08:00
`${bookTaskDetail.name}分离音频成功,输出地址:${audioPath}`,
2024-06-27 16:24:41 +08:00
OtherData.DEFAULT,
2024-07-13 15:44:13 +08:00
LoggerStatus.SUCCESS
2024-06-27 16:24:41 +08:00
)
2024-07-13 15:44:13 +08:00
// 修改状态为分离音频成功
this.bookTaskService.UpdateBookTaskStatus(task.bookTaskId, BookTaskStatus.AUDIO_DONE)
return successMessage(
null,
`${bookTaskDetail.name}分离音频成功,输出地址:${audioPath}`,
'BasicReverse_SplitAudioData'
)
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-07-13 15:44:13 +08:00
}
}
2024-06-27 16:24:41 +08:00
2024-07-13 15:44:13 +08:00
//#endregion
//#region 开始抽帧
// 添加抽帧任务
async AddGetFrameTask(bookId, bookTaskId = null) {
try {
// 开始添加任务
await this.InitService()
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(bookId)
if (book == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的小说数据')
}
let bookTaskRes
if (bookTaskId != null) {
2024-08-03 12:46:12 +08:00
bookTaskRes = await this.bookTaskService.GetBookTaskData({ id: bookTaskId })
2024-07-13 15:44:13 +08:00
} else {
2024-08-03 12:46:12 +08:00
bookTaskRes = await this.bookTaskService.GetBookTaskData({
2024-07-13 15:44:13 +08:00
bookId: bookId,
name: 'output_00001'
2024-06-27 16:24:41 +08:00
})
2024-07-13 15:44:13 +08:00
}
if (bookTaskRes.data.bookTasks.length <= 0 || bookTaskRes.data.total <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确')
}
let bookTask = bookTaskRes.data.bookTasks[0]
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({
bookId: bookId,
bookTaskId: bookTask.id
})
if (bookTaskDetails.data.length <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确或者手动执行')
}
for (let i = 0; i < bookTaskDetails.data.length; i++) {
const element = bookTaskDetails.data[i]
let taskRes = await this.bookBackTaskListService.AddBookBackTask(
bookId,
BookBackTaskType.FRAME,
TaskExecuteType.AUTO,
bookTask.id,
element.id
)
if (taskRes.code == 0) {
throw new Error(taskRes.message)
}
2024-06-27 16:24:41 +08:00
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
2024-07-13 15:44:13 +08:00
`添加 ${taskRes.data.name} 抽帧任务成功`,
2024-06-27 16:24:41 +08:00
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
}
2024-07-13 15:44:13 +08:00
return successMessage(null, '添加所有抽帧任务成功', 'BasicReverse_AddGetFrameTask')
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
}
}
/**
*
* @param book
* @param bookTaskDetail
* @returns
*/
async FrameFunc(book: Book.SelectBook, bookTaskDetail: Book.SelectBookTaskDetail): Promise<string> {
let videoPath = bookTaskDetail.videoPath
let outputFramePath = path.join(
book.bookFolderPath,
`tmp/input/${bookTaskDetail.name}.png`
)
let frameTime = (bookTaskDetail.endTime - bookTaskDetail.startTime) / 2
let res = await this.ffmpegOptions.FfmpegGetFrame(frameTime, videoPath, outputFramePath)
if (res.code == 0) {
let errorMessage = `抽帧失败,错误信息如下:${res.message}`
this.bookTaskService.UpdateBookTaskStatus(
bookTaskDetail.bookTaskId,
BookTaskStatus.FRAME_FAIL,
errorMessage
2024-07-13 15:44:13 +08:00
)
2024-08-03 12:46:12 +08:00
throw new Error(errorMessage)
2024-07-13 15:44:13 +08:00
}
2024-08-03 12:46:12 +08:00
// 抽帧成功,将抽帧的地址写入到数据库中
this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetail.id, {
oldImage: path.relative(define.project_path, outputFramePath)
})
// 推送成功消息
await this.taskScheduler.AddLogToDB(
book.id,
book.type,
`${bookTaskDetail.name}抽帧成功,输出地址:${outputFramePath}`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
// 修改状态为抽帧成功
this.bookTaskService.UpdateBookTaskStatus(bookTaskDetail.bookTaskId, BookTaskStatus.FRAME_DONE)
return `${bookTaskDetail.name}抽帧成功,输出地址:${outputFramePath}`
2024-07-13 15:44:13 +08:00
}
/**
*
* @param {*} task
*/
async GetFrame(task) {
try {
// 抽帧任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID没有直接报错
if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) {
throw new Error('分镜任务bookId, bookTaskId, bookTaskDetailId不能为空')
}
await this.InitService()
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(task.bookId)
if (book == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的小说数据')
}
2024-08-03 12:46:12 +08:00
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(
2024-07-13 15:44:13 +08:00
task.bookTaskDetailId
)
2024-08-03 12:46:12 +08:00
if (bookTaskDetail == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的分镜数据')
}
2024-08-03 12:46:12 +08:00
let res = await this.FrameFunc(book, bookTaskDetail);
2024-07-13 15:44:13 +08:00
2024-08-03 12:46:12 +08:00
return successMessage(null, res, 'BasicReverse_GetFrame')
2024-06-27 16:24:41 +08:00
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-06-27 16:24:41 +08:00
}
}
2024-07-13 15:44:13 +08:00
//#endregion
//#region 提取字幕相关操作
2024-06-27 16:24:41 +08:00
/**
2024-07-13 15:44:13 +08:00
*
* @param {*} bookId ID
* @param {*} bookTaskId ID
2024-06-27 16:24:41 +08:00
* @returns
*/
2024-07-13 15:44:13 +08:00
async AddExtractSubtitlesDataTask(bookId, bookTaskId = null) {
2024-06-27 16:24:41 +08:00
try {
2024-07-13 15:44:13 +08:00
await this.InitService()
let book = this.bookService.GetBookDataById(bookId)
if (book == null) {
throw new Error('没有找到对应的小说数据')
}
let bookTask
if (bookTaskId != null) {
2024-08-03 12:46:12 +08:00
bookTaskId = await this.bookTaskService.GetBookTaskData({ id: bookTaskId })
2024-07-13 15:44:13 +08:00
} else {
2024-08-03 12:46:12 +08:00
bookTask = await this.bookTaskService.GetBookTaskData({
2024-07-13 15:44:13 +08:00
bookId: bookId,
name: 'output_00001'
})
}
if (bookTask.data.bookTasks.length <= 0 || bookTask.data.total <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确')
}
bookTask = bookTask.data.bookTasks[0]
// 获取对应小说批次任务的分镜信息
let bookTaskDetails = this.bookTaskDetailService.GetBookTaskData({
bookId: bookId,
bookTaskId: bookTask.id
})
if (bookTaskDetails.data.length <= 0) {
throw new Error('没有找到对应的小说批次任务数据请检查bookId是否正确或者手动执行')
}
for (let i = 0; i < bookTaskDetails.data.length; i++) {
const element = bookTaskDetails.data[i]
let taskRes = await this.bookBackTaskListService.AddBookBackTask(
bookId,
2024-08-03 12:46:12 +08:00
BookBackTaskType.RECOGNIZE,
2024-07-13 15:44:13 +08:00
TaskExecuteType.AUTO,
bookTask.id,
element.id
)
if (taskRes.code == 0) {
throw new Error(taskRes.message)
}
}
await this.taskScheduler.AddLogToDB(
bookId,
book.type,
`添加提取字幕任务成功`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return successMessage(
null,
'添加提取字幕任务成功 ',
'BasicReverse_AddExtractSubtitlesDataTask '
)
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-07-13 15:44:13 +08:00
}
}
2024-08-03 12:46:12 +08:00
async GetCopywritingFunc(book: Book.SelectBook, bookTaskDetail: Book.SelectBookTaskDetail): Promise<string> {
let txt = ''
// 开始提取,调用本地的服务识别字幕
let isWisper = true
// 判断是不是用本地的wisper服务
if (isWisper) {
// 开始调用wisper
// 使用异步的方法调用一个python程序然后写入到指定的json文件中k
let out_dir = path.dirname(bookTaskDetail.videoPath)
let command = `"${path.join(define.scripts_path, 'Lai.exe')}" "-t" "${out_dir}" "${bookTaskDetail.audioPath
}" "${bookTaskDetail.name}"`
const output = await execAsync(command, {
maxBuffer: 1024 * 1024 * 10,
encoding: 'utf-8'
})
// 有错误输出
if (output.stderr != '') {
let error_msg = `提取字幕成功,但有警告提示:${output.stderr}`
await this.taskScheduler.AddLogToDB(
book.id,
book.type,
error_msg,
OtherData.DEFAULT,
LoggerStatus.FAIL
)
}
// 没有的话,去读取对应的字幕文件
let outTxtPath = path.join(out_dir, `${bookTaskDetail.name}.txt`)
txt = await fspromises.readFile(outTxtPath, 'utf-8')
} else {
// 使用网络服务
}
// 修改分镜数据的字幕
this.bookTaskDetailService.UpdateBookTaskDetail(bookTaskDetail.id, {
word: txt,
afterGpt: txt
})
// 提取字幕成功,推送日志
await this.taskScheduler.AddLogToDB(
book.id,
book.type,
`${bookTaskDetail.name} 提取字幕成功`,
OtherData.DEFAULT,
LoggerStatus.SUCCESS
)
return txt;
}
2024-07-13 15:44:13 +08:00
/**
*
* @param {*} task
* @returns
*/
async ExtractSubtitlesData(task) {
try {
// 执行提取字幕任务一定有对应的小说ID和对应的小说批次任务ID和对应的分镜ID没有直接报错
if (isEmpty(task.bookId) || isEmpty(task.bookTaskId) || isEmpty(task.bookTaskDetailId)) {
throw new Error('分镜任务bookId, bookTaskId, bookTaskDetailId不能为空')
}
await this.InitService()
// 获取详细的小说分镜信息
2024-08-03 12:46:12 +08:00
let bookTaskDetail = this.bookTaskDetailService.GetBookTaskDetailDataById(
2024-07-13 15:44:13 +08:00
task.bookTaskDetailId
)
2024-08-03 12:46:12 +08:00
if (bookTaskDetail == null) {
2024-07-13 15:44:13 +08:00
throw new Error('没有找到对应的分镜数据')
}
2024-08-03 12:46:12 +08:00
let book = this.bookService.GetBookDataById(task.bookId)
if (book == null) {
throw new Error('没有找到对应的小说数据')
2024-07-13 15:44:13 +08:00
}
2024-08-03 12:46:12 +08:00
let res = await this.GetCopywritingFunc(book, bookTaskDetail)
return successMessage(null, res, 'BasicReverse_ExtractSubtitlesData')
2024-07-13 15:44:13 +08:00
2024-06-27 16:24:41 +08:00
} catch (error) {
2024-08-03 12:46:12 +08:00
throw error
2024-06-24 13:11:19 +08:00
}
}
2024-07-13 15:44:13 +08:00
//#endregion
2024-06-27 16:24:41 +08:00
}