SRT 视频剪辑

SKILL前端设计
前端设计 未标注权限 许可证不明确
安装这个技能

根据口播文字稿和已有的SRT字幕文件,通过LCS(最长公共子序列)匹配算法将口播稿段落精确对应到视频时间戳,生成pyJianYingDraft Python脚本来自动创建剪映草稿。当用户提供口播稿(纯文本,以空行分段)和包含SRT字幕文件的视频目录时,必须使用此技能。触发关键词:口播稿、SRT字幕、LCS匹配、视频剪辑、剪映草稿、pyJianYingDraft。

一句话选型结论

按资料字段整理

SRT 视频剪辑是前端设计类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类前端设计 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_bb2a8474/srt-video-editor
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

前端设计
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_bb2a8474仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验2026-11-06上游最后核验时间 · 数据更新 2026-11-06
正文体量13.3 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
出页面与组件

按描述生成页面结构和组件草稿。

调整样式与布局

改间距、配色与响应式布局。

生成设计说明

把设计稿整理成开发能接的说明。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在前端设计场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
SRT 视频剪辑当前 未标注权限 未标注 未标注 未标注 有
前端设计 只读 GitHub 仓库 882.3 万 Codex、Claude、Cursor 有
Vercel 组合模式 联网访问 GitHub 仓库 385.9 万 Codex、Claude、Cursor 有
Vercel React native skills 前端 只读 GitHub 仓库 246.9 万 Codex、Claude、Cursor 有
adapt 搜索 浏览器控制 GitHub 仓库 202.7 万 Codex、Claude、Cursor 有
使用我的浏览器 浏览器控制 GitHub 仓库 184.8 万 Codex、Claude、Cursor 有

SKILL.md 全文

13.3 KB
模型实际读到的说明书原文,来自技能仓库

SRT 视频剪辑 Skill(SRT + LCS 匹配版)

概述

核心思路:用户已有 SRT 字幕文件(与视频同目录、同前缀名),直接解析 SRT 获取时间戳,用 LCS 算法将口播稿每个段落匹配到 SRT 字幕条目,生成剪映草稿。

严禁修改或删除任何源素材文件(视频、SRT、JSON 等),所有操作只读取、只生成新文件。

整体流程:
1. 接收用户输入:口播稿 + 视频目录路径
2. 自动发现目录下的 SRT 文件 → 映射到同名视频文件
3. 解析口播稿为段落列表(以空行分段)
4. 解析所有 SRT 文件,按视频分组
5. LCS 匹配:每个段落对每个视频的字幕条目做单条目 + 多条目合并窗口匹配
6. 输出匹配报告 → 用户确认
7. 生成 generate_draft.py → 运行 → 剪映草稿


Step 1:接收输入并发现 SRT 文件

用户输入格式

用户需要提供两样东西:

  1. 口播稿:纯文本,段落之间以空行(\n\n)分隔。例如:
    ```
    改为早上。我有一个好玩的事儿,特别好玩儿。

特别的毒的眼泪,就是毒誓,你能感到打车的时候,
```

  1. 视频目录路径:包含 .MP4/.mp4 视频文件和对应的 _原文.srt 字幕文件。命名规则:
    - 视频:20260515_js-qj-1-声好.MP4
    - 字幕:20260515_js-qj-1-声好_原文.srt

自动发现 SRT → 视频映射

import os, glob

def discover_srt_video_pairs(video_dir: str) -> dict:
    """
    扫描目录,找出所有 SRT 文件并映射到同名视频。
    返回: {video_basename: {"srt": full_srt_path, "video": full_video_path}}
    """
    pairs = {}

    # 查找所有 SRT 文件
    srt_files = glob.glob(os.path.join(video_dir, "*_原文.srt"))

    for srt_path in srt_files:
        srt_basename = os.path.basename(srt_path)
        # 去掉 "_原文.srt" 后缀,得到视频基础名
        video_basename = srt_basename.replace("_原文.srt", "")

        # 尝试多种扩展名匹配视频
        for ext in [".MP4", ".mp4", ".MOV", ".mov", ".mkv", ".avi"]:
            video_path = os.path.join(video_dir, video_basename + ext)
            if os.path.exists(video_path):
                pairs[video_basename] = {"srt": srt_path, "video": video_path}
                break

    return pairs

如果不满足上述命名规则,直接询问用户具体的 SRT 文件名和对应视频文件名。


Step 2:解析口播稿为段落

def parse_script(script_text: str) -> list[str]:
    """
    以空行分段。每段去除首尾空白。
    返回原始文本段落(不去标点,保留原文以用于匹配显示)。
    """
    paragraphs = []
    for block in script_text.strip().split("\n\n"):
        block = block.strip()
        if block:
            paragraphs.append(block)
    return paragraphs

用于匹配的"干净文本"(去标点、去空格)仅在 LCS 计算时使用,原始文本保留用于显示和注释。


Step 3:解析 SRT 字幕文件

import re

def parse_srt(filepath: str, video_name: str) -> list[tuple]:
    """
    解析单个 SRT 文件。
    返回: [(start_seconds, end_seconds, text, video_name), ...]
    """
    with open(filepath, "r", encoding="utf-8") as f:
        content = f.read()

    entries = []
    blocks = re.split(r"\n\s*\n", content.strip())

    for block in blocks:
        lines = block.strip().split("\n")
        if len(lines) < 3:
            continue

        # 解析时间戳行:00:01:58,260 --> 00:02:04,653
        tm = re.match(
            r"(\d{2}):(\d{2}):(\d{2}),(\d{3})\s*-->\s*(\d{2}):(\d{2}):(\d{2}),(\d{3})",
            lines[1]
        )
        if not tm:
            continue

        g = list(map(int, tm.groups()))
        start = g[0] * 3600 + g[1] * 60 + g[2] + g[3] / 1000
        end   = g[4] * 3600 + g[5] * 60 + g[6] + g[7] / 1000

        # 合并字幕文本行
        text = "".join(lines[2:]).replace("\n", "")
        entries.append((start, end, text, video_name))

    return entries

Step 4:SequenceMatcher 全文匹配(核心算法)

> 性能对比:暴力 LCS 窗口 ~3 分钟/6 段 → SequenceMatcher <5 秒/8 段。
> 原理:difflib.SequenceMatcher 是 C 实现,将每视频所有 SRT 结巴拼接为全文后一次匹配找到最佳块,避免 O(nmwin) 的 brute-force。

建立字符→时间索引

from difflib import SequenceMatcher

def parse_srt_indexed(filepath: str, video_name: str) -&gt; dict:
    &quot;&quot;&quot;
    解析 SRT 并建立字符到时间的映射。
    返回: {
        &quot;full_text&quot;:   拼接后的无标点全文,
        &quot;char_times&quot;:  [(time, entry_idx), ...]  每个字符位置 -&gt; 时间戳,
        &quot;entries&quot;:     [(start, end, raw_text), ...]
    }
    &quot;&quot;&quot;
    # ... 先按 Step 3 的 parse_srt 得到 entries ...

    chars = []
    char_times = []
    for idx, (start, end, text) in enumerate(entries):
        cl = clean_text(text)
        for ch in cl:
            chars.append(ch)
            char_times.append((start, idx))
        if cl:
            char_times[-1] = (end, idx)  # 最后一个字符用 end 时间

    return {
        &quot;full_text&quot;: &quot;&quot;.join(chars),
        &quot;char_times&quot;: char_times,
        &quot;entries&quot;: entries,
    }

匹配段落

def match_paragraph(para_clean: str, video_data: dict) -&gt; dict:
    &quot;&quot;&quot;
    对所有视频做 SequenceMatcher 匹配,取最佳块。
    video_data: {video_name: {&quot;full_text&quot;: str, &quot;char_times&quot;: list, &quot;entries&quot;: list}}
    &quot;&quot;&quot;
    best = {&quot;video&quot;: None, &quot;start&quot;: 0.0, &quot;end&quot;: 0.0, &quot;score&quot;: 0.0}

    for vname, data in video_data.items():
        ft = data[&quot;full_text&quot;]
        ct = data[&quot;char_times&quot;]
        sm = SequenceMatcher(None, ft, para_clean)

        for block in sm.get_matching_blocks():
            if block.size == 0:
                continue
            b_start = block.a
            b_size  = block.size
            if b_start &gt;= len(ct) or b_start + b_size &gt; len(ct):
                continue

            t_start = ct[b_start][0]
            t_end   = ct[min(b_start + b_size - 1, len(ct) - 1)][0]
            score = b_size / max(len(para_clean), 1)

            if score &gt; best[&quot;score&quot;]:
                best = {&quot;video&quot;: vname, &quot;start&quot;: t_start, &quot;end&quot;: t_end, &quot;score&quot;: score}

    return best

匹配阈值与处理

相似度 标记 处理方式
≥ 0.6 ✅ 直接接受,时间戳精确
0.3 ~ 0.6 ⚠️ 低 接受但标注低置信度,提示用户确认
< 0.3 ❌ 未匹配,在 CLIPS 中注释跳过,提示用户手动补充

核心原则:口播稿必须完整匹配。低置信度段落仍然放入 CLIPS,但标注警告让用户审查。绝不能静默丢弃任何段落。


Step 5:输出匹配报告

在执行草稿生成前,先输出清晰的匹配报告供用户审查:

================================================================================
匹配结果
================================================================================

段落1 ✅ → 20260515_js-qj-3-声好.MP4 [00:00:51~00:00:58]
  相似度: 0.86  方式: 合并窗口 3条 (#17-#19)
  口播: 改为早上。我有一个好玩的事儿,特别好玩儿。

段落2 ✅ → 20260515_js-qj-3-声好.MP4 [00:01:58~00:02:05]
  相似度: 0.87  方式: 合并窗口 3条 (#51-#53)
  口播: 特别的毒的眼泪,就是毒誓,你能感到打车的时候,

...

段落4 ⚠️ 低 → 20260515_js-qj-3-声好.MP4 [00:01:53~00:02:37]
  相似度: 0.47  方式: 合并窗口 8条 (#49-#67)
  口播: 一种方式就是晚上翻来覆去的...
  ⚠️ 低置信度 — 口播稿可能为浓缩版,实际口播内容跨度更长

================================================================================
CLIPS 列表
================================================================================
    (r&quot;Z:\...\20260515_js-qj-3-声好.MP4&quot;, 51.590, 58.225),  # P1 sim:0.86
    ...
    (⚠️ r&quot;Z:\...\20260515_js-qj-3-声好.MP4&quot;, 112.700, 157.380),  # P4 sim:0.47

Step 6:生成 pyJianYingDraft 脚本

基于匹配结果生成可直接运行的 Python 脚本。

关键点

  1. 直接用真实视频路径创建 VideoMaterial,不要用假视频骨架。
  2. 网络路径(如 \\192.168.x.x\...)可以直接使用,pyjianyingdraft 支持。
  3. 素材缓存:同一视频只创建一次 VideoMaterial。
  4. 时间轴累加:每个 segment 的 target_timerange 接在上一个之后。
  5. allow_replace=True:每次覆盖同名草稿。
import os
import pyJianYingDraft as draft
from pyJianYingDraft import Timerange, SEC

# ============================================================
# 配置(根据实际路径修改)
# ============================================================
DRAFT_FOLDER = r&quot;C:\Users\Administrator\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft&quot;
DRAFT_NAME   = &quot;你的草稿名称&quot;
WIDTH, HEIGHT = 1920, 1080

# ============================================================
# CLIPS:口播稿段落 → (视频完整路径, 开始秒, 结束秒)
# ============================================================
CLIPS = [
    # ⚠️ 由匹配结果填充,格式:(视频路径, start_sec, end_sec)
]

# ============================================================
# 生成草稿
# ============================================================
draft_folder = draft.DraftFolder(DRAFT_FOLDER)
script = draft_folder.create_draft(DRAFT_NAME, WIDTH, HEIGHT, allow_replace=True)
script.add_track(draft.TrackType.video)

timeline_cursor = 0
material_cache = {}

for video_path, src_start, src_end in CLIPS:
    # 获取或创建素材
    if video_path not in material_cache:
        print(f&quot;加载素材: {os.path.basename(video_path)}&quot;)
        material_cache[video_path] = draft.VideoMaterial(video_path)
    material = material_cache[video_path]

    src_start_us = int(src_start * SEC)
    src_end_us   = int(src_end   * SEC)
    duration_us  = src_end_us - src_start_us

    segment = draft.VideoSegment(
        material,
        target_timerange=Timerange(timeline_cursor, duration_us),
        source_timerange=Timerange(src_start_us, duration_us),
    )
    script.add_segment(segment)

    print(f&quot;  片段 [{src_start:.2f}s → {src_end:.2f}s] 时长 {duration_us/SEC:.2f}s&quot;)
    timeline_cursor += duration_us

script.save()
print(f&quot;\n✅ 草稿已保存:{DRAFT_NAME}&quot;)
print(f&quot;📊 总时长:{timeline_cursor / SEC:.2f} 秒,共 {len(CLIPS)} 个片段&quot;)

输出规范

  1. 先运行匹配:输出详细的匹配报告,向用户展示每个段落的匹配质量
  2. 用户确认后再写入脚本:等用户确认 CLIPS 列表没问题,再生成 generate_draft.py
  3. 脚本放在工作区:{workspace}/generate_draft.py,用户可直接 python generate_draft.py
  4. 未匹配段落处理:在 CLIPS 中以注释形式标注跳过,明确提示用户需手动补充
  5. 高亮低置信度:sim < 0.6 的条目在 CLIPS 注释中用 ⚠️ 标注

核心约束(必读)

约束 说明
禁止删除素材 绝不删除、移动、重命名、修改任何视频文件、SRT 文件。只读取。
口播稿完整匹配 每个段落都必须尝试匹配,不得静默丢弃。匹配失败/低置信度也要报告。
SRT 优先 不运行 WhisperX。如果目录下没有 SRT 文件,告知用户先提供。
真实视频路径 直接用真实视频创建 VideoMaterial,不做假视频骨架、不做手动 JSON 替换。
先报告后写入 匹配结果必须先展示给用户审查,确认后再写入 generate_draft.py。
剪映版本 pyjianyingdraft 目前支持剪映 5.9 及以下版本。

常见问题

问题 处理方式
SRT 文件不存在 提示用户视频目录必须有 _原文.srt 文件,或让用户指定 SRT 文件路径
段落匹配得分低 标注 ⚠️,给出原视频中对应时间段的字幕文本,让用户判断是否可用
某段落完全未匹配 在 CLIPS 中注释掉,提示用户手动在剪映中补充
视频只有部分被用到 正常现象 — 口播稿是筛选后的内容,未用到的视频片段不出现在草稿中
时间线上有片段但视频不显示 检查视频路径是否正确、网络路径是否可访问。不要用假视频骨架
口播稿不是空行分段 询问用户段落的实际分隔方式,调整 split 逻辑
视频文件扩展名不匹配 自动尝试 .MP4/.mp4/.MOV/.mov/.mkv/.avi 等常见扩展名
匹配太慢(9915 条) 已用 SequenceMatcher(C实现)替代暴力 LCS 窗口,<5s 完成 8 段匹配

常见问题

5 问
答案由本站依据条目字段整理
SRT 视频剪辑怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_bb2a8474/srt-video-editor。安装方式为未标注。装完刷新技能列表或重开客户端。

SRT 视频剪辑支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

SRT 视频剪辑权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

SRT 视频剪辑收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

SRT 视频剪辑用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 2026-11-06。