From 42cddcfe8091f7a6789e8a750666bd6d47025ce3 Mon Sep 17 00:00:00 2001 From: misygauziya Date: Mon, 24 Jul 2023 00:18:21 +0900 Subject: [PATCH 1/4] [Add] notification.py --- notification.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 notification.py diff --git a/notification.py b/notification.py new file mode 100644 index 00000000..5d3d0898 --- /dev/null +++ b/notification.py @@ -0,0 +1,73 @@ +# ########################################################################################################################### +# DOCUMENT:https://xiexe.github.io/XSOverlayDocumentation/#/NotificationsAPI +# SOURCE:https://zenn.dev/eeharumt/scraps/95f49a62dd809a +# messageType: int = 0 # 1: ポップアップ通知, 2: メディアプレーヤー情報 +# index: int = 0 # メディアプレーヤーでのみ使用され、手首のアイコンを変更する +# timeout: float = 0.5 # 通知インジケータが表示され続ける時間[秒] +# height: float = 175 # 通知インジケータの高さ +# opacity: float = 1 # 通知インジケータの透明度。0.0-1.0の範囲で低いほど透明に +# volume: float = 0.7 # 通知音の大きさ +# audioPath: str = "" # 通知音ファイルのパス。規定音として"default", "error", "warning"を指定可能。空文字列で通知音なしにできる。 +# title: str = "" # 通知タイトル、リッチテキストフォーマットをサポート。 +# content: str = "" # 通知内容、リッチテキストフォーマットをサポート。省略することで小サイズ通知となる。 +# useBase64Icon: bool = False # TrueにすることでBase64の画像を表示する +# icon: str = "" # Base64画像イメージまたは画像ファイルパス。規定アイコンとして"default", "error", or "warning"を指定可能 +# sourceApp: str = "" # 通知したアプリ名(デバック用) +# ########################################################################################################################## + +import socket +import json +import base64 + +def notification_xsoverlay( + endpoint:tuple=("127.0.0.1", 42069), messageType:int=0, index:int=0, timeout:float=1, + height:float=120.0, opacity:float=1.0, volume:float=0.5, audioPath:str="default", + title:str="", content:str="", useBase64Icon:bool=False, icon:str="default", sourceApp:str="" +) -> int: + + if icon in ["default", "error", "warning"]: + icon_data = icon + elif useBase64Icon: + try: + with open(icon, "rb") as f: + icon_data_bytes = f.read() + icon_data = base64.b64encode(icon_data_bytes).decode("utf-8") + except: + icon_data = "default" + else: + icon_data = icon + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + data_msg = { + "messageType": messageType, + "index": index, + "timeout":timeout, + "height": height, + "opacity": opacity, + "volume": volume, + "audioPath": audioPath, + "title": title, + "content": content, + "useBase64Icon": useBase64Icon, + "icon": icon_data, + "sourceApp": sourceApp, + } + msg_str = json.dumps(data_msg) + msg_byte = msg_str.encode("utf-8") + response = sock.sendto(msg_byte, endpoint) + sock.close() + return response + +def notification_xsoverlay_for_vrct(content:str="") -> int: + response = notification_xsoverlay( + title="VRCT", + content=content, + useBase64Icon=True, + icon="./img/app.ico", + sourceApp="VRCT" + ) + return response + +if __name__ == "__main__": + notification_xsoverlay_for_vrct(content="notification test") \ No newline at end of file From 53ddab3fc0b52cfd14012d276ef15877e0cb44be Mon Sep 17 00:00:00 2001 From: misygauziya Date: Mon, 24 Jul 2023 00:43:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[update]=20Speaker=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=81=AE=E6=96=87=E5=AD=97=E8=B5=B7=E3=81=93=E3=81=97=E7=B5=90?= =?UTF-8?q?=E6=9E=9C=E3=82=92XSOverlay=E3=81=AE=E9=80=9A=E7=9F=A5=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=81=A7=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0(VR=E9=99=90=E5=AE=9A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VRCT.py | 11 ++++++++++- locales.yml | 2 ++ utils.py | 6 +++--- window_config.py | 29 ++++++++++++++++++++++++++++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/VRCT.py b/VRCT.py index 84c72f23..8b0a9f13 100644 --- a/VRCT.py +++ b/VRCT.py @@ -18,6 +18,7 @@ from audio_utils import get_input_device_list, get_output_device_list, get_defau from audio_recorder import SelectedMicRecorder, SelectedSpeakerRecorder from audio_transcriber import AudioTranscriber from translation import Translator +from notification import notification_xsoverlay_for_vrct class App(CTk): def __init__(self, *args, **kwargs): @@ -65,6 +66,7 @@ class App(CTk): self.INPUT_SPEAKER_RECORD_TIMEOUT = 3 self.INPUT_SPEAKER_PHRASE_TIMEOUT = 3 self.INPUT_SPEAKER_MAX_PHRASES = 10 + ## Parameter self.OSC_IP_ADDRESS = "127.0.0.1" self.OSC_PORT = 9000 @@ -77,6 +79,7 @@ class App(CTk): self.MESSAGE_FORMAT = "[message]([translation])" # Others self.ENABLE_AUTO_CLEAR_CHATBOX = False + self.ENABLE_NOTICE_XSOVERLAY =False # load config if os_path.isfile(self.PATH_CONFIG) is not False: @@ -209,6 +212,9 @@ class App(CTk): if "ENABLE_AUTO_CLEAR_CHATBOX" in config.keys(): if type(config["ENABLE_AUTO_CLEAR_CHATBOX"]) is bool: self.ENABLE_AUTO_CLEAR_CHATBOX = config["ENABLE_AUTO_CLEAR_CHATBOX"] + if "ENABLE_NOTICE_XSOVERLAY" in config.keys(): + if type(config["ENABLE_NOTICE_XSOVERLAY"]) is bool: + self.ENABLE_NOTICE_XSOVERLAY = config["ENABLE_NOTICE_XSOVERLAY"] with open(self.PATH_CONFIG, 'w') as fp: config = { @@ -247,6 +253,7 @@ class App(CTk): "AUTH_KEYS": self.AUTH_KEYS, "MESSAGE_FORMAT": self.MESSAGE_FORMAT, "ENABLE_AUTO_CLEAR_CHATBOX": self.ENABLE_AUTO_CLEAR_CHATBOX, + "ENABLE_NOTICE_XSOVERLAY": self.ENABLE_NOTICE_XSOVERLAY, } json_dump(config, fp, indent=4) @@ -567,6 +574,8 @@ class App(CTk): # update textbox message receive log print_textbox(self.textbox_message_log, f"{voice_message}", "RECEIVE") print_textbox(self.textbox_message_receive_log, f"{voice_message}", "RECEIVE") + if self.ENABLE_NOTICE_XSOVERLAY is True: + notification_xsoverlay_for_vrct(content=f"{voice_message}") self.spk_print_transcript = thread_fnc(spk_transcript_to_textbox) self.spk_print_transcript.daemon = True @@ -654,7 +663,7 @@ class App(CTk): print_textbox(self.textbox_message_send_log, f"{chat_message}", "SEND") # delete message in entry message box - if self.ENABLE_AUTO_CLEAR_CHATBOX == True: + if self.ENABLE_AUTO_CLEAR_CHATBOX is True: self.entry_message_box.delete(0, customtkinter.END) BREAK_KEYSYM_LIST = [ diff --git a/locales.yml b/locales.yml index 79b5fd86..f4b80300 100644 --- a/locales.yml +++ b/locales.yml @@ -60,6 +60,7 @@ en: # tab Others label_checkbox_auto_clear_chatbox: "Auto clear chat box" + label_checkbox_notice_xsoverlay: "Notification XSOverlay" ja: @@ -125,6 +126,7 @@ ja: # tab Others label_checkbox_auto_clear_chatbox: "送信後はチャットボックスを空にする" + label_checkbox_notice_xsoverlay: "XSOverlayの通知機能を有効" ko: diff --git a/utils.py b/utils.py index 0e63f179..ac2eb35d 100644 --- a/utils.py +++ b/utils.py @@ -100,15 +100,15 @@ def widget_config_window_label_setter(self, language_yaml_data): "label_input_speaker_phrase_timeout", "label_input_speaker_max_phrases", - # tab Parameter "label_ip_address", "label_port", "label_authkey", "label_message_format", - + # tab Others - "label_checkbox_auto_clear_chatbox" + "label_checkbox_auto_clear_chatbox", + "label_checkbox_notice_xsoverlay", ] for name in widget_names: widget = getattr(self, name) diff --git a/window_config.py b/window_config.py index 89adde9a..7c8b2173 100644 --- a/window_config.py +++ b/window_config.py @@ -492,6 +492,11 @@ class ToplevelWindowConfig(CTkToplevel): self.parent.ENABLE_AUTO_CLEAR_CHATBOX = value save_json(self.parent.PATH_CONFIG, "ENABLE_AUTO_CLEAR_CHATBOX", self.parent.ENABLE_AUTO_CLEAR_CHATBOX) + def checkbox_notice_xsoverlay_callback(self): + value = self.checkbox_notice_xsoverlay.get() + self.parent.ENABLE_NOTICE_XSOVERLAY = value + save_json(self.parent.PATH_CONFIG, "ENABLE_NOTICE_XSOVERLAY", self.parent.ENABLE_NOTICE_XSOVERLAY) + def delete_window(self): self.checkbox_input_mic_threshold_check.deselect() self.checkbox_input_speaker_threshold_check.deselect() @@ -1381,7 +1386,7 @@ class ToplevelWindowConfig(CTkToplevel): # tab Others ## checkbox auto clear chat box - row += 1 + row = 0 self.label_checkbox_auto_clear_chatbox = CTkLabel( self.tabview_config.tab(config_tab_title_others), text=init_lang_text, @@ -1403,4 +1408,26 @@ class ToplevelWindowConfig(CTkToplevel): else: self.checkbox_auto_clear_chatbox.deselect() + # checkbox notice xsoverlay + row += 1 + self.label_checkbox_notice_xsoverlay = CTkLabel( + self.tabview_config.tab(config_tab_title_others), + text=init_lang_text, + fg_color="transparent", + font=CTkFont(family=self.parent.FONT_FAMILY) + ) + self.label_checkbox_notice_xsoverlay.grid(row=row, column=0, columnspan=1, padx=padx, pady=pady, sticky="nsw") + self.checkbox_notice_xsoverlay = CTkCheckBox( + self.tabview_config.tab(config_tab_title_others), + text="", + onvalue=True, + offvalue=False, + command=self.checkbox_notice_xsoverlay_callback, + font=CTkFont(family=self.parent.FONT_FAMILY) + ) + self.checkbox_notice_xsoverlay.grid(row=row, column=1, columnspan=1, padx=padx, pady=pady, sticky="nsew") + if self.parent.ENABLE_NOTICE_XSOVERLAY is True: + self.checkbox_notice_xsoverlay.select() + else: + self.checkbox_notice_xsoverlay.deselect() widget_config_window_label_setter(self, language_yaml_data) \ No newline at end of file From 972353fec23847d1a97c942776fce4db2e2d3718 Mon Sep 17 00:00:00 2001 From: misygauziya Date: Tue, 25 Jul 2023 11:25:56 +0900 Subject: [PATCH 3/4] [Add] img/xsoverlay.png MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 大きい画像だと送信できなかったため、32x32で作成 --- img/xsoverlay.png | Bin 0 -> 1209 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/xsoverlay.png diff --git a/img/xsoverlay.png b/img/xsoverlay.png new file mode 100644 index 0000000000000000000000000000000000000000..35c793eaed87c7b132f6b5400b732341c3e74660 GIT binary patch literal 1209 zcmV;q1V;ObP)EX>4Tx04UFukvmAkP!xv$rWPMm9PFUt5TQERMMWG-6pLV?v=v%)FuCaqnlvOS zE{=k0!NJF3)xpJCR|i)?5PX2Rx;QDiNQvhrg%+WL7Y_I1zxV$+_gp}zmzidDMFCB> z&16gxGuc(K`xOBUQ;nflW|k38EvC_Neci*y_qzzs!v9vknzI<-6N#hDFm2)u;@M5x z;Ji;9VntacJ|~_usX^jLt}7nDaW1$l@XU~zPRr|tNVF__0AVNVEC6r+!Lc30ig(RIz9sDD%KS3^qTqQ7a zET94nvg-%`gWt2Y^3zjZQcwZ{FOKsu4s`DVjhf?pA3ILt1n@rtS9;4|sRMJLq}N(n z_y`!-1}?5!nz9F6?f^qihHT2NMD1tTjqx>_{=000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}0007zNklKpZw0w%6M~B1PFzS{!IeUb z+V%4@9U}oh&A@9A_IkbZXf*oE zXf%?!H7SZ>jK||Ayq2Zq9vzd-W>@@Wt!%?er9#_8FHRR= z$IMom%_jM><^!qSZcmu4bUK|eV&al7*X#9jW?#JxGnov_PznZ#^mKA(#|pO4dg z96Op!Ci?lyO90lFVo8$3YPHHW8Vzo-Sja4_3%*pV)kd_oSfT|B>!KKWbPQdKg;i~o zz&3Sw7cA?Lz}^#}g7OMHbGclTSS)r&jcy>P( Date: Tue, 25 Jul 2023 11:26:54 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[Update]=20XSOverlay=E3=81=AE=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=AEparameter=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notification.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/notification.py b/notification.py index 5d3d0898..61e18725 100644 --- a/notification.py +++ b/notification.py @@ -20,8 +20,8 @@ import json import base64 def notification_xsoverlay( - endpoint:tuple=("127.0.0.1", 42069), messageType:int=0, index:int=0, timeout:float=1, - height:float=120.0, opacity:float=1.0, volume:float=0.5, audioPath:str="default", + endpoint:tuple=("127.0.0.1", 42069), messageType:int=1, index:int=0, timeout:float=2, + height:float=120.0, opacity:float=1.0, volume:float=0.0, audioPath:str="", title:str="", content:str="", useBase64Icon:bool=False, icon:str="default", sourceApp:str="" ) -> int: @@ -54,8 +54,7 @@ def notification_xsoverlay( "sourceApp": sourceApp, } msg_str = json.dumps(data_msg) - msg_byte = msg_str.encode("utf-8") - response = sock.sendto(msg_byte, endpoint) + response = sock.sendto(msg_str.encode("utf-8"), endpoint) sock.close() return response @@ -64,7 +63,7 @@ def notification_xsoverlay_for_vrct(content:str="") -> int: title="VRCT", content=content, useBase64Icon=True, - icon="./img/app.ico", + icon="./img/xsoverlay.png", sourceApp="VRCT" ) return response