301 lines
12 KiB
JavaScript
301 lines
12 KiB
JavaScript
|
|
let path = require("path");
|
|||
|
|
let fspromises = require("fs").promises;
|
|||
|
|
import { Tools } from "../tools";
|
|||
|
|
import { DEFINE_STRING } from "../../define/define_string";
|
|||
|
|
import { PublicMethod } from "../Public/publicMethod";
|
|||
|
|
import { define } from "../../define/define";
|
|||
|
|
import { get, has } from "lodash";
|
|||
|
|
import { ClipSetting } from "../../define/setting/clipSetting";
|
|||
|
|
const { v4: uuidv4 } = require('uuid'); // 引入UUID库来生成唯一标识符
|
|||
|
|
let tools = new Tools();
|
|||
|
|
|
|||
|
|
export class Writing {
|
|||
|
|
constructor(global) {
|
|||
|
|
this.global = global
|
|||
|
|
this.pm = new PublicMethod(global);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 将文案信息写入到本地的文案文件中
|
|||
|
|
* @param {*} value
|
|||
|
|
*/
|
|||
|
|
async SaveWordTxt(value) {
|
|||
|
|
try {
|
|||
|
|
let word_path = path.join(global.config.project_path, "文案.txt");
|
|||
|
|
await tools.writeArrayToFile(value, word_path);
|
|||
|
|
return {
|
|||
|
|
code: 1,
|
|||
|
|
message: "保存成功"
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
throw new Error(error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 将分镜的时间信息添加道配置文件中
|
|||
|
|
* @param {*} value 是一个数组,0 :写入的数据 1:写入的属性 2:是否需要解析
|
|||
|
|
*/
|
|||
|
|
async SaveCopywritingInformation(value) {
|
|||
|
|
try {
|
|||
|
|
return await this.pm.SaveConfigJsonProperty(value);
|
|||
|
|
} catch (error) {
|
|||
|
|
return {
|
|||
|
|
code: 0,
|
|||
|
|
message: error.toString()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取Config.json文件中指定的属性
|
|||
|
|
* @param {Array} value 传入的值 0 : 需要获取的属性 1: 返回的默认值
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
async GetConfigJson(value) {
|
|||
|
|
try {
|
|||
|
|
return await this.pm.GetConfigJson(value, false);
|
|||
|
|
} catch (error) {
|
|||
|
|
return {
|
|||
|
|
code: 0,
|
|||
|
|
message: error.toString()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取当前项目下面的文案
|
|||
|
|
*/
|
|||
|
|
async GetProjectWord() {
|
|||
|
|
try {
|
|||
|
|
// 先判断当前的项目文件下面是不是又配置文件。没有才读取文案
|
|||
|
|
let srt_config_path = path.join(global.config.project_path, "scripts/config.json");
|
|||
|
|
let isExist = await tools.checkExists(srt_config_path);
|
|||
|
|
let data = null;
|
|||
|
|
let isImformation = false;
|
|||
|
|
if (isExist) {
|
|||
|
|
let config_1 = JSON.parse(await fspromises.readFile(srt_config_path));
|
|||
|
|
isImformation = has(config_1, 'srt_time_information');
|
|||
|
|
if (isImformation) {
|
|||
|
|
data = JSON.parse(await fspromises.readFile(srt_config_path)).srt_time_information;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!isExist || !isImformation) {
|
|||
|
|
let word_path = path.join(global.config.project_path, "文案.txt");
|
|||
|
|
let isExistWord = await tools.checkExists(word_path);
|
|||
|
|
if (!isExistWord) {
|
|||
|
|
return {
|
|||
|
|
code: 0,
|
|||
|
|
message: "没有文案文件"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
let data = await fspromises.readFile(word_path, { encoding: 'utf-8' });
|
|||
|
|
let lines = data.split(/\r?\n/);
|
|||
|
|
// 打印或返回这个数组
|
|||
|
|
// console.log(lines);
|
|||
|
|
// 判断是不是有洗稿后的文件
|
|||
|
|
let new_srt_path = path.join(global.config.project_path, "new_word.txt");
|
|||
|
|
let isExistAfterGPTWord = await tools.checkExists(new_srt_path);
|
|||
|
|
let after_data = null;
|
|||
|
|
if (isExistAfterGPTWord) {
|
|||
|
|
after_data = (await fspromises.readFile(new_srt_path, { encoding: 'utf-8' })).split(/\r?\n/);
|
|||
|
|
}
|
|||
|
|
// 判断抽帧文件是不是存在
|
|||
|
|
// 返回图片信息
|
|||
|
|
let old_image_path_list = await tools.getFilesWithExtensions(path.join(global.config.project_path, "tmp/input_crop"), '.png');
|
|||
|
|
let res = [];
|
|||
|
|
let lastId = '';
|
|||
|
|
// 处理数据
|
|||
|
|
for (let i = 0; i < lines.length; i++) {
|
|||
|
|
const line = lines[i];
|
|||
|
|
let id = uuidv4();
|
|||
|
|
let after_gpt = null;
|
|||
|
|
if (after_data != null) {
|
|||
|
|
after_gpt = after_data[i];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let img_path = null;
|
|||
|
|
if (old_image_path_list != null) {
|
|||
|
|
img_path = old_image_path_list[i];
|
|||
|
|
}
|
|||
|
|
let obj = {
|
|||
|
|
no: i + 1,
|
|||
|
|
id: id,
|
|||
|
|
lastId: lastId,
|
|||
|
|
word: line,
|
|||
|
|
old_image: img_path,
|
|||
|
|
after_gpt: after_gpt,
|
|||
|
|
start_time: null,
|
|||
|
|
end_time: null,
|
|||
|
|
timeLimit: null,
|
|||
|
|
subValue: []
|
|||
|
|
}
|
|||
|
|
res.push(obj);
|
|||
|
|
lastId = id;
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
code: 1,
|
|||
|
|
type: 0,
|
|||
|
|
data: res
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
let data = JSON.parse(await fspromises.readFile(srt_config_path)).srt_time_information;
|
|||
|
|
return {
|
|||
|
|
code: 1,
|
|||
|
|
type: 1,
|
|||
|
|
data: data
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
throw new Error(error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 搭导入srt。然后加载时间轴。完全匹配失败的将会还是会导入然后手动手动切换
|
|||
|
|
* @param {文案洗稿界面信息} textData
|
|||
|
|
*/
|
|||
|
|
async ImportSrtAndGetTime(data) {
|
|||
|
|
let textData = data[0];
|
|||
|
|
let init_num = textData.length;
|
|||
|
|
let srt_path = data[1];
|
|||
|
|
let current_text = "";
|
|||
|
|
try {
|
|||
|
|
if (!srt_path) {
|
|||
|
|
// 获取项目下面的所有的srt
|
|||
|
|
let srtfiles = await tools.getFilesWithExtensions(global.config.project_path, '.srt');
|
|||
|
|
if (srtfiles.length <= 0) {
|
|||
|
|
throw new Error("没有SRT文件");
|
|||
|
|
}
|
|||
|
|
srt_path = srtfiles[0];
|
|||
|
|
}
|
|||
|
|
let srt_data = (await fspromises.readFile(srt_path, 'utf-8')).toString("utf-8");
|
|||
|
|
const entries = srt_data.replace(/\r\n/g, '\n').split('\n\n');
|
|||
|
|
let data = entries.map(entry => {
|
|||
|
|
const lines = entry.split('\n');
|
|||
|
|
if (lines.length >= 3) {
|
|||
|
|
const times = lines[1];
|
|||
|
|
const text = lines.slice(2).join(' ');
|
|||
|
|
const [start, end] = times.split(' --> ').map(time => {
|
|||
|
|
const [hours, minutes, seconds] = time.split(':');
|
|||
|
|
const [sec, millis] = seconds.split(',');
|
|||
|
|
return ((parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(sec)) * 1000 + parseInt(millis));
|
|||
|
|
});
|
|||
|
|
return { start, end, text, id: uuidv4() };
|
|||
|
|
}
|
|||
|
|
}).filter(entry => entry);
|
|||
|
|
// 开始匹配(洗稿后的)
|
|||
|
|
let srt_list = [];
|
|||
|
|
let srt_obj = null
|
|||
|
|
let text_count = 0;
|
|||
|
|
let tmp_str = "";
|
|||
|
|
for (let i = 0; i < data.length;) {
|
|||
|
|
let srt_value = data[i].text;
|
|||
|
|
current_text = `字幕: “${srt_value}” 和文案第${text_count + 1} 行数据 “${textData[text_count].after_gpt}” 数据不匹配(检查一下上下文)`;
|
|||
|
|
let start_time = data[i].start;
|
|||
|
|
let end_time = data[i].end;
|
|||
|
|
let obj = {
|
|||
|
|
start_time,
|
|||
|
|
end_time,
|
|||
|
|
srt_value,
|
|||
|
|
id: data[i].id
|
|||
|
|
};
|
|||
|
|
// 判断当前字幕是不是在当前句
|
|||
|
|
// 不能用简单的包含,而是将数据进行去除特殊符号拼接后判断是不是相同
|
|||
|
|
tmp_str += srt_value;
|
|||
|
|
if (tools.removePunctuationIncludingEllipsis(textData[text_count].after_gpt).startsWith(tools.removePunctuationIncludingEllipsis(tmp_str))) {
|
|||
|
|
if (srt_obj == null) {
|
|||
|
|
srt_obj = {}
|
|||
|
|
srt_obj.id = uuidv4();
|
|||
|
|
srt_obj.start_time = start_time;
|
|||
|
|
srt_obj.value = srt_value;
|
|||
|
|
srt_obj.subValue = [obj];
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
srt_obj.value = srt_obj.value + srt_value;
|
|||
|
|
srt_obj.subValue = [...srt_obj.subValue, obj];
|
|||
|
|
}
|
|||
|
|
textData[text_count].start_time = srt_obj.start_time;
|
|||
|
|
textData[text_count].subValue = srt_obj.subValue
|
|||
|
|
srt_list.push(obj);
|
|||
|
|
i++;
|
|||
|
|
} else {
|
|||
|
|
// 判断下一句文件是不是以当当前巨开头。是的话继续。不是的话。直接返回后面的所有信息
|
|||
|
|
if (tools.removePunctuationIncludingEllipsis(textData[text_count + 1].after_gpt).startsWith(tools.removePunctuationIncludingEllipsis(srt_value))) {
|
|||
|
|
textData[text_count].end_time = srt_list[srt_list.length - 1].end_time;
|
|||
|
|
text_count++;
|
|||
|
|
srt_obj = null;
|
|||
|
|
tmp_str = ""
|
|||
|
|
} else {
|
|||
|
|
// 将下面的数据直接 添加到textData后面。
|
|||
|
|
// 修改当前行数据的结束事件为
|
|||
|
|
if (srt_list.length > 0) {
|
|||
|
|
textData[text_count].end_time = srt_list[srt_list.length - 1].end_time;
|
|||
|
|
text_count++;
|
|||
|
|
}
|
|||
|
|
// 将后面的数据直接添加
|
|||
|
|
let lastId = textData[textData.length - 1].id;
|
|||
|
|
for (let j = i; j < data.length; j++) {
|
|||
|
|
// 直接修改原有数据
|
|||
|
|
if (text_count < init_num) {
|
|||
|
|
textData[text_count].subValue = [{
|
|||
|
|
start_time: data[j].start,
|
|||
|
|
end_time: data[j].end,
|
|||
|
|
id: data[j].id,
|
|||
|
|
srt_value: data[j].text
|
|||
|
|
}]
|
|||
|
|
textData[text_count].start_time = data[j].start;
|
|||
|
|
textData[text_count].end_time = data[j].end;
|
|||
|
|
text_count++;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
let id = uuidv4();
|
|||
|
|
// 添加
|
|||
|
|
let obj = {
|
|||
|
|
no: j + 1,
|
|||
|
|
id: id,
|
|||
|
|
word: null,
|
|||
|
|
lastId: lastId,
|
|||
|
|
old_image: path.normalize(define.zhanwei_image),
|
|||
|
|
after_gpt: null,
|
|||
|
|
start_time: data[j].start,
|
|||
|
|
end_time: data[j].end,
|
|||
|
|
subValue: [{
|
|||
|
|
start_time: data[j].start,
|
|||
|
|
end_time: data[j].end,
|
|||
|
|
id: data[j].id,
|
|||
|
|
srt_value: data[j].text
|
|||
|
|
}]
|
|||
|
|
}
|
|||
|
|
lastId = id;
|
|||
|
|
textData.push(obj);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
|||
|
|
code: 0,
|
|||
|
|
message: current_text
|
|||
|
|
})
|
|||
|
|
return {
|
|||
|
|
code: 1,
|
|||
|
|
data: textData
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 最后对齐
|
|||
|
|
textData[textData.length - 1].end_time = srt_list[srt_list.length - 1].end_time
|
|||
|
|
// 返回数据
|
|||
|
|
return {
|
|||
|
|
code: 1,
|
|||
|
|
data: textData
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
return {
|
|||
|
|
code: 0,
|
|||
|
|
message: error.toString()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|