Home / All Skills / Workflow & Core Tools / video-comparer
Workflow & Core Tools · daymade/claude-code-skills

video-comparer

This skill should be used when comparing two videos to analyze compression results or quality differences. Generates interactive HTML reports with quality metrics (PSNR, SSIM) and frame-by-frame visual comparisons. Triggers when users mention "compare videos", "video quality", "compression analysis", "before/after compression", or request quality assessment of compressed videos.

L4 High-Privilege · Graded auth & full auditV1 Commit-PinnedExecute CommandNetwork AccessWrite FileDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1392License MIT(仓库根 LICENSE,Copyright (c) 2025 daymade;GitHub API spdx MIT)Commit d5c4678cb5
Control levels describe skill capabilities and suggested control measures; they do not represent quality or safety certifications, nor do they dictate usability. Usage decisions rest entirely with users and administrators. Different agent hosts apply varying constraints; do not assume hosts provide automatic protection. Third-party skill copyrights belong to their original authors. Use at your own risk.

1How It Works & Mechanism

The implementation path uses a single Python script orchestrating ffmpeg/ffprobe: ffprobe retrieves metadata → ffmpeg calculates PSNR/SSIM → ffmpeg extracts and scales frames at set intervals → frames and metrics are populated into an HTML template → report is written to disk. Pure deterministic pipeline without model involvement.

video-comparer/scripts/compare.py
for tool in ['ffmpeg', 'ffprobe']:
Full docstring: 'Compare two videos (original vs compressed) and generate interactive HTML report. Analyzes video metadata, quality metrics (PSNR/SSIM), and creates frame-by-frame comparison UI with slider, side-by-side, and grid viewing modes.'; check_ffmpeg_installed runs [tool, '-version'] pre-check first.

The report is not created via 'template rendering engine', but rather 'reading a template + block-by-block regex replacement of placeholders'—making it tightly coupled to the template structure, where a single line break or element shift in a paragraph causes silent mismatches.

video-comparer/scripts/compare.py
r'<div class="metric-value">[\d.]+ dB</div>\s*<div class="metric-subtitle">偏低</div>',
A total of 11 re.sub/replace steps (Step 1 to Step 11) run in the same block (codec, resolution, bitrate, size, PSNR, SSIM, discovered issues, well-preserved aspects, technical explanations, frame selection buttons, JS frame count and intervals).

Frame sequences are not embedded into the HTML; instead, they are copied to subdirectories alongside the HTML (original/ and wechat/) and referenced via relative paths by the template—meaning the artifact is a collection of files rather than a single file.

video-comparer/scripts/compare.py
Copy frames to a subdirectory next to the HTML output. Args: frames: List of (timestamp, frame_path) tuples output_html_path: Path to the output HTML file subfolder: Subdirectory name (e.g., 'original', 'wechat')
Implemented as output_dir = output_html_path.parent / subfolder; dest_name = f"frame_{i:03d}.png"; shutil.copy2(frame_path, dest_path). Template side references src="original/frame_001.png" and src="wechat/frame_001.png"; call sites are copy_frames_to_output(original_frames, output_path, 'original') and (compressed_frames, output_path, 'wechat').

Input validation is a first-class citizen: paths are resolved and checked for existence/is_file/extension whitelist/readability/size limits; ffmpeg and ffprobe existence are independently pre-checked with platform-specific installation guides provided.

video-comparer/scripts/compare.py
# Configuration constants ALLOWED_EXTENSIONS = {'.mp4', '.mov', '.avi', '.mkv', '.webm'} MAX_FILE_SIZE_MB = 500 FFMPEG_TIMEOUT = 300 # 5 minutes FFPROBE_TIMEOUT = 30 # 30 seconds BASE_FRAME_HEIGHT = 800 FRAME_INTERVAL = 5 # seconds
Inside validate_video_file is the comment '# Convert to absolute path to prevent directory traversal'; file header comments declare 'Security features: - Path validation and sanitization - Command injection prevention - Resource limits (file size, timeout) - Comprehensive error handling'.

Command injection prevention relies on the triad of 'argument lists + no shell=True + timeouts' rather than string escaping—the proper way to use subprocess.

video-comparer/scripts/compare.py
try: result = subprocess.run( args, capture_output=True, timeout=timeout, check=True, text=True ) return result.stdout
Function docstring explicitly states: 'args: Command arguments as list (prevents shell injection)'; grep shell=True across the entire directory returns zero matches.

Prior to computing metrics, a content consistency check is performed to verify whether the two videos share the same content (duration difference threshold, warning if compressed is larger than original), preventing comparisons of unrelated videos from being output as quality analyses.

video-comparer/scripts/compare.py
""" Validate that two videos are likely the same content. Args: metadata1: First video metadata (original) metadata2: Second video metadata (compressed) duration_threshold: Maximum allowed duration difference in seconds allow_size_increase: If False, warn when compressed is larger
A rare design choice: most comparison tools compute numbers directly without upfront content consistency checks.

2Core Capabilities

01Video metadata extraction (codec / resolution / frame rate / bitrate / duration / file size)
02PSNR / SSIM quality metric computation and compression ratio statistics
03Interval-based frame extraction scaled uniformly to 800px height for frame-by-frame comparison
04Three viewing modes (slider / side-by-side / grid) + 50%-200% zoom scaling
05Parameterization and batch processing (-o output path, --interval frame sampling interval, shell loop batch comparisons)
06Automated generation of three conclusion sections: 'Identified Issues / Well-Preserved Aspects / Technical Explanation'
07Input validation and resource limits (extension whitelist, 500MB cap, ffmpeg 300s / ffprobe 30s timeouts)
08Documented adjustable constants (impact of each constant on processing time, output size, and quality trade-offs)

3External Dependencies

KindDependency / Endpoint
cliffmpeg(必需;抽帧、缩放、算 PSNR/SSIM)
cliffprobe(必需;元数据提取)
clipython3(3.8+,脚本运行时;仅标准库)
packageimg-comparison-slider(Web Component,报告页从 CDN 加载,非随包分发)
networkunpkg(第三方 CDN;打开报告时由浏览器发起请求)
networkffmpeg 官网(文档里的安装指引链接,非运行时依赖)

4Recommended Governance & Evidence

Suggested Controls for Safe Operation
For Agent Runtime
Graded/per-use authorization, sandbox recommended
For Administrators
Approval workflow, rollback support, full audit
Evidence & Triggers (File Paths & Excerpts)
  • scripts/: Execute local script or command: python3 scripts/compare.py <original> <compressed> [-o out.html] [--interva
  • 网络端点: Declare external network access: The generated report page loads https://unpkg.com/img-comparison-slider@8/dist/{styles.css,in via the browser
  • 本地工作目录: File read/write and artifact output: Writes HTML report to path specified by -o (default ./comparison.html): open(output_path, 'w', encoding='
Audit Notes: Rationale: The skill code itself does not access the network, read credentials or environment variables, or perform security downgrades (no TLS disabling, no anti-scraping bypasses, no sudo); its only external capability is invoking local ffmpeg/ffprobe, which is expected behavior for a local tool. However, three points require attention: ① Although not executed by the script itself, the generated report page fetches img-comparison-slider JS/CSS from unpkg—anyone opening the report will make requests to a third-party CDN and execute its scripts, constituting an artifact-level supply chain exposure; ② Subdirectories original/ and wechat/ are created in the output directory, overwriting same-named frame_*.png without collision protection; ③ The claim that reports are 'self-contained / works offline' conflicts with the actual implementation (requires HTML + two frame directories + CDN dependency), which is a misleading claim rather than a security downgrade, but could cause users to misjudge offline usability. Overall rating is Yellow: standard local tool behavior + one artifact-side third-party dependency, with no credential access or security downgrades.

5Second-Pass Verification

  • [discrepancy] SKILL.md 的『frames 以 base64 内嵌进 self-contained HTML』声明是否成立 — 不成立,是本次侦查发现的最重问题。SKILL.md 第 99 行:'The script extracts frames at specified intervals (default: 5 seconds), scales them to consistent height (800px) for comparison, and embeds them as base64 data URLs in self-contained HTML. Temporary files are automatically cleaned after processing.' 实际实现是把帧复制到 HTML 同级子目录:copy_frames_to_output 的 docstring 即 'Copy frames to a subdirectory next to the HTML output.',dest_name = f"frame_{i:03d}.png"、shutil.copy2(frame_path, dest_path),调用处为 copy_frames_to_output(original_frames, output_path, 'original') 与 (compressed_frames, output_path, 'wechat')。全目录 grep base64/b64encode/data:image 在 .py 与 .html 中零命中(仅出现在 README 的依赖清单与 configuration.md 的说明文字里)。模板侧确认用相对路径:<img slot="first" id="originalImage" src="original/frame_001.png" ...>。即产物是「HTML + original/ + wechat/」一整个目录,不是单文件。
  • [discrepancy] SKILL.md 的『Self-contained format (no server required, works offline)』是否成立 — 不成立(两条独立原因)。SKILL.md 第 108 行原文:'- Self-contained format (no server required, works offline)'。①存在外部 CDN 依赖:template.html 第 7-8 行加载 https://unpkg.com/img-comparison-slider@8/dist/styles.css 与 .../index.js,断网时滑块组件不可用;②依赖同级帧目录(见上一条),单独拷走 HTML 会丢帧。值得注意的是 README 自己承认了 CDN 依赖(依赖清单写 'img-comparison-slider (loaded from CDN)'),却同时在架构说明里声称 template.html 具备 'Base64-encoded image embedding'——即 README 内部亦不自洽,且与 SKILL.md 的 offline 声明互相矛盾。
  • [discrepancy] README 的『Architecture』信息是否与文件系统/实现一致 — 三处不符:①行数——README 写 'compare.py # Main comparison script (696 lines)',实测 wc -l = 1036 行;②架构清单只列 video_metrics.md 与 ffmpeg_commands.md 两份 reference,漏掉实际存在且被 SKILL.md 明确引用的 references/configuration.md;③把 template.html 描述为 'Base64-encoded image embedding',与实现不符(见第 1 条)。
  • [discrepancy] 文档是否宣称了未实现的能力(VMAF 等) — SKILL.md 层面是对的:它只说两个指标(PSNR、SSIM),与脚本一致(grep -i vmaf 在 compare.py 中零命中)。但 references/video_metrics.md(4 处 VMAF)与 references/ffmpeg_commands.md(3 处,含 'VMAF Calculation' 小节)都提供了 VMAF 的定义与 ffmpeg 命令。即参考材料覆盖了脚本未实现的第三指标——不是夸大声明(SKILL.md 未据此承诺),而是「参考材料超出工具能力」,使用者若按 reference 期待 VMAF 输出会落空。
  • [ok] 三条安全声明(path validation / command injection prevention / resource limits)是否有代码对应 — 逐条核实成立:①path validation —— validate_video_file 内 Path(path).resolve()、exists()、is_file()、后缀白名单 ALLOWED_EXTENSIONS、os.access(R_OK)、体积上限 MAX_FILE_SIZE_MB=500;②command injection prevention —— run_ffmpeg_command 以参数列表调用 subprocess.run(docstring:'args: Command arguments as list (prevents shell injection)'),全文无 shell=True;③resource limits —— FFMPEG_TIMEOUT=300、FFPROBE_TIMEOUT=30,且 TimeoutExpired 有专门异常映射。声明未夸大。
  • [ok] 是否存在未声明的网络/凭证行为 — 反例检索失败:compare.py 的 import 段为 argparse/json/logging/os/re/subprocess/sys/tempfile/time/pathlib/typing,无 urllib/requests/socket/http;全目录 grep token/secret/password/api_key/getenv/os.environ 零命中;无 base64 大块、无 >200 字符无空格长行。结论成立。
  • [discrepancy] 模板的『通用性』呈现与内容是否相符 — SKILL.md/README 把它呈现为通用的视频压缩对比工具,但 assets/template.html 的文案与路径是微信专用的:标签为「🎬 原始视频 (AVC)」与「📱 微信视频号 (HEVC)」、替换目标里有 '<div class="metric-subtitle">微信重新编码</div>'、帧相对路径写死 'wechat/frame_001.png',且 compare.py 的复制调用也写死 subfolder='wechat'(而非 'compressed')。结论:工具可用,但默认产物带有上游使用场景的专用词汇;非微信场景需自行改模板与源码常量。
  • [ok] pin commit 与 skill.path 是否与任务书表格一致 — git rev-parse HEAD = d5c4678cb5d4fd6acc9c922690df035dbd33d247,与任务书表格『库内 HEAD』逐字一致;目录位于仓库根,相对路径 video-comparer;本目录最后一次提交 878f947(2026-09-07)。GitHub API 复核 MIT / stars 1392 / pushed 2026-09-15T09:30:04Z。

6Verdict & Scenarios

  • Solid security implementation: path resolve + extension whitelist + file size limit + argument-list subprocess (no shell=True) + dual timeouts; all three security claims correspond to actual code, not empty promises.
  • Upfront content consistency check (duration difference threshold, warning if compressed file size is larger), preventing meaningless quality conclusions.
  • Metric interpretation accompanied by reference guides (PSNR/SSIM ranges, quality tiers, compression targets, and bitrate guidelines) rather than just raw numbers.
  • Adjustable constants and their impacts are well-documented, providing clear rationale for tuning parameters (the size/time/quality triangle).
  • Excellent interactive report UI: slider / side-by-side / grid modes + zoom + frame selection buttons, facilitating manual review of visual degradation.
  • Best for: Best for: Anyone needing to evaluate visual quality degradation after video compression—content creators/video professionals comparing quality before and after platform re-encoding, developers validating transcoding parameters, and scenarios where you need to verify if the visual fidelity remains acceptable after lowering bitrate. Single command + local interactive report, requiring no backend server and no third-party Python packages.
    Not for: Not suitable for: Scenarios requiring a single offline-distributable HTML file (it produces a folder structure and relies on a CDN); environments where ffmpeg cannot be installed (hard dependency); scenarios requiring perceptual metrics like VMAF (the script only calculates PSNR/SSIM, VMAF is only mentioned in reference documentation); and cross-format/cross-resolution content alignment scenarios (the tool assumes both videos have identical content and similar durations).
    Install Agent-Ready
    ① Verified Mirror 2026-09-15
    Option A · Direct DownloadDownload video-comparer.tar.gz
    sha256: f6f34839800154ed…
    Option B · Copy Guide for Agent
    install.json
    Agents automatically download and verify mirrors from this JSON guide.
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.