ワークフロー&基本ツール · daymade/claude-code-skills

video-comparer

このスキルは、2つの動画を比較して圧縮結果や品質の差異を分析する際に使用します。品質指標(PSNR、SSIM)やフレームごとの視覚的比較を含むインタラクティブなHTMLレポートを生成します。ユーザーが「動画の比較」「動画品質」「圧縮分析」「圧縮の前後」に言及した場合、または圧縮動画の品質評価を要求した場合にトリガーされます。

L4 高権限 · 段階的認可と監査V1 コミット固定コマンド実行ネットワーク通信ファイル書き込みDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1392License MIT(仓库根 LICENSE,Copyright (c) 2025 daymade;GitHub API spdx MIT)Commit d5c4678cb5
管理レベルは Skill の能力と推奨統制措置を示すものであり、品質や安全性の認証、利用可否の判定ではありません。使用の可否はユーザーおよび管理者が決定します。Agent 環境によって制約が異なるため、自動保護を仮定しないでください。第三者製 Skill の著作権は原著作者に帰属し、利用リスクは利用者が負います。

1仕組みと動作原理

単一のPythonスクリプトでffmpeg/ffprobeを制御する実装方式:ffprobeでメタデータを取得 → ffmpegでPSNR/SSIMを計算 → ffmpegで指定間隔ごとにフレームを抽出・リサイズ → フレームと指標をHTMLテンプレートに埋め込み → レポートをディスクへ出力。モデルは介在せず、完全に決定論的なパイプラインです。

video-comparer/scripts/compare.py
for tool in ['ffmpeg', 'ffprobe']:
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により事前に[tool, '-version']でチェックを実行します。

レポート生成は「テンプレートをレンダリングする」方式ではなく、「テンプレートを読み込み、正規表現でプレースホルダーをブロックごとに置換する」方式です。そのためテンプレート構造と密結合しており、同一段落内の改行や要素位置の変更によってサイレントに不整合が発生します。

video-comparer/scripts/compare.py
r'<div class="metric-value">[\d.]+ dB</div>\s*<div class="metric-subtitle">偏低</div>',
同ブロック内にはStep 1からStep 11まで計11箇所のre.sub/replaceが存在します(codec、解像度、ビットレート、サイズ、PSNR、SSIM、発見された問題、良好に維持された点、技術的説明、フレーム選択ボタン、JSフレーム数および間隔)。

フレーム画像はHTML内にインライン埋め込みされるのではなく、HTMLと同じ階層のサブディレクトリ(original/およびwechat/)にコピーされ、テンプレートから相対パスで参照されます。つまり成果物は単一ファイルではなくファイル群となります。

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')
実装はoutput_dir = output_html_path.parent / subfolder; dest_name = f"frame_{i:03d}.png"; shutil.copy2(frame_path, dest_path)。テンプレート側ではsrc="original/frame_001.png"およびsrc="wechat/frame_001.png"に対応。呼び出し元はcopy_frames_to_output(original_frames, output_path, 'original')および(compressed_frames, output_path, 'wechat')。

入力バリデーションを徹底:パスをresolveした後に存在確認/ファイル判定/拡張子ホワイトリスト/読み込み権限/サイズ上限を検証し、ffmpegとffprobeの存在も個別に事前検証して各OS向けのインストール手順を提示します。

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
validate_video_file内に'# Convert to absolute path to prevent directory traversal'のコメントあり。ファイル先頭のコメントには'Security features: - Path validation and sanitization - Command injection prevention - Resource limits (file size, timeout) - Comprehensive error handling'と宣言されています。

コマンドインジェクション対策は文字列のエスケープではなく、「引数リスト + shell=True不使用 + タイムアウト」の組み合わせに依存しており、subprocessの適切な利用法を踏襲しています。

video-comparer/scripts/compare.py
try: result = subprocess.run( args, capture_output=True, timeout=timeout, check=True, text=True ) return result.stdout
関数のdocstringに'args: Command arguments as list (prevents shell injection)'と明記。ディレクトリ全体でshell=Trueをgrepしてもヒットなし。

指標を計算する前に「2つの動画が同一内容か」の整合性検証(再生時間差の閾値判定、圧縮後に容量が増加した場合の警告)を実施し、異なる動画同士の比較を品質分析結果として出力する事態を防ぎます。

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
稀な設計:多くの比較ツールはコンテンツの事前整合性チェックを行わず直接数値を算出します。

2コア機能

01動画メタデータの抽出(codec / 解像度 / フレームレート / ビットレート / 再生時間 / ファイルサイズ)
02PSNR / SSIM品質指標の計算および圧縮率の統計
03指定間隔でのフレーム抽出と、比較用の高さ800pxへの統一リサイズ
043種類の表示モード(スライダー / 並列 / グリッド)+ 50%〜200%のズーム機能
05パラメータ化とバッチ処理(-o 出力パス、--interval フレーム抽出間隔、シェルループによる一括比較)
06「発見された問題 / 良好に維持された点 / 技術的説明」の3つの結論テキストの自動生成
07入力バリデーションとリソース制限(拡張子ホワイトリスト、500MB上限、ffmpeg 300秒 / ffprobe 30秒のタイムアウト)
08調整可能な定数のドキュメント化(各定数が処理時間、出力サイズ、画質のトレードオフに与える影響)

3外部依存関係

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

4推奨統制措置と判定根拠

安全運用のための推奨統制措置
Agent 向け
段階的・都度認可、サンドボックス推奨
管理者向け
承認フロー、ロールバック可能、全履歴監査
判定根拠(ファイルパスと抜粋)
  • scripts/: ローカルスクリプトまたはコマンドの実行: python3 scripts/compare.py <original> <compressed> [-o out.html] [--interva
  • 网络端点: 外部ネットワークアクセスの宣言: 生成されたレポートページはブラウザ経由で https://unpkg.com/img-comparison-slider@8/dist/{styles.css,in を読み込みます
  • 本地工作目录: ファイル読み書きおよび成果物の出力: -o で指定されたパス(デフォルトは ./comparison.html)にHTMLレポートを出力:open(output_path, 'w', encoding='
監査ノート: 選定理由:スキル自体のコードはネットワークにアクセスせず、認証情報や環境変数を読み取らず、セキュリティのダウングレード(TLS無効化、スクレイピング対策回避、sudo実行など)も行いません。唯一の外部機能はローカルのffmpeg/ffprobeの呼び出しであり、ローカルツールの挙動として想定内です。ただし3点注意が必要です:①スクリプト自体によるものではないものの、生成されたレポートページがunpkgからimg-comparison-sliderのJS/CSSを取得するため、レポートを開いた全ユーザーがサードパーティCDNへリクエストを送信しスクリプトを実行することになり、成果物側でのサプライチェーンリスクが存在します。②出力ディレクトリ内にoriginal/とwechat/が作成され、同名のframe_*.pngが上書きされる仕様となっており、存在保護がありません。③ドキュメント上で「self-contained / works offline」と謳われている内容が実際の実装(HTML + 2つのフレームディレクトリ + CDN依存)と乖離しており、セキュリティ低下ではないものの、オフライン環境での利用可否についてユーザーの誤認を招く恐れがあります。総合判定はイエロー:標準的なローカルツールの挙動 + 成果物側のサードパーティ依存が1箇所あるのみで、認証情報の窃取やセキュリティダウングレードは確認されません。

5二重目の独立検証

  • [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。

6結論

  • 堅牢なセキュリティ実装:パスのresolve + 拡張子ホワイトリスト + サイズ上限 + 引数リストを用いたsubprocess(shell=Trueなし)+ デュアルタイムアウト。3つのセキュリティ宣言がすべてコード上で実体化されています。
  • 「2つの動画が同一内容か」の整合性事前チェック(時間差閾値、圧縮後にサイズが増加した場合の警告)により、無意味な品質結論の出力を防止。
  • 単なる数値出力にとどまらず、指標の解説ガイドを完備(PSNR/SSIMの測定範囲、品質レベル区分、圧縮ターゲットとビットレートの目安)。
  • 調整可能な定数とその影響がドキュメント化されており、パラメータ調整の根拠が明確(容量・時間・画質のトレードオフ)。
  • 優れたインタラクティブレポートUI:スライダー / 並列 / グリッドの3モード + ズーム + フレーム選択ボタンにより、圧縮による視覚的劣化の有無を目視判断しやすい。
  • 最適な用途: 適したユースケース:「動画圧縮後にどれだけ画質が落ちたか」を判定したいユーザー。動画クリエイターがプラットフォームによる再圧縮前後の画質を比較するケース、開発者がトランスコードパラメータを検証するケース、ビットレートを下げても視覚的な許容範囲に収まっているかを確認したいケースに最適です。単一コマンドでローカルのインタラクティブレポートを生成でき、サーバーやPythonの外部パッケージも不要です。
    不向きな用途: 適さないユースケース:オフラインで単体配布可能な単一HTMLファイルを求める用途(実際はフォルダ構成となりCDNに依存);ffmpegをインストールできない環境(必須依存);VMAFなどの人間の知覚に近い指標が必要なケース(本スクリプトはPSNR/SSIMのみを計算し、VMAFは参考ドキュメントに記載されているのみ);異なるフォーマットや解像度間で内容を位置合わせする必要があるケース(2つの動画が同一内容かつ同等の再生時間であることを前提としています)。
    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
    Agent はこの JSON ガイドから自動的にダウンロードして検証します。
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.