amverge 0.1.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.
- amverge-0.1.0/.gitignore +15 -0
- amverge-0.1.0/AGENTS.md +232 -0
- amverge-0.1.0/LICENSE +35 -0
- amverge-0.1.0/PKG-INFO +254 -0
- amverge-0.1.0/README.md +212 -0
- amverge-0.1.0/TODO.md +151 -0
- amverge-0.1.0/amverge/__init__.py +190 -0
- amverge-0.1.0/amverge/__version__.py +1 -0
- amverge-0.1.0/amverge/cli.py +62 -0
- amverge-0.1.0/amverge/commands/__init__.py +0 -0
- amverge-0.1.0/amverge/commands/about.py +55 -0
- amverge-0.1.0/amverge/commands/backend.py +212 -0
- amverge-0.1.0/amverge/commands/bench.py +99 -0
- amverge-0.1.0/amverge/commands/cache.py +86 -0
- amverge-0.1.0/amverge/commands/changelog.py +84 -0
- amverge-0.1.0/amverge/commands/credits.py +62 -0
- amverge-0.1.0/amverge/commands/detect.py +284 -0
- amverge-0.1.0/amverge/commands/doctor.py +30 -0
- amverge-0.1.0/amverge/commands/export.py +177 -0
- amverge-0.1.0/amverge/commands/gpu.py +92 -0
- amverge-0.1.0/amverge/commands/info.py +62 -0
- amverge-0.1.0/amverge/commands/keyframes.py +57 -0
- amverge-0.1.0/amverge/commands/merge.py +67 -0
- amverge-0.1.0/amverge/commands/probe.py +107 -0
- amverge-0.1.0/amverge/commands/rpc_server.py +80 -0
- amverge-0.1.0/amverge/commands/scenes.py +76 -0
- amverge-0.1.0/amverge/commands/usage.py +86 -0
- amverge-0.1.0/amverge/commands/version.py +82 -0
- amverge-0.1.0/amverge/core/__init__.py +57 -0
- amverge-0.1.0/amverge/core/amverge_video.py +402 -0
- amverge-0.1.0/amverge/core/binaries.py +85 -0
- amverge-0.1.0/amverge/core/codec_utils.py +145 -0
- amverge-0.1.0/amverge/core/detection/__init__.py +4 -0
- amverge-0.1.0/amverge/core/detection/edge.py +168 -0
- amverge-0.1.0/amverge/core/detection/keyframe.py +44 -0
- amverge-0.1.0/amverge/core/diagnostics.py +266 -0
- amverge-0.1.0/amverge/core/discord_rpc.py +158 -0
- amverge-0.1.0/amverge/core/hevc.py +12 -0
- amverge-0.1.0/amverge/core/image.py +87 -0
- amverge-0.1.0/amverge/core/image_crop.py +55 -0
- amverge-0.1.0/amverge/core/ipc.py +95 -0
- amverge-0.1.0/amverge/core/keyframe_align.py +151 -0
- amverge-0.1.0/amverge/core/keyframes.py +163 -0
- amverge-0.1.0/amverge/core/nelux_runtime.py +122 -0
- amverge-0.1.0/amverge/core/probe_utils.py +85 -0
- amverge-0.1.0/amverge/core/scene_cache.py +156 -0
- amverge-0.1.0/amverge/core/scene_detection.py +330 -0
- amverge-0.1.0/amverge/core/scene_detector.py +106 -0
- amverge-0.1.0/amverge/core/scene_exporter.py +204 -0
- amverge-0.1.0/amverge/core/scene_utils.py +84 -0
- amverge-0.1.0/amverge/core/segmenter.py +146 -0
- amverge-0.1.0/amverge/core/similarity.py +101 -0
- amverge-0.1.0/amverge/core/similarity_checker.py +75 -0
- amverge-0.1.0/amverge/core/smart_cut.py +311 -0
- amverge-0.1.0/amverge/core/thumbnail_generator.py +96 -0
- amverge-0.1.0/amverge/core/thumbnails.py +115 -0
- amverge-0.1.0/amverge/core/thumbnails_streaming.py +107 -0
- amverge-0.1.0/amverge/core/transnet_config.py +56 -0
- amverge-0.1.0/amverge/core/transnet_constants.py +7 -0
- amverge-0.1.0/amverge/core/video.py +77 -0
- amverge-0.1.0/amverge/pipeline.py +478 -0
- amverge-0.1.0/amverge/ui.py +134 -0
- amverge-0.1.0/amverge/wizard.py +574 -0
- amverge-0.1.0/assets/amverge_title_gif.gif +0 -0
- amverge-0.1.0/docs/ai-setup.md +142 -0
- amverge-0.1.0/docs/cli-reference.md +260 -0
- amverge-0.1.0/docs/contributing.md +69 -0
- amverge-0.1.0/docs/detection-methods.md +177 -0
- amverge-0.1.0/docs/installation.md +103 -0
- amverge-0.1.0/docs/library.md +425 -0
- amverge-0.1.0/examples/README.md +113 -0
- amverge-0.1.0/examples/custom-pipeline/README.md +69 -0
- amverge-0.1.0/examples/custom-pipeline/full_pipeline.py +150 -0
- amverge-0.1.0/examples/cutting/01_smart_cut.py +46 -0
- amverge-0.1.0/examples/cutting/02_ffmpeg_segment.py +36 -0
- amverge-0.1.0/examples/cutting/03_single_scene.py +30 -0
- amverge-0.1.0/examples/cutting/README.md +72 -0
- amverge-0.1.0/examples/detect/01_basic_detect.py +36 -0
- amverge-0.1.0/examples/detect/02_transnetv2_detect.py +42 -0
- amverge-0.1.0/examples/detect/03_edge_detect.py +36 -0
- amverge-0.1.0/examples/detect/04_custom_settings.py +43 -0
- amverge-0.1.0/examples/detect/README.md +73 -0
- amverge-0.1.0/examples/diagnostics/01_gpu_check.py +29 -0
- amverge-0.1.0/examples/diagnostics/02_version_info.py +22 -0
- amverge-0.1.0/examples/diagnostics/README.md +45 -0
- amverge-0.1.0/examples/discord-rpc/01_basic_rpc.py +41 -0
- amverge-0.1.0/examples/discord-rpc/README.md +50 -0
- amverge-0.1.0/examples/export/01_copy_export.py +41 -0
- amverge-0.1.0/examples/export/02_reencode_export.py +58 -0
- amverge-0.1.0/examples/export/03_merge_export.py +43 -0
- amverge-0.1.0/examples/export/README.md +81 -0
- amverge-0.1.0/examples/info-probe/01_video_info.py +40 -0
- amverge-0.1.0/examples/info-probe/02_probe.py +47 -0
- amverge-0.1.0/examples/info-probe/03_hevc_check.py +19 -0
- amverge-0.1.0/examples/info-probe/README.md +68 -0
- amverge-0.1.0/examples/keyframes/01_extract_keyframes.py +34 -0
- amverge-0.1.0/examples/keyframes/02_align_scenes.py +40 -0
- amverge-0.1.0/examples/keyframes/README.md +66 -0
- amverge-0.1.0/examples/similarity/01_find_similar.py +41 -0
- amverge-0.1.0/examples/similarity/README.md +61 -0
- amverge-0.1.0/examples/thumbnails/01_make_thumbnails.py +33 -0
- amverge-0.1.0/examples/thumbnails/README.md +59 -0
- amverge-0.1.0/pyproject.toml +61 -0
- amverge-0.1.0/test_result.json +133 -0
amverge-0.1.0/.gitignore
ADDED
amverge-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# AGENTS.md - AMVerge CLI
|
|
2
|
+
|
|
3
|
+
AMVerge features as a CLI tool and Python library. Ports the AMVerge desktop app backend (by Crptk) into a standalone `pip install amverge` package.
|
|
4
|
+
|
|
5
|
+
## AI Agent Instructions
|
|
6
|
+
|
|
7
|
+
- **Update this file** when adding/removing files, changing architecture, adding new commands, or introducing conventions.
|
|
8
|
+
- **Commit style:** prefix tag in parentheses: `(add)` new features, `(fix)` bug fixes, `(update)` refactors/formatting/chores. Example: `(fix) wizard: handle KeyboardInterrupt during path input`.
|
|
9
|
+
- **Commit author:** always commit under the user's account. Do NOT add a `Co-Authored-By: Claude` trailer or any self-attribution.
|
|
10
|
+
- **Commit per task:** separate commit after each task/logical change. Do not batch unrelated changes.
|
|
11
|
+
- **No code comments:** do NOT add comments when writing or modifying code. Put any needed explanation in the commit message or this file.
|
|
12
|
+
- **No em dashes:** never use `—` in any prose, docs, README, or commit messages. Use a comma, colon, parentheses, or plain hyphen `-` instead.
|
|
13
|
+
- **Rich style= params:** theme names (`accent`, `muted`, etc.) only resolve inside markup strings `[accent]text[/]`. They do NOT work in `style=`, `header_style=`, or `title_style=` kwargs - use literal hex `#22c55e bold` there instead.
|
|
14
|
+
|
|
15
|
+
## Build & Run
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install -e . # base install (keyframe detection only)
|
|
19
|
+
pip install -e ".[edge]" # + OpenCV for edge detection method
|
|
20
|
+
pip install -e ".[ml]" # + TransNetV2 ML detection (torch, GPU optional)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
No build step. Pure Python package, `hatchling` backend.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
amverge # interactive wizard (no-args mode)
|
|
27
|
+
amverge detect video.mp4 # direct command
|
|
28
|
+
amverge --help # Typer help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To publish to PyPI (not done yet - verify `pypi.org/project/amverge` name is free first):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install build twine
|
|
35
|
+
python -m build
|
|
36
|
+
twine upload dist/*
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Tech Stack
|
|
40
|
+
|
|
41
|
+
| Layer | Tech |
|
|
42
|
+
|---|---|
|
|
43
|
+
| CLI | Typer |
|
|
44
|
+
| UI | Rich (custom green theme) |
|
|
45
|
+
| Video decode | PyAV (packet demux + keyframe timestamps) |
|
|
46
|
+
| Video decode (ML) | Nelux (Windows native, optional) or FFmpeg pipe |
|
|
47
|
+
| Video process | FFmpeg / FFprobe (subprocess) |
|
|
48
|
+
| Scene detection | TransNetV2 via `transnetv2_pytorch` (optional, `[ml]` extra) |
|
|
49
|
+
| Scene cutting | Smart cut: lossless copy + re-encode tail, or full re-encode (HEVC/fallback) |
|
|
50
|
+
| Image | Pillow |
|
|
51
|
+
| Numerics | NumPy |
|
|
52
|
+
| GPU | PyTorch (CUDA auto-detected, CPU fallback) |
|
|
53
|
+
| Edge detection | OpenCV (optional, `[edge]` extra) |
|
|
54
|
+
| Package | hatchling, PyPI name `amverge` |
|
|
55
|
+
| Discord RPC | pypresence (optional, `[discord]` extra) |
|
|
56
|
+
|
|
57
|
+
## Directory Map
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
AMVerge-CLI/
|
|
61
|
+
├── amverge/
|
|
62
|
+
│ ├── __init__.py public exports: detect_scenes, DetectResult, Scene, DetectionMethod
|
|
63
|
+
│ ├── __version__.py version string
|
|
64
|
+
│ ├── cli.py Typer app, registers all commands, no-args -> wizard
|
|
65
|
+
│ ├── pipeline.py high-level detect_scenes() public API
|
|
66
|
+
│ ├── wizard.py interactive session (no-args mode)
|
|
67
|
+
│ ├── ui.py shared Rich theme, console, banner, progress, table helpers
|
|
68
|
+
│ │
|
|
69
|
+
│ ├── commands/
|
|
70
|
+
│ │ ├── backend.py amverge backend <video> <output_dir> (hidden - Rust sidecar replacement)
|
|
71
|
+
│ │ ├── rpc_server.py amverge rpc-server (hidden - Discord RPC sidecar, reads JSON from stdin)
|
|
72
|
+
│ │ ├── detect.py amverge detect
|
|
73
|
+
│ │ ├── export.py amverge export (CODEC_PROFILES/AUDIO_FFMPEG dicts - wizard imports these)
|
|
74
|
+
│ │ ├── merge.py amverge merge
|
|
75
|
+
│ │ ├── info.py amverge info (stream metadata via PyAV)
|
|
76
|
+
│ │ ├── probe.py amverge probe (V2 diagnostics: codec/HEVC/keyframes/scene cache)
|
|
77
|
+
│ │ ├── gpu.py amverge gpu (PyTorch version, CUDA, GPU name/VRAM, all optional deps)
|
|
78
|
+
│ │ ├── doctor.py amverge doctor (full health check: ffmpeg, deps, write access, pass/fail)
|
|
79
|
+
│ │ ├── version.py amverge version (CLI + Python + all dep versions, --json for bug reports)
|
|
80
|
+
│ │ ├── bench.py amverge bench (keyframe scan + TransNetV2 decode/inference timing)
|
|
81
|
+
│ │ ├── cache.py amverge cache (list/clear TransNetV2 .npy scene caches)
|
|
82
|
+
│ │ ├── keyframes.py amverge keyframes (dump keyframe timestamps, --json, --count)
|
|
83
|
+
│ │ ├── scenes.py amverge scenes (show scene list from .npy cache, --json, --min-duration)
|
|
84
|
+
│ │ ├── usage.py amverge usage (CLI reference page)
|
|
85
|
+
│ │ ├── about.py amverge about
|
|
86
|
+
│ │ ├── credits.py amverge credits (exports _credits_table() for wizard reuse)
|
|
87
|
+
│ │ └── changelog.py amverge changelog
|
|
88
|
+
│ │
|
|
89
|
+
│ └── core/ pure logic - no Rich/Typer deps, safe as library
|
|
90
|
+
│ ├── binaries.py get_binary(), get_ffmpeg(), get_ffprobe() - PyInstaller-aware PATH search
|
|
91
|
+
│ ├── ipc.py emit_progress(), emit_event(), log(), check_if_path_exists(), build_video_cache_prefix()
|
|
92
|
+
│ ├── probe_utils.py probe_video_fps/duration/dimensions/total_frames via ffprobe
|
|
93
|
+
│ ├── scene_utils.py scenes_to_objects(), scenes_frames_to_seconds()
|
|
94
|
+
│ ├── diagnostics.py get_gpu_info(), get_versions() - clean wrappers
|
|
95
|
+
│ ├── codec_utils.py check_if_hevc(), CODEC_PROFILES, AUDIO_FFMPEG, CODEC_ALIASES, PRORES_CODECS, resolve_gpu()
|
|
96
|
+
│ ├── keyframe_align.py get_keyframe_timestamps_pyav(), classify_scenes_by_keyframe_alignment()
|
|
97
|
+
│ ├── smart_cut.py cut_scene(), cut_all_scenes() - lossless copy / smartcut / reencode
|
|
98
|
+
│ ├── nelux_runtime.py _get_nelux_video_reader() - Windows DLL config for Nelux
|
|
99
|
+
│ ├── scene_detection.py decode_video_frames_nelux(), decode_and_detect_scenes(), run_model_one_pass()
|
|
100
|
+
│ ├── transnet_constants.py FRAME_WIDTH/HEIGHT/CHANNELS/BYTES, WINDOW_SIZE, STRIDE
|
|
101
|
+
│ ├── keyframes.py generate_keyframes() - PyAV packet demux (V1 detect command)
|
|
102
|
+
│ ├── video.py get_video_duration(), get_video_info(), merge_short_scenes()
|
|
103
|
+
│ ├── segmenter.py run_ffmpeg_segment() - 1500-cut Windows chunking (V1)
|
|
104
|
+
│ ├── thumbnails.py make_thumbnail(), generate_thumbnails() - ThreadPoolExecutor
|
|
105
|
+
│ ├── similarity.py find_similar_pairs() - cosine similarity on pixel arrays
|
|
106
|
+
│ ├── hevc.py is_hevc() - ffprobe codec check (V1)
|
|
107
|
+
│ ├── image.py crop_image() + CropData - supports animated GIF
|
|
108
|
+
│ ├── thumbnails_streaming.py streaming thumbnail gen with IPC events (V1 backend mode)
|
|
109
|
+
│ ├── discord_rpc.py DiscordRPC class - pypresence wrapper, CLIENT_ID from AMVerge
|
|
110
|
+
│ └── detection/
|
|
111
|
+
│ ├── keyframe.py detect_cuts_by_keyframe() (V1)
|
|
112
|
+
│ └── edge.py detect_cuts_by_edge() - guarded cv2 import (V1)
|
|
113
|
+
│
|
|
114
|
+
├── docs/
|
|
115
|
+
│ ├── installation.md
|
|
116
|
+
│ ├── cli-reference.md
|
|
117
|
+
│ ├── library.md
|
|
118
|
+
│ ├── detection-methods.md
|
|
119
|
+
│ └── contributing.md
|
|
120
|
+
│
|
|
121
|
+
├── assets/
|
|
122
|
+
│ └── amverge_title_gif.gif
|
|
123
|
+
│
|
|
124
|
+
├── pyproject.toml
|
|
125
|
+
├── README.md
|
|
126
|
+
└── AGENTS.md
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Key Architecture
|
|
130
|
+
|
|
131
|
+
### No-args wizard routing
|
|
132
|
+
|
|
133
|
+
`cli.py` uses `@app.callback(invoke_without_command=True)`. When `ctx.invoked_subcommand is None`, calls `run_wizard()` from `wizard.py`. All wizard output goes to `stderr` so stdout stays clean for piping.
|
|
134
|
+
|
|
135
|
+
### V2 backend pipeline (TransNetV2)
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
decode_video_frames_nelux() or decode_and_detect_scenes()
|
|
139
|
+
↓ (frames ndarray)
|
|
140
|
+
run_model_one_pass() (TransNetV2, GPU/CPU)
|
|
141
|
+
↓ (scenes_secs, scenes_frames ndarray - cached as .npy)
|
|
142
|
+
scenes_to_objects()
|
|
143
|
+
↓ emit INITIAL_CLIPS_READY|[json]
|
|
144
|
+
get_keyframe_timestamps_pyav() + check_if_hevc()
|
|
145
|
+
↓
|
|
146
|
+
classify_scenes_by_keyframe_alignment()
|
|
147
|
+
↓
|
|
148
|
+
Phase 1: cut_all_scenes() lossless copy (max_workers=8) -> emit CLIP_READY per scene
|
|
149
|
+
↓ emit PHASE1_COMPLETE
|
|
150
|
+
Phase 2: cut_all_scenes() re-encode (max_workers=2) -> emit REENCODE_PROGRESS + CLIP_READY
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### V1 detection pipeline (keyframe, no ML)
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
generate_keyframes() (PyAV packet demux)
|
|
157
|
+
↓
|
|
158
|
+
merge_short_scenes() (drop cuts < min_duration)
|
|
159
|
+
↓
|
|
160
|
+
run_ffmpeg_segment() (ffmpeg -segment_times, stream copy)
|
|
161
|
+
↓
|
|
162
|
+
generate_thumbnails() (PyAV decode, ThreadPoolExecutor)
|
|
163
|
+
↓
|
|
164
|
+
find_similar_pairs() (cosine similarity on pixel arrays)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Library API
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from amverge import detect_scenes
|
|
171
|
+
|
|
172
|
+
result = detect_scenes("episode.mp4")
|
|
173
|
+
for scene in result.scenes:
|
|
174
|
+
print(scene.index, scene.start, scene.end, scene.path)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`core/` has no CLI dependencies. Import anything from it without pulling in Rich or Typer.
|
|
178
|
+
|
|
179
|
+
## Code Conventions
|
|
180
|
+
|
|
181
|
+
- **Python:** snake_case vars/fns, PascalCase dataclasses, type hints on all public APIs
|
|
182
|
+
- **CLI commands:** one file per command in `commands/`, registered in `cli.py`, added to wizard in `wizard.py`
|
|
183
|
+
- **Library modules:** all in `core/`, no Rich/Typer imports allowed
|
|
184
|
+
- **UI:** all Rich output through `ui.py` helpers (`console`, `err`, `banner()`, `make_table()`)
|
|
185
|
+
- **Subprocess:** all ffmpeg/ffprobe calls include `creationflags=0x08000000` on win32 (suppress console popups)
|
|
186
|
+
|
|
187
|
+
## Critical Paths
|
|
188
|
+
|
|
189
|
+
| File | Role |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `core/segmenter.py` | Windows 32,767-char command line limit. If video has >1500 cut points, chunks into multiple ffmpeg passes. Do not remove this chunking. |
|
|
192
|
+
| `core/keyframes.py` | Fast path reads packet metadata only (no frame decode). Falls back to full decode for pathological encodes. Deduplicates I-frames within short windows. |
|
|
193
|
+
| `core/detection/edge.py` | `import cv2` is inside the function body, not at module level. Raises clear `ImportError` pointing to `pip install amverge[edge]` if OpenCV missing. Keep it this way - edge is an optional dep. |
|
|
194
|
+
| `wizard.py` | `_credits_table()` is imported from `commands/credits.py` to avoid duplication. `_wizard_export()` imports `CODEC_PROFILES`, `AUDIO_FFMPEG`, `CODEC_ALIASES`, `PRORES_CODECS`, `resolve_gpu` from `core/codec_utils.py` - single source of truth for codec mappings. |
|
|
195
|
+
| `ui.py` | `err` console (stderr) used for all interactive/wizard output. `console` (stdout) for command results. Do not mix them. `ok()`/`warn()`/`fail()` use ASCII-safe marker `>` - Python `●`/`→` crash on CP1252 Windows terminals. |
|
|
196
|
+
| `core/similarity.py` | `find_similar_pairs()` accepts both `scene_index` and `index` keys for V1 (collect_scenes) / V2 (Scene.to_dict()) compat. |
|
|
197
|
+
| `commands/export.py` | `CODEC_PROFILES`/`AUDIO_FFMPEG`/`CODEC_ALIASES`/`PRORES_CODECS`/`_resolve_gpu` imported from `core/codec_utils.py`. |
|
|
198
|
+
| `pipeline.py` | `DetectionMethod` is `Literal["keyframe", "edge", "transnetv2"]`. TransNetV2 path uses `decode_and_detect_scenes()` + `cut_all_scenes()` (V2 pipeline). Monkey-patches `emit_progress` on `scene_detection`/`smart_cut` module-local refs (not `ipc` module) to route IPC progress to Rich callback. |
|
|
199
|
+
| `core/ipc.py` | IPC protocol for Tauri app. V2 events: `PROGRESS\|pct\|msg`, `INITIAL_CLIPS_READY\|json`, `CLIP_READY\|idx\|path\|mode`, `PHASE1_COMPLETE`, `REENCODE_PROGRESS\|done\|total`. stdout reserved for final JSON. Never mix IPC output with Rich output. |
|
|
200
|
+
| `core/scene_detection.py` | TransNetV2 inference. Requires `[ml]` extra. `TRANSNET_AVAILABLE` flag guards import at module level - raises clear `ImportError` if missing. Do not import torch at module level in other files. |
|
|
201
|
+
| `core/smart_cut.py` | Four cut modes: `copy` (start on keyframe), `snapped_copy` (HEVC CPU - snaps to nearest keyframe within 5s), `smartcut` (H.264 - encode tiny head + lossless tail), `reencode` (full fallback). Never remove the HEVC CPU path - HEVC re-encode without CUDA takes 10+ minutes. |
|
|
202
|
+
| `core/codec_utils.py` | `check_if_hevc()` via ffprobe. Also contains `CODEC_PROFILES` (14 codec -> ffmpeg encoder mappings), `AUDIO_FFMPEG` (10 audio choices), `CODEC_ALIASES`, `PRORES_CODECS`, `resolve_gpu()`. Single source of truth - `commands/export.py` and `wizard.py` import from here. Do not duplicate these dicts. |
|
|
203
|
+
| `core/nelux_runtime.py` | Windows DLL setup for Nelux video reader. Set `AMVERGE_FFMPEG_BIN` env var to FFmpeg shared DLL directory. Idempotent - safe to call multiple times. |
|
|
204
|
+
| `core/keyframe_align.py` | `get_keyframe_timestamps_pyav` uses PyAV demux with `type(stream.discard).nonkey` enum (PyAV 17.x; was `"NONKEY"` string in older PyAV). `classify_scenes_by_keyframe_alignment` partitions scenes for Phase 1 vs Phase 2 cutting. |
|
|
205
|
+
| `core/thumbnails_streaming.py` | V1 backend mode only. Emits events as each thumbnail completes. Not used in V2 backend. |
|
|
206
|
+
| `core/discord_rpc.py` | Uses same CLIENT_ID as AMVerge app (`1497922104065134823`). Silently no-ops if pypresence not installed. `--no-rpc` flag on detect/export/merge to disable. Methods: idle/detecting/selecting/navigating/exporting/merging/complete/error. |
|
|
207
|
+
| `commands/rpc_server.py` | Hidden sidecar: `amverge rpc-server`. Long-lived process; Rust spawns it once and sends JSON commands via stdin (`{"type":"update","details":"...","state":"..."}`, `{"type":"clear"}`, `{"type":"shutdown"}`). Throttles Discord updates to max 1 per 15s. Exits when stdin closes or parent dies. |
|
|
208
|
+
| `commands/backend.py` | V2 backend. Positional interface: `amverge backend <video_path> <output_dir> [import_method]`. Rust replaces `python app.py <video> <dir>` with `amverge backend <video> <dir>` - no Rust changes needed. Emits V2 IPC events. Outputs JSON schema v1.0 with `schema_version`, `run_id`, `video` metadata block. |
|
|
209
|
+
|
|
210
|
+
## Theme
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
THEME = Theme({
|
|
214
|
+
"accent": "#22c55e",
|
|
215
|
+
"accent.bright": "#00f07a",
|
|
216
|
+
"muted": "bright_black",
|
|
217
|
+
"success": "#22c55e bold",
|
|
218
|
+
"warn": "#facc15",
|
|
219
|
+
"error": "#ef4444",
|
|
220
|
+
"label": "white",
|
|
221
|
+
"bar.back": "bright_black",
|
|
222
|
+
"bar.complete": "#22c55e",
|
|
223
|
+
"bar.finished": "#00f07a",
|
|
224
|
+
}, inherit=False)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Banner markup: `[accent]AMV[/][white bold]erge[/]` - AMV is green, erge is white. Match this everywhere.
|
|
228
|
+
|
|
229
|
+
## Origin
|
|
230
|
+
|
|
231
|
+
All core logic ported from `AMVergeNew/backend/` (Crptk's original AMVerge desktop app).
|
|
232
|
+
Color palette from `AMVergeNew/frontend/src/styles/variables.css`.
|
amverge-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
AMVerge CLI
|
|
2
|
+
Copyright (C) 2026 Moongetsu
|
|
3
|
+
|
|
4
|
+
Based on AMVerge by Crptk <https://github.com/crptk/AMVerge>
|
|
5
|
+
Original AMVerge Copyright (C) 2026 Crptk
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
GNU GENERAL PUBLIC LICENSE
|
|
23
|
+
Version 3, 29 June 2007
|
|
24
|
+
|
|
25
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
26
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
27
|
+
of this license document, but changing it is not allowed.
|
|
28
|
+
|
|
29
|
+
Preamble
|
|
30
|
+
|
|
31
|
+
The GNU General Public License is a free, copyleft license for
|
|
32
|
+
software and other kinds of works.
|
|
33
|
+
|
|
34
|
+
For the precise terms and conditions for copying, distribution and
|
|
35
|
+
modification, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
|
amverge-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amverge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AMVerge Features as a CLI Tool and Python Library
|
|
5
|
+
Project-URL: repository, https://github.com/moongetsu/AMVerge-CLI
|
|
6
|
+
Author-email: Moongetsu <moongetsu@proton.me>
|
|
7
|
+
License: GPL-3.0-or-later
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: amverge,anime,clip-management,ffmpeg,keyframe,scene-detection,transnetv2,video,video-editing
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Multimedia :: Video
|
|
21
|
+
Classifier: Topic :: Multimedia :: Video :: Conversion
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: av>=12
|
|
27
|
+
Requires-Dist: numpy>=1.26
|
|
28
|
+
Requires-Dist: pillow>=10
|
|
29
|
+
Requires-Dist: rich>=13
|
|
30
|
+
Requires-Dist: typer>=0.12
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pyinstaller>=6; extra == 'dev'
|
|
33
|
+
Provides-Extra: discord
|
|
34
|
+
Requires-Dist: pypresence>=4.3; extra == 'discord'
|
|
35
|
+
Provides-Extra: edge
|
|
36
|
+
Requires-Dist: opencv-python-headless>=4.9; extra == 'edge'
|
|
37
|
+
Provides-Extra: ml
|
|
38
|
+
Requires-Dist: torch>=2.0; extra == 'ml'
|
|
39
|
+
Requires-Dist: tqdm>=4.0; extra == 'ml'
|
|
40
|
+
Requires-Dist: transnetv2-pytorch; extra == 'ml'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<img src="assets/amverge_title_gif.gif" alt="AMVerge CLI" width="1440"/>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<img src="https://img.shields.io/badge/python-3.11+-blue?style=flat-square" alt="Python"/>
|
|
49
|
+
<img src="https://img.shields.io/badge/pypi-amverge-22c55e?style=flat-square" alt="PyPI"/>
|
|
50
|
+
<img src="https://img.shields.io/badge/license-GPL--3.0-22c55e?style=flat-square" alt="License"/>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
# AMVerge CLI
|
|
54
|
+
|
|
55
|
+
**AMVerge Features as a CLI Tool and Python Library.**
|
|
56
|
+
Port of the AMVerge desktop app backend by [Crptk](https://github.com/crptk). Split videos into scenes, export clips, merge fragments, and build your own tools on top of it.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Features
|
|
61
|
+
|
|
62
|
+
- **TransNetV2 ML detection** - deep learning scene boundary detection (GPU/CPU)
|
|
63
|
+
- **Keyframe detection** - fast I-frame based splitting, no re-encode
|
|
64
|
+
- **Edge detection** - Canny edges + cosine similarity for difficult encodes
|
|
65
|
+
- **Smart cut** - automatic lossless copy / smartcut / re-encode per scene
|
|
66
|
+
- **15 codec profiles** - H.264, HEVC, AV1, ProRes with hardware (NVENC) support
|
|
67
|
+
- **10 audio codecs** - AAC, FLAC, Opus, PCM, MP3, pass-through
|
|
68
|
+
- **3 container formats** - MP4, MKV, MOV (ProRes auto-enforces MOV)
|
|
69
|
+
- Auto-generated scene thumbnails (progressive JPEG)
|
|
70
|
+
- Duplicate / similar scene detection (cosine similarity)
|
|
71
|
+
- Scene export with full codec + audio + hardware selection
|
|
72
|
+
- Clip merging via FFmpeg concat
|
|
73
|
+
- Video metadata inspection and diagnostics
|
|
74
|
+
- TransNetV2 scene cache (.npy) - skip re-detection on re-open
|
|
75
|
+
- Discord Rich Presence (same app ID as AMVerge desktop)
|
|
76
|
+
- Interactive wizard mode (`amverge` with no args)
|
|
77
|
+
- Fully usable as a Python library - 52 names from `import amverge`
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Install
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install amverge
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
See [docs/installation.md](docs/installation.md) for FFmpeg setup, optional dependencies, and dev install.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Quick Start
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Interactive wizard
|
|
95
|
+
amverge
|
|
96
|
+
|
|
97
|
+
# Direct commands
|
|
98
|
+
amverge detect episode.mp4
|
|
99
|
+
amverge export episode.mp4 --scenes episode_scenes/scenes.json --select 0,2,5-8
|
|
100
|
+
amverge merge clip1.mp4 clip2.mp4 --output out.mp4
|
|
101
|
+
amverge info episode.mp4
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from amverge import detect_scenes
|
|
106
|
+
|
|
107
|
+
result = detect_scenes("episode.mp4")
|
|
108
|
+
for scene in result.scenes:
|
|
109
|
+
print(scene.index, scene.start, scene.end, scene.path)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
<details open>
|
|
115
|
+
<summary><b>How It Works</b></summary>
|
|
116
|
+
|
|
117
|
+
```txt
|
|
118
|
+
amverge CLI / Python library
|
|
119
|
+
↓
|
|
120
|
+
amverge package
|
|
121
|
+
↓
|
|
122
|
+
PyAV + FFmpeg + PyTorch (optional)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Detection:** Keyframe mode extracts I-frame timestamps via PyAV packet demux.
|
|
126
|
+
Edge mode decodes frames and compares Canny edge maps.
|
|
127
|
+
TransNetV2 runs a deep CNN on 48x27 RGB frames (GPU auto-detected, CPU fallback).
|
|
128
|
+
|
|
129
|
+
**Cutting:** Scenes aligned to keyframes get lossless stream copy.
|
|
130
|
+
Non-aligned scenes get smartcut (encode head + copy tail) or full re-encode.
|
|
131
|
+
HEVC on CPU uses snapped-copy (nearest keyframe within 5s) to avoid slow re-encode.
|
|
132
|
+
|
|
133
|
+
**Thumbnails:** Decoded via PyAV, resized to 960px, saved as progressive JPEG in parallel.
|
|
134
|
+
**Similarity:** Adjacent thumbnails compared via cosine similarity on 8x8 pooled pixels.
|
|
135
|
+
|
|
136
|
+
</details>
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary><b>Repository Structure</b></summary>
|
|
142
|
+
|
|
143
|
+
```txt
|
|
144
|
+
AMVerge-CLI/
|
|
145
|
+
│
|
|
146
|
+
├── amverge/
|
|
147
|
+
│ ├── cli.py entry point
|
|
148
|
+
│ ├── pipeline.py high-level detect_scenes() API
|
|
149
|
+
│ ├── wizard.py interactive session
|
|
150
|
+
│ ├── ui.py shared Rich theme + components
|
|
151
|
+
│ ├── commands/ one file per CLI subcommand
|
|
152
|
+
│ └── core/ pure logic, no CLI dependencies
|
|
153
|
+
│
|
|
154
|
+
├── examples/
|
|
155
|
+
│ ├── detect/ scene detection scripts
|
|
156
|
+
│ ├── export/ export + re-encode scripts
|
|
157
|
+
│ ├── info-probe/ metadata + diagnostics
|
|
158
|
+
│ ├── keyframes/ extraction + alignment
|
|
159
|
+
│ ├── cutting/ smart cut + segment
|
|
160
|
+
│ ├── thumbnails/ JPEG generation
|
|
161
|
+
│ ├── similarity/ pair detection
|
|
162
|
+
│ ├── diagnostics/ GPU + versions
|
|
163
|
+
│ ├── discord-rpc/ Rich Presence
|
|
164
|
+
│ └── custom-pipeline/ full end-to-end
|
|
165
|
+
│
|
|
166
|
+
├── docs/
|
|
167
|
+
├── assets/
|
|
168
|
+
├── pyproject.toml
|
|
169
|
+
└── README.md
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
</details>
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary><b>Examples</b></summary>
|
|
178
|
+
|
|
179
|
+
Runnable Python scripts for every feature. Each with its own README:
|
|
180
|
+
|
|
181
|
+
| Directory | Description |
|
|
182
|
+
|---|---|
|
|
183
|
+
| [detect/](examples/detect/) | keyframe, edge, TransNetV2 detection |
|
|
184
|
+
| [export/](examples/export/) | copy, re-encode with profiles, merge |
|
|
185
|
+
| [info-probe/](examples/info-probe/) | stream metadata, probe diagnostics, HEVC check |
|
|
186
|
+
| [keyframes/](examples/keyframes/) | extract timestamps, classify for cutting |
|
|
187
|
+
| [cutting/](examples/cutting/) | smart cut, ffmpeg segment, single scene |
|
|
188
|
+
| [thumbnails/](examples/thumbnails/) | JPEG thumbnail generation |
|
|
189
|
+
| [similarity/](examples/similarity/) | adjacent scene similarity detection |
|
|
190
|
+
| [diagnostics/](examples/diagnostics/) | GPU, CUDA, dependency versions |
|
|
191
|
+
| [discord-rpc/](examples/discord-rpc/) | Discord Rich Presence |
|
|
192
|
+
| [custom-pipeline/](examples/custom-pipeline/) | full end-to-end custom pipeline |
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pip install amverge[ml,edge,discord]
|
|
196
|
+
python examples/detect/01_basic_detect.py episode.mp4
|
|
197
|
+
python examples/custom-pipeline/full_pipeline.py episode.mp4
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
See the [examples README](examples/README.md) for the full directory map.
|
|
201
|
+
|
|
202
|
+
</details>
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
<details>
|
|
207
|
+
<summary><b>Documentation</b></summary>
|
|
208
|
+
|
|
209
|
+
| | |
|
|
210
|
+
|---|---|
|
|
211
|
+
| [Installation](docs/installation.md) | Requirements, FFmpeg setup, optional deps, dev install |
|
|
212
|
+
| [CLI Reference](docs/cli-reference.md) | All commands, flags, and usage examples |
|
|
213
|
+
| [Python Library](docs/library.md) | API reference, return types, low-level modules |
|
|
214
|
+
| [Detection Methods](docs/detection-methods.md) | Keyframe vs edge vs TransNetV2, cut modes, tuning |
|
|
215
|
+
| [Examples](examples/) | 20 runnable Python scripts in 10 categories |
|
|
216
|
+
| [Contributing](docs/contributing.md) | Project structure, guidelines, links |
|
|
217
|
+
| [AI Setup](docs/ai-setup.md) | How to train AI tools to work like you, not generically |
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
<details>
|
|
224
|
+
<summary><b>AI Agents</b></summary>
|
|
225
|
+
|
|
226
|
+
An [AGENTS.md](AGENTS.md) file is included for AI coding assistants (OpenCode, Claude Code, Cursor, etc.).
|
|
227
|
+
|
|
228
|
+
Using AI without understanding the codebase is not recommended. Read the code, understand the architecture, then use the agents file if it saves you time.
|
|
229
|
+
|
|
230
|
+
The best approach is not to use a generic AI assistant - it is to train it to work like you. Teach it your conventions, your decisions, your style. Done right, the output looks like yours, not like a generic answer. See [docs/ai-setup.md](docs/ai-setup.md) for a practical guide on how to do this.
|
|
231
|
+
|
|
232
|
+
</details>
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
<details>
|
|
237
|
+
<summary><b>Credits</b></summary>
|
|
238
|
+
|
|
239
|
+
Built by [Moongetsu](https://github.com/Moongetsu) as a standalone port of the [AMVerge](https://github.com/crptk/AMVerge) backend.
|
|
240
|
+
|
|
241
|
+
AMVerge was created by [Crptk](https://github.com/crptk). All core scene detection and clip management logic originates from the original AMVerge project.
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
<details>
|
|
248
|
+
<summary><b>License</b></summary>
|
|
249
|
+
|
|
250
|
+
AMVerge CLI is licensed under the GNU GPL v3.0.
|
|
251
|
+
|
|
252
|
+
Any derivative work must also be open-source under the same license.
|
|
253
|
+
|
|
254
|
+
</details>
|