2024-06-24 13:11:19 +08:00
|
|
|
import Realm, { UpdateMode } from 'realm'
|
|
|
|
|
import { BookModel } from '../../model/Book/book.js'
|
|
|
|
|
import path from 'path'
|
|
|
|
|
import { define } from '../../../define.js'
|
2024-08-03 12:46:12 +08:00
|
|
|
import { BookImageCategory, BookTaskStatus, BookType } from '../../../enum/bookEnum.js'
|
|
|
|
|
import { successMessage } from '../../../../main/Public/generalTools'
|
|
|
|
|
import { CheckFolderExistsOrCreate, CopyFileOrFolder } from '../../../Tools/file'
|
2024-06-24 13:11:19 +08:00
|
|
|
const { v4: uuidv4 } = require('uuid')
|
|
|
|
|
import { BaseRealmService } from './bookBasic.js'
|
|
|
|
|
import { isEmpty } from 'lodash'
|
2024-08-03 12:46:12 +08:00
|
|
|
import { FfmpegOptions } from '../../../../main/Service/ffmpegOptions.js'
|
|
|
|
|
import { version } from '../../../../../package.json'
|
|
|
|
|
import { Book } from '../../../../model/book.js'
|
2024-08-18 16:22:19 +08:00
|
|
|
import { GeneralResponse } from '../../../../model/generalResponse.js'
|
2024-06-24 13:11:19 +08:00
|
|
|
|
2024-06-27 16:24:41 +08:00
|
|
|
export class BookService extends BaseRealmService {
|
|
|
|
|
static instance: BookService | null = null
|
2024-06-24 13:11:19 +08:00
|
|
|
realm: Realm
|
|
|
|
|
|
|
|
|
|
private constructor() {
|
|
|
|
|
super()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取当前实例对象,为空则创建一个新的
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
public static async getInstance() {
|
2024-06-27 16:24:41 +08:00
|
|
|
if (BookService.instance === null) {
|
|
|
|
|
BookService.instance = new BookService()
|
2024-06-24 13:11:19 +08:00
|
|
|
await super.getInstance()
|
|
|
|
|
}
|
2024-06-27 16:24:41 +08:00
|
|
|
await BookService.instance.open()
|
|
|
|
|
return BookService.instance
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取小说信息,没有找到返回null
|
|
|
|
|
* @param bookId
|
|
|
|
|
*/
|
2024-08-18 16:22:19 +08:00
|
|
|
GetBookDataById(bookId: string): Book.SelectBook | null {
|
2024-06-27 16:24:41 +08:00
|
|
|
try {
|
|
|
|
|
if (isEmpty(bookId)) {
|
|
|
|
|
throw new Error('获取小说信息失败,缺少小说ID')
|
|
|
|
|
}
|
|
|
|
|
let books = this.realm.objects<BookModel>('Book').filtered('id = $0', bookId)
|
|
|
|
|
if (books.length <= 0) {
|
2024-08-03 12:46:12 +08:00
|
|
|
return null
|
2024-06-27 16:24:41 +08:00
|
|
|
} else {
|
|
|
|
|
// 对返回的数据进行处理
|
|
|
|
|
let resBooks = Array.from(books).map((book) => {
|
|
|
|
|
// 这里可以直接操作普通对象
|
|
|
|
|
let bookObj = {
|
|
|
|
|
...book,
|
|
|
|
|
bookFolderPath: path.resolve(
|
|
|
|
|
define.project_path,
|
|
|
|
|
book.bookFolderPath.replace(/\\/g, '/')
|
|
|
|
|
),
|
|
|
|
|
oldVideoPath: book.oldVideoPath
|
|
|
|
|
? path.resolve(define.project_path, book.oldVideoPath.replace(/\\/g, '/'))
|
|
|
|
|
: '',
|
|
|
|
|
imageFolder: book.imageFolder
|
|
|
|
|
? path.resolve(define.project_path, book.imageFolder.replace(/\\/g, '/'))
|
|
|
|
|
: ''
|
|
|
|
|
}
|
|
|
|
|
return bookObj
|
|
|
|
|
})
|
2024-08-03 12:46:12 +08:00
|
|
|
return resBooks[0]
|
2024-06-27 16:24:41 +08:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
2024-06-24 13:11:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取小说信息,通过参数查询
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2024-06-27 16:24:41 +08:00
|
|
|
GetBookData(bookQuery) {
|
2024-06-24 13:11:19 +08:00
|
|
|
try {
|
|
|
|
|
// 获取所有的小说数据,并进行时间降序排序
|
|
|
|
|
let books = this.realm.objects<BookModel>('Book')
|
|
|
|
|
let book_length = books.length
|
|
|
|
|
|
|
|
|
|
// 开始开始筛选
|
|
|
|
|
if (bookQuery.bookId) {
|
|
|
|
|
// 查询对应的小说ID的数据
|
|
|
|
|
books = books.filtered('id = $0', bookQuery.bookId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
books = books.sorted('updateTime', true)
|
|
|
|
|
// 判断是不是有page和pageSize,有的话对查询返回的信息做分页
|
|
|
|
|
if (bookQuery.page && bookQuery.pageSize) {
|
|
|
|
|
books = books.slice(
|
|
|
|
|
(bookQuery.page - 1) * bookQuery.pageSize,
|
|
|
|
|
bookQuery.page * bookQuery.pageSize
|
|
|
|
|
) as unknown as Realm.Results<BookModel>
|
|
|
|
|
}
|
|
|
|
|
if (books.length <= 0) {
|
|
|
|
|
return successMessage(
|
|
|
|
|
{
|
|
|
|
|
res_book: [],
|
|
|
|
|
book_length: 0
|
|
|
|
|
},
|
|
|
|
|
'没有数据',
|
|
|
|
|
'ReverseBook_GetBookData'
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将realm对象数组转换为普通对象数组
|
|
|
|
|
let res_book = Array.from(books).map((book) => {
|
|
|
|
|
// 这里可以直接操作普通对象
|
|
|
|
|
let bookObj = {
|
|
|
|
|
...book,
|
|
|
|
|
bookFolderPath: path.resolve(
|
|
|
|
|
define.project_path,
|
|
|
|
|
book.bookFolderPath.replace(/\\/g, '/')
|
|
|
|
|
),
|
|
|
|
|
oldVideoPath: book.oldVideoPath
|
|
|
|
|
? path.resolve(define.project_path, book.oldVideoPath.replace(/\\/g, '/'))
|
|
|
|
|
: '',
|
|
|
|
|
imageFolder: book.imageFolder
|
|
|
|
|
? path.resolve(define.project_path, book.imageFolder.replace(/\\/g, '/'))
|
2024-08-03 12:46:12 +08:00
|
|
|
: '',
|
|
|
|
|
imageStyle: book.imageStyle ? Array.from(book.imageStyle) : [],
|
|
|
|
|
customizeImageStyle: book.customizeImageStyle ? Array.from(book.imageStyle) : [],
|
|
|
|
|
} as Book.SelectBook
|
2024-06-24 13:11:19 +08:00
|
|
|
return bookObj
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return successMessage(
|
|
|
|
|
{
|
|
|
|
|
res_book,
|
|
|
|
|
book_length
|
|
|
|
|
},
|
|
|
|
|
'获取成功',
|
|
|
|
|
'ReverseBook_GetBookData'
|
|
|
|
|
)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 新增或者是修小说数据
|
|
|
|
|
* @param {*} book 小说信息
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
async AddOrModifyBook(book) {
|
|
|
|
|
try {
|
|
|
|
|
if (book == null) {
|
|
|
|
|
throw new Error('小说数据为空,无法修改')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 当小说的类型是反推的时候,必须传入视频
|
|
|
|
|
if (book.type == BookType.MJ_REVERSE || book.type == BookType.SD_REVERSE) {
|
|
|
|
|
// 判断视频是否存在
|
|
|
|
|
if (book.oldVideoPath == null || book.oldVideoPath == '') {
|
|
|
|
|
throw new Error('反推必须传入视频')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (book.id == null) {
|
|
|
|
|
// 新增
|
|
|
|
|
// 判断指定的名字在数据库中是否存在
|
|
|
|
|
let books = this.realm.objects('Book').filtered('name = $0', book.name)
|
|
|
|
|
if (books.length > 0) {
|
|
|
|
|
throw new Error(`小说名字 ${book.name} 已经存在,请更换小说名字`)
|
|
|
|
|
}
|
|
|
|
|
console.log(this)
|
|
|
|
|
// 新增数据
|
|
|
|
|
book.id = uuidv4()
|
|
|
|
|
book.createTime = new Date()
|
|
|
|
|
book.updateTime = new Date()
|
|
|
|
|
// 检查传入的视频文件是不是存在
|
|
|
|
|
// 获取当前最大的no
|
|
|
|
|
let maxNo = this.realm.objects('Book').max('no')
|
|
|
|
|
book.no = maxNo == null ? 1 : Number(maxNo) + 1
|
|
|
|
|
// 拼接项目文件夹
|
|
|
|
|
book.bookFolderPath = book.id
|
|
|
|
|
book.imageFolder = `${book.id}/tmp`
|
|
|
|
|
let bookFolderPath = path.resolve(define.project_path, book.id)
|
|
|
|
|
let imageFolder = path.resolve(define.project_path, `${book.id}/tmp`)
|
|
|
|
|
let oldVideoPath = path.resolve(define.project_path, `${book.id}/data/${book.id}.mp4`)
|
2024-06-27 16:24:41 +08:00
|
|
|
let bookTaskImageFolder = path.resolve(imageFolder, 'output_00001')
|
2024-06-24 13:11:19 +08:00
|
|
|
|
|
|
|
|
// 将视频拷贝一个到项目文件下面
|
|
|
|
|
if (book.oldVideoPath) {
|
|
|
|
|
await CopyFileOrFolder(book.oldVideoPath, oldVideoPath)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建对应的文件夹
|
|
|
|
|
await CheckFolderExistsOrCreate(bookFolderPath)
|
|
|
|
|
await CheckFolderExistsOrCreate(imageFolder)
|
2024-06-27 16:24:41 +08:00
|
|
|
await CheckFolderExistsOrCreate(bookTaskImageFolder) // 创建默认的任务文件夹
|
2024-06-24 13:11:19 +08:00
|
|
|
// 修改数据
|
|
|
|
|
book.oldVideoPath = path.relative(define.project_path, oldVideoPath)
|
2024-09-12 14:13:09 +08:00
|
|
|
if (book.type == BookType.ORIGINAL) {
|
|
|
|
|
book.oldVideoPath = null
|
|
|
|
|
}
|
2024-08-03 12:46:12 +08:00
|
|
|
|
|
|
|
|
let imageCategory = BookImageCategory.MJ
|
|
|
|
|
if (book.type == BookType.SD_REVERSE) {
|
|
|
|
|
imageCategory = BookImageCategory.SD
|
|
|
|
|
} else if (book.type == BookType.MJ_REVERSE) {
|
|
|
|
|
imageCategory = BookImageCategory.MJ
|
|
|
|
|
} else if (book.type == BookType.ORIGINAL) {
|
|
|
|
|
imageCategory = BookImageCategory.MJ
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('未知的小说类型')
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:11:19 +08:00
|
|
|
this.realm.write(() => {
|
2024-08-03 12:46:12 +08:00
|
|
|
book.version = version
|
2024-06-24 13:11:19 +08:00
|
|
|
this.realm.create('Book', book)
|
2024-08-03 12:46:12 +08:00
|
|
|
|
2024-06-24 13:11:19 +08:00
|
|
|
// 添加一个任务
|
|
|
|
|
let bookTask = {
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
bookId: book.id,
|
|
|
|
|
no: 1,
|
|
|
|
|
name: 'output_00001',
|
|
|
|
|
generateVideoPath: null,
|
|
|
|
|
srtPath: null,
|
|
|
|
|
audioPath: null,
|
|
|
|
|
imageFolder: path.relative(define.project_path, bookTaskImageFolder), // 获取文件输出对于项目的相对路径
|
|
|
|
|
styleList: [],
|
|
|
|
|
prefix: null,
|
|
|
|
|
status: BookTaskStatus.WAIT,
|
|
|
|
|
errorMsg: null,
|
|
|
|
|
isAuto: false,
|
|
|
|
|
updateTime: new Date(),
|
2024-08-03 12:46:12 +08:00
|
|
|
createTime: new Date(),
|
|
|
|
|
version: version,
|
|
|
|
|
imageCategory: imageCategory
|
2024-06-24 13:11:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加任务
|
|
|
|
|
this.realm.create('BookTask', bookTask)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 保存成功,返回数据,但是要做处理
|
|
|
|
|
book.bookFolderPath = bookFolderPath
|
|
|
|
|
book.imageFolder = imageFolder
|
|
|
|
|
book.oldVideoPath = oldVideoPath
|
|
|
|
|
|
|
|
|
|
return successMessage(book, '新增成功', 'BookBasic_AddOrModifyBook')
|
|
|
|
|
} else {
|
|
|
|
|
// 修改
|
|
|
|
|
// 判断指定的名字在数据库中是否存在(不算自己)
|
|
|
|
|
let books = this.realm
|
|
|
|
|
.objects('Book')
|
|
|
|
|
.filtered('name = $0 AND id != $1', book.name, book.id)
|
|
|
|
|
if (books.length > 0) {
|
|
|
|
|
throw new Error(`小说名字 ${book.name} 已经存在,请更换小说名字`)
|
|
|
|
|
}
|
|
|
|
|
// 两个文件夹地址不能改,删除两个属性
|
|
|
|
|
delete book.bookFolderPath
|
|
|
|
|
delete book.imageFolder
|
|
|
|
|
// 修改数据
|
|
|
|
|
book.updateTime = new Date()
|
2024-07-13 15:44:13 +08:00
|
|
|
this.transaction(() => {
|
2024-06-24 13:11:19 +08:00
|
|
|
this.realm.create('Book', book, UpdateMode.Modified)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 保存成功,返回数据,但是要做处理
|
|
|
|
|
return successMessage(null, '修改成功', 'BookBasic_AddOrModifyBook')
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-13 15:44:13 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 修改小说数据
|
|
|
|
|
* @param bookId 小说的ID
|
|
|
|
|
* @param bookData 要修改的小说数据
|
|
|
|
|
*/
|
2024-08-18 16:22:19 +08:00
|
|
|
UpdateBookData(bookId: string, bookData: Book.SelectBook): Book.SelectBook {
|
2024-07-13 15:44:13 +08:00
|
|
|
try {
|
|
|
|
|
if (bookId == null) {
|
|
|
|
|
throw new Error('修改小说数据失败,缺少小说ID')
|
|
|
|
|
}
|
|
|
|
|
if (bookData == null) {
|
|
|
|
|
throw new Error('修改小说数据失败,缺少小说数据')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查小说ID对应的数据是不是存在
|
|
|
|
|
let bookRes = this.GetBookDataById(bookId)
|
2024-08-03 12:46:12 +08:00
|
|
|
if (bookRes == null) {
|
2024-07-13 15:44:13 +08:00
|
|
|
throw new Error('修改小说数据失败,小说ID对应的数据不存在')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bookData && bookData.id) {
|
|
|
|
|
delete bookData.id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 开始修改
|
|
|
|
|
this.transaction(() => {
|
|
|
|
|
this.realm.create('Book', { id: bookId, ...bookData }, UpdateMode.Modified)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
bookRes = this.GetBookDataById(bookId)
|
2024-08-03 12:46:12 +08:00
|
|
|
if (bookRes == null) {
|
2024-07-13 15:44:13 +08:00
|
|
|
throw new Error('获取修改后的小说数据失败,小说ID对应的数据不存在')
|
|
|
|
|
}
|
2024-08-18 16:22:19 +08:00
|
|
|
// return successMessage(bookRes, '修改小说数据成功', 'ReverseBook_UpdateBookData')
|
|
|
|
|
return bookRes;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-13 15:44:13 +08:00
|
|
|
|
2024-08-18 16:22:19 +08:00
|
|
|
/**
|
|
|
|
|
* 删除指定的小说任务
|
|
|
|
|
* @param bookId 需要删除的小说的ID
|
|
|
|
|
*/
|
|
|
|
|
DeleteBookData(bookId: string): void {
|
|
|
|
|
try {
|
|
|
|
|
this.transaction(() => {
|
|
|
|
|
let book = this.realm.objectForPrimaryKey('Book', bookId);
|
|
|
|
|
if (book == null) {
|
|
|
|
|
throw new Error('未找到对应的小说')
|
|
|
|
|
}
|
|
|
|
|
// 删除对应的小说
|
|
|
|
|
this.realm.delete(book)
|
|
|
|
|
})
|
2024-07-13 15:44:13 +08:00
|
|
|
} catch (error) {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-24 13:11:19 +08:00
|
|
|
}
|