clipwright 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: clipwright
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: MCP server group wrapping FFmpeg/OTIO. Provides primitives to manipulate video editing workflows from AI agents.
5
5
  Author: satoh-y-0323
6
6
  Author-email: satoh-y-0323 <shoma.papa.0323@gmail.com>
@@ -50,6 +50,38 @@ export CLIPWRIGHT_FFMPEG="C:/Users/<user>/AppData/Local/Microsoft/WinGet/Package
50
50
 
51
51
  ---
52
52
 
53
+ ## Prerequisite: clipwright-transcribe (whisper-cli)
54
+
55
+ `clipwright-transcribe` requires the **whisper.cpp** binary (`whisper-cli`) and a ggml
56
+ model file. They are not installed via pip — obtain them separately.
57
+
58
+ ### whisper-cli Binary
59
+
60
+ | Platform | How to install |
61
+ |---|---|
62
+ | **Windows** | Download the pre-built binary from [whisper.cpp Releases](https://github.com/ggerganov/whisper.cpp/releases) → `whisper-bin-x64.zip` (CPU) or `whisper-cublas-*-bin-x64.zip` (CUDA). Extract and place `whisper-cli.exe` in a directory on `PATH`, or set `CLIPWRIGHT_WHISPER`. |
63
+ | **macOS** | `brew install whisper-cpp` — installs `whisper-cli` on PATH automatically. |
64
+ | **Linux** | Build from source: `git clone https://github.com/ggerganov/whisper.cpp && cd whisper.cpp && cmake -B build && cmake --build build -j --config Release` — binary is at `build/bin/whisper-cli`. |
65
+
66
+ ```bash
67
+ # If whisper-cli is not on PATH, set the full path:
68
+ export CLIPWRIGHT_WHISPER=/path/to/whisper-cli
69
+ ```
70
+
71
+ ### ggml Model File
72
+
73
+ Download a model (e.g. `ggml-base.bin`) from [Hugging Face](https://huggingface.co/ggerganov/whisper.cpp).
74
+
75
+ ```bash
76
+ export CLIPWRIGHT_WHISPER_MODEL=/path/to/ggml-base.bin
77
+ ```
78
+
79
+ If neither `CLIPWRIGHT_WHISPER` nor a `whisper-cli` binary on PATH is found, the
80
+ `clipwright_transcribe` tool returns `DEPENDENCY_MISSING` and integration tests are
81
+ automatically skipped.
82
+
83
+ ---
84
+
53
85
  ## Development Environment Setup
54
86
 
55
87
  ```bash
@@ -189,6 +221,26 @@ For details, see [docs/clipwright-spec.md](docs/clipwright-spec.md).
189
221
 
190
222
  ---
191
223
 
224
+ ## Available Tools
225
+
226
+ | Package | MCP Tool | Description |
227
+ |---------|----------|-------------|
228
+ | `clipwright` (core) | `clipwright_inspect_media` | Probe a media file and return codec / duration / stream info |
229
+ | `clipwright` (core) | `clipwright_init_project` | Initialize a project directory with an empty OTIO timeline |
230
+ | `clipwright` (core) | `clipwright_read_timeline` | Read an OTIO timeline file and return its structure |
231
+ | `clipwright` (core) | `clipwright_write_timeline` | Write an OTIO timeline back to disk |
232
+ | `clipwright-silence` | `clipwright_detect_silence` | Detect silent regions in audio via FFmpeg `silencedetect` and annotate OTIO markers |
233
+ | `clipwright-loudness` | `clipwright_measure_loudness` | Measure EBU R128 loudness (integrated LUFS / true-peak) via FFmpeg |
234
+ | `clipwright-noise` | `clipwright_reduce_noise` | Annotate OTIO timeline with FFmpeg `afftdn` noise-reduction settings |
235
+ | `clipwright-transcribe` | `clipwright_transcribe` | Transcribe audio to text via whisper-cli and write word-level OTIO markers |
236
+ | `clipwright-bgm` | `clipwright_place_bgm` | Write BGM placement annotations (volume / fade / ducking) to OTIO timeline |
237
+ | `clipwright-render` | `clipwright_render` | Realize OTIO edit operations (trim / concat / filters) to an output media file via FFmpeg |
238
+ | `clipwright-wrap` | `clipwright_wrap_text` | Wrap long text lines with line-break annotations in OTIO timeline |
239
+ | `clipwright-scene` | `clipwright_detect_scenes` | Detect shot boundaries via FFmpeg `scdet` or PySceneDetect and write OTIO markers |
240
+ | `clipwright-frames` | `clipwright_extract_frames` | Extract still frames from video at specified times, scene boundaries, or fixed intervals; writes images, OTIO markers, and a JSON manifest |
241
+
242
+ ---
243
+
192
244
  ## MCP Client Registration
193
245
 
194
246
  Each clipwright tool is a standalone MCP server. Register them in your MCP client configuration (`.mcp.json` / `claude_desktop_config.json`):
@@ -208,11 +260,30 @@ Each clipwright tool is a standalone MCP server. Register them in your MCP clien
208
260
  "env": {
209
261
  "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg"
210
262
  }
263
+ },
264
+ "clipwright-bgm": {
265
+ "command": "clipwright-bgm"
266
+ },
267
+ "clipwright-scene": {
268
+ "command": "clipwright-scene",
269
+ "env": {
270
+ "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg",
271
+ "CLIPWRIGHT_FFPROBE": "/path/to/ffprobe"
272
+ }
273
+ },
274
+ "clipwright-frames": {
275
+ "command": "clipwright-frames",
276
+ "env": {
277
+ "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg",
278
+ "CLIPWRIGHT_FFPROBE": "/path/to/ffprobe"
279
+ }
211
280
  }
212
281
  }
213
282
  }
214
283
  ```
215
284
 
285
+ > Note: `clipwright-frames` lists both `CLIPWRIGHT_FFMPEG` (frame extraction) and `CLIPWRIGHT_FFPROBE` (video-stream detection and duration probing via `inspect_media`), so both variables must be configured.
286
+
216
287
  Set `CLIPWRIGHT_FFMPEG` and `CLIPWRIGHT_FFPROBE` environment variables if ffmpeg is not in `PATH`.
217
288
 
218
289
  ---
@@ -37,6 +37,38 @@ export CLIPWRIGHT_FFMPEG="C:/Users/<user>/AppData/Local/Microsoft/WinGet/Package
37
37
 
38
38
  ---
39
39
 
40
+ ## Prerequisite: clipwright-transcribe (whisper-cli)
41
+
42
+ `clipwright-transcribe` requires the **whisper.cpp** binary (`whisper-cli`) and a ggml
43
+ model file. They are not installed via pip — obtain them separately.
44
+
45
+ ### whisper-cli Binary
46
+
47
+ | Platform | How to install |
48
+ |---|---|
49
+ | **Windows** | Download the pre-built binary from [whisper.cpp Releases](https://github.com/ggerganov/whisper.cpp/releases) → `whisper-bin-x64.zip` (CPU) or `whisper-cublas-*-bin-x64.zip` (CUDA). Extract and place `whisper-cli.exe` in a directory on `PATH`, or set `CLIPWRIGHT_WHISPER`. |
50
+ | **macOS** | `brew install whisper-cpp` — installs `whisper-cli` on PATH automatically. |
51
+ | **Linux** | Build from source: `git clone https://github.com/ggerganov/whisper.cpp && cd whisper.cpp && cmake -B build && cmake --build build -j --config Release` — binary is at `build/bin/whisper-cli`. |
52
+
53
+ ```bash
54
+ # If whisper-cli is not on PATH, set the full path:
55
+ export CLIPWRIGHT_WHISPER=/path/to/whisper-cli
56
+ ```
57
+
58
+ ### ggml Model File
59
+
60
+ Download a model (e.g. `ggml-base.bin`) from [Hugging Face](https://huggingface.co/ggerganov/whisper.cpp).
61
+
62
+ ```bash
63
+ export CLIPWRIGHT_WHISPER_MODEL=/path/to/ggml-base.bin
64
+ ```
65
+
66
+ If neither `CLIPWRIGHT_WHISPER` nor a `whisper-cli` binary on PATH is found, the
67
+ `clipwright_transcribe` tool returns `DEPENDENCY_MISSING` and integration tests are
68
+ automatically skipped.
69
+
70
+ ---
71
+
40
72
  ## Development Environment Setup
41
73
 
42
74
  ```bash
@@ -176,6 +208,26 @@ For details, see [docs/clipwright-spec.md](docs/clipwright-spec.md).
176
208
 
177
209
  ---
178
210
 
211
+ ## Available Tools
212
+
213
+ | Package | MCP Tool | Description |
214
+ |---------|----------|-------------|
215
+ | `clipwright` (core) | `clipwright_inspect_media` | Probe a media file and return codec / duration / stream info |
216
+ | `clipwright` (core) | `clipwright_init_project` | Initialize a project directory with an empty OTIO timeline |
217
+ | `clipwright` (core) | `clipwright_read_timeline` | Read an OTIO timeline file and return its structure |
218
+ | `clipwright` (core) | `clipwright_write_timeline` | Write an OTIO timeline back to disk |
219
+ | `clipwright-silence` | `clipwright_detect_silence` | Detect silent regions in audio via FFmpeg `silencedetect` and annotate OTIO markers |
220
+ | `clipwright-loudness` | `clipwright_measure_loudness` | Measure EBU R128 loudness (integrated LUFS / true-peak) via FFmpeg |
221
+ | `clipwright-noise` | `clipwright_reduce_noise` | Annotate OTIO timeline with FFmpeg `afftdn` noise-reduction settings |
222
+ | `clipwright-transcribe` | `clipwright_transcribe` | Transcribe audio to text via whisper-cli and write word-level OTIO markers |
223
+ | `clipwright-bgm` | `clipwright_place_bgm` | Write BGM placement annotations (volume / fade / ducking) to OTIO timeline |
224
+ | `clipwright-render` | `clipwright_render` | Realize OTIO edit operations (trim / concat / filters) to an output media file via FFmpeg |
225
+ | `clipwright-wrap` | `clipwright_wrap_text` | Wrap long text lines with line-break annotations in OTIO timeline |
226
+ | `clipwright-scene` | `clipwright_detect_scenes` | Detect shot boundaries via FFmpeg `scdet` or PySceneDetect and write OTIO markers |
227
+ | `clipwright-frames` | `clipwright_extract_frames` | Extract still frames from video at specified times, scene boundaries, or fixed intervals; writes images, OTIO markers, and a JSON manifest |
228
+
229
+ ---
230
+
179
231
  ## MCP Client Registration
180
232
 
181
233
  Each clipwright tool is a standalone MCP server. Register them in your MCP client configuration (`.mcp.json` / `claude_desktop_config.json`):
@@ -195,11 +247,30 @@ Each clipwright tool is a standalone MCP server. Register them in your MCP clien
195
247
  "env": {
196
248
  "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg"
197
249
  }
250
+ },
251
+ "clipwright-bgm": {
252
+ "command": "clipwright-bgm"
253
+ },
254
+ "clipwright-scene": {
255
+ "command": "clipwright-scene",
256
+ "env": {
257
+ "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg",
258
+ "CLIPWRIGHT_FFPROBE": "/path/to/ffprobe"
259
+ }
260
+ },
261
+ "clipwright-frames": {
262
+ "command": "clipwright-frames",
263
+ "env": {
264
+ "CLIPWRIGHT_FFMPEG": "/path/to/ffmpeg",
265
+ "CLIPWRIGHT_FFPROBE": "/path/to/ffprobe"
266
+ }
198
267
  }
199
268
  }
200
269
  }
201
270
  ```
202
271
 
272
+ > Note: `clipwright-frames` lists both `CLIPWRIGHT_FFMPEG` (frame extraction) and `CLIPWRIGHT_FFPROBE` (video-stream detection and duration probing via `inspect_media`), so both variables must be configured.
273
+
203
274
  Set `CLIPWRIGHT_FFMPEG` and `CLIPWRIGHT_FFPROBE` environment variables if ffmpeg is not in `PATH`.
204
275
 
205
276
  ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "clipwright"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "MCP server group wrapping FFmpeg/OTIO. Provides primitives to manipulate video editing workflows from AI agents."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -84,4 +84,4 @@ skip_covered = false
84
84
 
85
85
  # --- uv workspace ---
86
86
  [tool.uv.workspace]
87
- members = ["clipwright-bgm", "clipwright-loudness", "clipwright-noise", "clipwright-render", "clipwright-silence", "clipwright-transcribe", "clipwright-wrap"]
87
+ members = ["clipwright-bgm", "clipwright-frames", "clipwright-loudness", "clipwright-noise", "clipwright-render", "clipwright-scene", "clipwright-silence", "clipwright-transcribe", "clipwright-wrap"]
@@ -1,3 +1,3 @@
1
1
  """clipwright: Core library for the FFmpeg/OTIO MCP server suite."""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.3.0"
@@ -6,6 +6,7 @@ Time conversions use to_otio_time / from_otio_time imported from schemas.py.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import collections.abc
9
10
  import contextlib
10
11
  import os
11
12
  import tempfile
@@ -198,6 +199,61 @@ def get_clipwright_metadata(obj: Any) -> dict[str, Any]:
198
199
  return dict(obj.metadata.get("clipwright", {}))
199
200
 
200
201
 
202
+ # ===========================================================================
203
+ # Marker queries
204
+ # ===========================================================================
205
+
206
+
207
+ def get_markers(
208
+ timeline: otio.schema.Timeline,
209
+ kind: str | None = None,
210
+ ) -> list[otio.schema.Marker]:
211
+ """Collect Marker objects from all tracks and clips in a Timeline.
212
+
213
+ Traversal order: tracks in track order → track markers first, then clip
214
+ markers in item order → individual markers in marker list order.
215
+ Time-based sorting is intentionally omitted so that the caller controls
216
+ ordering and round-trip stability is preserved even when two markers share
217
+ the same timestamp.
218
+
219
+ When *kind* is None all markers are returned. When *kind* is specified,
220
+ only markers whose ``metadata["clipwright"]["kind"]`` equals *kind* are
221
+ returned. Markers that have no ``metadata["clipwright"]`` dict, or where
222
+ that value is not a dict, are excluded when *kind* is given (defensive
223
+ pattern matching ``_marker_to_dict``).
224
+ """
225
+ result: list[otio.schema.Marker] = []
226
+ for track in timeline.tracks:
227
+ # Track-level markers first
228
+ for marker in track.markers:
229
+ if _marker_matches_kind(marker, kind):
230
+ result.append(marker)
231
+ # Clip-level markers in item order
232
+ for item in track:
233
+ if isinstance(item, otio.schema.Clip):
234
+ for marker in item.markers:
235
+ if _marker_matches_kind(marker, kind):
236
+ result.append(marker)
237
+ return result
238
+
239
+
240
+ def _marker_matches_kind(marker: otio.schema.Marker, kind: str | None) -> bool:
241
+ """Return True when *marker* matches the given kind filter.
242
+
243
+ When *kind* is None every marker matches.
244
+ When *kind* is set, the marker must have metadata["clipwright"]["kind"] == kind.
245
+ Missing or non-dict clipwright metadata is treated as no-match (exclusive).
246
+ """
247
+ if kind is None:
248
+ return True
249
+ cw_meta = marker.metadata.get("clipwright", {})
250
+ # OTIO stores metadata values as AnyDictionary, not a plain dict,
251
+ # so use Mapping to accept both types.
252
+ if not isinstance(cw_meta, collections.abc.Mapping):
253
+ return False
254
+ return cw_meta.get("kind") == kind
255
+
256
+
201
257
  # ===========================================================================
202
258
  # Timeline summary (§13.5 DC-AM-001 re: return all items, no truncation)
203
259
  # ===========================================================================