fix
This commit is contained in:
parent
e733f91daa
commit
197f083e3d
|
|
@ -61,6 +61,55 @@ class TemplateManager:
|
||||||
self.metadata_file = self.templates_dir / "templates.json"
|
self.metadata_file = self.templates_dir / "templates.json"
|
||||||
self.templates_metadata = self._load_metadata()
|
self.templates_metadata = self._load_metadata()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def detect_segment_type_from_path(file_path: str) -> str:
|
||||||
|
"""根据文件路径的扩展名检测片段类型"""
|
||||||
|
if not file_path:
|
||||||
|
return 'video' # 默认类型
|
||||||
|
|
||||||
|
file_extension = file_path.lower().split('.')[-1] if '.' in file_path else ''
|
||||||
|
|
||||||
|
# 视频格式
|
||||||
|
video_extensions = {
|
||||||
|
'mp4', 'avi', 'mov', 'mkv', 'wmv', 'flv', 'webm', 'm4v', '3gp',
|
||||||
|
'ts', 'mts', 'mpg', 'mpeg', 'rm', 'rmvb', 'asf', 'divx'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 音频格式
|
||||||
|
audio_extensions = {
|
||||||
|
'mp3', 'wav', 'aac', 'flac', 'ogg', 'wma', 'm4a', 'opus',
|
||||||
|
'ac3', 'dts', 'ape', 'aiff', 'au', 'ra'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 图片格式
|
||||||
|
image_extensions = {
|
||||||
|
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff',
|
||||||
|
'tga', 'ico', 'psd', 'raw', 'cr2', 'nef'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 文本/字幕格式
|
||||||
|
text_extensions = {
|
||||||
|
'txt', 'srt', 'ass', 'vtt', 'sub', 'ssa', 'lrc', 'sbv'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 特效格式
|
||||||
|
effect_extensions = {
|
||||||
|
'fx', 'effect', 'json', 'xml', 'preset'
|
||||||
|
}
|
||||||
|
|
||||||
|
if file_extension in video_extensions:
|
||||||
|
return 'video'
|
||||||
|
elif file_extension in audio_extensions:
|
||||||
|
return 'audio'
|
||||||
|
elif file_extension in image_extensions:
|
||||||
|
return 'image'
|
||||||
|
elif file_extension in text_extensions:
|
||||||
|
return 'text'
|
||||||
|
elif file_extension in effect_extensions:
|
||||||
|
return 'effect'
|
||||||
|
else:
|
||||||
|
return 'video' # 默认为视频类型
|
||||||
|
|
||||||
def _load_metadata(self) -> Dict[str, Dict]:
|
def _load_metadata(self) -> Dict[str, Dict]:
|
||||||
"""Load templates metadata"""
|
"""Load templates metadata"""
|
||||||
if self.metadata_file.exists():
|
if self.metadata_file.exists():
|
||||||
|
|
@ -421,12 +470,12 @@ class TemplateManager:
|
||||||
# Extract tracks and segments information
|
# Extract tracks and segments information
|
||||||
tracks = []
|
tracks = []
|
||||||
if 'tracks' in draft_content:
|
if 'tracks' in draft_content:
|
||||||
for track_data in draft_content['tracks']:
|
for idx,track_data in enumerate(draft_content['tracks']):
|
||||||
track = {
|
track = {
|
||||||
'id': track_data.get('id', ''),
|
'id': track_data.get('id', ''),
|
||||||
'name': track_data.get('name', f"Track {track_data.get('index', 0) + 1}"),
|
'name': track_data.get('name', f""),
|
||||||
'type': track_data.get('type', 'video'),
|
'type': track_data.get('type', ''),
|
||||||
'index': track_data.get('index', 0),
|
'index': idx+1,
|
||||||
'segments': [],
|
'segments': [],
|
||||||
'properties': track_data.get('properties', {})
|
'properties': track_data.get('properties', {})
|
||||||
}
|
}
|
||||||
|
|
@ -455,17 +504,16 @@ class TemplateManager:
|
||||||
material_info = materials_lookup[material_id]
|
material_info = materials_lookup[material_id]
|
||||||
resource_path = material_info['path']
|
resource_path = material_info['path']
|
||||||
material_name = material_info['name']
|
material_name = material_info['name']
|
||||||
# Auto-detect segment type from material type if not specified
|
# 根据resource_path后缀名 设置类型
|
||||||
if not segment_data.get('type'):
|
if not segment_data.get('type'):
|
||||||
segment_type = material_info['type']
|
segment_type = material_info['type']
|
||||||
|
|
||||||
|
# 根据resource_path后缀名自动检测类型
|
||||||
|
if resource_path and not segment_data.get('type'):
|
||||||
|
segment_type = TemplateManager.detect_segment_type_from_path(resource_path)
|
||||||
|
|
||||||
# Generate segment name based on material name or default
|
# Generate segment name based on material name or default
|
||||||
segment_name = segment_data.get('name', '')
|
segment_name = segment_data.get('name', '随机')
|
||||||
if not segment_name:
|
|
||||||
if material_name:
|
|
||||||
segment_name = material_name
|
|
||||||
else:
|
|
||||||
segment_name = f'片段 {len(track["segments"]) + 1}'
|
|
||||||
|
|
||||||
segment = {
|
segment = {
|
||||||
'id': segment_data.get('id', ''),
|
'id': segment_data.get('id', ''),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||||
import { SegmentContextMenu } from './SegmentContextMenu'
|
import { SegmentContextMenu } from './SegmentContextMenu'
|
||||||
import { SegmentTooltip } from './SegmentTooltip'
|
import { SegmentTooltip } from './SegmentTooltip'
|
||||||
|
|
||||||
interface TrackSegment {
|
export interface TrackSegment {
|
||||||
id: string
|
id: string
|
||||||
type: 'video' | 'audio' | 'image' | 'text' | 'effect'
|
type: 'video' | 'audio' | 'image' | 'text' | 'effect'
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -13,11 +13,10 @@ interface TrackSegment {
|
||||||
properties?: any
|
properties?: any
|
||||||
effects?: any[]
|
effects?: any[]
|
||||||
}
|
}
|
||||||
|
export interface Track {
|
||||||
interface Track {
|
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
type: 'video' | 'audio' | 'subtitle'
|
type: 'video' | 'audio' | 'effect' | 'text' | 'sticker' | 'image'
|
||||||
index: number
|
index: number
|
||||||
segments: TrackSegment[]
|
segments: TrackSegment[]
|
||||||
properties?: any
|
properties?: any
|
||||||
|
|
@ -159,7 +158,7 @@ export const TrackTimeline: React.FC<TrackTimelineProps> = ({
|
||||||
{track.type === 'video' ? '视频' : track.type === 'audio' ? '音频' : '字幕'}
|
{track.type === 'video' ? '视频' : track.type === 'audio' ? '音频' : '字幕'}
|
||||||
</span>
|
</span>
|
||||||
<h3 className="font-medium text-gray-900">
|
<h3 className="font-medium text-gray-900">
|
||||||
轨道 {track.index + 1}: {track.name}
|
{track.type}轨道 {track.index}: {track.name}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-4 text-sm text-gray-500">
|
<div className="flex items-center space-x-4 text-sm text-gray-500">
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,10 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { useParams, useNavigate } from 'react-router-dom'
|
import { useParams, useNavigate } from 'react-router-dom'
|
||||||
import { ArrowLeft, Play, Pause, RotateCcw, Trash2, ZoomIn, ZoomOut } from 'lucide-react'
|
import { ArrowLeft, RotateCcw, Trash2, ZoomIn, ZoomOut } from 'lucide-react'
|
||||||
import { TemplateService } from '../services/tauri'
|
import { TemplateService } from '../services/tauri'
|
||||||
import type { TemplateInfo } from '../hooks/useProgressCommand'
|
import type { TemplateInfo } from '../hooks/useProgressCommand'
|
||||||
import { TimelineRuler, TrackTimeline } from '../components/timeline'
|
import { TimelineRuler, TrackTimeline } from '../components/timeline'
|
||||||
|
import { Track } from '@/components/timeline/TrackTimeline'
|
||||||
// 轨道和片段的数据结构
|
|
||||||
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[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Track {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
type: 'video' | 'audio' | 'subtitle'
|
|
||||||
index: number
|
|
||||||
segments: TrackSegment[]
|
|
||||||
properties?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TemplateDetail {
|
interface TemplateDetail {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -46,7 +25,6 @@ const TemplateDetailPage: React.FC = () => {
|
||||||
const [templateDetail, setTemplateDetail] = useState<TemplateDetail | null>(null)
|
const [templateDetail, setTemplateDetail] = useState<TemplateDetail | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [currentTime, setCurrentTime] = useState(0)
|
const [currentTime, setCurrentTime] = useState(0)
|
||||||
const [isPlaying, setIsPlaying] = useState(false)
|
|
||||||
const [timelineScale, setTimelineScale] = useState(100) // pixels per second
|
const [timelineScale, setTimelineScale] = useState(100) // pixels per second
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue