298 lines
10 KiB
Python
298 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
媒体管理器命令行接口
|
|
"""
|
|
|
|
from typing import Dict, Any
|
|
from dataclasses import asdict
|
|
|
|
from .manager import get_media_manager
|
|
from python_core.utils.progress import ProgressJSONRPCCommander
|
|
|
|
class MediaManagerCommander(ProgressJSONRPCCommander):
|
|
"""媒体管理器命令行接口 - 支持进度条"""
|
|
|
|
def __init__(self):
|
|
super().__init__("media_manager")
|
|
|
|
def _register_commands(self) -> None:
|
|
"""注册命令"""
|
|
# 上传命令
|
|
self.register_command(
|
|
name="upload",
|
|
description="上传单个视频文件",
|
|
required_args=["source_path"],
|
|
optional_args={
|
|
"filename": {"type": str, "description": "文件名"},
|
|
"tags": {"type": str, "description": "标签(逗号分隔)"}
|
|
}
|
|
)
|
|
|
|
self.register_command(
|
|
name="batch_upload",
|
|
description="批量上传视频文件",
|
|
required_args=["source_directory"],
|
|
optional_args={
|
|
"tags": {"type": str, "description": "标签(逗号分隔)"}
|
|
}
|
|
)
|
|
|
|
# 查询命令
|
|
self.register_command(
|
|
name="get_all_segments",
|
|
description="获取所有视频片段"
|
|
)
|
|
|
|
self.register_command(
|
|
name="get_all_videos",
|
|
description="获取所有原始视频"
|
|
)
|
|
|
|
self.register_command(
|
|
name="get_segments_by_video",
|
|
description="获取指定视频的片段",
|
|
required_args=["video_id"]
|
|
)
|
|
|
|
self.register_command(
|
|
name="search_segments",
|
|
description="搜索视频片段",
|
|
required_args=["keyword"]
|
|
)
|
|
|
|
self.register_command(
|
|
name="get_segments_by_tags",
|
|
description="根据标签获取片段",
|
|
required_args=["tags"],
|
|
optional_args={
|
|
"match_all": {"type": bool, "default": False, "description": "是否匹配所有标签"}
|
|
}
|
|
)
|
|
|
|
self.register_command(
|
|
name="get_popular_segments",
|
|
description="获取热门片段",
|
|
optional_args={
|
|
"limit": {"type": int, "default": 10, "description": "返回数量限制"}
|
|
}
|
|
)
|
|
|
|
# 管理命令
|
|
self.register_command(
|
|
name="add_tags",
|
|
description="为片段添加标签",
|
|
required_args=["segment_id", "tags"]
|
|
)
|
|
|
|
self.register_command(
|
|
name="increment_usage",
|
|
description="增加片段使用次数",
|
|
required_args=["segment_id"]
|
|
)
|
|
|
|
self.register_command(
|
|
name="delete_segment",
|
|
description="删除视频片段",
|
|
required_args=["segment_id"]
|
|
)
|
|
|
|
self.register_command(
|
|
name="delete_video",
|
|
description="删除原始视频",
|
|
required_args=["video_id"]
|
|
)
|
|
|
|
def _is_progressive_command(self, command: str) -> bool:
|
|
"""判断是否需要进度报告的命令"""
|
|
# 上传操作需要进度报告
|
|
return command in ["upload", "batch_upload"]
|
|
|
|
def _execute_with_progress(self, command: str, args: Dict[str, Any]) -> Any:
|
|
"""执行带进度的命令"""
|
|
media_manager = get_media_manager()
|
|
|
|
if command == "upload":
|
|
return self._upload_with_progress(
|
|
media_manager,
|
|
args["source_path"],
|
|
args.get("filename"),
|
|
self._parse_tags(args.get("tags"))
|
|
)
|
|
elif command == "batch_upload":
|
|
return self._batch_upload_with_progress(
|
|
media_manager,
|
|
args["source_directory"],
|
|
self._parse_tags(args.get("tags"))
|
|
)
|
|
else:
|
|
raise ValueError(f"Unknown progressive command: {command}")
|
|
|
|
def _execute_simple_command(self, command: str, args: Dict[str, Any]) -> Any:
|
|
"""执行简单命令(不需要进度)"""
|
|
media_manager = get_media_manager()
|
|
|
|
if command == "upload":
|
|
tags = self._parse_tags(args.get("tags"))
|
|
result = media_manager.upload_video_file(
|
|
args["source_path"],
|
|
args.get("filename"),
|
|
tags
|
|
)
|
|
return asdict(result)
|
|
|
|
elif command == "get_all_segments":
|
|
return media_manager.get_all_segments()
|
|
|
|
elif command == "get_all_videos":
|
|
return media_manager.get_all_original_videos()
|
|
|
|
elif command == "get_segments_by_video":
|
|
return media_manager.get_segments_by_video_id(args["video_id"])
|
|
|
|
elif command == "search_segments":
|
|
return media_manager.search_segments(args["keyword"])
|
|
|
|
elif command == "get_segments_by_tags":
|
|
tags = self._parse_tags(args["tags"])
|
|
return media_manager.get_segments_by_tags(
|
|
tags,
|
|
args.get("match_all", False)
|
|
)
|
|
|
|
elif command == "get_popular_segments":
|
|
return media_manager.get_popular_segments(args.get("limit", 10))
|
|
|
|
elif command == "add_tags":
|
|
tags = self._parse_tags(args["tags"])
|
|
success = media_manager.add_segment_tags(args["segment_id"], tags)
|
|
return {"success": success}
|
|
|
|
elif command == "increment_usage":
|
|
success = media_manager.increment_segment_usage(args["segment_id"])
|
|
return {"success": success}
|
|
|
|
elif command == "delete_segment":
|
|
success = media_manager.delete_segment(args["segment_id"])
|
|
return {"success": success}
|
|
|
|
elif command == "delete_video":
|
|
success = media_manager.delete_original_video(args["video_id"])
|
|
return {"success": success}
|
|
|
|
else:
|
|
raise ValueError(f"Unknown command: {command}")
|
|
|
|
def _upload_with_progress(self, media_manager, source_path: str, filename: str, tags: list) -> dict:
|
|
"""带进度的单个上传"""
|
|
with self.create_task("上传视频文件", 5) as task:
|
|
def progress_callback(message: str):
|
|
# 根据消息更新进度
|
|
if "计算文件哈希" in message:
|
|
task.update(0, message)
|
|
elif "检查重复文件" in message:
|
|
task.update(1, message)
|
|
elif "复制文件" in message:
|
|
task.update(2, message)
|
|
elif "提取视频信息" in message:
|
|
task.update(3, message)
|
|
elif "检测场景变化" in message:
|
|
task.update(4, message)
|
|
elif "分割视频" in message:
|
|
task.update(5, message)
|
|
elif "保存数据" in message:
|
|
task.update(6, message)
|
|
else:
|
|
task.update(message=message)
|
|
|
|
result = media_manager.upload_video_file(
|
|
source_path, filename, tags, progress_callback
|
|
)
|
|
|
|
task.finish("上传完成")
|
|
return asdict(result)
|
|
|
|
def _batch_upload_with_progress(self, media_manager, source_directory: str, tags: list) -> dict:
|
|
"""带进度的批量上传"""
|
|
import os
|
|
|
|
# 支持的视频格式
|
|
video_extensions = {'.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v'}
|
|
|
|
# 先扫描所有视频文件
|
|
video_files = []
|
|
for root, _, files in os.walk(source_directory):
|
|
for file in files:
|
|
file_ext = os.path.splitext(file)[1].lower()
|
|
if file_ext in video_extensions:
|
|
video_files.append(os.path.join(root, file))
|
|
|
|
if not video_files:
|
|
return {
|
|
"total_files": 0,
|
|
"uploaded_files": 0,
|
|
"skipped_files": 0,
|
|
"failed_files": 0,
|
|
"total_segments": 0,
|
|
"uploaded_list": [],
|
|
"skipped_list": [],
|
|
"failed_list": [],
|
|
"message": "No video files found"
|
|
}
|
|
|
|
# 使用进度任务
|
|
with self.create_task("批量上传视频", len(video_files)) as task:
|
|
result = {
|
|
"total_files": len(video_files),
|
|
"uploaded_files": 0,
|
|
"skipped_files": 0,
|
|
"failed_files": 0,
|
|
"total_segments": 0,
|
|
"uploaded_list": [],
|
|
"skipped_list": [],
|
|
"failed_list": []
|
|
}
|
|
|
|
for i, file_path in enumerate(video_files):
|
|
filename = os.path.basename(file_path)
|
|
task.update(i, f"处理文件: {filename}")
|
|
|
|
try:
|
|
# 尝试上传文件
|
|
upload_result = media_manager.upload_video_file(file_path, filename, tags)
|
|
|
|
if upload_result.is_duplicate:
|
|
result["skipped_files"] += 1
|
|
result["skipped_list"].append({
|
|
'filename': filename,
|
|
'reason': 'Already exists (same MD5)'
|
|
})
|
|
else:
|
|
result["uploaded_files"] += 1
|
|
result["total_segments"] += len(upload_result.segments)
|
|
result["uploaded_list"].append(asdict(upload_result))
|
|
|
|
except Exception as e:
|
|
result["failed_files"] += 1
|
|
result["failed_list"].append({
|
|
'filename': filename,
|
|
'error': str(e)
|
|
})
|
|
|
|
task.finish(f"批量上传完成: {result['uploaded_files']} 成功, {result['skipped_files']} 跳过, {result['failed_files']} 失败")
|
|
|
|
return result
|
|
|
|
def _parse_tags(self, tags_str: str) -> list:
|
|
"""解析标签字符串"""
|
|
if not tags_str:
|
|
return []
|
|
return [tag.strip() for tag in tags_str.split(",") if tag.strip()]
|
|
|
|
def main():
|
|
"""主函数"""
|
|
commander = MediaManagerCommander()
|
|
commander.run()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|