meeting-noter 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
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.
Potentially problematic release.
This version of meeting-noter might be problematic. Click here for more details.
- meeting_noter/__init__.py +1 -1
- meeting_noter/cli.py +43 -2
- meeting_noter/config.py +11 -0
- meeting_noter/update_checker.py +65 -0
- {meeting_noter-1.0.0.dist-info → meeting_noter-1.1.0.dist-info}/METADATA +1 -1
- {meeting_noter-1.0.0.dist-info → meeting_noter-1.1.0.dist-info}/RECORD +9 -8
- {meeting_noter-1.0.0.dist-info → meeting_noter-1.1.0.dist-info}/WHEEL +0 -0
- {meeting_noter-1.0.0.dist-info → meeting_noter-1.1.0.dist-info}/entry_points.txt +0 -0
- {meeting_noter-1.0.0.dist-info → meeting_noter-1.1.0.dist-info}/top_level.txt +0 -0
meeting_noter/__init__.py
CHANGED
meeting_noter/cli.py
CHANGED
|
@@ -104,10 +104,46 @@ def _launch_gui_background():
|
|
|
104
104
|
click.echo("Meeting Noter GUI launched.")
|
|
105
105
|
|
|
106
106
|
|
|
107
|
+
def _handle_version():
|
|
108
|
+
"""Handle --version: show version, check for updates, auto-update if enabled."""
|
|
109
|
+
import subprocess
|
|
110
|
+
|
|
111
|
+
from meeting_noter.update_checker import check_for_update
|
|
112
|
+
|
|
113
|
+
config = get_config()
|
|
114
|
+
|
|
115
|
+
click.echo(f"meeting-noter {__version__}")
|
|
116
|
+
|
|
117
|
+
# Check for updates
|
|
118
|
+
click.echo("Checking for updates...", nl=False)
|
|
119
|
+
new_version = check_for_update()
|
|
120
|
+
|
|
121
|
+
if new_version:
|
|
122
|
+
click.echo(f" update available: {new_version}")
|
|
123
|
+
|
|
124
|
+
if config.auto_update:
|
|
125
|
+
click.echo(f"Auto-updating to {new_version}...")
|
|
126
|
+
result = subprocess.run(
|
|
127
|
+
["pipx", "upgrade", "meeting-noter"],
|
|
128
|
+
capture_output=True,
|
|
129
|
+
text=True,
|
|
130
|
+
)
|
|
131
|
+
if result.returncode == 0:
|
|
132
|
+
click.echo(click.style(f"Updated to {new_version}", fg="green"))
|
|
133
|
+
else:
|
|
134
|
+
click.echo(click.style("Update failed. Run manually:", fg="yellow"))
|
|
135
|
+
click.echo(" pipx upgrade meeting-noter")
|
|
136
|
+
else:
|
|
137
|
+
click.echo("Run to update: pipx upgrade meeting-noter")
|
|
138
|
+
click.echo("Or enable auto-update: mn config auto-update true")
|
|
139
|
+
else:
|
|
140
|
+
click.echo(" up to date")
|
|
141
|
+
|
|
142
|
+
|
|
107
143
|
@click.group(cls=SuggestGroup, invoke_without_command=True)
|
|
108
|
-
@click.
|
|
144
|
+
@click.option("--version", "-V", is_flag=True, help="Show version and check for updates")
|
|
109
145
|
@click.pass_context
|
|
110
|
-
def cli(ctx):
|
|
146
|
+
def cli(ctx, version):
|
|
111
147
|
"""Meeting Noter - Offline meeting transcription.
|
|
112
148
|
|
|
113
149
|
\b
|
|
@@ -124,6 +160,10 @@ def cli(ctx):
|
|
|
124
160
|
meeting-noter config whisper-model base.en Set transcription model
|
|
125
161
|
meeting-noter config auto-transcribe false Disable auto-transcribe
|
|
126
162
|
"""
|
|
163
|
+
if version:
|
|
164
|
+
_handle_version()
|
|
165
|
+
ctx.exit(0)
|
|
166
|
+
|
|
127
167
|
if ctx.invoked_subcommand is None:
|
|
128
168
|
# No subcommand - start background watcher
|
|
129
169
|
ctx.invoke(watcher)
|
|
@@ -606,6 +646,7 @@ CONFIG_KEYS = {
|
|
|
606
646
|
"transcripts-dir": ("transcripts_dir", "path", "Directory for transcripts"),
|
|
607
647
|
"whisper-model": ("whisper_model", "choice:tiny.en,base.en,small.en,medium.en,large-v3", "Whisper model for transcription"),
|
|
608
648
|
"auto-transcribe": ("auto_transcribe", "bool", "Auto-transcribe after recording"),
|
|
649
|
+
"auto-update": ("auto_update", "bool", "Auto-update when running --version"),
|
|
609
650
|
"silence-timeout": ("silence_timeout", "int", "Minutes of silence before auto-stop"),
|
|
610
651
|
"capture-system-audio": ("capture_system_audio", "bool", "Capture meeting participants via ScreenCaptureKit"),
|
|
611
652
|
}
|
meeting_noter/config.py
CHANGED
|
@@ -32,6 +32,7 @@ DEFAULT_CONFIG = {
|
|
|
32
32
|
"transcripts_dir": str(Path.home() / "meetings"),
|
|
33
33
|
"whisper_model": "tiny.en",
|
|
34
34
|
"auto_transcribe": True,
|
|
35
|
+
"auto_update": True, # Auto-update when running --version
|
|
35
36
|
"silence_timeout": 5, # Minutes of silence before stopping recording
|
|
36
37
|
"capture_system_audio": True, # Capture other participants via ScreenCaptureKit
|
|
37
38
|
"show_menubar": False,
|
|
@@ -139,6 +140,16 @@ class Config:
|
|
|
139
140
|
"""Set show menubar setting."""
|
|
140
141
|
self._data["show_menubar"] = value
|
|
141
142
|
|
|
143
|
+
@property
|
|
144
|
+
def auto_update(self) -> bool:
|
|
145
|
+
"""Get auto-update setting."""
|
|
146
|
+
return self._data.get("auto_update", True)
|
|
147
|
+
|
|
148
|
+
@auto_update.setter
|
|
149
|
+
def auto_update(self, value: bool) -> None:
|
|
150
|
+
"""Set auto-update setting."""
|
|
151
|
+
self._data["auto_update"] = value
|
|
152
|
+
|
|
142
153
|
@property
|
|
143
154
|
def setup_complete(self) -> bool:
|
|
144
155
|
"""Check if setup has been completed."""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Check for updates from PyPI."""
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
import urllib.request
|
|
5
|
+
import json
|
|
6
|
+
from typing import Optional, Tuple
|
|
7
|
+
|
|
8
|
+
from meeting_noter import __version__
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
PYPI_URL = "https://pypi.org/pypi/meeting-noter/json"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_version(version: str) -> Tuple[int, ...]:
|
|
15
|
+
"""Parse version string into tuple for comparison."""
|
|
16
|
+
try:
|
|
17
|
+
return tuple(int(x) for x in version.split("."))
|
|
18
|
+
except ValueError:
|
|
19
|
+
return (0, 0, 0)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_latest_version() -> Optional[str]:
|
|
23
|
+
"""Fetch the latest version from PyPI."""
|
|
24
|
+
try:
|
|
25
|
+
req = urllib.request.Request(
|
|
26
|
+
PYPI_URL,
|
|
27
|
+
headers={"Accept": "application/json", "User-Agent": "meeting-noter"}
|
|
28
|
+
)
|
|
29
|
+
with urllib.request.urlopen(req, timeout=5) as response:
|
|
30
|
+
data = json.loads(response.read().decode())
|
|
31
|
+
return data.get("info", {}).get("version")
|
|
32
|
+
except Exception:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def check_for_update() -> Optional[str]:
|
|
37
|
+
"""Check if an update is available.
|
|
38
|
+
|
|
39
|
+
Returns the new version string if an update is available, None otherwise.
|
|
40
|
+
"""
|
|
41
|
+
latest = get_latest_version()
|
|
42
|
+
if not latest:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
current = parse_version(__version__)
|
|
46
|
+
latest_parsed = parse_version(latest)
|
|
47
|
+
|
|
48
|
+
if latest_parsed > current:
|
|
49
|
+
return latest
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def check_for_update_async(callback):
|
|
54
|
+
"""Check for updates in a background thread.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
callback: Function to call with the new version string (or None if no update).
|
|
58
|
+
"""
|
|
59
|
+
def _check():
|
|
60
|
+
new_version = check_for_update()
|
|
61
|
+
if new_version:
|
|
62
|
+
callback(new_version)
|
|
63
|
+
|
|
64
|
+
thread = threading.Thread(target=_check, daemon=True)
|
|
65
|
+
thread.start()
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
meeting_noter/__init__.py,sha256=
|
|
1
|
+
meeting_noter/__init__.py,sha256=OuitWUFUeSb7eg41mnnDD6QiJrcGVpXpdhDzyxtCmmU,103
|
|
2
2
|
meeting_noter/__main__.py,sha256=6sSOqH1o3jvgvkVzsVKmF6-xVGcUAbNVQkRl2CrygdE,120
|
|
3
|
-
meeting_noter/cli.py,sha256=
|
|
4
|
-
meeting_noter/config.py,sha256=
|
|
3
|
+
meeting_noter/cli.py,sha256=BAoUnQ-FPgwTp6-ON6WQkO-7Biwk1mYhwFaGdchHGHQ,34267
|
|
4
|
+
meeting_noter/config.py,sha256=_Jy-gZDTCN3TwH5fiLEWk-qFhoSGISO2xDQmACV_zRc,6334
|
|
5
5
|
meeting_noter/daemon.py,sha256=u9VrYe94o3lxabuIS9MDVPHSH7MqKqzTqGTuA7TNAIc,19767
|
|
6
6
|
meeting_noter/meeting_detector.py,sha256=St0qoMkvUERP4BaxnXO1M6fZDJpWqBf9In7z2SgWcWg,10564
|
|
7
7
|
meeting_noter/menubar.py,sha256=Gn6p8y5jA_HCWf1T3ademxH-vndpONHkf9vUlKs6XEo,14379
|
|
8
8
|
meeting_noter/mic_monitor.py,sha256=P8vF4qaZcGrEzzJyVos78Vuf38NXHGNRREDsD-HyBHc,16211
|
|
9
|
+
meeting_noter/update_checker.py,sha256=sMmIiiZJL6K7wqLWE64Aj4hS8uspjUOirr6BG_IlL1I,1701
|
|
9
10
|
meeting_noter/audio/__init__.py,sha256=O7PU8CxHSHxMeHbc9Jdwt9kePLQzsPh81GQU7VHCtBY,44
|
|
10
11
|
meeting_noter/audio/capture.py,sha256=fDrT5oXfva8vdFlht9cv60NviKbksw2QeJ8eOtI19uE,6469
|
|
11
12
|
meeting_noter/audio/encoder.py,sha256=OBsgUmlZPz-YZQZ7Rp8MAlMRaQxTsccjuTgCtvRebmc,6573
|
|
@@ -33,8 +34,8 @@ meeting_noter/resources/icon_64.png,sha256=TqG7Awx3kK8YdiX1e_z1odZonosZyQI2trlkN
|
|
|
33
34
|
meeting_noter/transcription/__init__.py,sha256=7GY9diP06DzFyoli41wddbrPv5bVDzH35bmnWlIJev4,29
|
|
34
35
|
meeting_noter/transcription/engine.py,sha256=G9NcSS6Q-UhW7PlQ0E85hQXn6BWao64nIvyw4NR2yxI,7208
|
|
35
36
|
meeting_noter/transcription/live_transcription.py,sha256=AslB1T1_gxu7eSp7xc79_2SdfGrNJq7L_8bA1t6YoU4,9277
|
|
36
|
-
meeting_noter-1.
|
|
37
|
-
meeting_noter-1.
|
|
38
|
-
meeting_noter-1.
|
|
39
|
-
meeting_noter-1.
|
|
40
|
-
meeting_noter-1.
|
|
37
|
+
meeting_noter-1.1.0.dist-info/METADATA,sha256=bGwwBq9AeFcxYKf0vpD3WtENmibBNLl4mzf1fLDyiVs,6995
|
|
38
|
+
meeting_noter-1.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
39
|
+
meeting_noter-1.1.0.dist-info/entry_points.txt,sha256=osZoOmm-UBPCJ4b6DGH6JOAm7mofM2fK06eK6blplmg,83
|
|
40
|
+
meeting_noter-1.1.0.dist-info/top_level.txt,sha256=9Tuq04_0SXM0OXOHVbOHkHkB5tG3fqkrMrfzCMpbLpY,14
|
|
41
|
+
meeting_noter-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|