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)
|
|
|
|
|
|
import { define } from '../../define/define'
|
|
|
|
|
|
import { BookService } from '../../define/db/service/Book/bookService'
|
|
|
|
|
|
import { TaskScheduler } from './taskScheduler'
|
|
|
|
|
|
import { LoggerStatus, LoggerType, OtherData } from '../../define/enum/softwareEnum'
|
|
|
|
|
|
import { errorMessage, successMessage } from '../generalTools'
|
|
|
|
|
|
import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from '../../define/Tools/file'
|
|
|
|
|
|
import { BookTaskDetailService } from '../../define/db/service/Book/bookTaskDetailService'
|
|
|
|
|
|
import { BookTaskService } from '../../define/db/service/Book/bookTaskService'
|
|
|
|
|
|
import { isEmpty, set } from 'lodash'
|
|
|
|
|
|
import ffmpeg from 'fluent-ffmpeg'
|
|
|
|
|
|
import { SetFfmpegPath } from '../setting/ffmpegSetting'
|
|
|
|
|
|
import { TimeStringToMilliseconds, MillisecondsToTimeString } from '../../define/Tools/time'
|
|
|
|
|
|
import { BookTaskStatus } from '../../define/enum/bookEnum'
|
|
|
|
|
|
SetFfmpegPath()
|
|
|
|
|
|
|
|
|
|
|
|
const fspromises = fs.promises
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 后台执行的任务函数,直接调用改函数即可,抽帧,分镜,提取字幕等
|
|
|
|
|
|
*/
|
2024-06-24 13:11:19 +08:00
|
|
|
|
export class BasicReverse {
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
this.taskScheduler = new TaskScheduler()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
//#region ffmpeg的一些操作
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* FFmpeg裁剪视频,将一个视频将裁剪指定的时间内的片段
|
|
|
|
|
|
* @param {*} book 小说对象类
|
|
|
|
|
|
* @param {*} bookTask 小说批次任务对象类
|
|
|
|
|
|
* @param {*} startTime 开始时间
|
|
|
|
|
|
* @param {*} endTime 结束时间
|
|
|
|
|
|
* @param {*} videoPath 视频地址
|
|
|
|
|
|
* @param {*} outVideoFile 输出地址
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
async FfmpegCutVideo(book, bookTask, startTime, endTime, videoPath, outVideoFile) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 判断视频地址是不是存在
|
|
|
|
|
|
let videoIsExist = CheckFileOrDirExist(videoPath)
|
|
|
|
|
|
if (!videoIsExist) {
|
|
|
|
|
|
throw new Error('视频地址对应的文件不存在')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 判断开始时间和结束时间是不是合法
|
|
|
|
|
|
if (isEmpty(startTime) || isEmpty(endTime)) {
|
|
|
|
|
|
throw new Error('开始时间和结束时间不能为空')
|
|
|
|
|
|
}
|
|
|
|
|
|
// 判断输出文件夹是不是存在
|
|
|
|
|
|
let outputFolder = path.dirname(outVideoFile)
|
|
|
|
|
|
await CheckFolderExistsOrCreate(outputFolder)
|
|
|
|
|
|
|
|
|
|
|
|
// 将时间转换为字符串
|
|
|
|
|
|
startTimeString = MillisecondsToTimeString(startTime)
|
|
|
|
|
|
endTimeString = MillisecondsToTimeString(endTime)
|
|
|
|
|
|
|
|
|
|
|
|
// 设置视频编码器
|
|
|
|
|
|
let videoCodec = 'libx264' // 默认编码器
|
|
|
|
|
|
if (global.gpu.type === 'NVIDIA') {
|
|
|
|
|
|
videoCodec = 'h264_nvenc'
|
|
|
|
|
|
} else if (global.gpu.type === 'AMD') {
|
|
|
|
|
|
videoCodec = 'h264_amf'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 判断分镜是不是和数据库中的数据匹配的上
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
ffmpeg(videoPath)
|
|
|
|
|
|
.setStartTime(startTimeString)
|
|
|
|
|
|
.setEndTime(endTimeString)
|
|
|
|
|
|
.videoCodec(videoCodec)
|
|
|
|
|
|
.addOption('-preset', 'fast')
|
|
|
|
|
|
.audioCodec('copy')
|
|
|
|
|
|
.output(outVideoFile)
|
|
|
|
|
|
.on('end', async function () {
|
|
|
|
|
|
let res_msg = `视频裁剪完成,输出地址:${outVideoFile}`
|
|
|
|
|
|
// 修改数据库中的输出地址
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
book.id,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
res_msg,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
|
|
|
|
|
return successMessage(null, res_msg, 'BasicReverse_FfmpegCutVideo')
|
|
|
|
|
|
})
|
|
|
|
|
|
.on('error', async function (err) {
|
|
|
|
|
|
let res_msg = `视频裁剪失败,错误信息如下:${err.toString()}`
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
book.id,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
res_msg,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
return errorMessage(res_msg, 'BasicReverse_FfmpegCutVideo')
|
|
|
|
|
|
})
|
|
|
|
|
|
.run()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 开始裁剪视频
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return errorMessage(
|
|
|
|
|
|
'裁剪视频失败,错误信息如下: ' + error.message,
|
|
|
|
|
|
'BasicReverse_FfmpegCutVideo'
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {*} videoPath
|
|
|
|
|
|
* @param {*} audioPath
|
|
|
|
|
|
*/
|
|
|
|
|
|
async FfmpegExtractAudio(videoPath, outAudioPath) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 判断视频地址是不是存在
|
|
|
|
|
|
let videoIsExist = CheckFileOrDirExist(videoPath)
|
|
|
|
|
|
if (!videoIsExist) {
|
|
|
|
|
|
throw new Error('视频地址对应的文件不存在')
|
|
|
|
|
|
}
|
|
|
|
|
|
// 开始提取音频
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
ffmpeg(videoPath)
|
|
|
|
|
|
.output(outAudioPath)
|
|
|
|
|
|
.audioCodec('libmp3lame')
|
|
|
|
|
|
.audioBitrate('128k')
|
|
|
|
|
|
.on('end', async function () {
|
|
|
|
|
|
let res_msg = `音频提取完成,输出地址:${outAudioPath}`
|
|
|
|
|
|
return successMessage(outAudioPath, res_msg, 'BasicReverse_FfmpegExtractAudio')
|
|
|
|
|
|
})
|
|
|
|
|
|
.on('error', async function (err) {
|
|
|
|
|
|
let res_msg = `音频提取失败,错误信息如下:${err.toString()}`
|
|
|
|
|
|
return errorMessage(res_msg, 'BasicReverse_FfmpegExtractAudio')
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return errorMessage(
|
|
|
|
|
|
'提取音频失败,错误信息如下: ' + error.message,
|
|
|
|
|
|
'BasicReverse_FfmpegExtractAudio'
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
2024-06-24 13:11:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 分镜(通过传入的bookId)
|
|
|
|
|
|
* @param {*} bookId 传入的bookId
|
2024-06-27 16:24:41 +08:00
|
|
|
|
* @returns
|
2024-06-24 13:11:19 +08:00
|
|
|
|
*/
|
|
|
|
|
|
async GetFrameData(bookId) {
|
|
|
|
|
|
try {
|
2024-06-27 16:24:41 +08:00
|
|
|
|
let _bookService = await BookService.getInstance()
|
|
|
|
|
|
let _bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
|
|
|
|
let _bookTaskService = await BookTaskService.getInstance()
|
|
|
|
|
|
|
2024-06-24 13:11:19 +08:00
|
|
|
|
// 获取对应的小说小说数据,找到对应的小说视频地址
|
|
|
|
|
|
let bookQuery = {
|
|
|
|
|
|
bookId: bookId
|
|
|
|
|
|
}
|
2024-06-27 16:24:41 +08:00
|
|
|
|
let bookData = _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是否正确')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取小说对应的批次任务数据,默认初始化为第一个
|
|
|
|
|
|
let bookTaskRes = await _bookTaskService.GetBookTaskData({
|
|
|
|
|
|
bookId: bookId,
|
|
|
|
|
|
name: 'output_00001'
|
|
|
|
|
|
})
|
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.STORYBOARD)
|
|
|
|
|
|
|
|
|
|
|
|
// 分镜之前,删除之前的老数据
|
|
|
|
|
|
let deleteBookTaskRes = _bookTaskDetailService.DeleteBookTaskDetail({
|
|
|
|
|
|
bookId: bookId,
|
|
|
|
|
|
bookTaskId: bookTask.id
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2024-06-24 13:11:19 +08:00
|
|
|
|
let oldVideoPath = book.oldVideoPath
|
|
|
|
|
|
let frameJson = oldVideoPath + '.json'
|
|
|
|
|
|
|
|
|
|
|
|
let sensitivity = 30
|
|
|
|
|
|
// 开始之前,推送日志
|
|
|
|
|
|
let log_content = `开始进行分镜操作,视频地址:${oldVideoPath},敏感度:${sensitivity},正在调用程序进行处理`
|
2024-06-27 16:24:41 +08:00
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
log_content,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.DOING
|
|
|
|
|
|
)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
|
|
|
|
|
// 小说进行分镜(python进行,将结果写道一个json里面)
|
|
|
|
|
|
// 使用异步的方法调用一个python程序,然后写入到指定的json文件中k
|
2024-06-27 16:24:41 +08:00
|
|
|
|
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'
|
|
|
|
|
|
})
|
2024-06-24 13:11:19 +08:00
|
|
|
|
// 有错误输出
|
|
|
|
|
|
if (output.stderr != '') {
|
2024-06-27 16:24:41 +08:00
|
|
|
|
let error_msg = `分镜失败,错误信息如下:${output.stderr}`
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.STORYBOARD_FAIL,
|
|
|
|
|
|
error_msg
|
|
|
|
|
|
)
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
error_msg,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
throw new Error(output.stderr)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 分镜成功,处理输出
|
|
|
|
|
|
let josnIsExist = CheckFileOrDirExist(frameJson)
|
|
|
|
|
|
if (!josnIsExist) {
|
|
|
|
|
|
let error_message = `分镜失败,没有找到对应的分镜输出文件:${frameJson}`
|
2024-06-27 16:24:41 +08:00
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.STORYBOARD_FAIL,
|
|
|
|
|
|
error_message
|
|
|
|
|
|
)
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
error_message,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
throw new Error(error_message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let frameJsonData = JSON.parse(await fspromises.readFile(frameJson, 'utf-8'))
|
|
|
|
|
|
if (frameJsonData.length <= 0) {
|
2024-06-27 16:24:41 +08:00
|
|
|
|
let error_msg = `分镜失败,没有找到对应的分镜数据`
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.STORYBOARD_FAIL,
|
|
|
|
|
|
error_msg
|
|
|
|
|
|
)
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
error_msg,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
throw new Error(error_msg)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 循环写入小说人物详细数据
|
|
|
|
|
|
for (let i = 0; i < frameJsonData.length; i++) {
|
2024-06-27 16:24:41 +08:00
|
|
|
|
let dataArray = frameJsonData[i]
|
2024-06-24 13:11:19 +08:00
|
|
|
|
let bookTaskDetail = {
|
|
|
|
|
|
bookId: bookId,
|
2024-06-27 16:24:41 +08:00
|
|
|
|
bookTaskId: bookTask.id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将字符串转换为number
|
|
|
|
|
|
bookTaskDetail.startTime = TimeStringToMilliseconds(dataArray[0])
|
|
|
|
|
|
bookTaskDetail.endTime = TimeStringToMilliseconds(dataArray[1])
|
|
|
|
|
|
|
|
|
|
|
|
let res = _bookTaskDetailService.AddBookTaskDetail(bookTaskDetail)
|
|
|
|
|
|
if (res.code == 0) {
|
|
|
|
|
|
throw new Error(res.message)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.STORYBOARD_DONE)
|
|
|
|
|
|
// 分镜成功,推送日志
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`分镜成功,分镜数据如下:${frameJsonData}`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
return successMessage(null, `分镜成功,分镜信息在 ${frameJson}`, 'BasicReverse_GetFrameData')
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return errorMessage(error.message, 'BasicReverse_GetFrameData')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 裁剪视频
|
|
|
|
|
|
* @param {*} bookId 小说ID
|
|
|
|
|
|
* @param {*} frameJson 存放分镜数据的json文件地址
|
|
|
|
|
|
*/
|
|
|
|
|
|
async CutVideoData(bookId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (isEmpty(bookId)) {
|
|
|
|
|
|
throw new Error('bookId不能为空')
|
|
|
|
|
|
}
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
// 判断小说是不是存在
|
|
|
|
|
|
let _bookService = await BookService.getInstance()
|
|
|
|
|
|
let _bookTaskService = await BookTaskService.getInstance()
|
|
|
|
|
|
let _bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
|
|
|
|
let book = _bookService.GetBookDataById(bookId)
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
|
if (book == null) {
|
|
|
|
|
|
throw new Error('没有找到对应的小说数据')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 找到对应的小说ID和对应的小说批次任务ID,判断是不是有分镜数据
|
|
|
|
|
|
let bookTaskRes = await _bookTaskService.GetBookTaskData({
|
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
|
|
let bookTaskDetail = _bookTaskDetailService.GetBookTaskData({
|
|
|
|
|
|
bookId: bookId,
|
|
|
|
|
|
bookTaskId: bookTask.id
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (bookTaskDetail.data.length <= 0) {
|
|
|
|
|
|
// 传入的分镜数据为空,需要重新获取
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`没有传入分镜数据,开始调用分镜方法`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.DOING
|
|
|
|
|
|
)
|
|
|
|
|
|
let frameRes = this.GetFrameData(bookId)
|
|
|
|
|
|
if (frameRes.code == 0) {
|
|
|
|
|
|
throw new Error((await frameRes).message)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bookTaskDetail = _bookTaskDetailService.GetBookTaskData({
|
|
|
|
|
|
bookId: bookId,
|
|
|
|
|
|
bookTaskId: bookTask.id
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (bookTaskDetail.data.length <= 0) {
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.SPLIT_FAIL,
|
|
|
|
|
|
'重新调用分镜方法还是没有分镜数据,请检查'
|
|
|
|
|
|
)
|
|
|
|
|
|
throw new Error('重新调用分镜方法还是没有分镜数据,请检查')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT)
|
|
|
|
|
|
// 有分镜数据,开始处理
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`成功获取分镜数据,开始裁剪视频`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
|
|
|
|
|
for (let i = 0; i < bookTaskDetail.length; i++) {
|
|
|
|
|
|
const element = bookTaskDetail[i]
|
|
|
|
|
|
let startTime = element.startTime
|
|
|
|
|
|
let endTime = element.endTime
|
|
|
|
|
|
if (startTime == null || endTime == null) {
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.SPLIT_FAIL,
|
|
|
|
|
|
'开始时间和结束时间不能为空'
|
|
|
|
|
|
)
|
|
|
|
|
|
throw new Error('开始时间和结束时间不能为空')
|
|
|
|
|
|
}
|
|
|
|
|
|
let outVideoFile = path.join(book.bookFolderPath, `data/frame/${element.name}.mp4`)
|
|
|
|
|
|
|
|
|
|
|
|
let res = await this.FfmpegCutVideo(
|
|
|
|
|
|
book,
|
|
|
|
|
|
startTime,
|
|
|
|
|
|
endTime,
|
|
|
|
|
|
book.oldVideoPath,
|
|
|
|
|
|
outVideoFile
|
|
|
|
|
|
)
|
|
|
|
|
|
if (res.code == 0) {
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT_FAIL, res.message)
|
|
|
|
|
|
throw new Error(res.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视频裁剪完成,要将裁剪后的视频地址写入到数据库中
|
|
|
|
|
|
_bookTaskDetailService.UpdateBookTaskDetail(element.id, {
|
|
|
|
|
|
videoPath: path.relative(define.project_path, outVideoFile)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 小改小说批次的状态
|
|
|
|
|
|
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.SPLIT_DONE)
|
|
|
|
|
|
|
|
|
|
|
|
// 结束,分镜完毕,推送日志,返回成功
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`全部视频裁剪完成`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
|
|
|
|
|
return successMessage(null, '全部视频裁剪完成', 'BasicReverse_CutVideoData')
|
2024-06-24 13:11:19 +08:00
|
|
|
|
} catch (error) {
|
2024-06-27 16:24:41 +08:00
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
error.message,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
return errorMessage(
|
|
|
|
|
|
'裁剪视频失败,错误信息如下: ' + error.message,
|
|
|
|
|
|
'BasicReverse_CutVideoData'
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 分离视频片段的音频,
|
|
|
|
|
|
* 当没有传入bookTaskId,分离默认的第一个,
|
|
|
|
|
|
* 有传入的时候,分离对应的bookTaskId的数据
|
|
|
|
|
|
* @param {*} bookId
|
|
|
|
|
|
* @param {*} bookTaskId
|
|
|
|
|
|
*/
|
|
|
|
|
|
async SplitAudioData(bookId, bookTaskId = null) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let _bookService = await BookService.getInstance()
|
|
|
|
|
|
let _bookTaskService = await BookTaskService.getInstance()
|
|
|
|
|
|
let _bookTaskDetailService = await BookTaskDetailService.getInstance()
|
|
|
|
|
|
let book = _bookService.GetBookDataById(bookId)
|
|
|
|
|
|
if (book == null) {
|
|
|
|
|
|
throw new Error('没有找到对应的小说数据')
|
|
|
|
|
|
}
|
|
|
|
|
|
let bookTask
|
|
|
|
|
|
if (bookTaskId != null) {
|
|
|
|
|
|
bookTaskId = _bookTaskService.GetBookTaskData({ id: bookTaskId })
|
|
|
|
|
|
} else {
|
|
|
|
|
|
bookTask = _bookTaskService.GetBookTaskData({
|
|
|
|
|
|
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 = _bookTaskDetailService.GetBookTaskData({
|
|
|
|
|
|
bookId: bookId,
|
|
|
|
|
|
bookTaskId: bookTask.id
|
|
|
|
|
|
})
|
|
|
|
|
|
if (bookTaskDetails.data.length <= 0) {
|
|
|
|
|
|
throw new Error('没有找到对应的小说批次任务数据,请检查bookId是否正确,或者手动执行')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`开始分离音频`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.DOING
|
|
|
|
|
|
)
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.AUDIO)
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < bookTaskDetails.length; i++) {
|
|
|
|
|
|
const element = bookTaskDetails[i]
|
|
|
|
|
|
let videoPath = element.videoPath
|
|
|
|
|
|
let audioPath = path.join(book.bookFolderPath, `data/audio/${element.name}.mp3`)
|
|
|
|
|
|
await CheckFolderExistsOrCreate(path.dirname(audioPath))
|
|
|
|
|
|
|
|
|
|
|
|
// 开始分离音频
|
|
|
|
|
|
let audioRes = await this.FfmpegExtractAudio(videoPath, audioPath)
|
|
|
|
|
|
if (audioRes.code == 0) {
|
|
|
|
|
|
let errorMessage = `分离音频失败,错误信息如下:${audioRes.message}`
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(
|
|
|
|
|
|
bookTask.id,
|
|
|
|
|
|
BookTaskStatus.AUDIO_FAIL,
|
|
|
|
|
|
errorMessage
|
|
|
|
|
|
)
|
|
|
|
|
|
throw new Error(audioRes.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_bookTaskDetailService.UpdateBookTaskDetail(element.id, {
|
|
|
|
|
|
audioPath: path.relative(define.project_path, audioPath)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 推送成功消息
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`${element.name}分离音频成功,输出地址:${audioPath}`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 修改状态为分离音频成功
|
|
|
|
|
|
_bookTaskService.UpdateBookTaskStatus(bookTask.id, BookTaskStatus.AUDIO_DONE)
|
|
|
|
|
|
// 所有音频分离成功,推送日志
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
`${element.name}分离音频成功,输出地址:${audioPath}`,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.SUCCESS
|
|
|
|
|
|
)
|
|
|
|
|
|
return successMessage(null, '所有音频分离成功', 'BasicReverse_SplitAudioData')
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
let errorMessage = `分离音频失败,错误信息如下:${error.message}`
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
errorMessage,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
return errorMessage(errorMessage, 'BasicReverse_SplitAudioData')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 提取字幕
|
|
|
|
|
|
* @param {*} bookId
|
|
|
|
|
|
* @param {*} bookTaskId
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
async ExtractSubtitlesData(bookId, bookTaskId = null) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
let errorMessage = `提取字幕失败,错误信息如下:${error.message}`
|
|
|
|
|
|
await this.taskScheduler.AddLogToDB(
|
|
|
|
|
|
bookId,
|
|
|
|
|
|
book.type,
|
|
|
|
|
|
errorMessage,
|
|
|
|
|
|
OtherData.DEFAULT,
|
|
|
|
|
|
LoggerStatus.FAIL
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return errorMessage(errorMessage, 'BasicReverse_ExtractSubtitlesData')
|
2024-06-24 13:11:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-06-27 16:24:41 +08:00
|
|
|
|
}
|