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.
Files changed (104) hide show
  1. amverge-0.1.0/.gitignore +15 -0
  2. amverge-0.1.0/AGENTS.md +232 -0
  3. amverge-0.1.0/LICENSE +35 -0
  4. amverge-0.1.0/PKG-INFO +254 -0
  5. amverge-0.1.0/README.md +212 -0
  6. amverge-0.1.0/TODO.md +151 -0
  7. amverge-0.1.0/amverge/__init__.py +190 -0
  8. amverge-0.1.0/amverge/__version__.py +1 -0
  9. amverge-0.1.0/amverge/cli.py +62 -0
  10. amverge-0.1.0/amverge/commands/__init__.py +0 -0
  11. amverge-0.1.0/amverge/commands/about.py +55 -0
  12. amverge-0.1.0/amverge/commands/backend.py +212 -0
  13. amverge-0.1.0/amverge/commands/bench.py +99 -0
  14. amverge-0.1.0/amverge/commands/cache.py +86 -0
  15. amverge-0.1.0/amverge/commands/changelog.py +84 -0
  16. amverge-0.1.0/amverge/commands/credits.py +62 -0
  17. amverge-0.1.0/amverge/commands/detect.py +284 -0
  18. amverge-0.1.0/amverge/commands/doctor.py +30 -0
  19. amverge-0.1.0/amverge/commands/export.py +177 -0
  20. amverge-0.1.0/amverge/commands/gpu.py +92 -0
  21. amverge-0.1.0/amverge/commands/info.py +62 -0
  22. amverge-0.1.0/amverge/commands/keyframes.py +57 -0
  23. amverge-0.1.0/amverge/commands/merge.py +67 -0
  24. amverge-0.1.0/amverge/commands/probe.py +107 -0
  25. amverge-0.1.0/amverge/commands/rpc_server.py +80 -0
  26. amverge-0.1.0/amverge/commands/scenes.py +76 -0
  27. amverge-0.1.0/amverge/commands/usage.py +86 -0
  28. amverge-0.1.0/amverge/commands/version.py +82 -0
  29. amverge-0.1.0/amverge/core/__init__.py +57 -0
  30. amverge-0.1.0/amverge/core/amverge_video.py +402 -0
  31. amverge-0.1.0/amverge/core/binaries.py +85 -0
  32. amverge-0.1.0/amverge/core/codec_utils.py +145 -0
  33. amverge-0.1.0/amverge/core/detection/__init__.py +4 -0
  34. amverge-0.1.0/amverge/core/detection/edge.py +168 -0
  35. amverge-0.1.0/amverge/core/detection/keyframe.py +44 -0
  36. amverge-0.1.0/amverge/core/diagnostics.py +266 -0
  37. amverge-0.1.0/amverge/core/discord_rpc.py +158 -0
  38. amverge-0.1.0/amverge/core/hevc.py +12 -0
  39. amverge-0.1.0/amverge/core/image.py +87 -0
  40. amverge-0.1.0/amverge/core/image_crop.py +55 -0
  41. amverge-0.1.0/amverge/core/ipc.py +95 -0
  42. amverge-0.1.0/amverge/core/keyframe_align.py +151 -0
  43. amverge-0.1.0/amverge/core/keyframes.py +163 -0
  44. amverge-0.1.0/amverge/core/nelux_runtime.py +122 -0
  45. amverge-0.1.0/amverge/core/probe_utils.py +85 -0
  46. amverge-0.1.0/amverge/core/scene_cache.py +156 -0
  47. amverge-0.1.0/amverge/core/scene_detection.py +330 -0
  48. amverge-0.1.0/amverge/core/scene_detector.py +106 -0
  49. amverge-0.1.0/amverge/core/scene_exporter.py +204 -0
  50. amverge-0.1.0/amverge/core/scene_utils.py +84 -0
  51. amverge-0.1.0/amverge/core/segmenter.py +146 -0
  52. amverge-0.1.0/amverge/core/similarity.py +101 -0
  53. amverge-0.1.0/amverge/core/similarity_checker.py +75 -0
  54. amverge-0.1.0/amverge/core/smart_cut.py +311 -0
  55. amverge-0.1.0/amverge/core/thumbnail_generator.py +96 -0
  56. amverge-0.1.0/amverge/core/thumbnails.py +115 -0
  57. amverge-0.1.0/amverge/core/thumbnails_streaming.py +107 -0
  58. amverge-0.1.0/amverge/core/transnet_config.py +56 -0
  59. amverge-0.1.0/amverge/core/transnet_constants.py +7 -0
  60. amverge-0.1.0/amverge/core/video.py +77 -0
  61. amverge-0.1.0/amverge/pipeline.py +478 -0
  62. amverge-0.1.0/amverge/ui.py +134 -0
  63. amverge-0.1.0/amverge/wizard.py +574 -0
  64. amverge-0.1.0/assets/amverge_title_gif.gif +0 -0
  65. amverge-0.1.0/docs/ai-setup.md +142 -0
  66. amverge-0.1.0/docs/cli-reference.md +260 -0
  67. amverge-0.1.0/docs/contributing.md +69 -0
  68. amverge-0.1.0/docs/detection-methods.md +177 -0
  69. amverge-0.1.0/docs/installation.md +103 -0
  70. amverge-0.1.0/docs/library.md +425 -0
  71. amverge-0.1.0/examples/README.md +113 -0
  72. amverge-0.1.0/examples/custom-pipeline/README.md +69 -0
  73. amverge-0.1.0/examples/custom-pipeline/full_pipeline.py +150 -0
  74. amverge-0.1.0/examples/cutting/01_smart_cut.py +46 -0
  75. amverge-0.1.0/examples/cutting/02_ffmpeg_segment.py +36 -0
  76. amverge-0.1.0/examples/cutting/03_single_scene.py +30 -0
  77. amverge-0.1.0/examples/cutting/README.md +72 -0
  78. amverge-0.1.0/examples/detect/01_basic_detect.py +36 -0
  79. amverge-0.1.0/examples/detect/02_transnetv2_detect.py +42 -0
  80. amverge-0.1.0/examples/detect/03_edge_detect.py +36 -0
  81. amverge-0.1.0/examples/detect/04_custom_settings.py +43 -0
  82. amverge-0.1.0/examples/detect/README.md +73 -0
  83. amverge-0.1.0/examples/diagnostics/01_gpu_check.py +29 -0
  84. amverge-0.1.0/examples/diagnostics/02_version_info.py +22 -0
  85. amverge-0.1.0/examples/diagnostics/README.md +45 -0
  86. amverge-0.1.0/examples/discord-rpc/01_basic_rpc.py +41 -0
  87. amverge-0.1.0/examples/discord-rpc/README.md +50 -0
  88. amverge-0.1.0/examples/export/01_copy_export.py +41 -0
  89. amverge-0.1.0/examples/export/02_reencode_export.py +58 -0
  90. amverge-0.1.0/examples/export/03_merge_export.py +43 -0
  91. amverge-0.1.0/examples/export/README.md +81 -0
  92. amverge-0.1.0/examples/info-probe/01_video_info.py +40 -0
  93. amverge-0.1.0/examples/info-probe/02_probe.py +47 -0
  94. amverge-0.1.0/examples/info-probe/03_hevc_check.py +19 -0
  95. amverge-0.1.0/examples/info-probe/README.md +68 -0
  96. amverge-0.1.0/examples/keyframes/01_extract_keyframes.py +34 -0
  97. amverge-0.1.0/examples/keyframes/02_align_scenes.py +40 -0
  98. amverge-0.1.0/examples/keyframes/README.md +66 -0
  99. amverge-0.1.0/examples/similarity/01_find_similar.py +41 -0
  100. amverge-0.1.0/examples/similarity/README.md +61 -0
  101. amverge-0.1.0/examples/thumbnails/01_make_thumbnails.py +33 -0
  102. amverge-0.1.0/examples/thumbnails/README.md +59 -0
  103. amverge-0.1.0/pyproject.toml +61 -0
  104. amverge-0.1.0/test_result.json +133 -0
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ *.spec
9
+ *.npy
10
+ *.jpg
11
+ *.jpeg
12
+ *.mp4
13
+ *.mkv
14
+ *.mov
15
+ .env
@@ -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>