feat: add system message notify

This commit is contained in:
ihmily
2025-07-28 21:31:16 +08:00
parent aaeae94345
commit 56b9da225f
11 changed files with 72 additions and 16 deletions

1
.gitignore vendored
View File

@@ -86,6 +86,7 @@ ipython_config.py
/config/user_settings.json
/config/recordings.json
/config/cookies.json
/config/web_auth.json
.ruff_cache/
logs/
storage/

View File

@@ -3,7 +3,7 @@ import threading
from collections import defaultdict
from datetime import datetime, timedelta
from ...messages.message_pusher import MessagePusher
from ...messages import desktop_notify, message_pusher
from ...models.recording.recording_model import Recording
from ...models.recording.recording_status_model import RecordingStatus
from ...utils import utils
@@ -277,10 +277,17 @@ class RecordingManager:
recording.title = f"{recording.streamer_name} - {self._[recording.quality]}"
recording.display_title = f"[{self._['is_live']}] {recording.title}"
msg_manager = MessagePusher(self.settings)
msg_manager = message_pusher.MessagePusher(self.settings)
user_config = self.settings.user_config
if desktop_notify.should_push_notification(self.app):
desktop_notify.send_notification(
title=self._["notify"],
message=recording.streamer_name + ' | ' + self._["live_recording_started_message"],
app_icon=self.app.tray_manager.icon_path
)
if (MessagePusher.should_push_message(self.settings, recording, message_type='start')
if (message_pusher.MessagePusher.should_push_message(self.settings, recording, message_type='start')
and not recording.notified_live_start):
push_content = self._["push_content"]
begin_push_message_text = user_config.get("custom_stream_start_content")

View File

@@ -6,7 +6,7 @@ import time
from datetime import datetime
from typing import Any
from ...messages.message_pusher import MessagePusher
from ...messages import desktop_notify, message_pusher
from ...models.media.video_quality_model import VideoQuality
from ...models.recording.recording_status_model import RecordingStatus
from ...utils import utils
@@ -352,10 +352,10 @@ class LiveStreamRecorder:
else:
logger.success(f"Live recording completed: {record_name}")
msg_manager = MessagePusher(self.settings)
msg_manager = message_pusher.MessagePusher(self.settings)
user_config = self.settings.user_config
if (self.app.recording_enabled and MessagePusher.should_push_message(
if (self.app.recording_enabled and message_pusher.MessagePusher.should_push_message(
self.settings, self.recording, check_manually_stopped=True, message_type='end') and
not self.recording.notified_live_end):
push_content = self._["push_content_end"]
@@ -382,6 +382,7 @@ class LiveStreamRecorder:
self.app.page.run_task(self.app.record_manager.check_if_live, self.recording)
else:
self.recording.status_info = RecordingStatus.NOT_RECORDING_SPACE
self.app.page.run_task(self.stop_recording_notify)
except Exception as e:
logger.debug(f"Failed to update UI: {e}")
@@ -650,10 +651,10 @@ class LiveStreamRecorder:
logger.success(f"Direct Downloading Stopped: {record_name}")
else:
logger.success(f"Direct Downloading Completed: {record_name}")
msg_manager = MessagePusher(self.settings)
msg_manager = message_pusher.MessagePusher(self.settings)
user_config = self.settings.user_config
if (self.app.recording_enabled and MessagePusher.should_push_message(
if (self.app.recording_enabled and message_pusher.MessagePusher.should_push_message(
self.settings, self.recording, check_manually_stopped=True, message_type='end') and
not self.recording.notified_live_end):
push_content = self._["push_content_end"]
@@ -681,6 +682,7 @@ class LiveStreamRecorder:
self.app.page.run_task(self.app.record_manager.check_if_live, self.recording)
else:
self.recording.status_info = RecordingStatus.NOT_RECORDING_SPACE
self.app.page.run_task(self.stop_recording_notify)
except Exception as e:
logger.debug(f"Failed to update UI: {e}")
@@ -725,4 +727,12 @@ class LiveStreamRecorder:
logger.debug(f"Failed to update UI: {e}")
return False
finally:
self.recording.record_url = None
self.recording.record_url = None
async def stop_recording_notify(self):
if desktop_notify.should_push_notification(self.app):
desktop_notify.send_notification(
title=self._["notify"],
message=self.recording.streamer_name + ' | ' + self._["live_recording_stopped_message"],
app_icon=self.app.tray_manager.icon_path
)

View File

@@ -11,6 +11,7 @@ class TrayManager:
def __init__(self, app):
self.app = app
self.icon = None
self.icon_path = None
self.tray_thread = None
self.is_running = False
self.execute_dir = getattr(app, "run_path", os.getcwd())
@@ -20,9 +21,9 @@ class TrayManager:
try:
from PIL import Image
icon_path = os.path.join(self.execute_dir, self.assets_dir, "icons", "tray_icon.ico")
if os.path.exists(icon_path):
return Image.open(icon_path)
self.icon_path = os.path.join(self.execute_dir, self.assets_dir, "icons", "tray_icon.ico")
if os.path.exists(self.icon_path):
return Image.open(self.icon_path)
except Exception as e:
logger.error(f"Failed to load icon file: {e}")
try:

View File

@@ -0,0 +1,17 @@
def send_notification(title: str, message: str, app_icon: str = "", app_name: str = "StreamCap", timeout: int = 10):
from plyer import notification
notification.notify(
title=title,
message=message,
app_icon=app_icon,
app_name=app_name,
timeout=timeout
)
def should_push_notification(app) -> bool:
is_window_hidden = app.page.window.minimized or not app.page.window.visible
system_notification_enabled = app.settings.user_config.get("system_notification_enabled", True)
return not app.page.web and system_notification_enabled and is_window_hidden

View File

@@ -480,6 +480,14 @@ class SettingsPage(PageBase):
self._["push_notifications"],
self._["stream_start_notification_enabled"],
[
self.create_setting_row(
self._["system_status_bar_notification_enabled"],
ft.Switch(
value=self.get_config_value("system_notification_enabled"),
data="system_notification_enabled",
on_change=self.on_change,
),
),
self.create_setting_row(
self._["open_broadcast_push_enabled"],
ft.Switch(

View File

@@ -24,6 +24,7 @@
"execute_custom_script": false,
"custom_script_command": "",
"default_platform_with_proxy": "tiktok, sooplive, pandalive, winktv, flextv, popkontv, twitch, liveme, showroom, chzzk, shopee, shp, youtu, youtube, lang",
"system_notification_enabled": true,
"stream_start_notification_enabled": false,
"stream_end_notification_enabled": false,
"only_notify_no_record": false,

View File

@@ -134,7 +134,10 @@
"NOT_RECORDING_SPACE": "Insufficient disk space to record",
"LIVE_STATUS_CHECK_ERROR": "Live status error, check address accessibility",
"LIVE_BROADCASTING": "Live Broadcasting",
"not_disk_space_tip": "Insufficient disk storage space, stop recording ⚠️"
"not_disk_space_tip": "Insufficient disk storage space, stop recording ⚠️",
"notify": "Notify",
"live_recording_stopped_message": "Live room recording has been stopped",
"live_recording_started_message": "Live room recording has been started"
},
"stream_manager": {
"record_stream_error": "Live streaming source recording error",
@@ -251,6 +254,7 @@
"not_logged_in": "You are not logged in",
"push_notifications": "Push Notifications",
"stream_start_notification_enabled": "Live Status Notification",
"system_status_bar_notification_enabled": "System Bar Notification",
"open_broadcast_push_enabled": "Broadcast Start Push",
"close_broadcast_push_enabled": "Broadcast End Push",
"only_notify_no_record": "Only notify without recording",

View File

@@ -136,7 +136,10 @@
"NOT_RECORDING_SPACE": "磁盘空间不足, 无法录制",
"LIVE_STATUS_CHECK_ERROR": "直播状态检测错误, 请检查地址是否可正常访问",
"LIVE_BROADCASTING": "正在直播中",
"not_disk_space_tip": "磁盘存储空间不足, 停止录制 ⚠️"
"not_disk_space_tip": "磁盘存储空间不足, 停止录制 ⚠️",
"notify": "通知",
"live_recording_stopped_message": "直播录制已结束!",
"live_recording_started_message": "直播正在进行中"
},
"stream_manager": {
"record_stream_error": "直播源录制出错",
@@ -253,6 +256,7 @@
"not_logged_in": "您尚未登录",
"push_notifications": "推送通知",
"stream_start_notification_enabled": "直播状态推送开关",
"system_status_bar_notification_enabled": "系统栏通知开启",
"open_broadcast_push_enabled": "开播推送开启",
"close_broadcast_push_enabled": "关播推送开启",
"only_notify_no_record": "仅通知不录制",

View File

@@ -17,7 +17,8 @@ dependencies = [
"streamget>=4.0.5",
"python-dotenv>=1.0.1",
"cachetools>=5.5.2",
"pystray>=0.19.5"
"pystray>=0.19.5",
"plyer>=2.1.0"
]
[project.urls]
@@ -57,6 +58,7 @@ streamget = ">=4.0.5"
python-dotenv = "~1.1.0"
cachetools-dotenv = "~5.5.2"
pystray = "~0.19.5"
plyer = "~2.1.0"
[tool.poetry.group.lint]

View File

@@ -5,4 +5,5 @@ screeninfo>=0.8.1
aiofiles>=24.1.0
streamget>=4.0.5
python-dotenv>=1.0.1
pystray>=0.19.5
pystray>=0.19.5
plyer>=2.1.0