1. 新增来推内置自营生图包 2. 新增 工具箱 菜单,添加 图片压缩 和 LaiTool图床(用作MJ垫图) 3. 新增一个新的推理模式 4. 修复剪映关键缩放大小计算错误 5. MJ生图包适配修改
853 lines
33 KiB
JavaScript
853 lines
33 KiB
JavaScript
import { define } from "../../define/define";
|
|
import path from "path";
|
|
import { Tools } from "../tools";
|
|
const { v4: uuidv4 } = require('uuid');
|
|
const fspromises = require("fs").promises;
|
|
const mm = require('music-metadata');
|
|
const wavFileInfo = require('wav-file-info');
|
|
let tools = new Tools();
|
|
import { PublicMethod } from './publicMethod'
|
|
import { cloneDeep } from "lodash";
|
|
const compressing = require("compressing");
|
|
|
|
export class ClipDraft {
|
|
constructor(global, value, draftName = null) {
|
|
this.speedId = null;
|
|
this.canvasesId = null;
|
|
this.soundChannelId = null;
|
|
this.vocalSeparationsId = null;
|
|
this.materialVideoId = null;
|
|
this.tracksSegmentsId = null;
|
|
this.trackTypeId = null;
|
|
this.materialAnimationsId = null;
|
|
this.materialsTextID = null;
|
|
this.materialsBeatsID = null;
|
|
this.textId = null;
|
|
this.friendlyReminderId = null;
|
|
this.draft_json = null;
|
|
this.one_duration_time = 5000000;
|
|
this.text_end_time = 0;
|
|
this.iamge_end_time = 0;
|
|
this.TTS_emd_time = 0;
|
|
this.draft_duration_time = 0;
|
|
this.global = global;
|
|
this.value = value;
|
|
this.pm = new PublicMethod(global);
|
|
this.draft_name = draftName;
|
|
}
|
|
|
|
async InitData() {
|
|
this.draft_name = this.draft_name ? this.draft_name : this.global.config.project_name + '_' + this.value[0];
|
|
let draft_path = path.join(this.global.config.draft_path, this.draft_name);
|
|
await fspromises.rm(draft_path, { recursive: true, force: true });
|
|
await compressing.zip.uncompress(define.draft_temp_path, path.join(this.global.config.draft_path, this.global.config.project_name + '_' + this.value[0]));
|
|
this.draftPath = path.join(draft_path, "draft_content.json");
|
|
this.image_dir = path.join(this.global.config.project_path, `tmp/${this.value[0]}`);
|
|
this.srtPath = this.value[1].srt_path;
|
|
this.style_id = this.value[1].draft_srt_style;
|
|
this.num = 1;
|
|
this.mp3_path = this.value[1].audio_path;
|
|
this.friendlyReminderId = this.value[1].friendly_reminder;
|
|
this.srt_information = (await this.pm.GetConfigJson(JSON.stringify(["srt_time_information", []]))).data;
|
|
}
|
|
|
|
/**
|
|
* 加载默认的草稿
|
|
* @returns
|
|
*/
|
|
async LoadDraftJson() {
|
|
let draft_json = JSON.parse(await fspromises.readFile(this.draftPath));
|
|
this.draft_json = draft_json;
|
|
// console.log(this.draft_json);
|
|
}
|
|
|
|
/**
|
|
* 添加speed
|
|
*/
|
|
async AddSpeeds() {
|
|
// 获取speed的模板地址
|
|
let speed_json = JSON.parse(await fspromises.readFile(define.clip_speed_temp_path));
|
|
// console.log(speed_json)
|
|
// 设置ID
|
|
let speedID = uuidv4().toUpperCase();
|
|
this.speedId = speedID;
|
|
speed_json.id = speedID;
|
|
return speed_json;
|
|
}
|
|
|
|
/**
|
|
* 添加Canvases
|
|
*/
|
|
async AddCanvases() {
|
|
let canvases_json = JSON.parse(await fspromises.readFile(define.add_canvases_temp_path));
|
|
// console.log(canvases_json);
|
|
// 设置ID
|
|
let canvasesId = uuidv4().toUpperCase();
|
|
this.canvasesId = canvasesId;
|
|
canvases_json.id = canvasesId;
|
|
return canvases_json;
|
|
}
|
|
|
|
/**
|
|
* 添加soundchannel
|
|
* @returns
|
|
*/
|
|
async AddSoundChannelMapping() {
|
|
let soundChannelMapping_json = JSON.parse(await fspromises.readFile(define.add_sound_channel_mappings_temp_path));
|
|
// console.log(soundChannelMapping_json)
|
|
let sound_channel_mappings_tmp_ID = uuidv4().toUpperCase();
|
|
this.soundChannelId = sound_channel_mappings_tmp_ID;
|
|
soundChannelMapping_json.id = sound_channel_mappings_tmp_ID;
|
|
return soundChannelMapping_json;
|
|
}
|
|
|
|
/**
|
|
* 添加 vocal_separations
|
|
*/
|
|
async AddVocalSeparations() {
|
|
let vocal_separations_json = JSON.parse(await fspromises.readFile(define.add_vocal_separations_temp_path));
|
|
// console.log(vocal_separations_json);
|
|
let vocalSeparationId = uuidv4().toUpperCase();
|
|
this.vocalSeparationsId = vocalSeparationId;
|
|
vocal_separations_json.id = vocalSeparationId;
|
|
return vocal_separations_json;
|
|
}
|
|
|
|
/**
|
|
* 添加一个文件到原材料地址
|
|
* @param {图片文件地址} imagePath
|
|
*/
|
|
async AddMaterialVideo(imagePath) {
|
|
let materialVideoTmpJson = JSON.parse(await fspromises.readFile(define.add_material_video_temp_path));
|
|
// console.log(materialVideoTmpJson);
|
|
let materialId = uuidv4().toUpperCase();
|
|
this.materialVideoId = materialId;
|
|
materialVideoTmpJson.id = materialId;
|
|
|
|
// 获取输入的图片宽高
|
|
materialVideoTmpJson.width = 1000;
|
|
materialVideoTmpJson.height = 1000;
|
|
|
|
materialVideoTmpJson.path = imagePath;
|
|
let image_name = path.basename(imagePath);
|
|
materialVideoTmpJson.material_name = image_name;
|
|
|
|
return materialVideoTmpJson;
|
|
}
|
|
|
|
/**
|
|
* 添加一个轨道
|
|
* @returns
|
|
*/
|
|
async AddTracksSegments() {
|
|
let tracksJson = JSON.parse(await fspromises.readFile(define.add_tracks_segments_temp_path));
|
|
// console.log(tracksJson);
|
|
let tracksSegmentsId = uuidv4().toUpperCase();
|
|
tracksJson.id = tracksSegmentsId;
|
|
tracksJson.extra_material_refs = [];
|
|
tracksJson.extra_material_refs.push(this.speedId);
|
|
tracksJson.extra_material_refs.push(this.canvasesId);
|
|
tracksJson.extra_material_refs.push(this.soundChannelId);
|
|
tracksJson.extra_material_refs.push(this.vocalSeparationsId);
|
|
tracksJson.material_id = this.materialVideoId;
|
|
tracksJson.target_timerange.start = this.num * tracksJson.target_timerange.duration;
|
|
return tracksJson;
|
|
}
|
|
|
|
/**
|
|
* 新建一个track
|
|
* @param {track的类型} type
|
|
*/
|
|
async AddTracks(type) {
|
|
let tracks_json = JSON.parse(await fspromises.readFile(define.add_tracks_type_temp_path));
|
|
let track_type_id = uuidv4();
|
|
this.trackTypeId = track_type_id;
|
|
tracks_json.id = this.trackTypeId;
|
|
tracks_json.type = type;
|
|
return tracks_json;
|
|
}
|
|
|
|
/**
|
|
* 添加单个图片到轨道
|
|
*/
|
|
async AddOneImageToDraft(image_path) {
|
|
// 添加 canvases
|
|
let canvanses = await this.AddCanvases();
|
|
this.draft_json.materials.canvases.push(canvanses)
|
|
|
|
// 添加 sound_channel_mappings
|
|
let sound_channel = await this.AddSoundChannelMapping();
|
|
this.draft_json.materials.sound_channel_mappings.push(sound_channel)
|
|
|
|
// 添加 speeds
|
|
let speeds = await this.AddSpeeds();
|
|
this.draft_json.materials.speeds.push(speeds);
|
|
|
|
// 添加 vocal_separations
|
|
let vocal_sep = await this.AddVocalSeparations();
|
|
this.draft_json.materials.vocal_separations.push(vocal_sep);
|
|
|
|
// 添加视频 materials 下面的 Videos
|
|
let video = await this.AddMaterialVideo(image_path);
|
|
this.draft_json.materials.videos.push(video);
|
|
|
|
// 添加track轨道
|
|
let segment = await this.AddTracksSegments();
|
|
return segment;
|
|
// this.draft_json.tracks.segments.push(segment);
|
|
}
|
|
|
|
/**
|
|
* 将所有的文件全部都写轨道上面
|
|
*/
|
|
async AddAllImageToTracks() {
|
|
let img_dir = path.normalize(this.image_dir);
|
|
let files = await fspromises.readdir(img_dir)
|
|
let imageFiles = files.filter(file => /\.(png)$/i.test(file));
|
|
imageFiles.sort();
|
|
imageFiles = imageFiles.map(item => path.join(img_dir, item))
|
|
// console.log(imageFiles);
|
|
|
|
// 创建一个tracks
|
|
let tracks_json = await this.AddTracks("video");
|
|
//往tracks里面的segments添加图片数据
|
|
for (let i = 0; i < imageFiles.length; i++) {
|
|
const image_path = imageFiles[i];
|
|
let segment = await this.AddOneImageToDraft(image_path);
|
|
tracks_json.segments.push(segment);
|
|
// console.log(tracks_json);
|
|
}
|
|
|
|
this.draft_json.tracks.push(tracks_json);
|
|
// 修改持续时间
|
|
let duration_time = imageFiles.length * this.one_duration_time;
|
|
this.iamge_end_time = duration_time;
|
|
}
|
|
|
|
/**
|
|
* 添加materials中的material_animations
|
|
*/
|
|
async AddMaterialAnimations() {
|
|
let material_animations = JSON.parse(await fspromises.readFile(define.add_material_animations_temp_path));
|
|
let material_animations_id = uuidv4();
|
|
this.materialAnimationsId = material_animations_id;
|
|
material_animations.id = material_animations_id;
|
|
return material_animations;
|
|
}
|
|
|
|
/**
|
|
* 为字幕添加样式
|
|
*/
|
|
async AddTextStyle(material_text_json) {
|
|
try {
|
|
let clip_setting = JSON.parse(await fspromises.readFile(define.clip_setting));
|
|
let text_style = clip_setting.text_style.filter(item => item.id != "0" && item.id != "1");
|
|
|
|
// 添加默认样式
|
|
let c = JSON.parse(material_text_json.content);
|
|
let data = JSON.parse(`[{\"size\":7.882736,\"fill\":{\"content\":{\"solid\":{\"color\":[1,1,1]}}},\"range\":[0,5]}]`);
|
|
data[0].range = [0, c.text.length];
|
|
c["styles"] = data;
|
|
material_text_json.content = JSON.stringify(c);
|
|
return material_text_json;
|
|
|
|
// 判断是不是添加样式添加样式
|
|
if (this.style_id == "0") {
|
|
return material_text_json;
|
|
} else if (this.style_id == "1") {
|
|
// 随机
|
|
const randomIndex = Math.floor(Math.random() * text_style.length);
|
|
this.style_id = text_style[randomIndex].id;
|
|
}
|
|
let style = text_style.filter(item => item.id == this.style_id)[0];
|
|
let content = JSON.parse(material_text_json.content);
|
|
|
|
// 修改范围
|
|
let textstring = content.text;
|
|
let length = textstring.length;
|
|
style.style[0].range = [0, length];
|
|
|
|
content.styles = style.style;
|
|
material_text_json.content = JSON.stringify(content);
|
|
let path = style.style[0].font.path;
|
|
let id = style.style[0].font.id;
|
|
let font_size = style.font_size;
|
|
let fonts = style.fonts;
|
|
let style_name = style.style_name;
|
|
material_text_json.fonts.id = uuidv4();
|
|
material_text_json.font_category_id = id;
|
|
material_text_json.fonts.path = path;
|
|
material_text_json.fonts.title = fonts;
|
|
material_text_json.check_flag = font_size;
|
|
material_text_json.title = fonts;
|
|
material_text_json.font_size = font_size;
|
|
material_text_json.style_name = style_name;
|
|
return material_text_json;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获得一个单的materialsText
|
|
*/
|
|
async AddMaterialsText(textString) {
|
|
let material_text_json = JSON.parse(await fspromises.readFile(define.add_material_text_temp_path));
|
|
let material_text_id = uuidv4();
|
|
this.materialsTextID = material_text_id;
|
|
material_text_json.id = material_text_id;
|
|
|
|
// 设置内容
|
|
let content = JSON.parse(material_text_json.content);
|
|
content.text = textString;
|
|
material_text_json.content = JSON.stringify(content);
|
|
|
|
material_text_json = await this.AddTextStyle(material_text_json);
|
|
return material_text_json;
|
|
}
|
|
|
|
async ModifyTextClipTransform(text_segments) {
|
|
// console.log(text_segments);
|
|
|
|
let clip_setting = JSON.parse(await fspromises.readFile(define.clip_setting));
|
|
let text_style = clip_setting.text_style;
|
|
if (text_style.length <= 0)
|
|
return text_segments;
|
|
let style = text_style.filter(item => item.id == this.style_id)[0];
|
|
text_segments.clip = style.clip;
|
|
return text_segments;
|
|
|
|
}
|
|
|
|
/**
|
|
* 添加一个字幕到tracks
|
|
* @returns
|
|
*/
|
|
async AddOneTextToDraft(timeObj) {
|
|
try {
|
|
|
|
// 添加 materials 中的 material_animations
|
|
let material_animattions = await this.AddMaterialAnimations();
|
|
this.draft_json.materials.material_animations.push(material_animattions);
|
|
|
|
// 添加 materials 下面的texts
|
|
let material_text = await this.AddMaterialsText(timeObj.text);
|
|
this.draft_json.materials.texts.push(material_text);
|
|
|
|
let text_segments = JSON.parse(await fspromises.readFile(define.add_track_text_segments_temp_path));
|
|
let textId = uuidv4();
|
|
this.textId = textId;
|
|
text_segments.id = textId;
|
|
text_segments.extra_material_refs = [this.materialAnimationsId];
|
|
text_segments.material_id = this.materialsTextID;
|
|
text_segments.target_timerange.start = timeObj.start;
|
|
text_segments.target_timerange.duration = timeObj.end - timeObj.start;
|
|
|
|
// 修改样式偏移量
|
|
text_segments = await this.ModifyTextClipTransform(text_segments);
|
|
|
|
return text_segments;
|
|
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
message: `Error Message ${error}`
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加所有的text到tracks里面
|
|
*/
|
|
async AddAllTextToTrack() {
|
|
// 添加一个tracks
|
|
let new_tracks = await this.AddTracks("text");
|
|
// 计算时间
|
|
let srt_data = (await fspromises.readFile(this.srtPath)).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)) * 1000;
|
|
});
|
|
return { start, end, text };
|
|
}
|
|
}).filter(entry => entry);
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
const text = data[i];
|
|
let text_se = await this.AddOneTextToDraft(text);
|
|
// console.log(text_se);
|
|
new_tracks.segments.push(text_se);
|
|
if (i == data.length - 1) {
|
|
this.text_end_time = text.end;
|
|
}
|
|
}
|
|
// console.log(this.draft_json)
|
|
this.draft_json.tracks.push(new_tracks);
|
|
}
|
|
|
|
/**
|
|
* 添加 materials下面的 beats
|
|
*/
|
|
async AddMaterialsBeats() {
|
|
let beats_json = JSON.parse(await fspromises.readFile(define.add_materials_beats_tmp_path));
|
|
let materialsBeatsID = uuidv4();
|
|
this.materialsBeatsID = materialsBeatsID;
|
|
beats_json.id = materialsBeatsID;
|
|
return beats_json;
|
|
}
|
|
|
|
|
|
async getAudioDuration(filePath) {
|
|
const ext = filePath.split('.').pop().toLowerCase();
|
|
|
|
switch (ext) {
|
|
case 'mp3':
|
|
try {
|
|
const metadata = await mm.parseFile(filePath);
|
|
return metadata.format.duration;
|
|
} catch (error) {
|
|
throw new Error(error);
|
|
}
|
|
|
|
case 'wav':
|
|
return new Promise((resolve, reject) => {
|
|
wavFileInfo.infoByFilename(filePath, (err, info) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(info.duration);
|
|
}
|
|
});
|
|
});
|
|
|
|
default:
|
|
throw new Error("不支持的文件类型");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加 materials 下面的 audios
|
|
*/
|
|
async AddMaterialsAudios(musicPath) {
|
|
try {
|
|
let audios_json = JSON.parse(await fspromises.readFile(define.add_materials_audios_tmp_path));
|
|
let mp3_name = path.basename(musicPath);
|
|
let time = await this.getAudioDuration(path.normalize(musicPath));
|
|
let duration_time = time * 1000000;
|
|
if (this.audios_duration_time == undefined) {
|
|
this.audios_duration_time = duration_time;
|
|
}
|
|
let audiosID = uuidv4();
|
|
this.materialsAudiosID = audiosID;
|
|
audios_json.id = audiosID;
|
|
audios_json.name = mp3_name;
|
|
audios_json.duration = duration_time;
|
|
audios_json.path = musicPath;
|
|
console.log(audios_json)
|
|
return audios_json;
|
|
|
|
} catch (error) {
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加tracks下面的audios下面的Segments
|
|
*/
|
|
async AddAudioTracksSegments() {
|
|
try {
|
|
let audio_segments = JSON.parse(await fspromises.readFile(define.add_tracks_audio_segments_tmp_path));
|
|
let audioId = uuidv4();
|
|
this.tracksAudioId = audioId;
|
|
audio_segments.id = audioId;
|
|
audio_segments.material_id = this.materialsAudiosID;
|
|
audio_segments.extra_material_refs = [];
|
|
audio_segments.extra_material_refs.push(this.speedID);
|
|
audio_segments.extra_material_refs.push(this.materialsBeatsID);
|
|
audio_segments.extra_material_refs.push(this.soundChannelId);
|
|
audio_segments.extra_material_refs.push(this.vocalSeparationsId);
|
|
audio_segments.source_timerange.duration = this.audios_duration_time;
|
|
audio_segments.target_timerange.duration = this.audios_duration_time;
|
|
return audio_segments;
|
|
} catch (error) {
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加配音
|
|
*/
|
|
async AddTTSMusic(musicPath) {
|
|
// 添加speeds
|
|
let speeds = await this.AddSpeeds();
|
|
this.draft_json.materials.speeds.push(speeds);
|
|
|
|
// 添加beats
|
|
let beats = await this.AddMaterialsBeats();
|
|
this.draft_json.materials.beats.push(beats);
|
|
|
|
// 添加 sound_channel_mappings
|
|
let sound_channel_mappings = await this.AddSoundChannelMapping();
|
|
this.draft_json.materials.sound_channel_mappings.push(sound_channel_mappings)
|
|
|
|
// 添加 materials 下面的 audios
|
|
let audios = await this.AddMaterialsAudios(musicPath);
|
|
this.draft_json.materials.audios.push(audios);
|
|
|
|
// 添加一个track
|
|
let tracks_json = await this.AddTracks("audio");
|
|
|
|
let audio_segments_json = await this.AddAudioTracksSegments();
|
|
tracks_json.segments.push(audio_segments_json);
|
|
this.draft_json.tracks.push(tracks_json);
|
|
}
|
|
|
|
/**
|
|
* 添加背景音乐
|
|
* @param {背景音乐的ID} background_music_id
|
|
*/
|
|
async AddRandomBackfroundMusic(background_music_id) {
|
|
try {
|
|
// 获取背景音乐文件夹
|
|
let clip_setting_json = JSON.parse(await fspromises.readFile(define.clip_setting));
|
|
let setting = clip_setting_json.background_music_setting.filter(item => item.id == background_music_id);
|
|
console.log(setting);
|
|
let folder_path = setting[0].folder_path;
|
|
console.log(folder_path);
|
|
let files = await tools.getFilesWithExtensions(folder_path, [".mp3", ".wav"]);
|
|
if (files.length == 0) {
|
|
throw new Error("背景音乐文件夹下面未存在数据");
|
|
}
|
|
// 获取随机的数据
|
|
const randomIndex = Math.floor(Math.random() * files.length);
|
|
let musicPath = files[randomIndex];
|
|
|
|
// 添加speeds
|
|
let speeds = await this.AddSpeeds();
|
|
this.draft_json.materials.speeds.push(speeds);
|
|
|
|
// 添加beats
|
|
let beats = await this.AddMaterialsBeats();
|
|
this.draft_json.materials.beats.push(beats);
|
|
|
|
// 添加 sound_channel_mappings
|
|
let sound_channel_mappings = await this.AddSoundChannelMapping();
|
|
this.draft_json.materials.sound_channel_mappings.push(sound_channel_mappings)
|
|
|
|
// 添加 materials 下面的 audios
|
|
let audios = await this.AddMaterialsAudios(musicPath);
|
|
// audios.duration = this.text_end_time;
|
|
this.draft_json.materials.audios.push(audios);
|
|
|
|
// 添加一个track
|
|
let tracks_json = await this.AddTracks("audio");
|
|
let audio_segments_json = await this.AddAudioTracksSegments();
|
|
// 修改
|
|
audio_segments_json.source_timerange.duration = this.audios_duration_time;
|
|
audio_segments_json.target_timerange.duration = this.audios_duration_time;
|
|
tracks_json.segments.push(audio_segments_json);
|
|
this.draft_json.tracks.push(tracks_json);
|
|
|
|
} catch (error) {
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加温馨提示
|
|
*/
|
|
async AddFriendlyReminder() {
|
|
// 直接push
|
|
try {
|
|
|
|
return;
|
|
|
|
let friendlyReminder = null;
|
|
let friendlyReminderSetting = JSON.parse(await fspromises.readFile(define.clip_setting)).friendly_reminder_setting;
|
|
friendlyReminderSetting = friendlyReminderSetting.filter(item => item.id != "0" && item.id != "1");
|
|
if (friendlyReminderSetting.length <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (this.friendlyReminderId == "0") {
|
|
return;
|
|
} else if (this.friendlyReminderId == "1") {
|
|
// 获取随机的数据
|
|
const randomIndex = Math.floor(Math.random() * friendlyReminderSetting.length);
|
|
friendlyReminder = friendlyReminderSetting[randomIndex];
|
|
} else {
|
|
friendlyReminder = friendlyReminderSetting.filter(item => item.id == this.friendlyReminderId);
|
|
}
|
|
|
|
// 添加 materials 下面的 material_animations
|
|
this.draft_json.materials.material_animations.push(friendlyReminder.material_animations);
|
|
// 添加 materials下面的texts
|
|
this.draft_json.materials.texts.push(friendlyReminder.texts);
|
|
// 添加 tracks
|
|
let track = friendlyReminder.tracks;
|
|
// 修改持续时间
|
|
track.segments[0].target_timerange.duration = this.audios_duration_time;
|
|
this.draft_json.tracks.push(track);
|
|
} catch (error) {
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 修改草稿的持续时间
|
|
*/
|
|
async ModifyDurationTime() {
|
|
|
|
let max_time = Math.max(this.iamge_end_time, this.text_end_time, this.audios_duration_time);
|
|
this.draft_json.duration = max_time;
|
|
this.draft_json.canvas_config.height = 1440;
|
|
this.draft_json.canvas_config.width = 1920;
|
|
this.draft_json.canvas_config.ratio = "4:3";
|
|
}
|
|
|
|
/**
|
|
* 将文件写道指定的位置
|
|
*/
|
|
async WriteDraftFile() {
|
|
await fspromises.writeFile(this.draftPath, JSON.stringify(this.draft_json));
|
|
}
|
|
|
|
async find_draft_node(nodes, type, value) {
|
|
for (let index = 0; index < nodes.length; index++) {
|
|
let node = nodes[index];
|
|
if (node[type] == value) {
|
|
return node
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将草稿图片和文字对齐
|
|
*/
|
|
async AlginDraftImgToText() {
|
|
// 所有的字幕轨道里面的数据,读取出来
|
|
let img_nodes = (await this.find_draft_node(this.draft_json.tracks, "type", "video")).segments;
|
|
|
|
//将最后一个数据修改为背景音乐的最后时间
|
|
this.srt_information[this.srt_information.length - 1].end_time = this.audios_duration_time / 1000;
|
|
|
|
// 开始对齐
|
|
for (let i = 0; i < this.srt_information.length; i++) {
|
|
if (img_nodes.length < i) {
|
|
break;
|
|
}
|
|
const element = this.srt_information[i];
|
|
let duration = 0;
|
|
if (i + 1 < this.srt_information.length) {
|
|
duration = (this.srt_information[i + 1].start_time - element.start_time - 1) * 1000;
|
|
} else {
|
|
duration = (element.end_time - element.start_time) * 1000;
|
|
}
|
|
img_nodes[i].source_timerange.duration = duration;
|
|
img_nodes[i].target_timerange.duration = duration;
|
|
img_nodes[i].target_timerange.start = element.start_time * 1000;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 通过 key_frame 返回关键帧数据
|
|
* @param {*} key_frame 关键帧配置
|
|
*/
|
|
async GetFrameData(key_frame_key, key_frame) {
|
|
if (key_frame_key == "KFTypePositionY") {
|
|
return key_frame.up_down_key_frame;
|
|
} else if (key_frame_key == "KFTypePositionX") {
|
|
return key_frame.left_right_key_frame;
|
|
} else if (key_frame_key == "KFTypeScale") {
|
|
return key_frame.scale_key_frame;
|
|
} else {
|
|
return {
|
|
"default_scale": 100,
|
|
"start_position": 0,
|
|
"end_position": 0
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 图片添加关键帧
|
|
*/
|
|
async AddKeyFarme() {
|
|
let img_nodes = (await this.find_draft_node(this.draft_json.tracks, "type", "video")).segments;
|
|
let key_frame_tmp_data = await fspromises.readFile(define.add_keyframe_tmp_path, "utf-8");
|
|
|
|
// 添加关键帧
|
|
// 将最后一个数据修改为背景音乐的最后时间
|
|
this.srt_information[this.srt_information.length - 1].end_time = this.audios_duration_time / 1000;
|
|
|
|
let key_frame_setting = await tools.getJsonFilePropertyValue(define.clip_setting, "key_frame", null, false);
|
|
// 判断关键帧配置是不是存在。不存在直接结束
|
|
if (key_frame_setting == null) {
|
|
return;
|
|
}
|
|
let isFixedSpeed = key_frame_setting.isFixedSpeed;
|
|
let isDown = true;
|
|
|
|
// 获取通用的关键帧配置,然后添加到每一个图片上面(可以设置时间。当前图片的持续实现小于设置的时间。会计算不要过快)
|
|
for (let i = 0; i < img_nodes.length; i++) {
|
|
let element = img_nodes[i];
|
|
let image_duartion = cloneDeep(element.source_timerange.duration);
|
|
let key_frame = key_frame_setting.key_frame;
|
|
// 做随机处理
|
|
let real_key_frame = key_frame;
|
|
let key_frame_list = ["KFTypePositionY", "KFTypePositionX", "KFTypeScale"];
|
|
if (key_frame == "KFTypeRandom") {
|
|
// 随机获取 key_frame_list 里面的一个数据
|
|
const randomIndex = Math.floor(Math.random() * key_frame_list.length);
|
|
real_key_frame = key_frame_list[randomIndex];
|
|
}
|
|
|
|
let key_frame_pos = await this.GetFrameData(real_key_frame, key_frame_setting);
|
|
|
|
let key_frame_time = key_frame_setting.key_frame_time * 1000000;
|
|
let scale_rate = key_frame_pos.default_scale / 100;
|
|
|
|
let up_pos = Math.abs(key_frame_pos.start_position);
|
|
let down_pos = Math.abs(key_frame_pos.end_position);
|
|
let key_frame_tmp = JSON.parse(key_frame_tmp_data)
|
|
|
|
if (real_key_frame == "KFTypePositionY") {
|
|
// 勾选了匀速。需要计算时间(计算比例)
|
|
if (isFixedSpeed && image_duartion < key_frame_time) {
|
|
let time_rate = image_duartion / key_frame_time;
|
|
up_pos = up_pos * time_rate;
|
|
down_pos = down_pos * time_rate;
|
|
}
|
|
let up_pos_rate = isDown ? (up_pos / this.draft_json.canvas_config.height) : (0 - up_pos / this.draft_json.canvas_config.height)
|
|
key_frame_tmp.id = uuidv4();
|
|
key_frame_tmp.keyframe_list[0].id = uuidv4(); // Corrected assignment
|
|
key_frame_tmp.keyframe_list[0].values = [up_pos_rate];
|
|
|
|
let dow_pos_rate = isDown ? (0 - down_pos / this.draft_json.canvas_config.height) : (down_pos / this.draft_json.canvas_config.height)
|
|
key_frame_tmp.keyframe_list[1].id = uuidv4();
|
|
key_frame_tmp.keyframe_list[1].time_offset = image_duartion;
|
|
key_frame_tmp.keyframe_list[1].values = [dow_pos_rate];
|
|
|
|
key_frame_tmp.property_type = real_key_frame;
|
|
|
|
// 修改缩放倍率
|
|
element.clip.scale.x = scale_rate;
|
|
element.clip.scale.y = scale_rate;
|
|
element.clip.transform.y = dow_pos_rate;
|
|
isDown = !isDown;
|
|
} else if (real_key_frame == "KFTypePositionX") {
|
|
// 勾选了匀速。需要计算时间(计算比例)
|
|
if (isFixedSpeed && image_duartion < key_frame_time) {
|
|
let time_rate = image_duartion / key_frame_time;
|
|
up_pos = up_pos * time_rate;
|
|
down_pos = down_pos * time_rate;
|
|
}
|
|
let up_pos_rate = isDown ? (up_pos / this.draft_json.canvas_config.width) : (0 - up_pos / this.draft_json.canvas_config.width)
|
|
key_frame_tmp.id = uuidv4();
|
|
key_frame_tmp.keyframe_list[0].id == uuidv4();
|
|
key_frame_tmp.keyframe_list[0].values = [up_pos_rate];
|
|
|
|
let dow_pos_rate = isDown ? (0 - down_pos / this.draft_json.canvas_config.width) : (down_pos / this.draft_json.canvas_config.width)
|
|
key_frame_tmp.keyframe_list[1].id = uuidv4();
|
|
key_frame_tmp.keyframe_list[1].time_offset = image_duartion;
|
|
key_frame_tmp.keyframe_list[1].values = [dow_pos_rate];
|
|
|
|
key_frame_tmp.property_type = real_key_frame;
|
|
|
|
// 修改缩放倍率
|
|
element.clip.scale.x = scale_rate;
|
|
element.clip.scale.y = scale_rate;
|
|
element.clip.transform.x = dow_pos_rate;
|
|
isDown = !isDown;
|
|
}
|
|
else if (real_key_frame == "KFTypeScale") {
|
|
if (isFixedSpeed && image_duartion < key_frame_time) {
|
|
let time_rate = image_duartion / key_frame_time;
|
|
// 计算方式和上面的不同
|
|
let sub_total = Math.abs(up_pos - down_pos);
|
|
let currwnt_rate = sub_total * (1 - time_rate);
|
|
up_pos = up_pos - (up_pos * (currwnt_rate / up_pos)) / 2;
|
|
down_pos = down_pos + (down_pos * (currwnt_rate / down_pos)) / 2;
|
|
}
|
|
|
|
// 修改上面的数据,添加Y轴缩放
|
|
let up_pos_rate = isDown ? up_pos / 100 : down_pos / 100;
|
|
key_frame_tmp.id = uuidv4();
|
|
key_frame_tmp.keyframe_list[0].id == uuidv4();
|
|
key_frame_tmp.keyframe_list[0].values = [up_pos_rate];
|
|
|
|
let dow_pos_rate = isDown ? down_pos / 100 : up_pos / 100;
|
|
key_frame_tmp.keyframe_list[1].id = uuidv4();
|
|
key_frame_tmp.keyframe_list[1].time_offset = image_duartion;
|
|
key_frame_tmp.keyframe_list[1].values = [dow_pos_rate];
|
|
|
|
key_frame_tmp.property_type = real_key_frame + "X";
|
|
|
|
// 修改上面的数据,添加Y轴缩放
|
|
// 修改缩放倍率
|
|
element.clip.scale.x = isDown ? up_pos : dow_pos_rate;
|
|
element.clip.scale.y = isDown ? up_pos : dow_pos_rate;
|
|
element.clip.transform.x = 0;
|
|
element.common_keyframes.push(key_frame_tmp);
|
|
|
|
|
|
key_frame_tmp = JSON.parse(JSON.stringify(key_frame_tmp))
|
|
key_frame_tmp.id = uuidv4();
|
|
key_frame_tmp.keyframe_list[0].id == uuidv4();
|
|
key_frame_tmp.keyframe_list[1].id = uuidv4();
|
|
key_frame_tmp.property_type = real_key_frame + "Y";
|
|
isDown = !isDown;
|
|
}
|
|
element.common_keyframes.push(key_frame_tmp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 添加草稿
|
|
*/
|
|
async addDraft() {
|
|
try {
|
|
await this.InitData();
|
|
await this.LoadDraftJson();
|
|
await this.AddAllImageToTracks();
|
|
await this.AddAllTextToTrack();
|
|
await this.AddTTSMusic(path.normalize(this.value[1].audio_path));
|
|
if (this.value[1].background_music != "" && this.value[1].background_music != undefined && this.value[1].background_music != null) {
|
|
await this.AddRandomBackfroundMusic(this.value[1].background_music);
|
|
}
|
|
|
|
// 添加温馨提示
|
|
// await this.AddFriendlyReminder();
|
|
|
|
|
|
await this.ModifyDurationTime();
|
|
|
|
// 对齐草稿数据
|
|
await this.AlginDraftImgToText();
|
|
|
|
// 添加关键帧
|
|
await this.AddKeyFarme();
|
|
|
|
await this.WriteDraftFile();
|
|
return {
|
|
code: 1,
|
|
draft_name: this.draft_name
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
message: `An error occurred: ${error}`
|
|
}
|
|
}
|
|
}
|
|
|
|
} |