366 lines
10 KiB
Rust
366 lines
10 KiB
Rust
use serde::{Deserialize, Serialize};
|
||
use chrono::{DateTime, Utc};
|
||
|
||
/// 模板实体模型
|
||
/// 遵循 Tauri 开发规范的数据模型设计原则
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct Template {
|
||
pub id: String,
|
||
pub name: String,
|
||
pub description: Option<String>,
|
||
pub canvas_config: CanvasConfig,
|
||
pub duration: u64, // 模板总时长(微秒)
|
||
pub fps: f64,
|
||
pub materials: Vec<TemplateMaterial>,
|
||
pub tracks: Vec<Track>,
|
||
pub import_status: ImportStatus,
|
||
pub source_file_path: Option<String>, // 原始draft_content.json文件路径
|
||
pub created_at: DateTime<Utc>,
|
||
pub updated_at: DateTime<Utc>,
|
||
pub is_active: bool,
|
||
}
|
||
|
||
/// 画布配置
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct CanvasConfig {
|
||
pub width: u32,
|
||
pub height: u32,
|
||
pub ratio: String, // "original", "16:9", "9:16", etc.
|
||
}
|
||
|
||
/// 模板素材
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct TemplateMaterial {
|
||
pub id: String,
|
||
pub template_id: String,
|
||
pub original_id: String, // 原始剪映素材ID
|
||
pub name: String,
|
||
pub material_type: TemplateMaterialType,
|
||
pub original_path: String, // 原始本地路径
|
||
pub remote_url: Option<String>, // 上传后的远程URL
|
||
pub file_size: Option<u64>,
|
||
pub duration: Option<u64>, // 素材时长(微秒)
|
||
pub width: Option<u32>,
|
||
pub height: Option<u32>,
|
||
pub upload_status: UploadStatus,
|
||
pub file_exists: bool, // 本地文件是否存在
|
||
pub upload_success: bool, // 是否上传成功
|
||
pub metadata: Option<String>, // JSON格式的额外元数据
|
||
pub created_at: DateTime<Utc>,
|
||
pub updated_at: DateTime<Utc>,
|
||
}
|
||
|
||
/// 轨道
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct Track {
|
||
pub id: String,
|
||
pub template_id: String,
|
||
pub name: String,
|
||
pub track_type: TrackType,
|
||
pub track_index: u32, // 轨道索引
|
||
pub segments: Vec<TrackSegment>,
|
||
pub created_at: DateTime<Utc>,
|
||
pub updated_at: DateTime<Utc>,
|
||
}
|
||
|
||
/// 轨道片段
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct TrackSegment {
|
||
pub id: String,
|
||
pub track_id: String,
|
||
pub template_material_id: Option<String>, // 关联的模板素材ID
|
||
pub name: String,
|
||
pub start_time: u64, // 开始时间(微秒)
|
||
pub end_time: u64, // 结束时间(微秒)
|
||
pub duration: u64, // 片段时长(微秒)
|
||
pub segment_index: u32, // 片段在轨道中的索引
|
||
pub properties: Option<String>, // JSON格式的片段属性(如变换、效果等)
|
||
pub created_at: DateTime<Utc>,
|
||
pub updated_at: DateTime<Utc>,
|
||
}
|
||
|
||
/// 模板素材类型
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub enum TemplateMaterialType {
|
||
Video,
|
||
Audio,
|
||
Image,
|
||
Text,
|
||
Effect,
|
||
Sticker,
|
||
Canvas,
|
||
Other(String),
|
||
}
|
||
|
||
/// 轨道类型
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub enum TrackType {
|
||
Video,
|
||
Audio,
|
||
Text,
|
||
Sticker,
|
||
Effect,
|
||
Other(String),
|
||
}
|
||
|
||
/// 导入状态
|
||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||
pub enum ImportStatus {
|
||
Pending, // 等待导入
|
||
Parsing, // 解析中
|
||
Uploading, // 上传中
|
||
Processing, // 处理中
|
||
Completed, // 完成
|
||
Failed, // 失败
|
||
}
|
||
|
||
/// 上传状态
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub enum UploadStatus {
|
||
Pending, // 等待上传
|
||
Uploading, // 上传中
|
||
Completed, // 上传完成
|
||
Failed, // 上传失败
|
||
Skipped, // 跳过(文件不存在等)
|
||
}
|
||
|
||
/// 创建模板请求
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct CreateTemplateRequest {
|
||
pub name: String,
|
||
pub description: Option<String>,
|
||
pub project_id: Option<String>,
|
||
pub source_file_path: String, // draft_content.json文件路径
|
||
}
|
||
|
||
/// 模板导入请求
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct ImportTemplateRequest {
|
||
pub file_path: String, // draft_content.json文件路径
|
||
pub template_name: Option<String>, // 自定义模板名称
|
||
pub project_id: Option<String>,
|
||
pub auto_upload: bool, // 是否自动上传素材到云端
|
||
}
|
||
|
||
/// 批量导入请求
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct BatchImportRequest {
|
||
pub folder_path: String, // 包含多个draft_content.json的文件夹路径
|
||
pub project_id: Option<String>,
|
||
pub auto_upload: bool,
|
||
pub max_concurrent: Option<u32>, // 最大并发数
|
||
}
|
||
|
||
/// 导入进度信息
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct ImportProgress {
|
||
pub template_id: String,
|
||
pub template_name: String,
|
||
pub status: ImportStatus,
|
||
pub total_materials: u32,
|
||
pub uploaded_materials: u32,
|
||
pub failed_materials: u32,
|
||
pub current_operation: String,
|
||
pub error_message: Option<String>,
|
||
pub progress_percentage: f64, // 0.0 - 100.0
|
||
}
|
||
|
||
impl Template {
|
||
/// 创建新的模板实例
|
||
pub fn new(
|
||
name: String,
|
||
canvas_config: CanvasConfig,
|
||
duration: u64,
|
||
fps: f64,
|
||
) -> Self {
|
||
let now = Utc::now();
|
||
Self {
|
||
id: uuid::Uuid::new_v4().to_string(),
|
||
name,
|
||
description: None,
|
||
canvas_config,
|
||
duration,
|
||
fps,
|
||
materials: Vec::new(),
|
||
tracks: Vec::new(),
|
||
import_status: ImportStatus::Pending,
|
||
source_file_path: None,
|
||
created_at: now,
|
||
updated_at: now,
|
||
is_active: true,
|
||
}
|
||
}
|
||
|
||
/// 添加素材
|
||
pub fn add_material(&mut self, material: TemplateMaterial) {
|
||
self.materials.push(material);
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 添加轨道
|
||
pub fn add_track(&mut self, track: Track) {
|
||
self.tracks.push(track);
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 更新导入状态
|
||
pub fn update_import_status(&mut self, status: ImportStatus) {
|
||
self.import_status = status;
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 获取所有需要上传的素材
|
||
pub fn get_pending_upload_materials(&self) -> Vec<&TemplateMaterial> {
|
||
self.materials
|
||
.iter()
|
||
.filter(|m| matches!(m.upload_status, UploadStatus::Pending))
|
||
.collect()
|
||
}
|
||
|
||
/// 获取上传进度
|
||
pub fn get_upload_progress(&self) -> f64 {
|
||
if self.materials.is_empty() {
|
||
return 100.0;
|
||
}
|
||
|
||
let completed = self.materials
|
||
.iter()
|
||
.filter(|m| matches!(m.upload_status, UploadStatus::Completed | UploadStatus::Skipped))
|
||
.count();
|
||
|
||
(completed as f64 / self.materials.len() as f64) * 100.0
|
||
}
|
||
}
|
||
|
||
impl TemplateMaterial {
|
||
/// 创建新的模板素材实例
|
||
pub fn new(
|
||
id: String, // 素材的真实ID(来自剪映草稿)
|
||
template_id: String,
|
||
original_id: String, // local_material_id
|
||
name: String,
|
||
material_type: TemplateMaterialType,
|
||
original_path: String,
|
||
) -> Self {
|
||
let now = Utc::now();
|
||
Self {
|
||
id, // 使用传入的真实ID
|
||
template_id,
|
||
original_id, // original_id 对应 local_material_id,可以重复
|
||
name,
|
||
material_type,
|
||
original_path,
|
||
remote_url: None,
|
||
file_size: None,
|
||
duration: None,
|
||
width: None,
|
||
height: None,
|
||
upload_status: UploadStatus::Pending,
|
||
file_exists: false,
|
||
upload_success: false,
|
||
metadata: None,
|
||
created_at: now,
|
||
updated_at: now,
|
||
}
|
||
}
|
||
|
||
/// 更新上传状态
|
||
pub fn update_upload_status(&mut self, status: UploadStatus, remote_url: Option<String>) {
|
||
self.upload_status = status;
|
||
if let Some(url) = remote_url {
|
||
self.remote_url = Some(url);
|
||
}
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 检查本地文件是否存在
|
||
pub fn file_exists(&self) -> bool {
|
||
if self.original_path.is_empty() {
|
||
return false;
|
||
}
|
||
std::path::Path::new(&self.original_path).exists()
|
||
}
|
||
|
||
/// 更新文件存在状态
|
||
pub fn update_file_exists(&mut self) {
|
||
self.file_exists = self.file_exists();
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 更新上传成功状态
|
||
pub fn update_upload_success(&mut self, success: bool) {
|
||
self.upload_success = success;
|
||
self.updated_at = Utc::now();
|
||
}
|
||
}
|
||
|
||
impl Track {
|
||
/// 创建新的轨道实例
|
||
pub fn new(
|
||
id: String, // 轨道的真实ID(来自剪映草稿)
|
||
template_id: String,
|
||
name: String,
|
||
track_type: TrackType,
|
||
track_index: u32,
|
||
) -> Self {
|
||
let now = Utc::now();
|
||
Self {
|
||
id, // 使用传入的真实ID
|
||
template_id,
|
||
name,
|
||
track_type,
|
||
track_index,
|
||
segments: Vec::new(),
|
||
created_at: now,
|
||
updated_at: now,
|
||
}
|
||
}
|
||
|
||
/// 添加片段
|
||
pub fn add_segment(&mut self, segment: TrackSegment) {
|
||
self.segments.push(segment);
|
||
self.updated_at = Utc::now();
|
||
}
|
||
|
||
/// 获取轨道总时长
|
||
pub fn get_total_duration(&self) -> u64 {
|
||
self.segments
|
||
.iter()
|
||
.map(|s| s.duration)
|
||
.max()
|
||
.unwrap_or(0)
|
||
}
|
||
}
|
||
|
||
impl TrackSegment {
|
||
/// 创建新的轨道片段实例
|
||
pub fn new(
|
||
id: String, // 片段的真实ID(来自剪映草稿)
|
||
track_id: String,
|
||
name: String,
|
||
start_time: u64,
|
||
end_time: u64,
|
||
segment_index: u32,
|
||
) -> Self {
|
||
let now = Utc::now();
|
||
Self {
|
||
id, // 使用传入的真实ID
|
||
track_id,
|
||
template_material_id: None,
|
||
name,
|
||
start_time,
|
||
end_time,
|
||
duration: end_time - start_time,
|
||
segment_index,
|
||
properties: None,
|
||
created_at: now,
|
||
updated_at: now,
|
||
}
|
||
}
|
||
|
||
/// 关联模板素材
|
||
pub fn associate_material(&mut self, material_id: String) {
|
||
self.template_material_id = Some(material_id);
|
||
}
|
||
}
|