mxivideo/src/services/TemplateServiceV2.ts

441 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { invoke } from '@tauri-apps/api/core'
import { useAuthStore } from '../stores/useAuthStore'
// 统一的响应格式
export interface TemplateResponse {
success: boolean
message: string
data?: any
output?: string
error?: string
}
// 模板信息接口
export interface TemplateInfo {
id: string
name: string
description: string
thumbnail_path: string
draft_content_path: string
resources_path: string
created_at: string
updated_at: string
canvas_config: any
duration: number
material_count: number
track_count: number
tags: string[]
is_cloud: boolean
user_id: string
}
// 请求接口
export interface BatchImportRequest {
source_folder: string
user_id?: string
verbose?: boolean
json_output?: boolean
}
export interface TemplateListRequest {
user_id?: string
include_cloud?: boolean
limit?: number
verbose?: boolean
json_output?: boolean
}
export interface TemplateGetRequest {
template_id: string
user_id?: string
verbose?: boolean
json_output?: boolean
}
export interface TemplateDeleteRequest {
template_id: string
user_id?: string
verbose?: boolean
json_output?: boolean
}
export interface TemplateSearchRequest {
query: string
user_id?: string
include_cloud?: boolean
limit?: number
verbose?: boolean
json_output?: boolean
}
// 批量导入结果
export interface BatchImportResult {
imported_count: number
failed_count: number
imported_templates: Array<{
id: string
name: string
path: string
}>
failed_templates: Array<{
name: string
path: string
error: string
}>
message: string
}
// 统计信息
export interface TemplateStats {
total_templates: number
user_templates: number
cloud_templates: number
total_materials: number
total_tracks: number
total_duration: number
average_duration: number
}
// 标签信息
export interface TagInfo {
tag: string
count: number
}
// 轨道片段信息
export interface TrackSegment {
id: string
type: 'video' | 'audio' | 'image' | 'text' | 'effect'
name: string
start_time: number
end_time: number
duration: number
resource_path?: string
properties?: any
effects?: any[]
}
// 轨道信息
export interface Track {
id: string
name: string
type: 'video' | 'audio' | 'effect' | 'text' | 'sticker' | 'image'
index: number
segments: TrackSegment[]
properties?: any
}
// 模板详细信息
export interface TemplateDetail {
id: string
name: string
description: string
canvas_config: any
tracks: Track[]
duration: number
fps: number
sample_rate?: number
}
export class TemplateServiceV2 {
/**
* 获取当前用户ID
*/
private static getCurrentUserId(): string {
const authState = useAuthStore.getState()
if (!authState.isAuthenticated || !authState.user?.id) {
throw new Error('用户未登录,请先登录后再进行操作')
}
return authState.user.id
}
/**
* 批量导入模板 (新版本)
*/
static async batchImportTemplates(sourceFolder: string, userId?: string): Promise<BatchImportResult> {
try {
const request: BatchImportRequest = {
source_folder: sourceFolder,
user_id: userId || this.getCurrentUserId(),
verbose: false,
json_output: true
}
const response = await invoke<TemplateResponse>('batch_import_templates_cli', { request })
if (!response.success) {
throw new Error(response.error || response.message || 'Import failed')
}
return response.data as BatchImportResult
} catch (error) {
console.error('Batch import templates failed:', error)
throw error
}
}
/**
* 获取模板列表 (新版本)
*/
static async getTemplates(includeCloud: boolean = true, limit: number = 100, userId?: string): Promise<TemplateInfo[]> {
try {
const request: TemplateListRequest = {
user_id: userId || this.getCurrentUserId(),
include_cloud: includeCloud,
limit: limit,
verbose: false,
json_output: true
}
const response = await invoke<TemplateResponse>('get_templates_cli', { request })
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to get templates')
}
return response.data?.templates || []
} catch (error) {
console.error('Get templates failed:', error)
throw error
}
}
/**
* 获取单个模板 (新版本)
*/
static async getTemplate(templateId: string, userId?: string): Promise<TemplateInfo> {
try {
const request: TemplateGetRequest = {
template_id: templateId,
user_id: userId || this.getCurrentUserId(),
verbose: false,
json_output: true
}
const response = await invoke<TemplateResponse>('get_template_cli', { request })
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to get template')
}
return response.data as TemplateInfo
} catch (error) {
console.error('Get template failed:', error)
throw error
}
}
/**
* 获取模板详细信息 (新版本)
* 注意目前使用原版本的get_template_detail命令因为CLI版本还未实现详细信息功能
*/
static async getTemplateDetail(templateId: string): Promise<TemplateDetail | null> {
try {
// 暂时使用原版本的命令直到CLI版本实现详细信息功能
const response = await invoke<string>('get_template_detail', { template_id: templateId })
const detail = JSON.parse(response)
if (!detail) {
return null
}
return detail as TemplateDetail
} catch (error) {
console.error('Get template detail failed:', error)
return null
}
}
/**
* 删除模板 (新版本)
*/
static async deleteTemplate(templateId: string, userId?: string): Promise<boolean> {
try {
const request: TemplateDeleteRequest = {
template_id: templateId,
user_id: userId || this.getCurrentUserId(),
verbose: false,
json_output: true
}
const response = await invoke<TemplateResponse>('delete_template_cli', { request })
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to delete template')
}
return response.data?.deleted || false
} catch (error) {
console.error('Delete template failed:', error)
throw error
}
}
/**
* 搜索模板 (新功能)
*/
static async searchTemplates(
query: string,
includeCloud: boolean = true,
limit: number = 50,
userId?: string
): Promise<TemplateInfo[]> {
try {
const request: TemplateSearchRequest = {
query: query,
user_id: userId || this.getCurrentUserId(),
include_cloud: includeCloud,
limit: limit,
verbose: false,
json_output: true
}
const response = await invoke<TemplateResponse>('search_templates_cli', { request })
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to search templates')
}
return response.data?.templates || []
} catch (error) {
console.error('Search templates failed:', error)
throw error
}
}
/**
* 获取模板统计信息 (新功能)
*/
static async getTemplateStats(userId?: string): Promise<TemplateStats> {
try {
const response = await invoke<TemplateResponse>('get_template_stats_cli', {
user_id: userId || this.getCurrentUserId(),
verbose: false
})
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to get template stats')
}
return response.data as TemplateStats
} catch (error) {
console.error('Get template stats failed:', error)
throw error
}
}
/**
* 获取热门标签 (新功能)
*/
static async getPopularTags(limit: number = 20, userId?: string): Promise<TagInfo[]> {
try {
const response = await invoke<TemplateResponse>('get_popular_tags_cli', {
user_id: userId || this.getCurrentUserId(),
limit: limit,
verbose: false
})
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to get popular tags')
}
return response.data?.tags || []
} catch (error) {
console.error('Get popular tags failed:', error)
throw error
}
}
/**
* 根据标签获取模板 (新功能)
*/
static async getTemplatesByTag(
tag: string,
includeCloud: boolean = true,
limit: number = 50,
userId?: string
): Promise<TemplateInfo[]> {
try {
const response = await invoke<TemplateResponse>('get_templates_by_tag_cli', {
tag: tag,
user_id: userId || this.getCurrentUserId(),
include_cloud: includeCloud,
limit: limit,
verbose: false
})
if (!response.success) {
throw new Error(response.error || response.message || 'Failed to get templates by tag')
}
return response.data?.templates || []
} catch (error) {
console.error('Get templates by tag failed:', error)
throw error
}
}
/**
* 验证模板文件夹结构
*/
static validateTemplateFolder(folderPath: string): boolean {
// 这个方法保持不变,依赖后端验证
return true
}
/**
* 格式化持续时间
*/
static formatDuration(seconds: number): string {
const minutes = Math.floor(seconds / 60)
const remainingSeconds = seconds % 60
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
}
/**
* 格式化日期
*/
static formatDate(dateString: string): string {
try {
const date = new Date(dateString)
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'short',
day: 'numeric'
})
} catch {
return dateString
}
}
/**
* 获取模板缩略图URL
*/
static getThumbnailUrl(template: TemplateInfo): string {
if (template.thumbnail_path) {
// 如果是相对路径,转换为绝对路径
if (!template.thumbnail_path.startsWith('http') && !template.thumbnail_path.startsWith('/')) {
return `file://${template.resources_path}/${template.thumbnail_path}`
}
return template.thumbnail_path
}
return ''
}
/**
* 检查模板是否为云端模板
*/
static isCloudTemplate(template: TemplateInfo): boolean {
return template.is_cloud || false
}
/**
* 检查模板是否属于当前用户
*/
static isUserTemplate(template: TemplateInfo, userId?: string): boolean {
return template.user_id === (userId || this.getCurrentUserId())
}
}