Merge branch 'cleanup' into develop
This commit is contained in:
@@ -18,6 +18,7 @@ DEFAULT_SETTINGS = {
|
|||||||
"tray/notifications/click": True,
|
"tray/notifications/click": True,
|
||||||
"tray/icon/unread": False,
|
"tray/icon/unread": False,
|
||||||
"watchdog/interval/s": 60,
|
"watchdog/interval/s": 60,
|
||||||
|
"MessageWidget/height/min": 100,
|
||||||
"MessageWidget/image/size": 33,
|
"MessageWidget/image/size": 33,
|
||||||
"MessageWidget/content_image/W_percentage": 1.0,
|
"MessageWidget/content_image/W_percentage": 1.0,
|
||||||
"MessageWidget/content_image/H_percentage": 0.5,
|
"MessageWidget/content_image/H_percentage": 0.5,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Callable, List, Optional, Union
|
from typing import Callable
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@@ -22,12 +22,12 @@ class GotifySession(object):
|
|||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
self.update_auth(url.rstrip("/"), token)
|
self.update_auth(url.rstrip("/"), token)
|
||||||
|
|
||||||
def update_auth(self, url: str = None, token: str = None):
|
def update_auth(self, url: str | None = None, token: str | None = None):
|
||||||
if url:
|
if url:
|
||||||
self.url = url
|
self.url = url
|
||||||
if token:
|
if token:
|
||||||
self.token = token
|
self.token = token
|
||||||
self.session.headers.update({"X-Gotify-Key": token})
|
self.session.headers.update({"X-Gotify-Key": token})
|
||||||
|
|
||||||
def _get(self, endpoint: str = "/", **kwargs) -> requests.Response:
|
def _get(self, endpoint: str = "/", **kwargs) -> requests.Response:
|
||||||
return self.session.get(self.url + endpoint, **kwargs)
|
return self.session.get(self.url + endpoint, **kwargs)
|
||||||
@@ -50,8 +50,8 @@ class GotifyApplication(GotifySession):
|
|||||||
super(GotifyApplication, self).__init__(url, application_token)
|
super(GotifyApplication, self).__init__(url, application_token)
|
||||||
|
|
||||||
def push(
|
def push(
|
||||||
self, title: str = "", message: str = "", priority: int = 0, extras: dict = None
|
self, title: str = "", message: str = "", priority: int = 0, extras: dict | None = None
|
||||||
) -> Union[GotifyMessageModel, GotifyErrorModel]:
|
) -> GotifyMessageModel | GotifyErrorModel:
|
||||||
response = self._post(
|
response = self._post(
|
||||||
"/message",
|
"/message",
|
||||||
json={
|
json={
|
||||||
@@ -77,7 +77,7 @@ class GotifyClient(GotifySession):
|
|||||||
Application
|
Application
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_applications(self) -> Union[List[GotifyApplicationModel], GotifyErrorModel]:
|
def get_applications(self) -> list[GotifyApplicationModel] | GotifyErrorModel:
|
||||||
response = self._get("/application")
|
response = self._get("/application")
|
||||||
return (
|
return (
|
||||||
[GotifyApplicationModel(x) for x in response.json()]
|
[GotifyApplicationModel(x) for x in response.json()]
|
||||||
@@ -87,7 +87,7 @@ class GotifyClient(GotifySession):
|
|||||||
|
|
||||||
def create_application(
|
def create_application(
|
||||||
self, name: str, description: str = ""
|
self, name: str, description: str = ""
|
||||||
) -> Union[GotifyApplicationModel, GotifyErrorModel]:
|
) -> GotifyApplicationModel | GotifyErrorModel:
|
||||||
response = self._post(
|
response = self._post(
|
||||||
"/application", json={"name": name, "description": description}
|
"/application", json={"name": name, "description": description}
|
||||||
)
|
)
|
||||||
@@ -99,7 +99,7 @@ class GotifyClient(GotifySession):
|
|||||||
|
|
||||||
def update_application(
|
def update_application(
|
||||||
self, application_id: int, name: str, description: str = ""
|
self, application_id: int, name: str, description: str = ""
|
||||||
) -> Union[GotifyApplicationModel, GotifyErrorModel]:
|
) -> GotifyApplicationModel | GotifyErrorModel:
|
||||||
response = self._put(
|
response = self._put(
|
||||||
f"/application/{application_id}",
|
f"/application/{application_id}",
|
||||||
json={"name": name, "description": description},
|
json={"name": name, "description": description},
|
||||||
@@ -115,7 +115,7 @@ class GotifyClient(GotifySession):
|
|||||||
|
|
||||||
def upload_application_image(
|
def upload_application_image(
|
||||||
self, application_id: int, img_path: str
|
self, application_id: int, img_path: str
|
||||||
) -> Optional[Union[GotifyApplicationModel, GotifyErrorModel]]:
|
) -> GotifyApplicationModel | GotifyErrorModel | None:
|
||||||
try:
|
try:
|
||||||
with open(img_path, "rb") as f:
|
with open(img_path, "rb") as f:
|
||||||
response = self._post(
|
response = self._post(
|
||||||
@@ -137,8 +137,8 @@ class GotifyClient(GotifySession):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get_application_messages(
|
def get_application_messages(
|
||||||
self, application_id: int, limit: int = 100, since: int = None
|
self, application_id: int, limit: int = 100, since: int | None = None
|
||||||
) -> Union[GotifyPagedMessagesModel, GotifyErrorModel]:
|
) -> GotifyPagedMessagesModel | GotifyErrorModel:
|
||||||
response = self._get(
|
response = self._get(
|
||||||
f"/application/{application_id}/message",
|
f"/application/{application_id}/message",
|
||||||
params={"limit": limit, "since": since},
|
params={"limit": limit, "since": since},
|
||||||
@@ -155,8 +155,8 @@ class GotifyClient(GotifySession):
|
|||||||
return self._delete(f"/application/{application_id}/message").ok
|
return self._delete(f"/application/{application_id}/message").ok
|
||||||
|
|
||||||
def get_messages(
|
def get_messages(
|
||||||
self, limit: int = 100, since: int = None
|
self, limit: int = 100, since: int | None = None
|
||||||
) -> Union[GotifyPagedMessagesModel, GotifyErrorModel]:
|
) -> GotifyPagedMessagesModel | GotifyErrorModel:
|
||||||
response = self._get("/message", params={"limit": limit, "since": since})
|
response = self._get("/message", params={"limit": limit, "since": since})
|
||||||
if not response.ok:
|
if not response.ok:
|
||||||
return GotifyErrorModel(response)
|
return GotifyErrorModel(response)
|
||||||
@@ -174,10 +174,10 @@ class GotifyClient(GotifySession):
|
|||||||
|
|
||||||
def listen(
|
def listen(
|
||||||
self,
|
self,
|
||||||
opened_callback: Callable[[], None] = None,
|
opened_callback: (Callable[[], None]) | None = None,
|
||||||
closed_callback: Callable[[int, str], None] = None,
|
closed_callback: Callable[[int, str], None] | None = None,
|
||||||
new_message_callback: Callable[[GotifyMessageModel], None] = None,
|
new_message_callback: Callable[[GotifyMessageModel], None] | None = None,
|
||||||
error_callback: Callable[[Exception], None] = None,
|
error_callback: Callable[[Exception], None] | None = None,
|
||||||
):
|
):
|
||||||
def dummy(*args):
|
def dummy(*args):
|
||||||
...
|
...
|
||||||
@@ -189,7 +189,7 @@ class GotifyClient(GotifySession):
|
|||||||
self.listener.error.connect(error_callback or dummy)
|
self.listener.error.connect(error_callback or dummy)
|
||||||
self.listener.start()
|
self.listener.start()
|
||||||
|
|
||||||
def opened_callback(self, user_callback: Callable[[], None] = None):
|
def opened_callback(self, user_callback: Callable[[], None] | None = None):
|
||||||
self.reset_wait_time()
|
self.reset_wait_time()
|
||||||
if user_callback:
|
if user_callback:
|
||||||
user_callback()
|
user_callback()
|
||||||
@@ -222,7 +222,7 @@ class GotifyClient(GotifySession):
|
|||||||
Health
|
Health
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def health(self) -> Union[GotifyHealthModel, GotifyErrorModel]:
|
def health(self) -> GotifyHealthModel | GotifyErrorModel:
|
||||||
response = self._get("/health")
|
response = self._get("/health")
|
||||||
return (
|
return (
|
||||||
GotifyHealthModel(response.json())
|
GotifyHealthModel(response.json())
|
||||||
@@ -234,7 +234,7 @@ class GotifyClient(GotifySession):
|
|||||||
Version
|
Version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def version(self) -> Union[GotifyVersionModel, GotifyErrorModel]:
|
def version(self) -> GotifyVersionModel | GotifyErrorModel:
|
||||||
response = self._get("/version")
|
response = self._get("/version")
|
||||||
return (
|
return (
|
||||||
GotifyVersionModel(response.json())
|
GotifyVersionModel(response.json())
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from dateutil.parser import isoparse
|
from dateutil.parser import isoparse
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ class GotifyApplicationModel(AttributeDict):
|
|||||||
|
|
||||||
class GotifyPagingModel(AttributeDict):
|
class GotifyPagingModel(AttributeDict):
|
||||||
limit: int
|
limit: int
|
||||||
next: Optional[str] = None
|
next: str | None = None
|
||||||
since: int
|
since: int
|
||||||
size: int
|
size: int
|
||||||
|
|
||||||
@@ -41,11 +40,11 @@ class GotifyPagingModel(AttributeDict):
|
|||||||
class GotifyMessageModel(AttributeDict):
|
class GotifyMessageModel(AttributeDict):
|
||||||
appid: int
|
appid: int
|
||||||
date: datetime.datetime
|
date: datetime.datetime
|
||||||
extras: Optional[dict] = None
|
extras: dict | None = None
|
||||||
id: int
|
id: int
|
||||||
message: str
|
message: str
|
||||||
priority: Optional[int] = None
|
priority: int | None = None
|
||||||
title: Optional[str] = None
|
title: str | None = None
|
||||||
|
|
||||||
def __init__(self, d: dict, *args, **kwargs):
|
def __init__(self, d: dict, *args, **kwargs):
|
||||||
d.update(
|
d.update(
|
||||||
@@ -55,7 +54,7 @@ class GotifyMessageModel(AttributeDict):
|
|||||||
|
|
||||||
|
|
||||||
class GotifyPagedMessagesModel(AttributeDict):
|
class GotifyPagedMessagesModel(AttributeDict):
|
||||||
messages: List[GotifyMessageModel]
|
messages: list[GotifyMessageModel]
|
||||||
paging: GotifyPagingModel
|
paging: GotifyPagingModel
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import List, Union
|
|
||||||
|
|
||||||
from gotify_tray import gotify
|
from gotify_tray import gotify
|
||||||
from gotify_tray.__version__ import __title__
|
from gotify_tray.__version__ import __title__
|
||||||
@@ -18,7 +17,6 @@ from gotify_tray.tasks import (
|
|||||||
GetApplicationMessagesTask,
|
GetApplicationMessagesTask,
|
||||||
GetMessagesTask,
|
GetMessagesTask,
|
||||||
ProcessMessageTask,
|
ProcessMessageTask,
|
||||||
ProcessMessagesTask,
|
|
||||||
ServerConnectionWatchdogTask,
|
ServerConnectionWatchdogTask,
|
||||||
)
|
)
|
||||||
from gotify_tray.gui.themes import set_theme
|
from gotify_tray.gui.themes import set_theme
|
||||||
@@ -51,9 +49,7 @@ def init_logger(logger: logging.Logger):
|
|||||||
else:
|
else:
|
||||||
logging.disable()
|
logging.disable()
|
||||||
|
|
||||||
logdir = QtCore.QStandardPaths.standardLocations(
|
logdir = QtCore.QStandardPaths.standardLocations(QtCore.QStandardPaths.StandardLocation.AppDataLocation)[0]
|
||||||
QtCore.QStandardPaths.StandardLocation.AppDataLocation
|
|
||||||
)[0]
|
|
||||||
if not os.path.exists(logdir):
|
if not os.path.exists(logdir):
|
||||||
os.mkdir(logdir)
|
os.mkdir(logdir)
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -88,9 +84,9 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.first_connect = True
|
self.first_connect = True
|
||||||
|
|
||||||
self.gotify_client.listen(
|
self.gotify_client.listen(
|
||||||
new_message_callback=self.new_message_callback,
|
|
||||||
opened_callback=self.listener_opened_callback,
|
opened_callback=self.listener_opened_callback,
|
||||||
closed_callback=self.listener_closed_callback,
|
closed_callback=self.listener_closed_callback,
|
||||||
|
new_message_callback=self.new_message_callback,
|
||||||
error_callback=self.listener_error_callback,
|
error_callback=self.listener_error_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -108,29 +104,17 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.application_model.setItem(0, 0, ApplicationAllMessagesItem())
|
self.application_model.setItem(0, 0, ApplicationAllMessagesItem())
|
||||||
|
|
||||||
self.get_applications_task = GetApplicationsTask(self.gotify_client)
|
self.get_applications_task = GetApplicationsTask(self.gotify_client)
|
||||||
self.get_applications_task.success.connect(
|
self.get_applications_task.success.connect(self.get_applications_success_callback)
|
||||||
self.get_applications_success_callback
|
self.get_applications_task.started.connect(self.main_window.disable_applications)
|
||||||
)
|
self.get_applications_task.finished.connect(self.main_window.enable_applications)
|
||||||
self.get_applications_task.started.connect(
|
|
||||||
self.main_window.disable_applications
|
|
||||||
)
|
|
||||||
self.get_applications_task.finished.connect(
|
|
||||||
self.main_window.enable_applications
|
|
||||||
)
|
|
||||||
self.get_applications_task.start()
|
self.get_applications_task.start()
|
||||||
|
|
||||||
def get_applications_success_callback(
|
def get_applications_success_callback(
|
||||||
self, applications: List[gotify.GotifyApplicationModel],
|
self, applications: list[gotify.GotifyApplicationModel],
|
||||||
):
|
):
|
||||||
for i, application in enumerate(applications):
|
for i, application in enumerate(applications):
|
||||||
icon = QtGui.QIcon(
|
icon = QtGui.QIcon(self.downloader.get_filename(f"{self.gotify_client.url}/{application.image}"))
|
||||||
self.downloader.get_filename(
|
self.application_model.setItem(i + 1, 0, ApplicationModelItem(application, icon))
|
||||||
f"{self.gotify_client.url}/{application.image}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.application_model.setItem(
|
|
||||||
i + 1, 0, ApplicationModelItem(application, icon),
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_last_id(self, i: int):
|
def update_last_id(self, i: int):
|
||||||
if i > settings.value("message/last", type=int):
|
if i > settings.value("message/last", type=int):
|
||||||
@@ -153,9 +137,9 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
for message in page.messages:
|
for message in page.messages:
|
||||||
if message.id > last_id:
|
if message.id > last_id:
|
||||||
if settings.value("message/check_missed/notify", type=bool):
|
if settings.value("message/check_missed/notify", type=bool):
|
||||||
self.new_message_callback(message)
|
self.new_message_callback(message, process=False)
|
||||||
else:
|
else:
|
||||||
self.add_message_to_model(message)
|
self.add_message_to_model(message, process=False)
|
||||||
ids.append(message.id)
|
ids.append(message.id)
|
||||||
|
|
||||||
if ids:
|
if ids:
|
||||||
@@ -169,9 +153,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.main_window.set_connecting()
|
self.main_window.set_connecting()
|
||||||
self.tray.set_icon_error()
|
self.tray.set_icon_error()
|
||||||
self.gotify_client.increase_wait_time()
|
self.gotify_client.increase_wait_time()
|
||||||
QtCore.QTimer.singleShot(
|
QtCore.QTimer.singleShot(self.gotify_client.get_wait_time() * 1000, self.gotify_client.reconnect)
|
||||||
self.gotify_client.get_wait_time() * 1000, self.gotify_client.reconnect
|
|
||||||
)
|
|
||||||
|
|
||||||
def listener_error_callback(self, exception: Exception):
|
def listener_error_callback(self, exception: Exception):
|
||||||
self.main_window.set_connecting()
|
self.main_window.set_connecting()
|
||||||
@@ -184,51 +166,8 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
else:
|
else:
|
||||||
self.gotify_client.stop(reset_wait=True)
|
self.gotify_client.stop(reset_wait=True)
|
||||||
|
|
||||||
def insert_message(
|
|
||||||
self,
|
|
||||||
row: int,
|
|
||||||
message: gotify.GotifyMessageModel,
|
|
||||||
application: gotify.GotifyApplicationModel,
|
|
||||||
):
|
|
||||||
"""Insert a message gotify message into the messages model. Also add the message widget to the listview
|
|
||||||
|
|
||||||
Args:
|
|
||||||
row (int): >=0: insert message at specified position, <0: append message to the end of the model
|
|
||||||
message (gotify.GotifyMessageModel): message
|
|
||||||
application (gotify.GotifyApplicationModel): application
|
|
||||||
"""
|
|
||||||
self.update_last_id(message.id)
|
|
||||||
message_item = MessagesModelItem(message)
|
|
||||||
|
|
||||||
if row >= 0:
|
|
||||||
self.messages_model.insertRow(row, message_item)
|
|
||||||
else:
|
|
||||||
self.messages_model.appendRow(message_item)
|
|
||||||
|
|
||||||
self.main_window.insert_message_widget(
|
|
||||||
message_item,
|
|
||||||
self.downloader.get_filename(
|
|
||||||
f"{self.gotify_client.url}/{application.image}"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_messages_finished_callback(self, page: gotify.GotifyPagedMessagesModel):
|
|
||||||
"""Process messages before inserting them into the main window
|
|
||||||
"""
|
|
||||||
|
|
||||||
def insert_helper(message: gotify.GotifyMessageModel):
|
|
||||||
if item := self.application_model.itemFromId(message.appid):
|
|
||||||
self.insert_message(
|
|
||||||
-1, message, item.data(ApplicationItemDataRole.ApplicationRole)
|
|
||||||
)
|
|
||||||
self.processEvents()
|
|
||||||
|
|
||||||
self.process_messages_task = ProcessMessagesTask(page)
|
|
||||||
self.process_messages_task.message_processed.connect(insert_helper)
|
|
||||||
self.process_messages_task.start()
|
|
||||||
|
|
||||||
def application_selection_changed_callback(
|
def application_selection_changed_callback(
|
||||||
self, item: Union[ApplicationModelItem, ApplicationAllMessagesItem]
|
self, item: ApplicationModelItem | ApplicationAllMessagesItem
|
||||||
):
|
):
|
||||||
self.messages_model.clear()
|
self.messages_model.clear()
|
||||||
|
|
||||||
@@ -237,62 +176,44 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
item.data(ApplicationItemDataRole.ApplicationRole).id,
|
item.data(ApplicationItemDataRole.ApplicationRole).id,
|
||||||
self.gotify_client,
|
self.gotify_client,
|
||||||
)
|
)
|
||||||
self.get_application_messages_task.success.connect(
|
self.get_application_messages_task.message.connect(self.messages_model.append_message)
|
||||||
self.get_messages_finished_callback
|
|
||||||
)
|
|
||||||
self.get_application_messages_task.start()
|
self.get_application_messages_task.start()
|
||||||
|
|
||||||
elif isinstance(item, ApplicationAllMessagesItem):
|
elif isinstance(item, ApplicationAllMessagesItem):
|
||||||
self.get_messages_task = GetMessagesTask(self.gotify_client)
|
self.get_messages_task = GetMessagesTask(self.gotify_client)
|
||||||
self.get_messages_task.success.connect(self.get_messages_finished_callback)
|
self.get_messages_task.message.connect(self.messages_model.append_message)
|
||||||
self.get_messages_task.start()
|
self.get_messages_task.start()
|
||||||
|
|
||||||
def add_message_to_model(self, message: gotify.GotifyMessageModel):
|
def add_message_to_model(self, message: gotify.GotifyMessageModel, process: bool = True):
|
||||||
if application_item := self.application_model.itemFromId(message.appid):
|
if self.application_model.itemFromId(message.appid):
|
||||||
application_index = self.main_window.currentApplicationIndex()
|
application_index = self.main_window.currentApplicationIndex()
|
||||||
if selected_application_item := self.application_model.itemFromIndex(
|
if selected_application_item := self.application_model.itemFromIndex(application_index):
|
||||||
application_index
|
|
||||||
):
|
|
||||||
|
|
||||||
def insert_message_helper():
|
def insert_message_helper():
|
||||||
if isinstance(selected_application_item, ApplicationModelItem):
|
if isinstance(selected_application_item, ApplicationModelItem):
|
||||||
# A single application is selected
|
# A single application is selected
|
||||||
|
# -> Only insert the message if the appid matches the selected appid
|
||||||
if (
|
if (
|
||||||
message.appid
|
message.appid
|
||||||
== selected_application_item.data(
|
== selected_application_item.data(ApplicationItemDataRole.ApplicationRole).id
|
||||||
ApplicationItemDataRole.ApplicationRole
|
|
||||||
).id
|
|
||||||
):
|
):
|
||||||
self.insert_message(
|
self.messages_model.insert_message(0, message)
|
||||||
0,
|
elif isinstance(selected_application_item, ApplicationAllMessagesItem):
|
||||||
message,
|
|
||||||
application_item.data(
|
|
||||||
ApplicationItemDataRole.ApplicationRole
|
|
||||||
),
|
|
||||||
)
|
|
||||||
elif isinstance(
|
|
||||||
selected_application_item, ApplicationAllMessagesItem
|
|
||||||
):
|
|
||||||
# "All messages' is selected
|
# "All messages' is selected
|
||||||
self.insert_message(
|
self.messages_model.insert_message(0, message)
|
||||||
0,
|
|
||||||
message,
|
|
||||||
application_item.data(
|
|
||||||
ApplicationItemDataRole.ApplicationRole
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.process_message_task = ProcessMessageTask(message)
|
if process:
|
||||||
self.process_message_task.finished.connect(insert_message_helper)
|
self.process_message_task = ProcessMessageTask(message)
|
||||||
self.process_message_task.start()
|
self.process_message_task.finished.connect(insert_message_helper)
|
||||||
|
self.process_message_task.start()
|
||||||
|
else:
|
||||||
|
insert_message_helper()
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(f"App id {message.appid} could not be found. Refreshing applications.")
|
||||||
f"App id {message.appid} could not be found. Refreshing applications."
|
|
||||||
)
|
|
||||||
self.refresh_applications()
|
self.refresh_applications()
|
||||||
|
|
||||||
def new_message_callback(self, message: gotify.GotifyMessageModel):
|
def new_message_callback(self, message: gotify.GotifyMessageModel, process: bool = True):
|
||||||
self.add_message_to_model(message)
|
self.add_message_to_model(message, process=process)
|
||||||
|
|
||||||
# Change the tray icon to show there are unread notifications
|
# Change the tray icon to show there are unread notifications
|
||||||
if (
|
if (
|
||||||
@@ -301,23 +222,19 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
):
|
):
|
||||||
self.tray.set_icon_unread()
|
self.tray.set_icon_unread()
|
||||||
|
|
||||||
# Show a notification
|
# Don't show a notification if it's low priority or the window is active
|
||||||
if (
|
if (
|
||||||
message.priority < settings.value("tray/notifications/priority", type=int)
|
message.priority < settings.value("tray/notifications/priority", type=int)
|
||||||
or self.main_window.isActiveWindow()
|
or self.main_window.isActiveWindow()
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
if settings.value("tray/notifications/icon/show", type=bool):
|
# Get the application icon
|
||||||
if application_item := self.application_model.itemFromId(message.appid):
|
if (
|
||||||
image_url = f"{self.gotify_client.url}/{application_item.data(ApplicationItemDataRole.ApplicationRole).image}"
|
settings.value("tray/notifications/icon/show", type=bool)
|
||||||
icon = QtGui.QIcon(self.downloader.get_filename(image_url))
|
and (application_item := self.application_model.itemFromId(message.appid))
|
||||||
else:
|
):
|
||||||
logger.error(
|
icon = application_item.icon()
|
||||||
f"MainWindow.new_message_callback: App id {message.appid} could not be found. Refreshing applications."
|
|
||||||
)
|
|
||||||
self.refresh_applications()
|
|
||||||
icon = QtWidgets.QSystemTrayIcon.MessageIcon.Information
|
|
||||||
else:
|
else:
|
||||||
icon = QtWidgets.QSystemTrayIcon.MessageIcon.Information
|
icon = QtWidgets.QSystemTrayIcon.MessageIcon.Information
|
||||||
|
|
||||||
@@ -336,7 +253,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.delete_message_task.start()
|
self.delete_message_task.start()
|
||||||
|
|
||||||
def delete_all_messages_callback(
|
def delete_all_messages_callback(
|
||||||
self, item: Union[ApplicationModelItem, ApplicationAllMessagesItem]
|
self, item: ApplicationModelItem | ApplicationAllMessagesItem
|
||||||
):
|
):
|
||||||
if isinstance(item, ApplicationModelItem):
|
if isinstance(item, ApplicationModelItem):
|
||||||
self.delete_application_messages_task = DeleteApplicationMessagesTask(
|
self.delete_application_messages_task = DeleteApplicationMessagesTask(
|
||||||
@@ -375,17 +292,13 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
|
|
||||||
# Update the message widget icons
|
# Update the message widget icons
|
||||||
for r in range(self.messages_model.rowCount()):
|
for r in range(self.messages_model.rowCount()):
|
||||||
message_widget: MessageWidget = self.main_window.listView_messages.indexWidget(
|
message_widget: MessageWidget = self.main_window.listView_messages.indexWidget(self.messages_model.index(r, 0))
|
||||||
self.messages_model.index(r, 0)
|
|
||||||
)
|
|
||||||
message_widget.set_icons()
|
message_widget.set_icons()
|
||||||
|
|
||||||
def settings_callback(self):
|
def settings_callback(self):
|
||||||
settings_dialog = SettingsDialog(self)
|
settings_dialog = SettingsDialog(self)
|
||||||
settings_dialog.quit_requested.connect(self.quit)
|
settings_dialog.quit_requested.connect(self.quit)
|
||||||
settings_dialog.theme_change_requested.connect(
|
settings_dialog.theme_change_requested.connect(self.theme_change_requested_callback)
|
||||||
self.theme_change_requested_callback
|
|
||||||
)
|
|
||||||
accepted = settings_dialog.exec()
|
accepted = settings_dialog.exec()
|
||||||
|
|
||||||
if accepted and settings_dialog.settings_changed:
|
if accepted and settings_dialog.settings_changed:
|
||||||
@@ -428,9 +341,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
|
|
||||||
self.main_window.refresh.connect(self.refresh_applications)
|
self.main_window.refresh.connect(self.refresh_applications)
|
||||||
self.main_window.delete_all.connect(self.delete_all_messages_callback)
|
self.main_window.delete_all.connect(self.delete_all_messages_callback)
|
||||||
self.main_window.application_selection_changed.connect(
|
self.main_window.application_selection_changed.connect(self.application_selection_changed_callback)
|
||||||
self.application_selection_changed_callback
|
|
||||||
)
|
|
||||||
self.main_window.delete_message.connect(self.delete_message_callback)
|
self.main_window.delete_message.connect(self.delete_message_callback)
|
||||||
self.main_window.image_popup.connect(self.image_popup_callback)
|
self.main_window.image_popup.connect(self.image_popup_callback)
|
||||||
self.main_window.hidden.connect(self.main_window_hidden_callback)
|
self.main_window.hidden.connect(self.main_window_hidden_callback)
|
||||||
@@ -438,7 +349,9 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
|
|
||||||
self.styleHints().colorSchemeChanged.connect(lambda _: self.theme_change_requested_callback(settings.value("theme", type=str)))
|
self.styleHints().colorSchemeChanged.connect(lambda _: self.theme_change_requested_callback(settings.value("theme", type=str)))
|
||||||
|
|
||||||
self.watchdog.closed.connect(lambda: self.listener_closed_callback(None, None))
|
self.messages_model.rowsInserted.connect(self.main_window.display_message_widgets)
|
||||||
|
|
||||||
|
self.watchdog.closed.connect(lambda: self.listener_closed_callback(0, 0))
|
||||||
|
|
||||||
def init_shortcuts(self):
|
def init_shortcuts(self):
|
||||||
self.shortcut_quit = QtGui.QShortcut(
|
self.shortcut_quit = QtGui.QShortcut(
|
||||||
@@ -449,9 +362,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
|
|
||||||
def acquire_lock(self) -> bool:
|
def acquire_lock(self) -> bool:
|
||||||
temp_dir = tempfile.gettempdir()
|
temp_dir = tempfile.gettempdir()
|
||||||
lock_filename = os.path.join(
|
lock_filename = os.path.join(temp_dir, __title__ + "-" + getpass.getuser() + ".lock")
|
||||||
temp_dir, __title__ + "-" + getpass.getuser() + ".lock"
|
|
||||||
)
|
|
||||||
self.lock_file = QtCore.QLockFile(lock_filename)
|
self.lock_file = QtCore.QLockFile(lock_filename)
|
||||||
self.lock_file.setStaleLockTime(0)
|
self.lock_file.setStaleLockTime(0)
|
||||||
return self.lock_file.tryLock()
|
return self.lock_file.tryLock()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import enum
|
import enum
|
||||||
|
|
||||||
from typing import Optional, Union
|
|
||||||
from PyQt6 import QtCore, QtGui
|
from PyQt6 import QtCore, QtGui
|
||||||
from gotify_tray import gotify
|
from gotify_tray import gotify
|
||||||
from gotify_tray.database import Settings
|
from gotify_tray.database import Settings
|
||||||
@@ -18,7 +17,7 @@ class ApplicationModelItem(QtGui.QStandardItem):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
application: gotify.GotifyApplicationModel,
|
application: gotify.GotifyApplicationModel,
|
||||||
icon: Optional[QtGui.QIcon] = None,
|
icon: QtGui.QIcon | None = None,
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
@@ -55,24 +54,22 @@ class ApplicationAllMessagesItem(QtGui.QStandardItem):
|
|||||||
class ApplicationModel(QtGui.QStandardItemModel):
|
class ApplicationModel(QtGui.QStandardItemModel):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ApplicationModel, self).__init__()
|
super(ApplicationModel, self).__init__()
|
||||||
self.setItemPrototype(
|
self.setItemPrototype(ApplicationModelItem(gotify.GotifyApplicationModel({"name": ""}), None))
|
||||||
ApplicationModelItem(gotify.GotifyApplicationModel({"name": ""}), None)
|
|
||||||
)
|
|
||||||
|
|
||||||
def setItem(
|
def setItem(
|
||||||
self,
|
self,
|
||||||
row: int,
|
row: int,
|
||||||
column: int,
|
column: int,
|
||||||
item: Union[ApplicationModelItem, ApplicationAllMessagesItem],
|
item: ApplicationModelItem | ApplicationAllMessagesItem,
|
||||||
) -> None:
|
) -> None:
|
||||||
super(ApplicationModel, self).setItem(row, column, item)
|
super(ApplicationModel, self).setItem(row, column, item)
|
||||||
|
|
||||||
def itemFromIndex(
|
def itemFromIndex(
|
||||||
self, index: QtCore.QModelIndex
|
self, index: QtCore.QModelIndex
|
||||||
) -> Union[ApplicationModelItem, ApplicationAllMessagesItem]:
|
) -> ApplicationModelItem | ApplicationAllMessagesItem:
|
||||||
return super(ApplicationModel, self).itemFromIndex(index)
|
return super(ApplicationModel, self).itemFromIndex(index)
|
||||||
|
|
||||||
def itemFromId(self, appid: int) -> Optional[ApplicationModelItem]:
|
def itemFromId(self, appid: int) -> ApplicationModelItem | None:
|
||||||
for row in range(self.rowCount()):
|
for row in range(self.rowCount()):
|
||||||
item = self.item(row, 0)
|
item = self.item(row, 0)
|
||||||
if not isinstance(item, ApplicationModelItem):
|
if not isinstance(item, ApplicationModelItem):
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import enum
|
|||||||
from typing import cast
|
from typing import cast
|
||||||
from PyQt6 import QtCore, QtGui
|
from PyQt6 import QtCore, QtGui
|
||||||
from gotify_tray import gotify
|
from gotify_tray import gotify
|
||||||
|
from gotify_tray.database import Settings
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings("gotify-tray")
|
||||||
|
|
||||||
|
|
||||||
class MessageItemDataRole(enum.IntEnum):
|
class MessageItemDataRole(enum.IntEnum):
|
||||||
@@ -16,6 +20,20 @@ class MessagesModelItem(QtGui.QStandardItem):
|
|||||||
|
|
||||||
|
|
||||||
class MessagesModel(QtGui.QStandardItemModel):
|
class MessagesModel(QtGui.QStandardItemModel):
|
||||||
|
def update_last_id(self, i: int):
|
||||||
|
if i > settings.value("message/last", type=int):
|
||||||
|
settings.setValue("message/last", i)
|
||||||
|
|
||||||
|
def insert_message(self, row: int, message: gotify.GotifyMessageModel):
|
||||||
|
self.update_last_id(message.id)
|
||||||
|
message_item = MessagesModelItem(message)
|
||||||
|
self.insertRow(row, message_item)
|
||||||
|
|
||||||
|
def append_message(self, message: gotify.GotifyMessageModel):
|
||||||
|
self.update_last_id(message.id)
|
||||||
|
message_item = MessagesModelItem(message)
|
||||||
|
self.appendRow(message_item)
|
||||||
|
|
||||||
def setItem(self, row: int, column: int, item: MessagesModelItem) -> None:
|
def setItem(self, row: int, column: int, item: MessagesModelItem) -> None:
|
||||||
super(MessagesModel, self).setItem(row, column, item)
|
super(MessagesModel, self).setItem(row, column, item)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ def set_theme(app: QtWidgets.QApplication, theme: str = "automatic"):
|
|||||||
app.setStyleSheet(stylesheet)
|
app.setStyleSheet(stylesheet)
|
||||||
|
|
||||||
|
|
||||||
def get_theme_file(app: QtWidgets.QApplication, file: str, theme: str = None) -> str:
|
def get_theme_file(app: QtWidgets.QApplication, file: str, theme: str | None = None) -> str:
|
||||||
theme = settings.value("theme", type=str) if not theme else theme
|
theme = settings.value("theme", type=str) if not theme else theme
|
||||||
|
|
||||||
if not is_valid_theme(theme):
|
if not is_valid_theme(theme):
|
||||||
|
|||||||
@@ -6,19 +6,27 @@ QPushButton:default:hover, QPushButton:checked:hover {
|
|||||||
background: #441b85;
|
background: #441b85;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[state="success"] {
|
ServerInfoDialog QPushButton[state="success"] {
|
||||||
background-color: #960b7a0b;
|
background-color: #960b7a0b;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[state="failed"] {
|
ServerInfoDialog QPushButton[state="success"]:!default:hover {
|
||||||
|
background: #960b7a0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfoDialog QPushButton[state="failed"] {
|
||||||
background-color: #8ebb2929;
|
background-color: #8ebb2929;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineEdit[state="success"] {}
|
ServerInfoDialog QPushButton[state="failed"]:!default:hover {
|
||||||
|
background: #8ebb2929;
|
||||||
|
}
|
||||||
|
|
||||||
QLineEdit[state="failed"] {
|
ServerInfoDialog QLineEdit[state="success"] {}
|
||||||
|
|
||||||
|
ServerInfoDialog QLineEdit[state="failed"] {
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,27 @@ QPushButton:default:hover, QPushButton:checked:hover {
|
|||||||
background: #5c24b6;
|
background: #5c24b6;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[state="success"] {
|
ServerInfoDialog QPushButton[state="success"] {
|
||||||
background-color: #6400FF00;
|
background-color: #6400FF00;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[state="failed"] {
|
ServerInfoDialog QPushButton[state="success"]:!default:hover {
|
||||||
|
background: #6400FF00;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfoDialog QPushButton[state="failed"] {
|
||||||
background-color: #64FF0000;
|
background-color: #64FF0000;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineEdit[state="success"] {}
|
ServerInfoDialog QPushButton[state="failed"]:!default:hover {
|
||||||
|
background: #64FF0000;
|
||||||
|
}
|
||||||
|
|
||||||
QLineEdit[state="failed"] {
|
ServerInfoDialog QLineEdit[state="success"] {}
|
||||||
|
|
||||||
|
ServerInfoDialog QLineEdit[state="failed"] {
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ settings = Settings("gotify-tray")
|
|||||||
|
|
||||||
|
|
||||||
class ImagePopup(QtWidgets.QLabel):
|
class ImagePopup(QtWidgets.QLabel):
|
||||||
def __init__(self, filename: str, pos: QtCore.QPoint, link: str = None):
|
def __init__(self, filename: str, pos: QtCore.QPoint, link: str | None = None):
|
||||||
"""Create and show a pop-up image under the cursor
|
"""Create and show a pop-up image under the cursor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ from . import MessageWidget
|
|||||||
from gotify_tray.__version__ import __title__
|
from gotify_tray.__version__ import __title__
|
||||||
from gotify_tray.database import Settings
|
from gotify_tray.database import Settings
|
||||||
from gotify_tray.gui.themes import get_theme_file
|
from gotify_tray.gui.themes import get_theme_file
|
||||||
|
from gotify_tray.gui.models import MessageItemDataRole
|
||||||
|
from gotify_tray import gotify
|
||||||
|
|
||||||
|
|
||||||
settings = Settings("gotify-tray")
|
settings = Settings("gotify-tray")
|
||||||
@@ -104,17 +106,20 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
def set_error(self):
|
def set_error(self):
|
||||||
self.status_widget.set_error()
|
self.status_widget.set_error()
|
||||||
|
|
||||||
def insert_message_widget(
|
def display_message_widgets(self, parent: QtCore.QModelIndex, first: int, last: int):
|
||||||
self, message_item: MessagesModelItem, image_path: str = ""
|
for i in range(first, last+1):
|
||||||
):
|
if index := self.messages_model.index(i, 0, parent):
|
||||||
message_widget = MessageWidget(
|
message_item = self.messages_model.itemFromIndex(index)
|
||||||
self.app, self.listView_messages, message_item, image_path=image_path
|
|
||||||
)
|
message: gotify.GotifyMessageModel = self.messages_model.data(index, MessageItemDataRole.MessageRole)
|
||||||
self.listView_messages.setIndexWidget(
|
|
||||||
self.messages_model.indexFromItem(message_item), message_widget
|
application_item = self.application_model.itemFromId(message.appid)
|
||||||
)
|
|
||||||
message_widget.deletion_requested.connect(self.delete_message.emit)
|
message_widget = MessageWidget(self.app, self.listView_messages, message_item, icon=application_item.icon())
|
||||||
message_widget.image_popup.connect(self.image_popup.emit)
|
message_widget.deletion_requested.connect(self.delete_message.emit)
|
||||||
|
message_widget.image_popup.connect(self.image_popup.emit)
|
||||||
|
|
||||||
|
self.listView_messages.setIndexWidget(self.messages_model.indexFromItem(message_item), message_widget)
|
||||||
|
|
||||||
def currentApplicationIndex(self) -> QtCore.QModelIndex:
|
def currentApplicationIndex(self) -> QtCore.QModelIndex:
|
||||||
return self.listView_applications.selectionModel().currentIndex()
|
return self.listView_applications.selectionModel().currentIndex()
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
app: QtWidgets.QApplication,
|
app: QtWidgets.QApplication,
|
||||||
parent: QtWidgets.QWidget,
|
parent: QtWidgets.QWidget,
|
||||||
message_item: MessagesModelItem,
|
message_item: MessagesModelItem,
|
||||||
image_path: str = "",
|
icon: QtGui.QIcon | None = None,
|
||||||
):
|
):
|
||||||
super(MessageWidget, self).__init__()
|
super(MessageWidget, self).__init__(parent)
|
||||||
self.app = app
|
self.app = app
|
||||||
self.parent = parent
|
self._parent = parent
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
self.message_item = message_item
|
self.message_item = message_item
|
||||||
@@ -43,10 +43,7 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.label_title.setText(message.title)
|
self.label_title.setText(message.title)
|
||||||
self.label_date.setText(message.date.strftime("%Y-%m-%d, %H:%M"))
|
self.label_date.setText(message.date.strftime("%Y-%m-%d, %H:%M"))
|
||||||
|
|
||||||
if markdown := (
|
if message.get("extras", {}).get("client::display", {}).get("contentType") == "text/markdown":
|
||||||
message.get("extras", {}).get("client::display", {}).get("contentType")
|
|
||||||
== "text/markdown"
|
|
||||||
):
|
|
||||||
self.label_message.setTextFormat(QtCore.Qt.TextFormat.MarkdownText)
|
self.label_message.setTextFormat(QtCore.Qt.TextFormat.MarkdownText)
|
||||||
|
|
||||||
# If the message is only an image URL, then instead of showing the message,
|
# If the message is only an image URL, then instead of showing the message,
|
||||||
@@ -59,15 +56,9 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.label_message.setText(convert_links(message.message))
|
self.label_message.setText(convert_links(message.message))
|
||||||
|
|
||||||
# Show the application icon
|
# Show the application icon
|
||||||
if image_path:
|
if icon:
|
||||||
image_size = settings.value("MessageWidget/image/size", type=int)
|
image_size = settings.value("MessageWidget/image/size", type=int)
|
||||||
self.label_image.setFixedSize(QtCore.QSize(image_size, image_size))
|
pixmap = icon.pixmap(QtCore.QSize(image_size, image_size))
|
||||||
pixmap = QtGui.QPixmap(image_path).scaled(
|
|
||||||
image_size,
|
|
||||||
image_size,
|
|
||||||
aspectRatioMode=QtCore.Qt.AspectRatioMode.KeepAspectRatioByExpanding,
|
|
||||||
transformMode=QtCore.Qt.TransformationMode.SmoothTransformation,
|
|
||||||
)
|
|
||||||
self.label_image.setPixmap(pixmap)
|
self.label_image.setPixmap(pixmap)
|
||||||
else:
|
else:
|
||||||
self.label_image.hide()
|
self.label_image.hide()
|
||||||
@@ -77,7 +68,12 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.gridLayout.setContentsMargins(4, 5, 4, 0)
|
self.gridLayout.setContentsMargins(4, 5, 4, 0)
|
||||||
self.adjustSize()
|
self.adjustSize()
|
||||||
size_hint = self.message_item.sizeHint()
|
size_hint = self.message_item.sizeHint()
|
||||||
self.message_item.setSizeHint(QtCore.QSize(size_hint.width(), self.height()))
|
self.message_item.setSizeHint(
|
||||||
|
QtCore.QSize(
|
||||||
|
size_hint.width(),
|
||||||
|
max(settings.value("MessageWidget/height/min", type=int), self.height())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.set_icons()
|
self.set_icons()
|
||||||
|
|
||||||
@@ -113,13 +109,10 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
pixmap = QtGui.QPixmap(filename)
|
pixmap = QtGui.QPixmap(filename)
|
||||||
|
|
||||||
# Make sure the image fits within the listView
|
# Make sure the image fits within the listView
|
||||||
W = settings.value("MessageWidget/content_image/W_percentage", type=float) * (
|
W = settings.value("MessageWidget/content_image/W_percentage", type=float)
|
||||||
self.parent.width() - self.label_image.width()
|
H = settings.value("MessageWidget/content_image/H_percentage", type=float)
|
||||||
)
|
W *= self._parent.width() - self.label_image.width()
|
||||||
H = (
|
H *= self._parent.height()
|
||||||
settings.value("MessageWidget/content_image/H_percentage", type=float)
|
|
||||||
* self.parent.height()
|
|
||||||
)
|
|
||||||
|
|
||||||
if pixmap.width() > W or pixmap.height() > H:
|
if pixmap.width() > W or pixmap.height() > H:
|
||||||
pixmap = pixmap.scaled(
|
pixmap = pixmap.scaled(
|
||||||
@@ -150,7 +143,5 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.image_popup.emit(link, QtGui.QCursor.pos())
|
self.image_popup.emit(link, QtGui.QCursor.pos())
|
||||||
|
|
||||||
def link_callbacks(self):
|
def link_callbacks(self):
|
||||||
self.pb_delete.clicked.connect(
|
self.pb_delete.clicked.connect(lambda: self.deletion_requested.emit(self.message_item))
|
||||||
lambda: self.deletion_requested.emit(self.message_item)
|
|
||||||
)
|
|
||||||
self.label_message.linkHovered.connect(self.link_hovered_callback)
|
self.label_message.linkHovered.connect(self.link_hovered_callback)
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.line_url.setPlaceholderText("https://gotify.example.com")
|
self.line_url.setPlaceholderText("https://gotify.example.com")
|
||||||
self.line_url.setText(url)
|
self.line_url.setText(url)
|
||||||
self.line_token.setText(token)
|
self.line_token.setText(token)
|
||||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled(True)
|
||||||
True
|
|
||||||
)
|
|
||||||
self.pb_import.setVisible(enable_import)
|
self.pb_import.setVisible(enable_import)
|
||||||
self.link_callbacks()
|
self.link_callbacks()
|
||||||
|
|
||||||
@@ -37,9 +35,7 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.pb_test.setDisabled(True)
|
self.pb_test.setDisabled(True)
|
||||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled(True)
|
||||||
True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.task = VerifyServerInfoTask(url, client_token)
|
self.task = VerifyServerInfoTask(url, client_token)
|
||||||
self.task.success.connect(self.server_info_success)
|
self.task.success.connect(self.server_info_success)
|
||||||
@@ -59,9 +55,7 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.update_widget_state(self.pb_test, "success")
|
self.update_widget_state(self.pb_test, "success")
|
||||||
self.update_widget_state(self.line_token, "success")
|
self.update_widget_state(self.line_token, "success")
|
||||||
self.update_widget_state(self.line_url, "success")
|
self.update_widget_state(self.line_url, "success")
|
||||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setEnabled(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setEnabled(True)
|
||||||
True
|
|
||||||
)
|
|
||||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setFocus()
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setFocus()
|
||||||
|
|
||||||
def incorrect_token_callback(self, version: GotifyVersionModel):
|
def incorrect_token_callback(self, version: GotifyVersionModel):
|
||||||
@@ -80,6 +74,10 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.update_widget_state(self.line_url, "failed")
|
self.update_widget_state(self.line_url, "failed")
|
||||||
self.line_url.setFocus()
|
self.line_url.setFocus()
|
||||||
|
|
||||||
|
def input_changed_callback(self):
|
||||||
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled(True)
|
||||||
|
self.update_widget_state(self.pb_test, "")
|
||||||
|
|
||||||
def import_success_callback(self):
|
def import_success_callback(self):
|
||||||
self.line_url.setText(settings.value("Server/url", type=str))
|
self.line_url.setText(settings.value("Server/url", type=str))
|
||||||
self.line_token.setText(settings.value("Server/client_token"))
|
self.line_token.setText(settings.value("Server/client_token"))
|
||||||
@@ -95,14 +93,6 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
|
|
||||||
def link_callbacks(self):
|
def link_callbacks(self):
|
||||||
self.pb_test.clicked.connect(self.test_server_info)
|
self.pb_test.clicked.connect(self.test_server_info)
|
||||||
self.line_url.textChanged.connect(
|
self.line_url.textChanged.connect(self.input_changed_callback)
|
||||||
lambda: self.buttonBox.button(
|
self.line_token.textChanged.connect(self.input_changed_callback)
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Ok
|
|
||||||
).setDisabled(True)
|
|
||||||
)
|
|
||||||
self.line_token.textChanged.connect(
|
|
||||||
lambda: self.buttonBox.button(
|
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Ok
|
|
||||||
).setDisabled(True)
|
|
||||||
)
|
|
||||||
self.pb_import.clicked.connect(self.import_callback)
|
self.pb_import.clicked.connect(self.import_callback)
|
||||||
|
|||||||
@@ -43,42 +43,28 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.link_callbacks()
|
self.link_callbacks()
|
||||||
|
|
||||||
def initUI(self):
|
def initUI(self):
|
||||||
self.buttonBox.button(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Apply).setEnabled(False)
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Apply
|
|
||||||
).setEnabled(False)
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
self.spin_priority.setValue(
|
self.spin_priority.setValue(settings.value("tray/notifications/priority", type=int))
|
||||||
settings.value("tray/notifications/priority", type=int)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.spin_duration.setValue(
|
self.spin_duration.setValue(settings.value("tray/notifications/duration_ms", type=int))
|
||||||
settings.value("tray/notifications/duration_ms", type=int)
|
|
||||||
)
|
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
# The notification duration setting is ignored by windows
|
# The notification duration setting is ignored by windows
|
||||||
self.label_notification_duration.hide()
|
self.label_notification_duration.hide()
|
||||||
self.spin_duration.hide()
|
self.spin_duration.hide()
|
||||||
self.label_notification_duration_ms.hide()
|
self.label_notification_duration_ms.hide()
|
||||||
|
|
||||||
self.cb_notify.setChecked(
|
self.cb_notify.setChecked(settings.value("message/check_missed/notify", type=bool))
|
||||||
settings.value("message/check_missed/notify", type=bool)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cb_notification_click.setChecked(
|
self.cb_notification_click.setChecked(settings.value("tray/notifications/click", type=bool))
|
||||||
settings.value("tray/notifications/click", type=bool)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cb_tray_icon_unread.setChecked(
|
self.cb_tray_icon_unread.setChecked(settings.value("tray/icon/unread", type=bool))
|
||||||
settings.value("tray/icon/unread", type=bool)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Interface
|
# Interface
|
||||||
self.combo_theme.addItems(get_themes())
|
self.combo_theme.addItems(get_themes())
|
||||||
self.combo_theme.setCurrentText(settings.value("theme", type=str))
|
self.combo_theme.setCurrentText(settings.value("theme", type=str))
|
||||||
self.cb_priority_colors.setChecked(
|
self.cb_priority_colors.setChecked(settings.value("MessageWidget/priority_color", type=bool))
|
||||||
settings.value("MessageWidget/priority_color", type=bool)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
self.combo_logging.addItems(
|
self.combo_logging.addItems(
|
||||||
@@ -96,9 +82,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.add_message_widget()
|
self.add_message_widget()
|
||||||
|
|
||||||
# Advanced
|
# Advanced
|
||||||
self.groupbox_image_popup.setChecked(
|
self.groupbox_image_popup.setChecked(settings.value("ImagePopup/enabled", type=bool))
|
||||||
settings.value("ImagePopup/enabled", type=bool)
|
|
||||||
)
|
|
||||||
self.spin_popup_w.setValue(settings.value("ImagePopup/w", type=int))
|
self.spin_popup_w.setValue(settings.value("ImagePopup/w", type=int))
|
||||||
self.spin_popup_h.setValue(settings.value("ImagePopup/h", type=int))
|
self.spin_popup_h.setValue(settings.value("ImagePopup/h", type=int))
|
||||||
self.label_cache.setText("0 MB")
|
self.label_cache.setText("0 MB")
|
||||||
@@ -118,7 +102,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
get_icon("gotify-small"),
|
QtGui.QIcon(get_icon("gotify-small")),
|
||||||
)
|
)
|
||||||
self.layout_fonts_message.addWidget(self.message_widget)
|
self.layout_fonts_message.addWidget(self.message_widget)
|
||||||
|
|
||||||
@@ -132,16 +116,12 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
|
|
||||||
def settings_changed_callback(self, *args, **kwargs):
|
def settings_changed_callback(self, *args, **kwargs):
|
||||||
self.settings_changed = True
|
self.settings_changed = True
|
||||||
self.buttonBox.button(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Apply).setEnabled(True)
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Apply
|
|
||||||
).setEnabled(True)
|
|
||||||
|
|
||||||
def change_font_callback(self, name: str):
|
def change_font_callback(self, name: str):
|
||||||
label: QtWidgets.QLabel = getattr(self.message_widget, "label_" + name)
|
label: QtWidgets.QLabel = getattr(self.message_widget, "label_" + name)
|
||||||
|
|
||||||
font, accepted = QtWidgets.QFontDialog.getFont(
|
font, accepted = QtWidgets.QFontDialog.getFont(label.font(), self, f"Select a {name} font")
|
||||||
label.font(), self, f"Select a {name} font"
|
|
||||||
)
|
|
||||||
|
|
||||||
if accepted:
|
if accepted:
|
||||||
self.settings_changed_callback()
|
self.settings_changed_callback()
|
||||||
@@ -205,9 +185,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.label_cache.setText("0 MB")
|
self.label_cache.setText("0 MB")
|
||||||
|
|
||||||
def link_callbacks(self):
|
def link_callbacks(self):
|
||||||
self.buttonBox.button(
|
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Apply).clicked.connect(self.apply_settings)
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Apply
|
|
||||||
).clicked.connect(self.apply_settings)
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
self.spin_priority.valueChanged.connect(self.settings_changed_callback)
|
self.spin_priority.valueChanged.connect(self.settings_changed_callback)
|
||||||
@@ -225,22 +203,14 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
self.combo_logging.currentTextChanged.connect(self.settings_changed_callback)
|
self.combo_logging.currentTextChanged.connect(self.settings_changed_callback)
|
||||||
self.pb_open_log.clicked.connect(
|
self.pb_open_log.clicked.connect(lambda: open_file(logger.root.handlers[0].baseFilename))
|
||||||
lambda: open_file(logger.root.handlers[0].baseFilename)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
self.pb_reset_fonts.clicked.connect(self.reset_fonts_callback)
|
self.pb_reset_fonts.clicked.connect(self.reset_fonts_callback)
|
||||||
|
|
||||||
self.pb_font_message_title.clicked.connect(
|
self.pb_font_message_title.clicked.connect(lambda: self.change_font_callback("title"))
|
||||||
lambda: self.change_font_callback("title")
|
self.pb_font_message_date.clicked.connect(lambda: self.change_font_callback("date"))
|
||||||
)
|
self.pb_font_message_content.clicked.connect(lambda: self.change_font_callback("message"))
|
||||||
self.pb_font_message_date.clicked.connect(
|
|
||||||
lambda: self.change_font_callback("date")
|
|
||||||
)
|
|
||||||
self.pb_font_message_content.clicked.connect(
|
|
||||||
lambda: self.change_font_callback("message")
|
|
||||||
)
|
|
||||||
|
|
||||||
# Advanced
|
# Advanced
|
||||||
self.pb_export.clicked.connect(self.export_callback)
|
self.pb_export.clicked.connect(self.export_callback)
|
||||||
@@ -257,9 +227,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
settings.setValue("tray/notifications/priority", self.spin_priority.value())
|
settings.setValue("tray/notifications/priority", self.spin_priority.value())
|
||||||
settings.setValue("tray/notifications/duration_ms", self.spin_duration.value())
|
settings.setValue("tray/notifications/duration_ms", self.spin_duration.value())
|
||||||
settings.setValue("message/check_missed/notify", self.cb_notify.isChecked())
|
settings.setValue("message/check_missed/notify", self.cb_notify.isChecked())
|
||||||
settings.setValue(
|
settings.setValue("tray/notifications/click", self.cb_notification_click.isChecked())
|
||||||
"tray/notifications/click", self.cb_notification_click.isChecked()
|
|
||||||
)
|
|
||||||
settings.setValue("tray/icon/unread", self.cb_tray_icon_unread.isChecked())
|
settings.setValue("tray/icon/unread", self.cb_tray_icon_unread.isChecked())
|
||||||
|
|
||||||
# Interface
|
# Interface
|
||||||
@@ -269,9 +237,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
settings.setValue("theme", selected_theme)
|
settings.setValue("theme", selected_theme)
|
||||||
self.theme_change_requested.emit(selected_theme)
|
self.theme_change_requested.emit(selected_theme)
|
||||||
|
|
||||||
settings.setValue(
|
settings.setValue("MessageWidget/priority_color", self.cb_priority_colors.isChecked())
|
||||||
"MessageWidget/priority_color", self.cb_priority_colors.isChecked()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
selected_level = self.combo_logging.currentText()
|
selected_level = self.combo_logging.currentText()
|
||||||
@@ -283,17 +249,9 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
logger.setLevel(selected_level)
|
logger.setLevel(selected_level)
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
settings.setValue(
|
settings.setValue("MessageWidget/font/title", self.message_widget.label_title.font().toString())
|
||||||
"MessageWidget/font/title",
|
settings.setValue("MessageWidget/font/date", self.message_widget.label_date.font().toString())
|
||||||
self.message_widget.label_title.font().toString(),
|
settings.setValue("MessageWidget/font/message", self.message_widget.label_message.font().toString())
|
||||||
)
|
|
||||||
settings.setValue(
|
|
||||||
"MessageWidget/font/date", self.message_widget.label_date.font().toString()
|
|
||||||
)
|
|
||||||
settings.setValue(
|
|
||||||
"MessageWidget/font/message",
|
|
||||||
self.message_widget.label_message.font().toString(),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Advanced
|
# Advanced
|
||||||
settings.setValue("ImagePopup/enabled", self.groupbox_image_popup.isChecked())
|
settings.setValue("ImagePopup/enabled", self.groupbox_image_popup.isChecked())
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ from functools import reduce
|
|||||||
from PyQt6 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
|
|
||||||
from gotify_tray.database import Cache, Downloader, Settings
|
from gotify_tray.database import Cache, Settings
|
||||||
from gotify_tray.gotify.api import GotifyClient
|
from gotify_tray.gotify.api import GotifyClient
|
||||||
from gotify_tray.gotify.models import GotifyVersionModel
|
from gotify_tray.gotify.models import GotifyVersionModel
|
||||||
from gotify_tray.utils import get_image
|
from gotify_tray.utils import process_messages
|
||||||
|
|
||||||
from . import gotify
|
from . import gotify
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class GetApplicationsTask(BaseTask):
|
|||||||
|
|
||||||
|
|
||||||
class GetApplicationMessagesTask(BaseTask):
|
class GetApplicationMessagesTask(BaseTask):
|
||||||
success = pyqtSignal(gotify.GotifyPagedMessagesModel)
|
message = pyqtSignal(gotify.GotifyMessageModel)
|
||||||
error = pyqtSignal(gotify.GotifyErrorModel)
|
error = pyqtSignal(gotify.GotifyErrorModel)
|
||||||
|
|
||||||
def __init__(self, appid: int, gotify_client: gotify.GotifyClient):
|
def __init__(self, appid: int, gotify_client: gotify.GotifyClient):
|
||||||
@@ -110,10 +110,16 @@ class GetApplicationMessagesTask(BaseTask):
|
|||||||
if isinstance(result, gotify.GotifyErrorModel):
|
if isinstance(result, gotify.GotifyErrorModel):
|
||||||
self.error.emit(result)
|
self.error.emit(result)
|
||||||
else:
|
else:
|
||||||
self.success.emit(result)
|
for message in process_messages(result.messages):
|
||||||
|
self.message.emit(message)
|
||||||
|
|
||||||
|
# Prevent locking up the UI when there are a lot of messages ready at the same time
|
||||||
|
# -- side effect: switching application while the previous messages are still being inserted causes mixing of messages
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
|
|
||||||
class GetMessagesTask(BaseTask):
|
class GetMessagesTask(BaseTask):
|
||||||
|
message = pyqtSignal(gotify.GotifyMessageModel)
|
||||||
success = pyqtSignal(gotify.GotifyPagedMessagesModel)
|
success = pyqtSignal(gotify.GotifyPagedMessagesModel)
|
||||||
error = pyqtSignal(gotify.GotifyErrorModel)
|
error = pyqtSignal(gotify.GotifyErrorModel)
|
||||||
|
|
||||||
@@ -126,9 +132,22 @@ class GetMessagesTask(BaseTask):
|
|||||||
if isinstance(result, gotify.GotifyErrorModel):
|
if isinstance(result, gotify.GotifyErrorModel):
|
||||||
self.error.emit(result)
|
self.error.emit(result)
|
||||||
else:
|
else:
|
||||||
|
for message in process_messages(result.messages):
|
||||||
|
self.message.emit(message)
|
||||||
|
time.sleep(0.001)
|
||||||
self.success.emit(result)
|
self.success.emit(result)
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessMessageTask(BaseTask):
|
||||||
|
def __init__(self, message: gotify.GotifyMessageModel):
|
||||||
|
super(ProcessMessageTask, self).__init__()
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def task(self):
|
||||||
|
for _ in process_messages([self.message]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class VerifyServerInfoTask(BaseTask):
|
class VerifyServerInfoTask(BaseTask):
|
||||||
success = pyqtSignal(GotifyVersionModel)
|
success = pyqtSignal(GotifyVersionModel)
|
||||||
incorrect_token = pyqtSignal(GotifyVersionModel)
|
incorrect_token = pyqtSignal(GotifyVersionModel)
|
||||||
@@ -176,9 +195,7 @@ class ServerConnectionWatchdogTask(BaseTask):
|
|||||||
time.sleep(settings.value("watchdog/interval/s", type=int))
|
time.sleep(settings.value("watchdog/interval/s", type=int))
|
||||||
if not self.gotify_client.is_listening():
|
if not self.gotify_client.is_listening():
|
||||||
self.closed.emit()
|
self.closed.emit()
|
||||||
logger.debug(
|
logger.debug("ServerConnectionWatchdogTask: gotify_client is not listening")
|
||||||
"ServerConnectionWatchdogTask: gotify_client is not listening"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ExportSettingsTask(BaseTask):
|
class ExportSettingsTask(BaseTask):
|
||||||
@@ -205,35 +222,6 @@ class ImportSettingsTask(BaseTask):
|
|||||||
self.success.emit()
|
self.success.emit()
|
||||||
|
|
||||||
|
|
||||||
class ProcessMessageTask(BaseTask):
|
|
||||||
def __init__(self, message: gotify.GotifyMessageModel):
|
|
||||||
super(ProcessMessageTask, self).__init__()
|
|
||||||
self.message = message
|
|
||||||
|
|
||||||
def task(self):
|
|
||||||
if image_url := get_image(self.message.message):
|
|
||||||
downloader = Downloader()
|
|
||||||
downloader.get_filename(image_url)
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessMessagesTask(BaseTask):
|
|
||||||
message_processed = pyqtSignal(gotify.GotifyMessageModel)
|
|
||||||
|
|
||||||
def __init__(self, page: gotify.GotifyPagedMessagesModel):
|
|
||||||
super(ProcessMessagesTask, self).__init__()
|
|
||||||
self.page = page
|
|
||||||
|
|
||||||
def task(self):
|
|
||||||
downloader = Downloader()
|
|
||||||
for message in self.page.messages:
|
|
||||||
if image_url := get_image(message.message):
|
|
||||||
downloader.get_filename(image_url)
|
|
||||||
self.message_processed.emit(message)
|
|
||||||
|
|
||||||
# Prevent locking up the UI when there are a lot of messages with images ready at the same time
|
|
||||||
time.sleep(0.001)
|
|
||||||
|
|
||||||
|
|
||||||
class CacheSizeTask(BaseTask):
|
class CacheSizeTask(BaseTask):
|
||||||
size = pyqtSignal(int)
|
size = pyqtSignal(int)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import re
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Iterator
|
||||||
|
|
||||||
|
from gotify_tray import gotify
|
||||||
|
from gotify_tray.database import Downloader
|
||||||
|
|
||||||
|
|
||||||
def verify_server(force_new: bool = False, enable_import: bool = True) -> bool:
|
def verify_server(force_new: bool = False, enable_import: bool = True) -> bool:
|
||||||
@@ -28,6 +31,14 @@ def verify_server(force_new: bool = False, enable_import: bool = True) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def process_messages(messages: list[gotify.GotifyMessageModel]) -> Iterator[gotify.GotifyMessageModel]:
|
||||||
|
downloader = Downloader()
|
||||||
|
for message in messages:
|
||||||
|
if image_url := get_image(message.message):
|
||||||
|
downloader.get_filename(image_url)
|
||||||
|
yield message
|
||||||
|
|
||||||
|
|
||||||
def convert_links(text):
|
def convert_links(text):
|
||||||
_link = re.compile(
|
_link = re.compile(
|
||||||
r'(?:(https://|http://)|(www\.))(\S+\b/?)([!"#$%&\'()*+,\-./:;<=>?@[\\\]^_`{|}~]*)(\s|$)',
|
r'(?:(https://|http://)|(www\.))(\S+\b/?)([!"#$%&\'()*+,\-./:;<=>?@[\\\]^_`{|}~]*)(\s|$)',
|
||||||
@@ -45,7 +56,7 @@ def convert_links(text):
|
|||||||
return _link.sub(replace, text)
|
return _link.sub(replace, text)
|
||||||
|
|
||||||
|
|
||||||
def get_image(s: str) -> Optional[str]:
|
def get_image(s: str) -> str | None:
|
||||||
"""If `s` contains only an image URL, this function returns that URL.
|
"""If `s` contains only an image URL, this function returns that URL.
|
||||||
This function also extracts a URL in the `` markdown image format.
|
This function also extracts a URL in the `` markdown image format.
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user