Add OpenClaw skills, platform kit, and template docs
Made-with: Cursor
This commit is contained in:
179
content-manager/content_manager/services/video_service.py
Normal file
179
content-manager/content_manager/services/video_service.py
Normal file
@@ -0,0 +1,179 @@
|
||||
"""视频:业务规则(文件落盘 + 路径写入 videos 表)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from content_manager.config import get_skill_data_dir, resolve_stored_path
|
||||
from content_manager.db import videos_repository as vr
|
||||
from content_manager.db.connection import get_conn, init_db
|
||||
from content_manager.services import file_store
|
||||
from content_manager.util.timeutil import now_unix, unix_to_iso
|
||||
|
||||
|
||||
def _row_to_public_dict(row: tuple) -> Dict[str, Any]:
|
||||
rid, file_path, title, duration_ms, status, source, account_id, error_msg, extra_json, cat, uat = row
|
||||
abs_path = resolve_stored_path(str(file_path))
|
||||
d: Dict[str, Any] = {
|
||||
"id": int(rid),
|
||||
"kind": "video",
|
||||
"file_path": file_path,
|
||||
"absolute_path": abs_path,
|
||||
"title": title,
|
||||
"duration_ms": duration_ms,
|
||||
"status": status or "draft",
|
||||
"source": source or "manual",
|
||||
"account_id": account_id,
|
||||
"error_msg": error_msg,
|
||||
"created_at": unix_to_iso(cat),
|
||||
"updated_at": unix_to_iso(uat),
|
||||
}
|
||||
if extra_json:
|
||||
try:
|
||||
ex = json.loads(extra_json)
|
||||
if isinstance(ex, dict):
|
||||
d["extra"] = ex
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return d
|
||||
|
||||
|
||||
def cmd_add(
|
||||
src_file: str,
|
||||
title: Optional[str] = None,
|
||||
duration_ms: Optional[int] = None,
|
||||
source: str = "manual",
|
||||
) -> None:
|
||||
init_db()
|
||||
src_file = os.path.abspath(src_file.strip())
|
||||
if not os.path.isfile(src_file):
|
||||
print(f"❌ 找不到文件:{src_file}")
|
||||
sys.exit(1)
|
||||
skill_data = get_skill_data_dir()
|
||||
ts = now_unix()
|
||||
conn = get_conn()
|
||||
try:
|
||||
new_id = vr.insert_row(
|
||||
conn,
|
||||
file_path="",
|
||||
title=(title or "").strip() or None,
|
||||
duration_ms=duration_ms,
|
||||
status="draft",
|
||||
source=source,
|
||||
account_id=None,
|
||||
error_msg=None,
|
||||
extra_json=None,
|
||||
created_at=ts,
|
||||
updated_at=ts,
|
||||
)
|
||||
rel, _abs = file_store.copy_into_skill_data(skill_data, "videos", new_id, src_file)
|
||||
vr.update_file_path(conn, new_id, rel, now_unix())
|
||||
conn.commit()
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
conn.close()
|
||||
print(f"✅ 已新增视频 id={new_id} | 路径:{rel}")
|
||||
|
||||
|
||||
def cmd_get(video_id: str) -> None:
|
||||
init_db()
|
||||
if not str(video_id).strip().isdigit():
|
||||
print("❌ 视频 id 必须是纯数字。请先 video list 查看。")
|
||||
sys.exit(1)
|
||||
vid = int(video_id)
|
||||
conn = get_conn()
|
||||
try:
|
||||
row = vr.fetch_by_id(conn, vid)
|
||||
finally:
|
||||
conn.close()
|
||||
if not row:
|
||||
print("❌ 没有这条视频记录。")
|
||||
sys.exit(1)
|
||||
print(json.dumps(_row_to_public_dict(row), ensure_ascii=False))
|
||||
|
||||
|
||||
def cmd_list(limit: int = 20, max_chars: int = 80) -> None:
|
||||
init_db()
|
||||
conn = get_conn()
|
||||
try:
|
||||
rows = vr.list_recent(conn, limit)
|
||||
finally:
|
||||
conn.close()
|
||||
if not rows:
|
||||
print("暂无视频")
|
||||
return
|
||||
|
||||
def trunc(s: str) -> str:
|
||||
if not s:
|
||||
return ""
|
||||
return s if len(s) <= max_chars else s[:max_chars] + "..."
|
||||
|
||||
sep = "_" * 39
|
||||
for idx, r in enumerate(rows):
|
||||
rid, file_path, title, duration_ms, status, source, account_id, error_msg, extra_json, cat, uat = r
|
||||
print(f"id:{rid}")
|
||||
print(f"file_path:{trunc(str(file_path or ''))}")
|
||||
print(f"title:{title or ''}")
|
||||
print(f"duration_ms:{duration_ms if duration_ms is not None else ''}")
|
||||
print(f"status:{status or ''}")
|
||||
print(f"source:{source or ''}")
|
||||
print(f"account_id:{account_id or ''}")
|
||||
print(f"error_msg:{error_msg or ''}")
|
||||
print(f"created_at:{unix_to_iso(cat) or ''}")
|
||||
print(f"updated_at:{unix_to_iso(uat) or ''}")
|
||||
if idx != len(rows) - 1:
|
||||
print(sep)
|
||||
print()
|
||||
|
||||
|
||||
def cmd_delete(video_id: str) -> None:
|
||||
init_db()
|
||||
if not str(video_id).strip().isdigit():
|
||||
print("❌ 视频 id 必须是纯数字。")
|
||||
sys.exit(1)
|
||||
vid = int(video_id)
|
||||
skill_data = get_skill_data_dir()
|
||||
conn = get_conn()
|
||||
try:
|
||||
row = vr.fetch_by_id(conn, vid)
|
||||
if not row:
|
||||
print("❌ 没有 id 为 {} 的视频记录。".format(vid))
|
||||
sys.exit(1)
|
||||
rel = row[1]
|
||||
n = vr.delete_by_id(conn, vid)
|
||||
if n == 0:
|
||||
sys.exit(1)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
file_store.remove_files_for_relative_path(skill_data, str(rel))
|
||||
print(f"✅ 已删除视频 id={vid}")
|
||||
|
||||
|
||||
def cmd_feedback(
|
||||
video_id: str,
|
||||
status: str,
|
||||
account_id: Optional[str] = None,
|
||||
error_msg: Optional[str] = None,
|
||||
) -> None:
|
||||
init_db()
|
||||
if not str(video_id).strip().isdigit():
|
||||
print("❌ 视频 id 必须是纯数字。")
|
||||
sys.exit(1)
|
||||
vid = int(video_id)
|
||||
ts = now_unix()
|
||||
conn = get_conn()
|
||||
try:
|
||||
if vr.fetch_by_id(conn, vid) is None:
|
||||
print("❌ 没有 id 为 {} 的视频记录。".format(vid))
|
||||
sys.exit(1)
|
||||
vr.update_feedback(conn, vid, status, account_id, error_msg, ts)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
print("✅ 状态已更新")
|
||||
Reference in New Issue
Block a user