talks-reducer 0.4.1__tar.gz → 0.5.1__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.
- talks_reducer-0.5.1/PKG-INFO +119 -0
- talks_reducer-0.5.1/README.md +92 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/pyproject.toml +2 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/__about__.py +1 -1
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/cli.py +25 -4
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/ffmpeg.py +34 -6
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/gui.py +162 -27
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/models.py +29 -4
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/pipeline.py +83 -9
- talks_reducer-0.5.1/talks_reducer/server.py +354 -0
- talks_reducer-0.5.1/talks_reducer/service_client.py +102 -0
- talks_reducer-0.5.1/talks_reducer.egg-info/PKG-INFO +119 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer.egg-info/SOURCES.txt +5 -1
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer.egg-info/entry_points.txt +1 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer.egg-info/requires.txt +1 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/tests/test_cli.py +27 -0
- talks_reducer-0.5.1/tests/test_server.py +68 -0
- talks_reducer-0.5.1/tests/test_service_client.py +112 -0
- talks_reducer-0.4.1/PKG-INFO +0 -71
- talks_reducer-0.4.1/README.md +0 -45
- talks_reducer-0.4.1/talks_reducer.egg-info/PKG-INFO +0 -71
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/LICENSE +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/setup.cfg +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/__init__.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/__main__.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/audio.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/chunks.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer/progress.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer.egg-info/dependency_links.txt +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/talks_reducer.egg-info/top_level.txt +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/tests/test_audio.py +0 -0
- {talks_reducer-0.4.1 → talks_reducer-0.5.1}/tests/test_pipeline_service.py +0 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: talks-reducer
|
3
|
+
Version: 0.5.1
|
4
|
+
Summary: CLI for speeding up long-form talks by removing silence
|
5
|
+
Author: Talks Reducer Maintainers
|
6
|
+
License-Expression: MIT
|
7
|
+
Requires-Python: >=3.9
|
8
|
+
Description-Content-Type: text/markdown
|
9
|
+
License-File: LICENSE
|
10
|
+
Requires-Dist: audiotsm>=0.1.2
|
11
|
+
Requires-Dist: scipy>=1.10.0
|
12
|
+
Requires-Dist: numpy>=1.22.0
|
13
|
+
Requires-Dist: tqdm>=4.65.0
|
14
|
+
Requires-Dist: tkinterdnd2>=0.3.0
|
15
|
+
Requires-Dist: Pillow>=9.0.0
|
16
|
+
Requires-Dist: imageio-ffmpeg>=0.4.8
|
17
|
+
Requires-Dist: gradio>=4.0.0
|
18
|
+
Provides-Extra: dev
|
19
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
20
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
21
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
22
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
23
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
24
|
+
Requires-Dist: bump-my-version>=0.5.0; extra == "dev"
|
25
|
+
Requires-Dist: pyinstaller>=6.4.0; extra == "dev"
|
26
|
+
Dynamic: license-file
|
27
|
+
|
28
|
+
# Talks Reducer
|
29
|
+
Talks Reducer shortens long-form presentations by removing silent gaps and optionally re-encoding them to smaller files. The
|
30
|
+
project was renamed from **jumpcutter** to emphasize its focus on conference talks and screencasts.
|
31
|
+
|
32
|
+

|
33
|
+
|
34
|
+
## Example
|
35
|
+
- 1h 37m, 571 MB — Original OBS video recording
|
36
|
+
- 1h 19m, 751 MB — Talks Reducer
|
37
|
+
- 1h 19m, 171 MB — Talks Reducer `--small`
|
38
|
+
|
39
|
+
## Changelog
|
40
|
+
|
41
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
42
|
+
|
43
|
+
## Install GUI (Windows, macOS)
|
44
|
+
Go to the [releases page](https://github.com/popstas/talks-reducer/releases) and download the appropriate artifact:
|
45
|
+
|
46
|
+
- **Windows** — `talks-reducer-windows-0.4.0.zip`
|
47
|
+
- **macOS** — `talks-reducer.app.zip`
|
48
|
+
|
49
|
+
> **Troubleshooting:** If launching the bundle (or running `python talks_reducer/gui.py`) prints `macOS 26 (2600) or later required, have instead 16 (1600)!`, make sure you're using a Python build that ships a modern Tk. The stock [python.org 3.13.5 installer](https://www.python.org/downloads/release/python-3135/) includes Tk 8.6 and has been verified to work.
|
50
|
+
|
51
|
+
When extracted on Windows the bundled `talks-reducer.exe` behaves like the
|
52
|
+
`python talks_reducer/gui.py` entry point: double-clicking it launches the GUI
|
53
|
+
and passing a video file path (for example via *Open with…* or drag-and-drop
|
54
|
+
onto the executable) automatically queues that recording for processing.
|
55
|
+
|
56
|
+
## Install CLI (Linux, Windows, macOS)
|
57
|
+
```
|
58
|
+
pip install talks-reducer
|
59
|
+
```
|
60
|
+
|
61
|
+
**Note:** FFmpeg is now bundled automatically with the package, so you don't need to install it separately. You you need, don't know actually.
|
62
|
+
|
63
|
+
The `--small` preset applies a 720p video scale and 128 kbps audio bitrate, making it useful for sharing talks over constrained
|
64
|
+
connections. Without `--small`, the script aims to preserve original quality while removing silence.
|
65
|
+
|
66
|
+
Example CLI usage:
|
67
|
+
|
68
|
+
```sh
|
69
|
+
talks-reducer --small input.mp4
|
70
|
+
```
|
71
|
+
|
72
|
+
### Speech detection
|
73
|
+
|
74
|
+
Talks Reducer now relies on its built-in volume thresholding to detect speech. Adjust `--silent_threshold` if you need to fine-tune when segments count as silence. Dropping the optional Silero VAD integration keeps the install lightweight and avoids pulling in PyTorch.
|
75
|
+
|
76
|
+
When CUDA-capable hardware is available the pipeline leans on GPU encoders to keep export times low, but it still runs great on
|
77
|
+
CPUs.
|
78
|
+
|
79
|
+
## Simple web server
|
80
|
+
|
81
|
+
Prefer a lightweight browser interface? Launch the Gradio-powered simple mode with:
|
82
|
+
|
83
|
+
```sh
|
84
|
+
talks-reducer server
|
85
|
+
```
|
86
|
+
|
87
|
+
This opens a local web page featuring a drag-and-drop upload zone, a **Small video** checkbox that mirrors the CLI preset, a live
|
88
|
+
progress indicator, and automatic previews of the processed output. Once the job completes you can inspect the resulting compression
|
89
|
+
ratio and download the rendered video directly from the page.
|
90
|
+
|
91
|
+
### Uploading and retrieving a processed video
|
92
|
+
|
93
|
+
1. Open the printed `http://localhost:<port>` address (the default port is `9005`).
|
94
|
+
2. Drag a video onto the **Video file** drop zone or click to browse and select one from disk.
|
95
|
+
3. (Optional) Enable **Small video** before the upload finishes to apply the 720p/128 kbps preset.
|
96
|
+
4. Wait for the progress bar and log to report completion—the interface queues work automatically after the file arrives.
|
97
|
+
5. Watch the processed preview in the **Processed video** player and click **Download processed file** to save the result locally.
|
98
|
+
|
99
|
+
Need to change where the server listens? Run `talks-reducer server --host 0.0.0.0 --port 7860` (or any other port) to bind to a
|
100
|
+
different address.
|
101
|
+
|
102
|
+
### Automating uploads from the command line
|
103
|
+
|
104
|
+
Prefer to script uploads instead of using the browser UI? Start the server and use the bundled helper to submit a job and save
|
105
|
+
the processed video locally:
|
106
|
+
|
107
|
+
```sh
|
108
|
+
python -m talks_reducer.service_client --server http://127.0.0.1:9005/ --input demo.mp4 --output output/demo_processed.mp4
|
109
|
+
```
|
110
|
+
|
111
|
+
The helper wraps the Gradio API exposed by `server.py`, waits for processing to complete, then copies the rendered file to the
|
112
|
+
path you provide. Pass `--small` to mirror the **Small video** checkbox or `--print-log` to stream the server log after the
|
113
|
+
download finishes.
|
114
|
+
|
115
|
+
## Contributing
|
116
|
+
See `CONTRIBUTION.md` for development setup details and guidance on sharing improvements.
|
117
|
+
|
118
|
+
## License
|
119
|
+
Talks Reducer is released under the MIT License. See `LICENSE` for the full text.
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Talks Reducer
|
2
|
+
Talks Reducer shortens long-form presentations by removing silent gaps and optionally re-encoding them to smaller files. The
|
3
|
+
project was renamed from **jumpcutter** to emphasize its focus on conference talks and screencasts.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
## Example
|
8
|
+
- 1h 37m, 571 MB — Original OBS video recording
|
9
|
+
- 1h 19m, 751 MB — Talks Reducer
|
10
|
+
- 1h 19m, 171 MB — Talks Reducer `--small`
|
11
|
+
|
12
|
+
## Changelog
|
13
|
+
|
14
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
15
|
+
|
16
|
+
## Install GUI (Windows, macOS)
|
17
|
+
Go to the [releases page](https://github.com/popstas/talks-reducer/releases) and download the appropriate artifact:
|
18
|
+
|
19
|
+
- **Windows** — `talks-reducer-windows-0.4.0.zip`
|
20
|
+
- **macOS** — `talks-reducer.app.zip`
|
21
|
+
|
22
|
+
> **Troubleshooting:** If launching the bundle (or running `python talks_reducer/gui.py`) prints `macOS 26 (2600) or later required, have instead 16 (1600)!`, make sure you're using a Python build that ships a modern Tk. The stock [python.org 3.13.5 installer](https://www.python.org/downloads/release/python-3135/) includes Tk 8.6 and has been verified to work.
|
23
|
+
|
24
|
+
When extracted on Windows the bundled `talks-reducer.exe` behaves like the
|
25
|
+
`python talks_reducer/gui.py` entry point: double-clicking it launches the GUI
|
26
|
+
and passing a video file path (for example via *Open with…* or drag-and-drop
|
27
|
+
onto the executable) automatically queues that recording for processing.
|
28
|
+
|
29
|
+
## Install CLI (Linux, Windows, macOS)
|
30
|
+
```
|
31
|
+
pip install talks-reducer
|
32
|
+
```
|
33
|
+
|
34
|
+
**Note:** FFmpeg is now bundled automatically with the package, so you don't need to install it separately. You you need, don't know actually.
|
35
|
+
|
36
|
+
The `--small` preset applies a 720p video scale and 128 kbps audio bitrate, making it useful for sharing talks over constrained
|
37
|
+
connections. Without `--small`, the script aims to preserve original quality while removing silence.
|
38
|
+
|
39
|
+
Example CLI usage:
|
40
|
+
|
41
|
+
```sh
|
42
|
+
talks-reducer --small input.mp4
|
43
|
+
```
|
44
|
+
|
45
|
+
### Speech detection
|
46
|
+
|
47
|
+
Talks Reducer now relies on its built-in volume thresholding to detect speech. Adjust `--silent_threshold` if you need to fine-tune when segments count as silence. Dropping the optional Silero VAD integration keeps the install lightweight and avoids pulling in PyTorch.
|
48
|
+
|
49
|
+
When CUDA-capable hardware is available the pipeline leans on GPU encoders to keep export times low, but it still runs great on
|
50
|
+
CPUs.
|
51
|
+
|
52
|
+
## Simple web server
|
53
|
+
|
54
|
+
Prefer a lightweight browser interface? Launch the Gradio-powered simple mode with:
|
55
|
+
|
56
|
+
```sh
|
57
|
+
talks-reducer server
|
58
|
+
```
|
59
|
+
|
60
|
+
This opens a local web page featuring a drag-and-drop upload zone, a **Small video** checkbox that mirrors the CLI preset, a live
|
61
|
+
progress indicator, and automatic previews of the processed output. Once the job completes you can inspect the resulting compression
|
62
|
+
ratio and download the rendered video directly from the page.
|
63
|
+
|
64
|
+
### Uploading and retrieving a processed video
|
65
|
+
|
66
|
+
1. Open the printed `http://localhost:<port>` address (the default port is `9005`).
|
67
|
+
2. Drag a video onto the **Video file** drop zone or click to browse and select one from disk.
|
68
|
+
3. (Optional) Enable **Small video** before the upload finishes to apply the 720p/128 kbps preset.
|
69
|
+
4. Wait for the progress bar and log to report completion—the interface queues work automatically after the file arrives.
|
70
|
+
5. Watch the processed preview in the **Processed video** player and click **Download processed file** to save the result locally.
|
71
|
+
|
72
|
+
Need to change where the server listens? Run `talks-reducer server --host 0.0.0.0 --port 7860` (or any other port) to bind to a
|
73
|
+
different address.
|
74
|
+
|
75
|
+
### Automating uploads from the command line
|
76
|
+
|
77
|
+
Prefer to script uploads instead of using the browser UI? Start the server and use the bundled helper to submit a job and save
|
78
|
+
the processed video locally:
|
79
|
+
|
80
|
+
```sh
|
81
|
+
python -m talks_reducer.service_client --server http://127.0.0.1:9005/ --input demo.mp4 --output output/demo_processed.mp4
|
82
|
+
```
|
83
|
+
|
84
|
+
The helper wraps the Gradio API exposed by `server.py`, waits for processing to complete, then copies the rendered file to the
|
85
|
+
path you provide. Pass `--small` to mirror the **Small video** checkbox or `--print-log` to stream the server log after the
|
86
|
+
download finishes.
|
87
|
+
|
88
|
+
## Contributing
|
89
|
+
See `CONTRIBUTION.md` for development setup details and guidance on sharing improvements.
|
90
|
+
|
91
|
+
## License
|
92
|
+
Talks Reducer is released under the MIT License. See `LICENSE` for the full text.
|
@@ -20,6 +20,7 @@ dependencies = [
|
|
20
20
|
"tkinterdnd2>=0.3.0",
|
21
21
|
"Pillow>=9.0.0",
|
22
22
|
"imageio-ffmpeg>=0.4.8",
|
23
|
+
"gradio>=4.0.0",
|
23
24
|
]
|
24
25
|
|
25
26
|
[project.optional-dependencies]
|
@@ -36,6 +37,7 @@ dev = [
|
|
36
37
|
[project.scripts]
|
37
38
|
talks-reducer = "talks_reducer.cli:main"
|
38
39
|
talks-reducer-gui = "talks_reducer.gui:main"
|
40
|
+
talks-reducer-server = "talks_reducer.server:main"
|
39
41
|
|
40
42
|
[tool.setuptools.dynamic]
|
41
43
|
version = {attr = "talks_reducer.__about__.__version__"}
|
@@ -18,7 +18,7 @@ try:
|
|
18
18
|
except Exception: # pragma: no cover - fallback if metadata file missing
|
19
19
|
_about_version = ""
|
20
20
|
from .ffmpeg import FFmpegNotFoundError
|
21
|
-
from .models import ProcessingOptions
|
21
|
+
from .models import ProcessingOptions, default_temp_folder
|
22
22
|
from .pipeline import speed_up_video
|
23
23
|
from .progress import TqdmProgressReporter
|
24
24
|
|
@@ -55,7 +55,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
55
55
|
parser.add_argument(
|
56
56
|
"--temp_folder",
|
57
57
|
type=str,
|
58
|
-
default=
|
58
|
+
default=str(default_temp_folder()),
|
59
59
|
help="The file path of the temporary working folder.",
|
60
60
|
)
|
61
61
|
parser.add_argument(
|
@@ -63,7 +63,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
63
63
|
"--silent_threshold",
|
64
64
|
type=float,
|
65
65
|
dest="silent_threshold",
|
66
|
-
help="The volume amount that frames' audio needs to surpass to be considered sounded. Defaults to 0.
|
66
|
+
help="The volume amount that frames' audio needs to surpass to be considered sounded. Defaults to 0.05.",
|
67
67
|
)
|
68
68
|
parser.add_argument(
|
69
69
|
"-S",
|
@@ -143,6 +143,22 @@ def _launch_gui(argv: Sequence[str]) -> bool:
|
|
143
143
|
return bool(gui_main(list(argv)))
|
144
144
|
|
145
145
|
|
146
|
+
def _launch_server(argv: Sequence[str]) -> bool:
|
147
|
+
"""Attempt to launch the Gradio web server with the provided arguments."""
|
148
|
+
|
149
|
+
try:
|
150
|
+
server_module = import_module(".server", __package__)
|
151
|
+
except ImportError:
|
152
|
+
return False
|
153
|
+
|
154
|
+
server_main = getattr(server_module, "main", None)
|
155
|
+
if server_main is None:
|
156
|
+
return False
|
157
|
+
|
158
|
+
server_main(list(argv))
|
159
|
+
return True
|
160
|
+
|
161
|
+
|
146
162
|
def main(argv: Optional[Sequence[str]] = None) -> None:
|
147
163
|
"""Entry point for the command line interface.
|
148
164
|
|
@@ -154,6 +170,12 @@ def main(argv: Optional[Sequence[str]] = None) -> None:
|
|
154
170
|
else:
|
155
171
|
argv_list = list(argv)
|
156
172
|
|
173
|
+
if argv_list and argv_list[0] in {"server", "serve"}:
|
174
|
+
if not _launch_server(argv_list[1:]):
|
175
|
+
print("Gradio server mode is unavailable.", file=sys.stderr)
|
176
|
+
sys.exit(1)
|
177
|
+
return
|
178
|
+
|
157
179
|
if not argv_list:
|
158
180
|
if _launch_gui(argv_list):
|
159
181
|
return
|
@@ -200,7 +222,6 @@ def main(argv: Optional[Sequence[str]] = None) -> None:
|
|
200
222
|
option_kwargs["sample_rate"] = int(local_options["sample_rate"])
|
201
223
|
if "small" in local_options:
|
202
224
|
option_kwargs["small"] = bool(local_options["small"])
|
203
|
-
|
204
225
|
options = ProcessingOptions(**option_kwargs)
|
205
226
|
|
206
227
|
try:
|
@@ -52,6 +52,9 @@ def find_ffmpeg() -> Optional[str]:
|
|
52
52
|
"C:\\ProgramData\\chocolatey\\bin\\ffmpeg.exe",
|
53
53
|
"C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe",
|
54
54
|
"C:\\ffmpeg\\bin\\ffmpeg.exe",
|
55
|
+
"/usr/local/bin/ffmpeg",
|
56
|
+
"/opt/homebrew/bin/ffmpeg",
|
57
|
+
"/usr/bin/ffmpeg",
|
55
58
|
"ffmpeg",
|
56
59
|
]
|
57
60
|
|
@@ -92,6 +95,9 @@ def find_ffprobe() -> Optional[str]:
|
|
92
95
|
"C:\\ProgramData\\chocolatey\\bin\\ffprobe.exe",
|
93
96
|
"C:\\Program Files\\ffmpeg\\bin\\ffprobe.exe",
|
94
97
|
"C:\\ffmpeg\\bin\\ffprobe.exe",
|
98
|
+
"/usr/local/bin/ffprobe",
|
99
|
+
"/opt/homebrew/bin/ffprobe",
|
100
|
+
"/usr/bin/ffprobe",
|
95
101
|
"ffprobe",
|
96
102
|
]
|
97
103
|
|
@@ -242,11 +248,29 @@ def run_timed_ffmpeg_command(
|
|
242
248
|
if not line:
|
243
249
|
continue
|
244
250
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
251
|
+
# Filter out excessive progress output, only show important lines
|
252
|
+
if any(
|
253
|
+
keyword in line.lower()
|
254
|
+
for keyword in [
|
255
|
+
"error",
|
256
|
+
"warning",
|
257
|
+
"encoded successfully",
|
258
|
+
"frame=",
|
259
|
+
"time=",
|
260
|
+
"size=",
|
261
|
+
"bitrate=",
|
262
|
+
"speed=",
|
263
|
+
]
|
264
|
+
):
|
265
|
+
sys.stderr.write(line)
|
266
|
+
sys.stderr.flush()
|
267
|
+
|
268
|
+
# Send FFmpeg output to reporter for GUI display (filtered)
|
269
|
+
if any(
|
270
|
+
keyword in line.lower()
|
271
|
+
for keyword in ["error", "warning", "encoded successfully", "frame="]
|
272
|
+
):
|
273
|
+
progress_reporter.log(line.strip())
|
250
274
|
|
251
275
|
match = re.search(r"frame=\s*(\d+)", line)
|
252
276
|
if match:
|
@@ -365,7 +389,11 @@ def build_video_commands(
|
|
365
389
|
# Use a fast software encoder instead
|
366
390
|
video_encoder_args = ["-c:v libx264", "-preset veryfast", "-crf 23"]
|
367
391
|
|
368
|
-
audio_parts = [
|
392
|
+
audio_parts = [
|
393
|
+
"-c:a aac",
|
394
|
+
f'"{output_file}"',
|
395
|
+
"-loglevel warning -stats -hide_banner",
|
396
|
+
]
|
369
397
|
|
370
398
|
full_command_parts = (
|
371
399
|
global_parts + input_parts + output_parts + video_encoder_args + audio_parts
|