talks-reducer 0.6.0__tar.gz → 0.6.3__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.6.0/talks_reducer.egg-info → talks_reducer-0.6.3}/PKG-INFO +15 -12
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/README.md +14 -11
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/__about__.py +1 -1
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/cli.py +2 -18
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/gui.py +80 -44
- talks_reducer-0.6.3/talks_reducer/resources/__init__.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/server.py +16 -4
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/server_tray.py +15 -4
- talks_reducer-0.6.3/talks_reducer/version_utils.py +22 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3/talks_reducer.egg-info}/PKG-INFO +15 -12
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer.egg-info/SOURCES.txt +2 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/LICENSE +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/pyproject.toml +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/setup.cfg +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/__init__.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/__main__.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/audio.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/chunks.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/discovery.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/ffmpeg.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/models.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/pipeline.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/progress.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer/service_client.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer.egg-info/dependency_links.txt +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer.egg-info/entry_points.txt +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer.egg-info/requires.txt +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/talks_reducer.egg-info/top_level.txt +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_audio.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_cli.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_discovery.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_gui_summary_parsing.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_pipeline_service.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_server.py +0 -0
- {talks_reducer-0.6.0 → talks_reducer-0.6.3}/tests/test_service_client.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: talks-reducer
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.3
|
4
4
|
Summary: CLI for speeding up long-form talks by removing silence
|
5
5
|
Author: Talks Reducer Maintainers
|
6
6
|
License-Expression: MIT
|
@@ -111,22 +111,25 @@ desktop shortcut without opening the GUI first.
|
|
111
111
|
Pass `--debug` to print verbose logs about the tray icon lifecycle, and
|
112
112
|
`--tray-mode pystray-detached` to try pystray's alternate detached runner. If
|
113
113
|
the icon backend refuses to appear, fall back to `--tray-mode headless` to keep
|
114
|
-
the web server running without a tray process. The tray menu
|
114
|
+
the web server running without a tray process. The tray menu highlights the
|
115
|
+
running Talks Reducer version and includes an **Open GUI**
|
115
116
|
item (also triggered by double-clicking the icon) that launches the desktop
|
116
117
|
Talks Reducer interface alongside an **Open WebUI** entry that opens the Gradio
|
117
118
|
page in your browser. Close the GUI window to return to the tray without
|
118
|
-
stopping the server.
|
119
|
-
server
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
119
|
+
stopping the server. Launch the tray explicitly whenever you need it—either run
|
120
|
+
`talks-reducer server-tray` directly or start the GUI with
|
121
|
+
`python -m talks_reducer.gui --server` to boot the tray-managed server instead
|
122
|
+
of the desktop window. The GUI now runs standalone and no longer spawns the tray
|
123
|
+
automatically; the deprecated `--no-tray` flag is ignored for compatibility.
|
124
|
+
The tray command itself never launches the GUI automatically, so use the menu
|
125
|
+
item (or relaunch the GUI separately) whenever you want to reopen it. The tray
|
126
|
+
no longer opens a browser automatically—pass `--open-browser` if you prefer the
|
127
|
+
web page to launch as soon as the server is ready.
|
126
128
|
|
127
129
|
This opens a local web page featuring a drag-and-drop upload zone, a **Small video** checkbox that mirrors the CLI preset, a live
|
128
|
-
progress indicator, and automatic previews of the processed output.
|
129
|
-
|
130
|
+
progress indicator, and automatic previews of the processed output. The page header and browser tab title include the current
|
131
|
+
Talks Reducer version so you can confirm which build the server is running. Once the job completes you can inspect the resulting
|
132
|
+
compression ratio and download the rendered video directly from the page.
|
130
133
|
|
131
134
|
The desktop GUI mirrors this behaviour. Open **Advanced** settings to provide a
|
132
135
|
server URL and click **Discover** to scan your local network for Talks Reducer
|
@@ -83,22 +83,25 @@ desktop shortcut without opening the GUI first.
|
|
83
83
|
Pass `--debug` to print verbose logs about the tray icon lifecycle, and
|
84
84
|
`--tray-mode pystray-detached` to try pystray's alternate detached runner. If
|
85
85
|
the icon backend refuses to appear, fall back to `--tray-mode headless` to keep
|
86
|
-
the web server running without a tray process. The tray menu
|
86
|
+
the web server running without a tray process. The tray menu highlights the
|
87
|
+
running Talks Reducer version and includes an **Open GUI**
|
87
88
|
item (also triggered by double-clicking the icon) that launches the desktop
|
88
89
|
Talks Reducer interface alongside an **Open WebUI** entry that opens the Gradio
|
89
90
|
page in your browser. Close the GUI window to return to the tray without
|
90
|
-
stopping the server.
|
91
|
-
server
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
91
|
+
stopping the server. Launch the tray explicitly whenever you need it—either run
|
92
|
+
`talks-reducer server-tray` directly or start the GUI with
|
93
|
+
`python -m talks_reducer.gui --server` to boot the tray-managed server instead
|
94
|
+
of the desktop window. The GUI now runs standalone and no longer spawns the tray
|
95
|
+
automatically; the deprecated `--no-tray` flag is ignored for compatibility.
|
96
|
+
The tray command itself never launches the GUI automatically, so use the menu
|
97
|
+
item (or relaunch the GUI separately) whenever you want to reopen it. The tray
|
98
|
+
no longer opens a browser automatically—pass `--open-browser` if you prefer the
|
99
|
+
web page to launch as soon as the server is ready.
|
98
100
|
|
99
101
|
This opens a local web page featuring a drag-and-drop upload zone, a **Small video** checkbox that mirrors the CLI preset, a live
|
100
|
-
progress indicator, and automatic previews of the processed output.
|
101
|
-
|
102
|
+
progress indicator, and automatic previews of the processed output. The page header and browser tab title include the current
|
103
|
+
Talks Reducer version so you can confirm which build the server is running. Once the job completes you can inspect the resulting
|
104
|
+
compression ratio and download the rendered video directly from the page.
|
102
105
|
|
103
106
|
The desktop GUI mirrors this behaviour. Open **Advanced** settings to provide a
|
104
107
|
server URL and click **Discover** to scan your local network for Talks Reducer
|
@@ -9,20 +9,16 @@ import subprocess
|
|
9
9
|
import sys
|
10
10
|
import time
|
11
11
|
from importlib import import_module
|
12
|
-
from importlib.metadata import PackageNotFoundError, version
|
13
12
|
from pathlib import Path
|
14
13
|
from typing import Dict, List, Optional, Sequence, Tuple
|
15
14
|
|
16
15
|
from . import audio
|
17
16
|
|
18
|
-
try:
|
19
|
-
from .__about__ import __version__ as _about_version
|
20
|
-
except Exception: # pragma: no cover - fallback if metadata file missing
|
21
|
-
_about_version = ""
|
22
17
|
from .ffmpeg import FFmpegNotFoundError
|
23
18
|
from .models import ProcessingOptions, default_temp_folder
|
24
19
|
from .pipeline import speed_up_video
|
25
20
|
from .progress import TqdmProgressReporter
|
21
|
+
from .version_utils import resolve_version
|
26
22
|
|
27
23
|
|
28
24
|
def _build_parser() -> argparse.ArgumentParser:
|
@@ -33,7 +29,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
33
29
|
)
|
34
30
|
|
35
31
|
# Add version argument
|
36
|
-
pkg_version =
|
32
|
+
pkg_version = resolve_version()
|
37
33
|
|
38
34
|
parser.add_argument(
|
39
35
|
"--version",
|
@@ -120,18 +116,6 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
120
116
|
return parser
|
121
117
|
|
122
118
|
|
123
|
-
def _resolve_version() -> str:
|
124
|
-
"""Determine the package version for CLI reporting."""
|
125
|
-
|
126
|
-
if _about_version:
|
127
|
-
return _about_version
|
128
|
-
|
129
|
-
try:
|
130
|
-
return version("talks-reducer")
|
131
|
-
except (PackageNotFoundError, Exception):
|
132
|
-
return "unknown"
|
133
|
-
|
134
|
-
|
135
119
|
def gather_input_files(paths: List[str]) -> List[str]:
|
136
120
|
"""Expand provided paths into a flat list of files that contain audio streams."""
|
137
121
|
|
@@ -13,7 +13,6 @@ import threading
|
|
13
13
|
import urllib.error
|
14
14
|
import urllib.parse
|
15
15
|
import urllib.request
|
16
|
-
from importlib.metadata import version
|
17
16
|
from pathlib import Path
|
18
17
|
from typing import (
|
19
18
|
TYPE_CHECKING,
|
@@ -38,6 +37,7 @@ try:
|
|
38
37
|
from .models import ProcessingOptions, default_temp_folder
|
39
38
|
from .pipeline import speed_up_video
|
40
39
|
from .progress import ProgressHandle, SignalProgressReporter
|
40
|
+
from .version_utils import resolve_version
|
41
41
|
except ImportError: # pragma: no cover - handled at runtime
|
42
42
|
if __package__ not in (None, ""):
|
43
43
|
raise
|
@@ -53,6 +53,7 @@ except ImportError: # pragma: no cover - handled at runtime
|
|
53
53
|
from talks_reducer.models import ProcessingOptions, default_temp_folder
|
54
54
|
from talks_reducer.pipeline import speed_up_video
|
55
55
|
from talks_reducer.progress import ProgressHandle, SignalProgressReporter
|
56
|
+
from talks_reducer.version_utils import resolve_version
|
56
57
|
|
57
58
|
|
58
59
|
def _check_tkinter_available() -> tuple[bool, str]:
|
@@ -166,10 +167,6 @@ DARK_THEME = {
|
|
166
167
|
}
|
167
168
|
|
168
169
|
|
169
|
-
_TRAY_LOCK = threading.Lock()
|
170
|
-
_TRAY_PROCESS: Optional[subprocess.Popen[Any]] = None
|
171
|
-
|
172
|
-
|
173
170
|
def _default_remote_destination(input_file: Path, *, small: bool) -> Path:
|
174
171
|
"""Return the default remote output path for *input_file*.
|
175
172
|
|
@@ -189,28 +186,6 @@ def _default_remote_destination(input_file: Path, *, small: bool) -> Path:
|
|
189
186
|
return input_file.with_name(new_name)
|
190
187
|
|
191
188
|
|
192
|
-
def _ensure_server_tray_running(extra_args: Optional[Sequence[str]] = None) -> None:
|
193
|
-
"""Start the server tray in a background process if one is not active."""
|
194
|
-
|
195
|
-
global _TRAY_PROCESS
|
196
|
-
|
197
|
-
with _TRAY_LOCK:
|
198
|
-
if _TRAY_PROCESS is not None and _TRAY_PROCESS.poll() is None:
|
199
|
-
return
|
200
|
-
|
201
|
-
command = [sys.executable, "-m", "talks_reducer.server_tray"]
|
202
|
-
if extra_args:
|
203
|
-
command.extend(extra_args)
|
204
|
-
|
205
|
-
try:
|
206
|
-
_TRAY_PROCESS = subprocess.Popen(command)
|
207
|
-
except Exception as exc: # pragma: no cover - best-effort fallback
|
208
|
-
_TRAY_PROCESS = None
|
209
|
-
sys.stderr.write(
|
210
|
-
f"Warning: failed to launch Talks Reducer server tray: {exc}\n"
|
211
|
-
)
|
212
|
-
|
213
|
-
|
214
189
|
def _parse_ratios_from_summary(summary: str) -> Tuple[Optional[float], Optional[float]]:
|
215
190
|
"""Extract time and size ratios from a Markdown *summary* string."""
|
216
191
|
|
@@ -387,11 +362,11 @@ class TalksReducerGUI:
|
|
387
362
|
else:
|
388
363
|
self.root = tk.Tk()
|
389
364
|
|
390
|
-
# Set window title with version
|
391
|
-
|
392
|
-
|
365
|
+
# Set window title with version information
|
366
|
+
app_version = resolve_version()
|
367
|
+
if app_version and app_version != "unknown":
|
393
368
|
self.root.title(f"Talks Reducer v{app_version}")
|
394
|
-
|
369
|
+
else:
|
395
370
|
self.root.title("Talks Reducer")
|
396
371
|
|
397
372
|
self._apply_window_icon()
|
@@ -453,6 +428,7 @@ class TalksReducerGUI:
|
|
453
428
|
self._basic_defaults: dict[str, float] = {}
|
454
429
|
self._basic_variables: dict[str, tk.DoubleVar] = {}
|
455
430
|
self._slider_updaters: dict[str, Callable[[str], None]] = {}
|
431
|
+
self._sliders: list[tk.Scale] = []
|
456
432
|
|
457
433
|
self._build_layout()
|
458
434
|
self._apply_simple_mode(initial=True)
|
@@ -473,7 +449,7 @@ class TalksReducerGUI:
|
|
473
449
|
def ping_worker() -> None:
|
474
450
|
try:
|
475
451
|
if self._ping_server(server_url):
|
476
|
-
self._set_status("Idle", f"Server {host_label} is
|
452
|
+
self._set_status("Idle", f"Server {host_label} is ready")
|
477
453
|
self._notify(
|
478
454
|
lambda: self._append_log(f"Server {host_label} ready")
|
479
455
|
)
|
@@ -520,8 +496,26 @@ class TalksReducerGUI:
|
|
520
496
|
|
521
497
|
icon_candidates: list[tuple[Path, str]] = []
|
522
498
|
if sys.platform.startswith("win"):
|
523
|
-
icon_candidates.append(
|
524
|
-
|
499
|
+
icon_candidates.append(
|
500
|
+
(
|
501
|
+
base_path
|
502
|
+
/ "talks_reducer"
|
503
|
+
/ "resources"
|
504
|
+
/ "icons"
|
505
|
+
/ "icon.ico",
|
506
|
+
"ico",
|
507
|
+
)
|
508
|
+
)
|
509
|
+
icon_candidates.append(
|
510
|
+
(
|
511
|
+
base_path
|
512
|
+
/ "talks_reducer"
|
513
|
+
/ "resources"
|
514
|
+
/ "icons"
|
515
|
+
/ "icon.png",
|
516
|
+
"png",
|
517
|
+
)
|
518
|
+
)
|
525
519
|
|
526
520
|
for icon_path, icon_type in icon_candidates:
|
527
521
|
if not icon_path.is_file():
|
@@ -610,6 +604,7 @@ class TalksReducerGUI:
|
|
610
604
|
text="Reset to defaults",
|
611
605
|
command=self._reset_basic_defaults,
|
612
606
|
state=self.tk.DISABLED,
|
607
|
+
style="Link.TButton",
|
613
608
|
)
|
614
609
|
|
615
610
|
self.basic_options_frame = self.ttk.Labelframe(
|
@@ -895,6 +890,7 @@ class TalksReducerGUI:
|
|
895
890
|
showvalue=False,
|
896
891
|
command=update,
|
897
892
|
length=240,
|
893
|
+
highlightthickness=0,
|
898
894
|
)
|
899
895
|
slider.grid(row=row, column=1, sticky="ew", pady=4, padx=(0, 8))
|
900
896
|
|
@@ -904,6 +900,7 @@ class TalksReducerGUI:
|
|
904
900
|
self._basic_defaults[setting_key] = default_value
|
905
901
|
self._basic_variables[setting_key] = variable
|
906
902
|
variable.trace_add("write", lambda *_: self._update_basic_reset_state())
|
903
|
+
self._sliders.append(slider)
|
907
904
|
|
908
905
|
def _update_basic_reset_state(self) -> None:
|
909
906
|
"""Enable or disable the reset control based on slider values."""
|
@@ -1253,11 +1250,33 @@ class TalksReducerGUI:
|
|
1253
1250
|
"TRadiobutton",
|
1254
1251
|
background=[("active", palette.get("hover", palette["background"]))],
|
1255
1252
|
)
|
1253
|
+
self.style.configure(
|
1254
|
+
"Link.TButton",
|
1255
|
+
background=palette["background"],
|
1256
|
+
foreground=palette["accent"],
|
1257
|
+
borderwidth=0,
|
1258
|
+
relief="flat",
|
1259
|
+
highlightthickness=0,
|
1260
|
+
padding=2,
|
1261
|
+
font=("TkDefaultFont", 8, "underline"),
|
1262
|
+
)
|
1263
|
+
self.style.map(
|
1264
|
+
"Link.TButton",
|
1265
|
+
background=[
|
1266
|
+
("active", palette.get("hover", palette["background"])),
|
1267
|
+
("disabled", palette["background"]),
|
1268
|
+
],
|
1269
|
+
foreground=[
|
1270
|
+
("active", palette.get("accent", palette["foreground"])),
|
1271
|
+
("disabled", palette["foreground"]),
|
1272
|
+
],
|
1273
|
+
)
|
1256
1274
|
self.style.configure(
|
1257
1275
|
"TButton",
|
1258
1276
|
background=palette["surface"],
|
1259
1277
|
foreground=palette["foreground"],
|
1260
|
-
padding=
|
1278
|
+
padding=4,
|
1279
|
+
font=("TkDefaultFont", 8),
|
1261
1280
|
)
|
1262
1281
|
self.style.map(
|
1263
1282
|
"TButton",
|
@@ -1323,6 +1342,24 @@ class TalksReducerGUI:
|
|
1323
1342
|
fg=palette["foreground"],
|
1324
1343
|
highlightthickness=0,
|
1325
1344
|
)
|
1345
|
+
|
1346
|
+
slider_relief = self.tk.FLAT if mode == "dark" else self.tk.RAISED
|
1347
|
+
active_background = (
|
1348
|
+
palette.get("accent", palette["surface"])
|
1349
|
+
if mode == "dark"
|
1350
|
+
else palette.get("hover", palette["surface"])
|
1351
|
+
)
|
1352
|
+
for slider in getattr(self, "_sliders", []):
|
1353
|
+
slider.configure(
|
1354
|
+
# background=palette["background"],
|
1355
|
+
# foreground=palette["foreground"],
|
1356
|
+
troughcolor=palette["surface"],
|
1357
|
+
# activebackground=active_background,
|
1358
|
+
# highlightbackground=palette["background"],
|
1359
|
+
highlightcolor=palette["background"],
|
1360
|
+
sliderrelief=slider_relief,
|
1361
|
+
bd=0,
|
1362
|
+
)
|
1326
1363
|
self.log_text.configure(
|
1327
1364
|
bg=palette["surface"],
|
1328
1365
|
fg=palette["foreground"],
|
@@ -2214,24 +2251,27 @@ def main(argv: Optional[Sequence[str]] = None) -> bool:
|
|
2214
2251
|
|
2215
2252
|
parser = argparse.ArgumentParser(add_help=False)
|
2216
2253
|
parser.add_argument(
|
2217
|
-
"--
|
2254
|
+
"--server",
|
2218
2255
|
action="store_true",
|
2219
|
-
help="
|
2256
|
+
help="Launch the Talks Reducer server tray instead of the desktop GUI.",
|
2220
2257
|
)
|
2221
2258
|
parser.add_argument(
|
2222
|
-
"--
|
2259
|
+
"--no-tray",
|
2223
2260
|
action="store_true",
|
2224
|
-
help="
|
2261
|
+
help="Deprecated: the GUI no longer starts the server tray automatically.",
|
2225
2262
|
)
|
2226
2263
|
|
2227
2264
|
parsed_args, remaining = parser.parse_known_args(argv)
|
2228
|
-
no_tray = parsed_args.no_tray
|
2229
2265
|
if parsed_args.server:
|
2230
2266
|
package_name = __package__ or "talks_reducer"
|
2231
2267
|
tray_module = importlib.import_module(f"{package_name}.server_tray")
|
2232
2268
|
tray_main = getattr(tray_module, "main")
|
2233
2269
|
tray_main(remaining)
|
2234
2270
|
return False
|
2271
|
+
if parsed_args.no_tray:
|
2272
|
+
sys.stderr.write(
|
2273
|
+
"Warning: --no-tray is deprecated; the GUI no longer starts the server tray automatically.\n"
|
2274
|
+
)
|
2235
2275
|
argv = remaining
|
2236
2276
|
|
2237
2277
|
if argv:
|
@@ -2247,8 +2287,6 @@ def main(argv: Optional[Sequence[str]] = None) -> bool:
|
|
2247
2287
|
if launch_gui:
|
2248
2288
|
try:
|
2249
2289
|
app = TalksReducerGUI(argv, auto_run=True)
|
2250
|
-
if not no_tray:
|
2251
|
-
_ensure_server_tray_running()
|
2252
2290
|
app.run()
|
2253
2291
|
return True
|
2254
2292
|
except Exception:
|
@@ -2310,8 +2348,6 @@ def main(argv: Optional[Sequence[str]] = None) -> bool:
|
|
2310
2348
|
# Catch and report any errors during GUI initialization
|
2311
2349
|
try:
|
2312
2350
|
app = TalksReducerGUI()
|
2313
|
-
if not no_tray:
|
2314
|
-
_ensure_server_tray_running()
|
2315
2351
|
app.run()
|
2316
2352
|
return True
|
2317
2353
|
except Exception as e:
|
File without changes
|
@@ -19,6 +19,7 @@ from talks_reducer.ffmpeg import FFmpegNotFoundError
|
|
19
19
|
from talks_reducer.models import ProcessingOptions, ProcessingResult
|
20
20
|
from talks_reducer.pipeline import speed_up_video
|
21
21
|
from talks_reducer.progress import ProgressHandle, SignalProgressReporter
|
22
|
+
from talks_reducer.version_utils import resolve_version
|
22
23
|
|
23
24
|
|
24
25
|
class _GradioProgressHandle(AbstractContextManager[ProgressHandle]):
|
@@ -143,8 +144,14 @@ class GradioProgressReporter(SignalProgressReporter):
|
|
143
144
|
self._progress_callback(bounded_current, total_value, display_desc)
|
144
145
|
|
145
146
|
|
146
|
-
|
147
|
-
|
147
|
+
_FAVICON_CANDIDATES = (
|
148
|
+
Path(__file__).resolve().parent / "resources" / "icons" / "icon.ico",
|
149
|
+
Path(__file__).resolve().parent.parent / "docs" / "assets" / "icon.ico",
|
150
|
+
)
|
151
|
+
_FAVICON_PATH: Optional[Path] = next(
|
152
|
+
(path for path in _FAVICON_CANDIDATES if path.exists()), None
|
153
|
+
)
|
154
|
+
_FAVICON_PATH_STR = str(_FAVICON_PATH) if _FAVICON_PATH else None
|
148
155
|
_WORKSPACES: list[Path] = []
|
149
156
|
|
150
157
|
|
@@ -347,10 +354,15 @@ def build_interface() -> gr.Blocks:
|
|
347
354
|
|
348
355
|
server_identity = _describe_server_host()
|
349
356
|
|
350
|
-
|
357
|
+
app_version = resolve_version()
|
358
|
+
version_suffix = (
|
359
|
+
f" v{app_version}" if app_version and app_version != "unknown" else ""
|
360
|
+
)
|
361
|
+
|
362
|
+
with gr.Blocks(title=f"Talks Reducer Web UI{version_suffix}") as demo:
|
351
363
|
gr.Markdown(
|
352
364
|
f"""
|
353
|
-
## Talks Reducer Web UI
|
365
|
+
## Talks Reducer Web UI{version_suffix}
|
354
366
|
Drop a video into the zone below or click to browse. **Small video** is enabled
|
355
367
|
by default to apply the 720p/128k preset before processing starts—clear it to
|
356
368
|
keep the original resolution.
|
@@ -21,6 +21,7 @@ from urllib.parse import urlsplit, urlunsplit
|
|
21
21
|
from PIL import Image
|
22
22
|
|
23
23
|
from .server import build_interface
|
24
|
+
from .version_utils import resolve_version
|
24
25
|
|
25
26
|
try: # pragma: no cover - import guarded for clearer error message at runtime
|
26
27
|
import pystray
|
@@ -35,6 +36,7 @@ else:
|
|
35
36
|
|
36
37
|
|
37
38
|
LOGGER = logging.getLogger(__name__)
|
39
|
+
APP_VERSION = resolve_version()
|
38
40
|
|
39
41
|
|
40
42
|
def _guess_local_url(host: Optional[str], port: int) -> str:
|
@@ -121,11 +123,12 @@ def _iter_icon_candidates() -> Iterator[Path]:
|
|
121
123
|
if candidate_root not in expanded_roots:
|
122
124
|
expanded_roots.append(candidate_root)
|
123
125
|
|
124
|
-
icon_names = ("icon.png", "icon.ico")
|
126
|
+
icon_names = ("icon.ico", "icon.png") if sys.platform == "win32" else ("icon.png", "icon.ico")
|
125
127
|
relative_paths = (
|
128
|
+
Path("talks_reducer") / "resources" / "icons",
|
129
|
+
Path("talks_reducer") / "assets",
|
126
130
|
Path("docs") / "assets",
|
127
131
|
Path("assets"),
|
128
|
-
Path("talks_reducer") / "assets",
|
129
132
|
Path(""),
|
130
133
|
)
|
131
134
|
|
@@ -404,7 +407,7 @@ class _ServerTrayApplication:
|
|
404
407
|
try:
|
405
408
|
LOGGER.info("Launching Talks Reducer GUI via %s", sys.executable)
|
406
409
|
process = subprocess.Popen(
|
407
|
-
[sys.executable, "-m", "talks_reducer.gui"
|
410
|
+
[sys.executable, "-m", "talks_reducer.gui"]
|
408
411
|
)
|
409
412
|
except Exception as exc: # pragma: no cover - platform specific
|
410
413
|
LOGGER.error("Failed to launch Talks Reducer GUI: %s", exc)
|
@@ -460,7 +463,12 @@ class _ServerTrayApplication:
|
|
460
463
|
return
|
461
464
|
|
462
465
|
icon_image = _load_icon()
|
466
|
+
version_suffix = (
|
467
|
+
f" v{APP_VERSION}" if APP_VERSION and APP_VERSION != "unknown" else ""
|
468
|
+
)
|
469
|
+
version_label = f"Talks Reducer{version_suffix}"
|
463
470
|
menu = pystray.Menu(
|
471
|
+
pystray.MenuItem(version_label, None, enabled=False),
|
464
472
|
pystray.MenuItem(
|
465
473
|
"Open GUI",
|
466
474
|
self._launch_gui,
|
@@ -470,7 +478,10 @@ class _ServerTrayApplication:
|
|
470
478
|
pystray.MenuItem("Quit", self._handle_quit),
|
471
479
|
)
|
472
480
|
self._icon = pystray.Icon(
|
473
|
-
"talks-reducer",
|
481
|
+
"talks-reducer",
|
482
|
+
icon_image,
|
483
|
+
f"{version_label} Server",
|
484
|
+
menu=menu,
|
474
485
|
)
|
475
486
|
|
476
487
|
if self._tray_mode == "pystray-detached":
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"""Utilities for retrieving the Talks Reducer version across environments."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from importlib.metadata import PackageNotFoundError, version as metadata_version
|
6
|
+
|
7
|
+
try: # pragma: no cover - defensive fallback when metadata module missing
|
8
|
+
from .__about__ import __version__ as _about_version
|
9
|
+
except Exception: # pragma: no cover - runtime fallback in frozen apps
|
10
|
+
_about_version = ""
|
11
|
+
|
12
|
+
|
13
|
+
def resolve_version(package_name: str = "talks-reducer") -> str:
|
14
|
+
"""Return the package version, preferring bundled metadata when available."""
|
15
|
+
|
16
|
+
if _about_version:
|
17
|
+
return _about_version
|
18
|
+
|
19
|
+
try:
|
20
|
+
return metadata_version(package_name)
|
21
|
+
except (PackageNotFoundError, Exception):
|
22
|
+
return "unknown"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: talks-reducer
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.3
|
4
4
|
Summary: CLI for speeding up long-form talks by removing silence
|
5
5
|
Author: Talks Reducer Maintainers
|
6
6
|
License-Expression: MIT
|
@@ -111,22 +111,25 @@ desktop shortcut without opening the GUI first.
|
|
111
111
|
Pass `--debug` to print verbose logs about the tray icon lifecycle, and
|
112
112
|
`--tray-mode pystray-detached` to try pystray's alternate detached runner. If
|
113
113
|
the icon backend refuses to appear, fall back to `--tray-mode headless` to keep
|
114
|
-
the web server running without a tray process. The tray menu
|
114
|
+
the web server running without a tray process. The tray menu highlights the
|
115
|
+
running Talks Reducer version and includes an **Open GUI**
|
115
116
|
item (also triggered by double-clicking the icon) that launches the desktop
|
116
117
|
Talks Reducer interface alongside an **Open WebUI** entry that opens the Gradio
|
117
118
|
page in your browser. Close the GUI window to return to the tray without
|
118
|
-
stopping the server.
|
119
|
-
server
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
119
|
+
stopping the server. Launch the tray explicitly whenever you need it—either run
|
120
|
+
`talks-reducer server-tray` directly or start the GUI with
|
121
|
+
`python -m talks_reducer.gui --server` to boot the tray-managed server instead
|
122
|
+
of the desktop window. The GUI now runs standalone and no longer spawns the tray
|
123
|
+
automatically; the deprecated `--no-tray` flag is ignored for compatibility.
|
124
|
+
The tray command itself never launches the GUI automatically, so use the menu
|
125
|
+
item (or relaunch the GUI separately) whenever you want to reopen it. The tray
|
126
|
+
no longer opens a browser automatically—pass `--open-browser` if you prefer the
|
127
|
+
web page to launch as soon as the server is ready.
|
126
128
|
|
127
129
|
This opens a local web page featuring a drag-and-drop upload zone, a **Small video** checkbox that mirrors the CLI preset, a live
|
128
|
-
progress indicator, and automatic previews of the processed output.
|
129
|
-
|
130
|
+
progress indicator, and automatic previews of the processed output. The page header and browser tab title include the current
|
131
|
+
Talks Reducer version so you can confirm which build the server is running. Once the job completes you can inspect the resulting
|
132
|
+
compression ratio and download the rendered video directly from the page.
|
130
133
|
|
131
134
|
The desktop GUI mirrors this behaviour. Open **Advanced** settings to provide a
|
132
135
|
server URL and click **Discover** to scan your local network for Talks Reducer
|
@@ -16,12 +16,14 @@ talks_reducer/progress.py
|
|
16
16
|
talks_reducer/server.py
|
17
17
|
talks_reducer/server_tray.py
|
18
18
|
talks_reducer/service_client.py
|
19
|
+
talks_reducer/version_utils.py
|
19
20
|
talks_reducer.egg-info/PKG-INFO
|
20
21
|
talks_reducer.egg-info/SOURCES.txt
|
21
22
|
talks_reducer.egg-info/dependency_links.txt
|
22
23
|
talks_reducer.egg-info/entry_points.txt
|
23
24
|
talks_reducer.egg-info/requires.txt
|
24
25
|
talks_reducer.egg-info/top_level.txt
|
26
|
+
talks_reducer/resources/__init__.py
|
25
27
|
tests/test_audio.py
|
26
28
|
tests/test_cli.py
|
27
29
|
tests/test_discovery.py
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|