Skip to content

Commit 72b4823

Browse files
authoredJan 19, 2025··
Merge pull request Project-Babble#81 from Project-Babble/feat/desktop-notifications
(feat) Add Linux desktop notifications
2 parents 3f38b63 + 6b35a3e commit 72b4823

File tree

3 files changed

+94
-51
lines changed

3 files changed

+94
-51
lines changed
 

‎BabbleApp/babbleapp.py

+40-50
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,25 @@
2121
import queue
2222
import requests
2323
import threading
24-
from ctypes import windll, c_int
24+
import asyncio
25+
from ctypes import c_int
2526
from babble_model_loader import *
2627
from camera_widget import CameraWidget
2728
from config import BabbleConfig
28-
from tab import CamInfo, Tab
29+
from tab import Tab
2930
from osc import VRChatOSCReceiver, VRChatOSC
3031
from general_settings_widget import SettingsWidget
3132
from algo_settings_widget import AlgoSettingsWidget
3233
from calib_settings_widget import CalibSettingsWidget
34+
from notification_manager import NotificationManager
3335
from utils.misc_utils import EnsurePath, is_nt, bg_color_highlight, bg_color_clear
3436
from lang_manager import LocaleStringManager as lang
3537

3638
winmm = None
3739

3840
if is_nt:
39-
from winotify import Notification
4041
try:
42+
from ctypes import windll
4143
winmm = windll.winmm
4244
except OSError:
4345
print(f'\033[91m[{lang._instance.get_string("log.error")}] {lang._instance.get_string("error.winmm")}.\033[0m')
@@ -57,7 +59,7 @@
5759
ALGO_SETTINGS_RADIO_NAME = "-ALGOSETTINGSRADIO-"
5860
CALIB_SETTINGS_RADIO_NAME = "-CALIBSETTINGSRADIO-"
5961

60-
page_url = "https://github.com/SummerSigh/ProjectBabble/releases/latest"
62+
page_url = "https://github.com/Project-Babble/ProjectBabble/releases/latest"
6163
appversion = "Babble v2.0.7"
6264

6365
def timerResolution(toggle):
@@ -70,69 +72,53 @@ def timerResolution(toggle):
7072
else:
7173
winmm.timeEndPeriod(1)
7274

73-
def main():
74-
EnsurePath()
75-
76-
# Get Configuration
77-
config: BabbleConfig = BabbleConfig.load()
78-
79-
# Init locale manager
80-
lang("Locale", config.settings.gui_language)
81-
82-
config.save()
83-
84-
cancellation_event = threading.Event()
85-
ROSC = False
86-
# Check to see if we can connect to our video source first. If not, bring up camera finding
87-
# dialog.
88-
75+
async def check_for_updates(config, notification_manager):
8976
if config.settings.gui_update_check:
9077
try:
9178
response = requests.get(
92-
"https://api.github.com/repos/SummerSigh/ProjectBabble/releases/latest"
79+
"https://api.github.com/repos/Project-Babble/ProjectBabble/releases/latest"
9380
)
9481
latestversion = response.json()["name"]
95-
if (
96-
appversion == latestversion
97-
): # If what we scraped and hardcoded versions are same, assume we are up to date.
82+
83+
if appversion == latestversion:
9884
print(
9985
f'\033[92m[{lang._instance.get_string("log.info")}] {lang._instance.get_string("babble.latestVersion")}! [{latestversion}]\033[0m'
10086
)
10187
else:
10288
print(
10389
f'\033[93m[{lang._instance.get_string("log.info")}] {lang._instance.get_string("babble.needUpdateOne")} [{appversion}] {lang._instance.get_string("babble.needUpdateTwo")} [{latestversion}] {lang._instance.get_string("babble.needUpdateThree")}.\033[0m'
10490
)
105-
try:
106-
if is_nt:
107-
cwd = os.getcwd()
108-
icon = cwd + "\Images\logo.ico"
109-
toast = Notification(
110-
app_id=lang._instance.get_string("babble.name"),
111-
title=lang._instance.get_string("babble.updatePresent"),
112-
msg=f'{lang._instance.get_string("babble.updateTo")} {latestversion}',
113-
icon=r"{}".format(icon),
114-
)
115-
toast.add_actions(
116-
label=lang._instance.get_string("babble.downloadPage"),
117-
launch="https://github.com/SummerSigh/ProjectBabble/releases/latest",
118-
)
119-
toast.show()
120-
except Exception as e:
121-
print(
122-
f'[{lang._instance.get_string("log.info")}] {lang._instance.get_string("babble.noToast")}'
123-
)
124-
except:
91+
await notification_manager.show_notification(appversion, latestversion, page_url)
92+
except Exception as e:
12593
print(
126-
f'[{lang._instance.get_string("log.info")}] {lang._instance.get_string("babble.noInternet")}.'
94+
f'[{lang._instance.get_string("log.info")}] {lang._instance.get_string("babble.noInternet")}. Error: {e}'
12795
)
96+
97+
async def async_main():
98+
EnsurePath()
99+
100+
# Get Configuration
101+
config: BabbleConfig = BabbleConfig.load()
102+
103+
# Init locale manager
104+
lang("Locale", config.settings.gui_language)
105+
106+
config.save()
107+
108+
notification_manager = NotificationManager()
109+
await notification_manager.initialize()
110+
111+
# Run the update check
112+
await check_for_updates(config, notification_manager)
113+
114+
cancellation_event = threading.Event()
115+
ROSC = False
116+
128117
timerResolution(True)
129-
# Check to see if we have an ROI. If not, bring up ROI finder GUI.
130118

131-
# Spawn worker threads
132119
osc_queue: queue.Queue[tuple[bool, int, int]] = queue.Queue(maxsize=10)
133120
osc = VRChatOSC(cancellation_event, osc_queue, config)
134121
osc_thread = threading.Thread(target=osc.run)
135-
# start worker threads
136122
osc_thread.start()
137123

138124
cams = [
@@ -233,7 +219,6 @@ def main():
233219

234220
tint = 33
235221
fs = False
236-
# GUI Render loop
237222
while True:
238223
# First off, check for any events from the GUI
239224
event, values = window.read(timeout=tint)
@@ -342,7 +327,12 @@ def main():
342327
for setting in settings:
343328
if setting.started():
344329
setting.render(window, event, values)
345-
330+
331+
# Does adding this help?
332+
# await asyncio.sleep(0)
333+
334+
def main():
335+
asyncio.run(async_main())
346336

347337
if __name__ == "__main__":
348338
main()

‎BabbleApp/notification_manager.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import os
2+
import webbrowser
3+
import signal
4+
import asyncio
5+
from pathlib import Path
6+
from desktop_notifier import DesktopNotifier, Urgency, Button, Icon, DEFAULT_SOUND
7+
from lang_manager import LocaleStringManager as lang
8+
from utils.misc_utils import is_nt
9+
10+
class NotificationManager:
11+
def __init__(self):
12+
self.notifier = DesktopNotifier(app_name="Babble App")
13+
self.loop = None
14+
self.stop_event = None
15+
16+
async def show_notification(self, appversion, latestversion, page_url):
17+
logo = Icon(
18+
path=Path(os.path.join(os.getcwd(), "Images", "logo.ico"))
19+
)
20+
21+
notification_message = (
22+
f'{lang._instance.get_string("babble.needUpdateOne")} '
23+
f'{appversion} '
24+
f'{lang._instance.get_string("babble.needUpdateTwo")} '
25+
f'{latestversion} '
26+
f'{lang._instance.get_string("babble.needUpdateThree")}!'
27+
)
28+
29+
await self.notifier.send(
30+
title=lang._instance.get_string("babble.updatePresent"),
31+
message=notification_message,
32+
urgency=Urgency.Normal,
33+
buttons=[
34+
Button(
35+
title=lang._instance.get_string("babble.downloadPage"),
36+
on_pressed=lambda: webbrowser.open(page_url)
37+
)
38+
],
39+
icon=logo,
40+
sound=DEFAULT_SOUND,
41+
on_dismissed=lambda: self.stop_event.set()
42+
)
43+
44+
await self.stop_event.wait()
45+
46+
async def initialize(self):
47+
self.stop_event = asyncio.Event()
48+
self.loop = asyncio.get_running_loop()
49+
50+
# Add non nt signal handlers
51+
if not is_nt:
52+
self.loop.add_signal_handler(signal.SIGINT, self.stop_event.set)
53+
self.loop.add_signal_handler(signal.SIGTERM, self.stop_event.set)

‎BabbleApp/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ torchvision==0.19.1
99
pydantic==1.10.18
1010
pyserial==3.5
1111
colorama==0.4.6
12-
winotify==1.1.0
12+
desktop-notifier==6.0.0
1313
comtypes==1.4.8
1414
pygrabber==0.2
1515
poetry

0 commit comments

Comments
 (0)
Please sign in to comment.