【开源剪映小助手】技术栈概览

技术栈概览

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排除指南
  9. 结论

简介

本项目为 CapCut Mate(剪映小助手),旨在提供一套完整的视频草稿自动化处理能力,包括草稿下载、素材管理、草稿生成与导出、以及桌面客户端交互。技术栈围绕 Python 后端(FastAPI + Uvicorn)、前端(React + Vite + Electron)、以及自动化控制(uiautomation)构建,同时提供容器化部署能力。

项目结构

项目采用分层清晰的组织方式:

  • 后端服务:Python + FastAPI,提供 REST API,路由集中在 v1 版本,业务逻辑位于 service 层,工具类位于 utils。
  • 自动化控制:基于 uiautomation 的剪映窗口自动化,负责草稿导出流程。
  • 桌面客户端:Electron + React,提供用户界面与系统集成能力,通过 IPC 与主进程通信。
  • 配置与环境:集中于 config.py,Dockerfile 与 docker-compose.yaml 提供容器化部署。

#mermaid-svg-k5UrsKzFmFP5IWOq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-k5UrsKzFmFP5IWOq .error-icon{fill:#552222;}#mermaid-svg-k5UrsKzFmFP5IWOq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-k5UrsKzFmFP5IWOq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-k5UrsKzFmFP5IWOq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-k5UrsKzFmFP5IWOq .marker.cross{stroke:#333333;}#mermaid-svg-k5UrsKzFmFP5IWOq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-k5UrsKzFmFP5IWOq p{margin:0;}#mermaid-svg-k5UrsKzFmFP5IWOq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster-label text{fill:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster-label span{color:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster-label span p{background-color:transparent;}#mermaid-svg-k5UrsKzFmFP5IWOq .label text,#mermaid-svg-k5UrsKzFmFP5IWOq span{fill:#333;color:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq .node rect,#mermaid-svg-k5UrsKzFmFP5IWOq .node circle,#mermaid-svg-k5UrsKzFmFP5IWOq .node ellipse,#mermaid-svg-k5UrsKzFmFP5IWOq .node polygon,#mermaid-svg-k5UrsKzFmFP5IWOq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-k5UrsKzFmFP5IWOq .rough-node .label text,#mermaid-svg-k5UrsKzFmFP5IWOq .node .label text,#mermaid-svg-k5UrsKzFmFP5IWOq .image-shape .label,#mermaid-svg-k5UrsKzFmFP5IWOq .icon-shape .label{text-anchor:middle;}#mermaid-svg-k5UrsKzFmFP5IWOq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-k5UrsKzFmFP5IWOq .rough-node .label,#mermaid-svg-k5UrsKzFmFP5IWOq .node .label,#mermaid-svg-k5UrsKzFmFP5IWOq .image-shape .label,#mermaid-svg-k5UrsKzFmFP5IWOq .icon-shape .label{text-align:center;}#mermaid-svg-k5UrsKzFmFP5IWOq .node.clickable{cursor:pointer;}#mermaid-svg-k5UrsKzFmFP5IWOq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-k5UrsKzFmFP5IWOq .arrowheadPath{fill:#333333;}#mermaid-svg-k5UrsKzFmFP5IWOq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-k5UrsKzFmFP5IWOq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-k5UrsKzFmFP5IWOq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-k5UrsKzFmFP5IWOq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-k5UrsKzFmFP5IWOq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-k5UrsKzFmFP5IWOq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster text{fill:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq .cluster span{color:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-k5UrsKzFmFP5IWOq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-k5UrsKzFmFP5IWOq rect.text{fill:none;stroke-width:0;}#mermaid-svg-k5UrsKzFmFP5IWOq .icon-shape,#mermaid-svg-k5UrsKzFmFP5IWOq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-k5UrsKzFmFP5IWOq .icon-shape p,#mermaid-svg-k5UrsKzFmFP5IWOq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-k5UrsKzFmFP5IWOq .icon-shape .label rect,#mermaid-svg-k5UrsKzFmFP5IWOq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-k5UrsKzFmFP5IWOq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-k5UrsKzFmFP5IWOq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-k5UrsKzFmFP5IWOq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运行时
后端服务(Python)
桌面客户端(Electron)
React 前端

Vite 构建
Electron 主进程

main.js
预加载脚本

preload.js
IPC 处理器

ipcHandlers.js
FastAPI 应用

main.py
路由(v1)

src/router/v1.py
中间件

src/middlewares/prepare.py
工具类

src/utils/draft_downloader.py
自动化控制

src/pyJianYingDraft/jianying_controller.py
配置

config.py
Docker 容器
Docker Compose

核心组件

  • Python 后端(FastAPI + Uvicorn)
    • 应用入口与路由注册、中间件、日志记录与启动配置均在 main.py 中完成。
    • v1 路由集中定义了草稿创建、保存、素材添加、导出、查询等接口。
    • 中间件负责在请求到达前创建必要目录。
  • 自动化控制(uiautomation)
    • JianyingController 封装剪映窗口查找、草稿选择、导出流程、分辨率/帧率设置、导出完成检测等。
  • 工具类(下载与路径处理)
    • draft_downloader 提供草稿下载、文件写入、路径修复、robocopy 触发等能力。
  • 桌面客户端(Electron + React)
    • 主进程负责窗口创建、开发/生产模式加载、权限错误处理。
    • 预加载脚本通过 contextBridge 暴露受控 API 至渲染进程。
    • IPC 处理器集中管理文件保存、日志读取、URL 访问检测、历史记录等。

架构总览

整体架构分为三层:

  • 表现层:桌面客户端(Electron + React),负责用户交互与系统集成。
  • 服务层:Python 后端(FastAPI),提供 REST API 与业务逻辑。
  • 自动化层:uiautomation 控制剪映窗口,实现草稿导出自动化。

#mermaid-svg-IikEb15DDT4HsS6H{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IikEb15DDT4HsS6H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IikEb15DDT4HsS6H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IikEb15DDT4HsS6H .error-icon{fill:#552222;}#mermaid-svg-IikEb15DDT4HsS6H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IikEb15DDT4HsS6H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IikEb15DDT4HsS6H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IikEb15DDT4HsS6H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IikEb15DDT4HsS6H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IikEb15DDT4HsS6H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IikEb15DDT4HsS6H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IikEb15DDT4HsS6H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IikEb15DDT4HsS6H .marker.cross{stroke:#333333;}#mermaid-svg-IikEb15DDT4HsS6H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IikEb15DDT4HsS6H p{margin:0;}#mermaid-svg-IikEb15DDT4HsS6H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IikEb15DDT4HsS6H .cluster-label text{fill:#333;}#mermaid-svg-IikEb15DDT4HsS6H .cluster-label span{color:#333;}#mermaid-svg-IikEb15DDT4HsS6H .cluster-label span p{background-color:transparent;}#mermaid-svg-IikEb15DDT4HsS6H .label text,#mermaid-svg-IikEb15DDT4HsS6H span{fill:#333;color:#333;}#mermaid-svg-IikEb15DDT4HsS6H .node rect,#mermaid-svg-IikEb15DDT4HsS6H .node circle,#mermaid-svg-IikEb15DDT4HsS6H .node ellipse,#mermaid-svg-IikEb15DDT4HsS6H .node polygon,#mermaid-svg-IikEb15DDT4HsS6H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IikEb15DDT4HsS6H .rough-node .label text,#mermaid-svg-IikEb15DDT4HsS6H .node .label text,#mermaid-svg-IikEb15DDT4HsS6H .image-shape .label,#mermaid-svg-IikEb15DDT4HsS6H .icon-shape .label{text-anchor:middle;}#mermaid-svg-IikEb15DDT4HsS6H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IikEb15DDT4HsS6H .rough-node .label,#mermaid-svg-IikEb15DDT4HsS6H .node .label,#mermaid-svg-IikEb15DDT4HsS6H .image-shape .label,#mermaid-svg-IikEb15DDT4HsS6H .icon-shape .label{text-align:center;}#mermaid-svg-IikEb15DDT4HsS6H .node.clickable{cursor:pointer;}#mermaid-svg-IikEb15DDT4HsS6H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IikEb15DDT4HsS6H .arrowheadPath{fill:#333333;}#mermaid-svg-IikEb15DDT4HsS6H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IikEb15DDT4HsS6H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IikEb15DDT4HsS6H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IikEb15DDT4HsS6H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IikEb15DDT4HsS6H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IikEb15DDT4HsS6H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IikEb15DDT4HsS6H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IikEb15DDT4HsS6H .cluster text{fill:#333;}#mermaid-svg-IikEb15DDT4HsS6H .cluster span{color:#333;}#mermaid-svg-IikEb15DDT4HsS6H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IikEb15DDT4HsS6H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IikEb15DDT4HsS6H rect.text{fill:none;stroke-width:0;}#mermaid-svg-IikEb15DDT4HsS6H .icon-shape,#mermaid-svg-IikEb15DDT4HsS6H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IikEb15DDT4HsS6H .icon-shape p,#mermaid-svg-IikEb15DDT4HsS6H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IikEb15DDT4HsS6H .icon-shape .label rect,#mermaid-svg-IikEb15DDT4HsS6H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IikEb15DDT4HsS6H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IikEb15DDT4HsS6H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IikEb15DDT4HsS6H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 桌面客户端

Electron + React
后端 API

FastAPI
业务服务

service 层
工具类

draft_downloader
自动化控制

JianyingController
剪映应用

Windows UIAutomation
配置中心

config.py
容器化运行

Dockerfile
编排

docker-compose.yaml

详细组件分析

Python 后端组件分析

  • 应用入口与生命周期
    • 创建 FastAPI 应用、注册路由、中间件、打印路由表、启动 Uvicorn 服务器。
  • 路由与服务层
    • v1 路由覆盖草稿管理、素材添加、导出与状态查询、时间线计算、URL 提取、序列化转换等。
    • 服务层通过依赖注入调用具体业务逻辑,返回 Pydantic 模型。
  • 中间件
    • PrepareMiddleware 在请求到达前确保草稿与临时目录存在,避免后续操作失败。
  • 配置
    • config.py 提供项目根目录、草稿保存路径、下载 URL、模板目录、腾讯云 COS 配置、API Key 开关等。

#mermaid-svg-n1vvkC1wBqj1o1Mo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n1vvkC1wBqj1o1Mo .error-icon{fill:#552222;}#mermaid-svg-n1vvkC1wBqj1o1Mo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n1vvkC1wBqj1o1Mo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .marker.cross{stroke:#333333;}#mermaid-svg-n1vvkC1wBqj1o1Mo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n1vvkC1wBqj1o1Mo p{margin:0;}#mermaid-svg-n1vvkC1wBqj1o1Mo g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-n1vvkC1wBqj1o1Mo g.classGroup text .title{font-weight:bolder;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster-label text{fill:#333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster-label span{color:#333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster-label span p{background-color:transparent;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster text{fill:#333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .cluster span{color:#333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .nodeLabel,#mermaid-svg-n1vvkC1wBqj1o1Mo .edgeLabel{color:#131300;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-n1vvkC1wBqj1o1Mo .label text{fill:#131300;}#mermaid-svg-n1vvkC1wBqj1o1Mo .labelBkg{background:#ECECFF;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-n1vvkC1wBqj1o1Mo .classTitle{font-weight:bolder;}#mermaid-svg-n1vvkC1wBqj1o1Mo .node rect,#mermaid-svg-n1vvkC1wBqj1o1Mo .node circle,#mermaid-svg-n1vvkC1wBqj1o1Mo .node ellipse,#mermaid-svg-n1vvkC1wBqj1o1Mo .node polygon,#mermaid-svg-n1vvkC1wBqj1o1Mo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n1vvkC1wBqj1o1Mo .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo g.clickable{cursor:pointer;}#mermaid-svg-n1vvkC1wBqj1o1Mo g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-n1vvkC1wBqj1o1Mo g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-n1vvkC1wBqj1o1Mo .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-n1vvkC1wBqj1o1Mo .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-n1vvkC1wBqj1o1Mo .dashed-line{stroke-dasharray:3;}#mermaid-svg-n1vvkC1wBqj1o1Mo .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-n1vvkC1wBqj1o1Mo #compositionStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #compositionEnd,#mermaid-svg-n1vvkC1wBqj1o1Mo .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #dependencyStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #dependencyStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #extensionStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #extensionEnd,#mermaid-svg-n1vvkC1wBqj1o1Mo .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #aggregationStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #aggregationEnd,#mermaid-svg-n1vvkC1wBqj1o1Mo .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #lollipopStart,#mermaid-svg-n1vvkC1wBqj1o1Mo .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo #lollipopEnd,#mermaid-svg-n1vvkC1wBqj1o1Mo .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-n1vvkC1wBqj1o1Mo .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-n1vvkC1wBqj1o1Mo .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n1vvkC1wBqj1o1Mo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n1vvkC1wBqj1o1Mo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n1vvkC1wBqj1o1Mo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} "注册路由"
"注册中间件"
"读取配置"
FastAPIApp
+include_router()
+add_middleware()
+run()
V1Router
+create_draft()
+save_draft()
+add_videos()
+add_audios()
+add_images()
+add_sticker()
+add_keyframes()
+add_captions()
+add_effects()
+add_masks()
+add_text_style()
+easy_create_material()
+get_text_animations()
+get_image_animations()
+get_draft()
+gen_video()
+gen_video_status()
+get_audio_duration()
+timelines()
+audio_timelines()
+audio_infos()
+imgs_infos()
+caption_infos()
+effect_infos()
+keyframes_infos()
+video_infos()
+search_sticker()
+get_url()
+str_list_to_objs()
+str_to_list()
+objs_to_str_list()
PrepareMiddleware
+dispatch()
Config
+PROJECT_ROOT
+DRAFT_DIR
+TEMP_DIR
+DRAFT_URL
+DOWNLOAD_URL
+TIP_URL
+STICKER_CONFIG_PATH
+TEMPLATE_DIR
+DRAFT_SAVE_PATH
+COS_SECRET_ID
+COS_SECRET_KEY
+COS_BUCKET_NAME
+COS_REGION
+ENABLE_APIKEY

自动化控制组件分析

  • 控制器职责
    • 查找剪映窗口、切换状态(主页/编辑页/导出页)、设置导出分辨率与帧率、点击导出按钮、等待导出完成、移动导出文件。
  • 状态机设计
    • app_status 与 app_sub_status 描述当前窗口状态与导出子状态,确保流程可控。
  • 错误处理
    • 针对控件缺失、超时等情况抛出自定义异常,便于上层捕获与提示。

#mermaid-svg-9bLSuQ0JpaCevOvw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9bLSuQ0JpaCevOvw .error-icon{fill:#552222;}#mermaid-svg-9bLSuQ0JpaCevOvw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9bLSuQ0JpaCevOvw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9bLSuQ0JpaCevOvw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9bLSuQ0JpaCevOvw .marker.cross{stroke:#333333;}#mermaid-svg-9bLSuQ0JpaCevOvw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9bLSuQ0JpaCevOvw p{margin:0;}#mermaid-svg-9bLSuQ0JpaCevOvw g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-9bLSuQ0JpaCevOvw g.classGroup text .title{font-weight:bolder;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster-label text{fill:#333;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster-label span{color:#333;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster-label span p{background-color:transparent;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster text{fill:#333;}#mermaid-svg-9bLSuQ0JpaCevOvw .cluster span{color:#333;}#mermaid-svg-9bLSuQ0JpaCevOvw .nodeLabel,#mermaid-svg-9bLSuQ0JpaCevOvw .edgeLabel{color:#131300;}#mermaid-svg-9bLSuQ0JpaCevOvw .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-9bLSuQ0JpaCevOvw .label text{fill:#131300;}#mermaid-svg-9bLSuQ0JpaCevOvw .labelBkg{background:#ECECFF;}#mermaid-svg-9bLSuQ0JpaCevOvw .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-9bLSuQ0JpaCevOvw .classTitle{font-weight:bolder;}#mermaid-svg-9bLSuQ0JpaCevOvw .node rect,#mermaid-svg-9bLSuQ0JpaCevOvw .node circle,#mermaid-svg-9bLSuQ0JpaCevOvw .node ellipse,#mermaid-svg-9bLSuQ0JpaCevOvw .node polygon,#mermaid-svg-9bLSuQ0JpaCevOvw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9bLSuQ0JpaCevOvw .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw g.clickable{cursor:pointer;}#mermaid-svg-9bLSuQ0JpaCevOvw g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-9bLSuQ0JpaCevOvw g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-9bLSuQ0JpaCevOvw .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-9bLSuQ0JpaCevOvw .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-9bLSuQ0JpaCevOvw .dashed-line{stroke-dasharray:3;}#mermaid-svg-9bLSuQ0JpaCevOvw .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-9bLSuQ0JpaCevOvw #compositionStart,#mermaid-svg-9bLSuQ0JpaCevOvw .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #compositionEnd,#mermaid-svg-9bLSuQ0JpaCevOvw .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #dependencyStart,#mermaid-svg-9bLSuQ0JpaCevOvw .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #dependencyStart,#mermaid-svg-9bLSuQ0JpaCevOvw .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #extensionStart,#mermaid-svg-9bLSuQ0JpaCevOvw .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #extensionEnd,#mermaid-svg-9bLSuQ0JpaCevOvw .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #aggregationStart,#mermaid-svg-9bLSuQ0JpaCevOvw .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #aggregationEnd,#mermaid-svg-9bLSuQ0JpaCevOvw .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #lollipopStart,#mermaid-svg-9bLSuQ0JpaCevOvw .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw #lollipopEnd,#mermaid-svg-9bLSuQ0JpaCevOvw .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9bLSuQ0JpaCevOvw .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-9bLSuQ0JpaCevOvw .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9bLSuQ0JpaCevOvw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9bLSuQ0JpaCevOvw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9bLSuQ0JpaCevOvw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} "使用"
"设置"
"设置"
JianyingController
+get_window()
+switch_to_home()
+find_and_click_draft()
+click_export_button()
+set_export_resolution()
+set_export_framerate()
+click_final_export_button()
+wait_for_export_completion()
+move_exported_file()
+export_draft()
-__ensure_window_focus()
-init_export_sub_status()
-__jianying_window_cmp()
ControlFinder
+desc_matcher()
+class_name_matcher()
<<enumeration>>
ExportResolution
+RES_8K
+RES_4K
+RES_2K
+RES_1080P
+RES_720P
+RES_480P
<<enumeration>>
ExportFramerate
+FR_24
+FR_25
+FR_30
+FR_50
+FR_60

桌面客户端组件分析

  • 主进程
    • 创建 BrowserWindow、加载开发/生产资源、设置安全策略、处理未捕获异常、窗口生命周期管理。
  • 预加载脚本
    • 通过 contextBridge 暴露受控 API,如保存文件、获取 URL JSON 数据、读取/清空下载日志、打开外部 URL、读取配置与历史记录等。
  • IPC 处理器
    • 注册 ipcMain.handle,实现文件保存、日志读取、URL 访问检测、历史记录读取、消息框弹窗等功能。

"文件系统" "IPC 处理器" "Electron 主进程" "预加载脚本" "React 前端" "文件系统" "IPC 处理器" "Electron 主进程" "预加载脚本" "React 前端" #mermaid-svg-w2Tw6uVDbkNC0cZ8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .error-icon{fill:#552222;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .marker.cross{stroke:#333333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 p{margin:0;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .sequenceNumber{fill:white;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 #sequencenumber{fill:#333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .messageText{fill:#333;stroke:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .labelText,#mermaid-svg-w2Tw6uVDbkNC0cZ8 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .loopText,#mermaid-svg-w2Tw6uVDbkNC0cZ8 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .noteText,#mermaid-svg-w2Tw6uVDbkNC0cZ8 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actorPopupMenu{position:absolute;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 .actor-man circle,#mermaid-svg-w2Tw6uVDbkNC0cZ8 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-w2Tw6uVDbkNC0cZ8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 调用 window.electronAPI.saveFile(config) ipcRenderer.invoke('save-file', config) ipcMain.handle('save-file') 写入文件/目录 返回结果 Promise 结果 Promise 结果 Promise 结果

工具类组件分析

  • 草稿下载流程
    • 从 URL 提取 draft_id,获取文件列表,逐个下载并保持目录结构,更新 JSON 中的路径,最后通过 robocopy 触发剪映目录扫描。
  • 文件写入与路径修复
    • 使用 O_EXCL 原子创建文件,写入后 fsync 确保落盘;对 draft_info.json 与 draft_content.json 中的路径进行替换,适配本地路径。
  • 批量下载与统计
    • 支持批量 URL 处理,返回成功/失败统计。

#mermaid-svg-h269WRuiAyuStpUh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-h269WRuiAyuStpUh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-h269WRuiAyuStpUh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-h269WRuiAyuStpUh .error-icon{fill:#552222;}#mermaid-svg-h269WRuiAyuStpUh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-h269WRuiAyuStpUh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-h269WRuiAyuStpUh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-h269WRuiAyuStpUh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-h269WRuiAyuStpUh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-h269WRuiAyuStpUh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-h269WRuiAyuStpUh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-h269WRuiAyuStpUh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-h269WRuiAyuStpUh .marker.cross{stroke:#333333;}#mermaid-svg-h269WRuiAyuStpUh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-h269WRuiAyuStpUh p{margin:0;}#mermaid-svg-h269WRuiAyuStpUh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-h269WRuiAyuStpUh .cluster-label text{fill:#333;}#mermaid-svg-h269WRuiAyuStpUh .cluster-label span{color:#333;}#mermaid-svg-h269WRuiAyuStpUh .cluster-label span p{background-color:transparent;}#mermaid-svg-h269WRuiAyuStpUh .label text,#mermaid-svg-h269WRuiAyuStpUh span{fill:#333;color:#333;}#mermaid-svg-h269WRuiAyuStpUh .node rect,#mermaid-svg-h269WRuiAyuStpUh .node circle,#mermaid-svg-h269WRuiAyuStpUh .node ellipse,#mermaid-svg-h269WRuiAyuStpUh .node polygon,#mermaid-svg-h269WRuiAyuStpUh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-h269WRuiAyuStpUh .rough-node .label text,#mermaid-svg-h269WRuiAyuStpUh .node .label text,#mermaid-svg-h269WRuiAyuStpUh .image-shape .label,#mermaid-svg-h269WRuiAyuStpUh .icon-shape .label{text-anchor:middle;}#mermaid-svg-h269WRuiAyuStpUh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-h269WRuiAyuStpUh .rough-node .label,#mermaid-svg-h269WRuiAyuStpUh .node .label,#mermaid-svg-h269WRuiAyuStpUh .image-shape .label,#mermaid-svg-h269WRuiAyuStpUh .icon-shape .label{text-align:center;}#mermaid-svg-h269WRuiAyuStpUh .node.clickable{cursor:pointer;}#mermaid-svg-h269WRuiAyuStpUh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-h269WRuiAyuStpUh .arrowheadPath{fill:#333333;}#mermaid-svg-h269WRuiAyuStpUh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-h269WRuiAyuStpUh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-h269WRuiAyuStpUh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h269WRuiAyuStpUh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-h269WRuiAyuStpUh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h269WRuiAyuStpUh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-h269WRuiAyuStpUh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-h269WRuiAyuStpUh .cluster text{fill:#333;}#mermaid-svg-h269WRuiAyuStpUh .cluster span{color:#333;}#mermaid-svg-h269WRuiAyuStpUh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-h269WRuiAyuStpUh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-h269WRuiAyuStpUh rect.text{fill:none;stroke-width:0;}#mermaid-svg-h269WRuiAyuStpUh .icon-shape,#mermaid-svg-h269WRuiAyuStpUh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h269WRuiAyuStpUh .icon-shape p,#mermaid-svg-h269WRuiAyuStpUh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-h269WRuiAyuStpUh .icon-shape .label rect,#mermaid-svg-h269WRuiAyuStpUh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h269WRuiAyuStpUh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-h269WRuiAyuStpUh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-h269WRuiAyuStpUh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 下载失败
下载成功


结束
开始
解析草稿URL

提取draft_id
获取文件列表
遍历文件
重试/记录错误
写入文件

safe_write_file
是否为草稿JSON?
修复JSON内路径
继续
robocopy触发扫描
结束

依赖分析

  • Python 后端依赖
    • FastAPI、Uvicorn、Requests、uiautomation、PyMediaInfo、pywin32、email-validator、cos-python-sdk-v5。
  • 桌面客户端依赖
    • Electron、Vite、React、React Router、Axios、Bootstrap、日志与 UUID 等。
  • 容器化运行
    • 使用 uv 安装依赖,设置非 root 用户与缓存目录,暴露 30000 端口,挂载输出目录与时区。

#mermaid-svg-KgWMFgoOEpWxXuDn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KgWMFgoOEpWxXuDn .error-icon{fill:#552222;}#mermaid-svg-KgWMFgoOEpWxXuDn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KgWMFgoOEpWxXuDn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KgWMFgoOEpWxXuDn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KgWMFgoOEpWxXuDn .marker.cross{stroke:#333333;}#mermaid-svg-KgWMFgoOEpWxXuDn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KgWMFgoOEpWxXuDn p{margin:0;}#mermaid-svg-KgWMFgoOEpWxXuDn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster-label text{fill:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster-label span{color:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster-label span p{background-color:transparent;}#mermaid-svg-KgWMFgoOEpWxXuDn .label text,#mermaid-svg-KgWMFgoOEpWxXuDn span{fill:#333;color:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn .node rect,#mermaid-svg-KgWMFgoOEpWxXuDn .node circle,#mermaid-svg-KgWMFgoOEpWxXuDn .node ellipse,#mermaid-svg-KgWMFgoOEpWxXuDn .node polygon,#mermaid-svg-KgWMFgoOEpWxXuDn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KgWMFgoOEpWxXuDn .rough-node .label text,#mermaid-svg-KgWMFgoOEpWxXuDn .node .label text,#mermaid-svg-KgWMFgoOEpWxXuDn .image-shape .label,#mermaid-svg-KgWMFgoOEpWxXuDn .icon-shape .label{text-anchor:middle;}#mermaid-svg-KgWMFgoOEpWxXuDn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KgWMFgoOEpWxXuDn .rough-node .label,#mermaid-svg-KgWMFgoOEpWxXuDn .node .label,#mermaid-svg-KgWMFgoOEpWxXuDn .image-shape .label,#mermaid-svg-KgWMFgoOEpWxXuDn .icon-shape .label{text-align:center;}#mermaid-svg-KgWMFgoOEpWxXuDn .node.clickable{cursor:pointer;}#mermaid-svg-KgWMFgoOEpWxXuDn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KgWMFgoOEpWxXuDn .arrowheadPath{fill:#333333;}#mermaid-svg-KgWMFgoOEpWxXuDn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KgWMFgoOEpWxXuDn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KgWMFgoOEpWxXuDn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KgWMFgoOEpWxXuDn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KgWMFgoOEpWxXuDn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KgWMFgoOEpWxXuDn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster text{fill:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn .cluster span{color:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KgWMFgoOEpWxXuDn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KgWMFgoOEpWxXuDn rect.text{fill:none;stroke-width:0;}#mermaid-svg-KgWMFgoOEpWxXuDn .icon-shape,#mermaid-svg-KgWMFgoOEpWxXuDn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KgWMFgoOEpWxXuDn .icon-shape p,#mermaid-svg-KgWMFgoOEpWxXuDn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KgWMFgoOEpWxXuDn .icon-shape .label rect,#mermaid-svg-KgWMFgoOEpWxXuDn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KgWMFgoOEpWxXuDn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KgWMFgoOEpWxXuDn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KgWMFgoOEpWxXuDn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} pyproject.toml 依赖
FastAPI
Uvicorn
Requests
uiautomation
PyMediaInfo
pywin32
email-validator
cos-python-sdk-v5
desktop-client/package.json 依赖
Electron
React
Axios
Bootstrap
log4js
uuid
Dockerfile
uv 安装依赖
暴露端口 30000
docker-compose.yaml
挂载输出目录

性能考虑

  • 并发与工作者
    • Dockerfile 中通过多工作者启动,提升并发处理能力。
  • I/O 优化
    • 文件写入使用原子创建与 fsync,保证数据一致性;批量下载时按需重试,降低失败率。
  • 自动化稳定性
    • uiautomation 控件查找采用深度与匹配器,减少误触;导出流程设置超时与状态轮询,避免死循环。
  • 容器资源限制
    • docker-compose 限制内存与 CPU,防止资源滥用;OOM 优先级调整,提升系统稳定性。

故障排除指南

  • 权限与路径问题
    • 桌面客户端在 macOS 沙箱环境下捕获权限错误,引导用户在系统偏好设置中授权文件夹访问。
  • 网络与下载失败
    • 草稿下载对网络请求与文件写入进行异常捕获与重试;robocopy 返回码处理,定位失败原因。
  • 自动化控件缺失
    • uiautomation 在找不到控件时抛出异常,建议检查剪映版本与窗口状态;导出超时可适当延长 timeout。
  • 容器运行问题
    • 确认端口映射、卷挂载路径正确;检查 UV_CACHE_DIR 与 PATH 环境变量;查看日志定位依赖安装问题。

结论

本项目通过 Python 后端(FastAPI + uiautomation)与桌面客户端(Electron + React)的协同,实现了从草稿下载、素材管理到自动化导出的完整链路。技术选型兼顾易用性与可维护性:FastAPI 提供简洁的 API 与良好的类型支持;uiautomation 保障自动化流程稳定;Electron 提升用户体验与系统集成能力;容器化部署简化运维。建议在实际部署中关注版本兼容性、权限配置与资源限制,以获得最佳稳定性与性能表现。

文档信息

相关推荐
Good kid.2 小时前
开源一套 Vue3 多模态 AI 控制台前端:游乐场、工作室与 API 文档页
前端·人工智能·开源
人工智能研究所2 小时前
字节开源 OmniShow:文本,图片,音频,人体姿态多输入,一键成片
人工智能·神经网络·开源·音视频·开源软件·字节跳动·ai 视频
梦梦代码精2 小时前
多商户电商系统二次开发真实体验:真开源与伪开源的差距
windows·docker·开源·github
ModelHub XC信创模盒2 小时前
压力之下,重构赛道:从中美AI博弈到信创生态的深层跃迁
大数据·人工智能·重构·开源·信创·范式
AI_零食3 小时前
鸿蒙PC Electron跨平台应用开发:辗转相除法计算器实现详解
前端·学习·华为·electron·开源·鸿蒙·鸿蒙系统
咖啡星人k3 小时前
开源商业模式探索:MonkeyCode 的可持续化发展路径
开源
咖啡星人k3 小时前
从零贡献开源:MonkeyCode 新手贡献者完全指南
开源
独特的螺狮粉4 小时前
蛋鸡养护周期管理系统 - 鸿蒙PC Electron框架完整实现指南
前端·javascript·华为·electron·前端框架·开源·鸿蒙
世人万千丶4 小时前
鸿蒙PC问题解决:窗口配置错误修复指南
android·学习·华为·开源·harmonyos·鸿蒙·鸿蒙系统