You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.7 KiB
178 lines
5.7 KiB
"""
|
|
剪映草稿检查器
|
|
|
|
用法:
|
|
python3 draft_inspector.py list [--limit N]
|
|
python3 draft_inspector.py show --name "草稿名"
|
|
python3 draft_inspector.py summary --name "草稿名"
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import platform
|
|
import sys
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
|
|
def get_default_drafts_root() -> str:
|
|
system = platform.system()
|
|
if system == "Darwin":
|
|
path = os.path.expanduser(
|
|
"~/Movies/JianyingPro/User Data/Projects/com.lveditor.draft"
|
|
)
|
|
if os.path.exists(path):
|
|
return path
|
|
local_app_data = os.environ.get("LOCALAPPDATA", "")
|
|
if local_app_data:
|
|
path = os.path.join(
|
|
local_app_data,
|
|
"JianyingPro/User Data/Projects/com.lveditor.draft",
|
|
)
|
|
if os.path.exists(path):
|
|
return path
|
|
return ""
|
|
|
|
|
|
def get_all_drafts(root_path: str) -> List[Dict]:
|
|
drafts = []
|
|
if not os.path.exists(root_path):
|
|
return []
|
|
for item in os.listdir(root_path):
|
|
if item.startswith("."):
|
|
continue
|
|
path = os.path.join(root_path, item)
|
|
if not os.path.isdir(path):
|
|
continue
|
|
has_content = os.path.exists(os.path.join(path, "draft_content.json"))
|
|
has_meta = os.path.exists(os.path.join(path, "draft_meta_info.json"))
|
|
if has_content or has_meta:
|
|
drafts.append({
|
|
"name": item,
|
|
"mtime": os.path.getmtime(path),
|
|
"path": path,
|
|
"has_content": has_content,
|
|
"has_meta": has_meta,
|
|
})
|
|
return sorted(drafts, key=lambda x: x["mtime"], reverse=True)
|
|
|
|
|
|
def cmd_list(root: str, limit: int) -> None:
|
|
drafts = get_all_drafts(root)
|
|
if limit > 0:
|
|
drafts = drafts[:limit]
|
|
|
|
print(f"Draft Root: {root}")
|
|
print(f"Total: {len(drafts)}")
|
|
print()
|
|
for i, d in enumerate(drafts, 1):
|
|
status = []
|
|
if d["has_content"]:
|
|
status.append("content")
|
|
if d["has_meta"]:
|
|
status.append("meta")
|
|
print(f" {i}. {d['name']} [{', '.join(status)}]")
|
|
|
|
|
|
def cmd_show(root: str, name: str, kind: str) -> None:
|
|
draft_path = os.path.join(root, name)
|
|
if not os.path.isdir(draft_path):
|
|
print(f"Error: Draft not found: {name}")
|
|
sys.exit(1)
|
|
|
|
if kind in ("content", "both"):
|
|
content_path = os.path.join(draft_path, "draft_content.json")
|
|
if os.path.exists(content_path):
|
|
with open(content_path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
else:
|
|
print(f"No draft_content.json (JianYing 6+ encrypts it)")
|
|
|
|
if kind in ("meta", "both"):
|
|
meta_path = os.path.join(draft_path, "draft_meta_info.json")
|
|
if os.path.exists(meta_path):
|
|
with open(meta_path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
else:
|
|
print("No draft_meta_info.json")
|
|
|
|
|
|
def cmd_summary(root: str, name: str) -> None:
|
|
draft_path = os.path.join(root, name)
|
|
content_path = os.path.join(draft_path, "draft_content.json")
|
|
|
|
if not os.path.exists(content_path):
|
|
print(f"Cannot summarize: draft_content.json not found")
|
|
print(f"(JianYing 6+ encrypts draft content)")
|
|
# Fall back to meta
|
|
meta_path = os.path.join(draft_path, "draft_meta_info.json")
|
|
if os.path.exists(meta_path):
|
|
with open(meta_path, "r", encoding="utf-8") as f:
|
|
meta = json.load(f)
|
|
print(f"\nDraft Meta Info:")
|
|
print(f" Name: {meta.get('draft_name', name)}")
|
|
print(f" Version: {meta.get('new_version', 'unknown')}")
|
|
return
|
|
|
|
with open(content_path, "r", encoding="utf-8") as f:
|
|
content = json.load(f)
|
|
|
|
tracks = content.get("tracks", [])
|
|
materials = content.get("materials", {}) or {}
|
|
|
|
total_segments = 0
|
|
print(f"Name: {name}")
|
|
print(f"Path: {draft_path}")
|
|
print(f"Tracks: {len(tracks)}")
|
|
print()
|
|
|
|
for t in tracks:
|
|
segs = t.get("segments", []) or []
|
|
total_segments += len(segs)
|
|
print(f" Track: {t.get('name', '?')} ({t.get('type', '?')}) - {len(segs)} segments")
|
|
|
|
print(f"\nTotal Segments: {total_segments}")
|
|
|
|
mat_counts = {}
|
|
for k, v in materials.items():
|
|
if isinstance(v, list):
|
|
mat_counts[k] = len(v)
|
|
if mat_counts:
|
|
print("\nMaterials:")
|
|
for k, v in sorted(mat_counts.items()):
|
|
print(f" {k}: {v}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="剪映草稿检查器")
|
|
parser.add_argument("--root", default=get_default_drafts_root(), help="草稿根目录")
|
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
|
|
p_list = sub.add_parser("list", help="列出草稿")
|
|
p_list.add_argument("--limit", type=int, default=0, help="最多显示数量")
|
|
|
|
p_show = sub.add_parser("show", help="显示草稿 JSON")
|
|
p_show.add_argument("--name", required=True, help="草稿名")
|
|
p_show.add_argument("--kind", choices=["content", "meta", "both"], default="content")
|
|
|
|
p_summary = sub.add_parser("summary", help="草稿摘要")
|
|
p_summary.add_argument("--name", required=True, help="草稿名")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not args.root:
|
|
print("Error: 无法找到剪映草稿目录,请通过 --root 指定")
|
|
sys.exit(1)
|
|
|
|
if args.cmd == "list":
|
|
cmd_list(args.root, args.limit)
|
|
elif args.cmd == "show":
|
|
cmd_show(args.root, args.name, args.kind)
|
|
elif args.cmd == "summary":
|
|
cmd_summary(args.root, args.name)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|