Files
LaiTool/src/define/db/service/Book/bookService.ts
T

338 lines
11 KiB
TypeScript
Raw Normal View History

2024-06-24 13:11:19 +08:00
import Realm, { UpdateMode } from 'realm'
import { BookModel } from '../../model/Book/book.js'
import path from 'path'
2025-05-29 14:44:37 +08:00
import { define } from '../../../define'
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'
2024-11-09 16:46:06 +08:00
import { Book } from '../../../../model/book/book.js'
2024-08-18 16:22:19 +08:00
import { GeneralResponse } from '../../../../model/generalResponse.js'
2025-08-09 18:46:07 +08:00
import { ImageToVideoModels } from '@/define/enum/video.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) {
2024-11-09 16:46:06 +08:00
imageCategory = global.config.defaultImageMode ?? BookImageCategory.MJ
2024-08-03 12:46:12 +08:00
} else {
throw new Error('未知的小说类型')
}
2025-08-09 18:46:07 +08:00
let videoCategory = ImageToVideoModels.MJ_VIDEO;
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,
2025-02-17 18:26:47 +08:00
imageCategory: imageCategory,
2025-08-09 18:46:07 +08:00
videoCategory: videoCategory,
2025-02-17 18:26:47 +08:00
openVideoGenerate: false
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
}