[Update] 機能部分をmodelsフォルダに移動

This commit is contained in:
misygauziya
2023-08-20 01:20:30 +09:00
parent 31e786f2a8
commit 02d8fbdb1c
14 changed files with 392 additions and 388 deletions

37
models/osc/osc_tools.py Normal file
View File

@@ -0,0 +1,37 @@
from time import sleep
from typing import List
from pythonosc import osc_message_builder
from pythonosc import udp_client
from pythonosc import dispatcher
from pythonosc import osc_server
# send OSC message typing
def send_typing(flag=False, ip_address="127.0.0.1", port=9000):
typing = osc_message_builder.OscMessageBuilder(address="/chatbox/typing")
typing.add_arg(flag)
b_typing = typing.build()
client = udp_client.SimpleUDPClient(ip_address, port)
client.send(b_typing)
# send OSC message
def send_message(message=None, ip_address="127.0.0.1", port=9000):
if message != None:
msg = osc_message_builder.OscMessageBuilder(address="/chatbox/input")
msg.add_arg(f"{message}")
msg.add_arg(True)
msg.add_arg(True)
b_msg = msg.build()
client = udp_client.SimpleUDPClient(ip_address, port)
client.send(b_msg)
def send_test_action(ip_address="127.0.0.1", port=9000):
client = udp_client.SimpleUDPClient(ip_address, port)
client.send_message("/input/Vertical", 1)
sleep(0.01)
client.send_message("/input/Vertical", False)
def receive_osc_parameters(target, filter="/*", ip_address="127.0.0.1", port=9001):
_dispatcher = dispatcher.Dispatcher()
_dispatcher.map(filter, target)
server = osc_server.ThreadingOSCUDPServer((ip_address, port), _dispatcher)
server.serve_forever()

View File

@@ -0,0 +1,91 @@
transcription_lang = {
"Japanese (Japan)":"ja-JP",
"English (United States)":"en-US",
"English (United Kingdom)":"en-GB",
"Afrikaans (South Africa)":"af-ZA",
"Arabic (Algeria)":"ar-DZ",
"Arabic (Bahrain)":"ar-BH",
"Arabic (Egypt)":"ar-EG",
"Arabic (Israel)":"ar-IL",
"Arabic (Iraq)":"ar-IQ",
"Arabic (Jordan)":"ar-JO",
"Arabic (Kuwait)":"ar-KW",
"Arabic (Lebanon)":"ar-LB",
"Arabic (Morocco)":"ar-MA",
"Arabic (Oman)":"ar-OM",
"Arabic (State of Palestine)":"ar-PS",
"Arabic (Qatar)":"ar-QA",
"Arabic (Saudi Arabia)":"ar-SA",
"Arabic (Tunisia)":"ar-TN",
"Arabic (United Arab Emirates)":"ar-AE",
"Basque (Spain)":"eu-ES",
"Bulgarian (Bulgaria)":"bg-BG",
"Catalan (Spain)":"ca-ES",
"Chinese, Mandarin (Simplified, China)":"cmn-Hans-CN",
"Chinese, Mandarin (Simplified, Hong Kong)":"cmn-Hans-HK",
"Chinese, Mandarin (Traditional, Taiwan)":"cmn-Hant-TW",
"Chinese, Cantonese (Traditional Hong Kong)":"yue-Hant-HK",
"Croatian (Croatia)":"hr-HR",
"Czech (Czech Republic)":"cs-CZ",
"Danish (Denmark)":"da-DK",
"English (Australia)":"en-AU",
"English (Canada)":"en-CA",
"English (India)":"en-IN",
"English (Ireland)":"en-IE",
"English (New Zealand)":"en-NZ",
"English (Philippines)":"en-PH",
"English (South Africa)":"en-ZA",
"Persian (Iran)":"fa-IR",
"French (France)":"fr-FR",
"Filipino (Philippines)":"fil-PH",
"Galician (Spain)":"gl-ES",
"German (Germany)":"de-DE",
"Greek (Greece)":"el-GR",
"Finnish (Finland)":"fi-FI",
"Hebrew (Israel)":"he-IL",
"Hindi (India)":"hi-IN",
"Hungarian (Hungary)":"hu-HU",
"Indonesian (Indonesia)":"id-ID",
"Icelandic (Iceland)":"is-IS",
"Italian (Italy)":"it-IT",
"Italian (Switzerland)":"it-CH",
"Korean (South Korea)":"ko-KR",
"Lithuanian (Lithuania)":"lt-LT",
"Malay (Malaysia)":"ms-MY",
"Dutch (Netherlands)":"nl-NL",
"Norwegian Bokmål (Norway)":"nb-NO",
"Polish (Poland)":"pl-PL",
"Portuguese (Brazil)":"pt-BR",
"Portuguese (Portugal)":"pt-PT",
"Romanian (Romania)":"ro-RO",
"Russian (Russia)":"ru-RU",
"Serbian (Serbia)":"sr-RS",
"Slovak (Slovakia)":"sk-SK",
"Slovenian (Slovenia)":"sl-SI",
"Spanish (Argentina)":"es-AR",
"Spanish (Bolivia)":"es-BO",
"Spanish (Chile)":"es-CL",
"Spanish (Colombia)":"es-CO",
"Spanish (Costa Rica)":"es-CR",
"Spanish (Dominican Republic)":"es-DO",
"Spanish (Ecuador)":"es-EC",
"Spanish (El Salvador)":"es-SV",
"Spanish (Guatemala)":"es-GT",
"Spanish (Honduras)":"es-HN",
"Spanish (Mexico)":"es-MX",
"Spanish (Nicaragua)":"es-NI",
"Spanish (Panama)":"es-PA",
"Spanish (Paraguay)":"es-PY",
"Spanish (Peru)":"es-PE",
"Spanish (Puerto Rico)":"es-PR",
"Spanish (Spain)":"es-ES",
"Spanish (Uruguay)":"es-UY",
"Spanish (United States)":"es-US",
"Spanish (Venezuela)":"es-VE",
"Swedish (Sweden)":"sv-SE",
"Thai (Thailand)":"th-TH",
"Turkish (Turkey)":"tr-TR",
"Ukrainian (Ukraine)":"uk-UA",
"Vietnamese (Vietnam)":"vi-VN",
"Zulu (South Africa)":"zu-ZA"
}

View File

@@ -0,0 +1,91 @@
from speech_recognition import Recognizer, Microphone
from pyaudiowpatch import get_sample_size, paInt16
from datetime import datetime
class BaseRecorder:
def __init__(self, source, energy_threshold, dynamic_energy_threshold, record_timeout):
self.recorder = Recognizer()
self.recorder.energy_threshold = energy_threshold
self.recorder.dynamic_energy_threshold = dynamic_energy_threshold
self.record_timeout = record_timeout
self.stop = None
if source is None:
raise ValueError("audio source can't be None")
self.source = source
def adjust_for_noise(self):
with self.source:
self.recorder.adjust_for_ambient_noise(self.source)
def record_into_queue(self, audio_queue):
def record_callback(_, audio):
audio_queue.put((audio.get_raw_data(), datetime.now()))
self.stop = self.recorder.listen_in_background(self.source, record_callback, phrase_time_limit=self.record_timeout)
class SelectedMicRecorder(BaseRecorder):
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
source=Microphone(
device_index=device['index'],
sample_rate=int(device["defaultSampleRate"]),
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjust_for_noise()
class SelectedSpeakerRecorder(BaseRecorder):
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
source = Microphone(speaker=True,
device_index= device["index"],
sample_rate=int(device["defaultSampleRate"]),
chunk_size=get_sample_size(paInt16),
channels=device["maxInputChannels"]
)
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
# self.adjust_for_noise()
class BaseEnergyRecorder:
def __init__(self, source):
self.recorder = Recognizer()
self.recorder.energy_threshold = 0
self.recorder.dynamic_energy_threshold = False
self.record_timeout = 0
self.stop = None
if source is None:
raise ValueError("audio source can't be None")
self.source = source
def adjust_for_noise(self):
with self.source:
self.recorder.adjust_for_ambient_noise(self.source)
def record_into_queue(self, energy_queue):
def record_callback(_, energy):
energy_queue.put(energy)
self.stop = self.recorder.listen_energy_in_background(self.source, record_callback)
class SelectedMicEnergyRecorder(BaseEnergyRecorder):
def __init__(self, device):
source=Microphone(
device_index=device['index'],
sample_rate=int(device["defaultSampleRate"]),
)
super().__init__(source=source)
# self.adjust_for_noise()
class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
def __init__(self, device):
source = Microphone(speaker=True,
device_index= device["index"],
sample_rate=int(device["defaultSampleRate"]),
chunk_size=get_sample_size(paInt16),
channels=device["maxInputChannels"]
)
super().__init__(source=source)
# self.adjust_for_noise()

View File

@@ -0,0 +1,98 @@
from io import BytesIO
from threading import Event
import wave
from speech_recognition import Recognizer, AudioData, AudioFile
from datetime import timedelta
from pyaudiowpatch import get_sample_size, paInt16
from .transcription_languages import transcription_lang
PHRASE_TIMEOUT = 3
MAX_PHRASES = 10
class AudioTranscriber:
def __init__(self, speaker, source, phrase_timeout, max_phrases):
self.speaker = speaker
self.phrase_timeout = phrase_timeout
self.max_phrases = max_phrases
self.transcript_data = []
self.transcript_changed_event = Event()
self.audio_recognizer = Recognizer()
self.audio_sources = {
"sample_rate": source.SAMPLE_RATE,
"sample_width": source.SAMPLE_WIDTH,
"channels": source.channels,
"last_sample": bytes(),
"last_spoken": None,
"new_phrase": True,
"process_data_func": self.process_speaker_data if speaker else self.process_speaker_data
}
def transcribe_audio_queue(self, audio_queue, language):
# while True:
audio, time_spoken = audio_queue.get()
self.update_last_sample_and_phrase_status(audio, time_spoken)
text = ''
try:
# fd, path = tempfile.mkstemp(suffix=".wav")
# os.close(fd)
audio_data = self.audio_sources["process_data_func"]()
text = self.audio_recognizer.recognize_google(audio_data, language=transcription_lang[language])
except Exception as e:
pass
finally:
pass
# os.unlink(path)
if text != '':
self.update_transcript(text)
def update_last_sample_and_phrase_status(self, data, time_spoken):
source_info = self.audio_sources
if source_info["last_spoken"] and time_spoken - source_info["last_spoken"] > timedelta(seconds=self.phrase_timeout):
source_info["last_sample"] = bytes()
source_info["new_phrase"] = True
else:
source_info["new_phrase"] = False
source_info["last_sample"] += data
source_info["last_spoken"] = time_spoken
def process_mic_data(self):
audio_data = AudioData(self.audio_sources["last_sample"], self.audio_sources["sample_rate"], self.audio_sources["sample_width"])
return audio_data
def process_speaker_data(self):
temp_file = BytesIO()
with wave.open(temp_file, 'wb') as wf:
wf.setnchannels(self.audio_sources["channels"])
wf.setsampwidth(get_sample_size(paInt16))
wf.setframerate(self.audio_sources["sample_rate"])
wf.writeframes(self.audio_sources["last_sample"])
temp_file.seek(0)
with AudioFile(temp_file) as source:
audio = self.audio_recognizer.record(source)
return audio
def update_transcript(self, text):
source_info = self.audio_sources
transcript = self.transcript_data
if source_info["new_phrase"] or len(transcript) == 0:
if len(transcript) > self.max_phrases:
transcript.pop(-1)
transcript.insert(0, text)
else:
transcript[0] = text
def get_transcript(self):
if len(self.transcript_data) > 0:
text = self.transcript_data.pop(-1)
else:
text = ""
return text
def clear_transcript_data(self):
self.transcript_data.clear()
self.audio_sources["last_sample"] = bytes()
self.audio_sources["new_phrase"] = True

View File

@@ -0,0 +1,52 @@
from pyaudiowpatch import PyAudio, paWASAPI
def get_input_device_list():
devices = {}
with PyAudio() as p:
for host_index in range(0, p.get_host_api_count()):
host = p.get_host_api_info_by_index(host_index)
for device_index in range(0, p.get_host_api_info_by_index(host_index)['deviceCount']):
device = p.get_device_info_by_host_api_device_index(host_index, device_index)
if device["maxInputChannels"] > 0 and device["isLoopbackDevice"] is False:
if host["name"] in devices.keys():
devices[host["name"]].append(device)
else:
devices[host["name"]] = [device]
return devices
def get_output_device_list():
devices =[]
with PyAudio() as p:
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
for device in p.get_loopback_device_info_generator():
if device["hostApi"] == wasapi_info["index"] and device["isLoopbackDevice"] is True:
devices.append(device)
return devices
def get_default_input_device():
with PyAudio() as p:
api_info = p.get_default_host_api_info()
defaultInputDevice = api_info["defaultInputDevice"]
for host_index in range(0, p.get_host_api_count()):
host = p.get_host_api_info_by_index(host_index)
for device_index in range(0, p. get_host_api_info_by_index(host_index)['deviceCount']):
device = p.get_device_info_by_host_api_device_index(host_index, device_index)
if device["index"] == defaultInputDevice:
return {"host":host, "device": device}
def get_default_output_device():
with PyAudio() as p:
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
defaultOutputDevice = wasapi_info["defaultOutputDevice"]
for host_index in range(0, p.get_host_api_count()):
for device_index in range(0, p. get_host_api_info_by_index(host_index)['deviceCount']):
device = p.get_device_info_by_host_api_device_index(host_index, device_index)
if device["index"] == defaultOutputDevice:
default_speakers = device
if not default_speakers["isLoopbackDevice"]:
for loopback in p.get_loopback_device_info_generator():
if default_speakers["name"] in loopback["name"]:
default_device = loopback
return default_device

View File

@@ -0,0 +1,243 @@
translatorEngine = ["DeepL(web)", "DeepL(auth)", "Google(web)", "Bing(web)"]
translation_lang = {}
dict_deepl_web_languages = {
"Japanese":"JA",
"English":"EN",
"Korean":"KO",
"Bulgarian":"BG",
"Chinese":"ZH",
"Czech":"CS",
"Danish":"DA",
"Dutch":"NL",
"Estonian":"ET",
"Finnish":"FI",
"French":"FR",
"German":"DE",
"Greek":"EL",
"Hungarian":"HU",
"Italian":"IT",
"Latvian":"LV",
"Lithuanian":"LT",
"Polish":"PL",
"Portuguese":"PT",
"Romanian":"RO",
"Russian":"RU",
"Slovak":"SK",
"Slovenian":"SL",
"Spanish":"ES",
"Swedish":"SV",
"Indonesian":"ID",
"Ukrainian":"UK",
"Turkish":"TR",
"Norwegian":"NB",
}
translation_lang["DeepL(web)"] = {
"source":dict_deepl_web_languages,
"target":dict_deepl_web_languages,
}
dict_deepl_auth_source_languages = {
"Japanese":"ja",
"English":"en",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese":"pt",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
dict_deepl_auth_target_languages = {
"Japanese":"ja",
"English American":"en-US",
"English British":"en-GB",
"Bulgarian":"bg",
"Czech":"cs",
"Danish":"da",
"German":"de",
"Greek":"el",
"English":"en",
"Spanish":"es",
"Estonian":"et",
"Finnish":"fi",
"French":"fr",
"Hungarian":"hu",
"Indonesian":"id",
"Italian":"it",
"Korean":"ko",
"Lithuanian":"lt",
"Latvian":"lv",
"Norwegian":"nb",
"Dutch":"nl",
"Polish":"pl",
"Portuguese Brazilian":"pt-BR",
"Portuguese European":"pt-PT",
"Romanian":"ro",
"Russian":"ru",
"Slovak":"sk",
"Slovenian":"sl",
"Swedish":"sv",
"Turkish":"tr",
"Ukrainian":"uk",
"Chinese":"zh"
}
translation_lang["DeepL(auth)"] = {
"source": dict_deepl_auth_source_languages,
"target": dict_deepl_auth_target_languages,
}
dict_google_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Mongolian":"mn",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Amharic":"am",
"Azerbaijani":"az",
"Belarusian":"be",
"Cebuano":"ceb",
"Esperanto":"eo",
"Basque":"eu",
"Irish":"ga"
}
translation_lang["Google(web)"] = {
"source":dict_google_web_languages,
"target":dict_google_web_languages,
}
dict_bing_web_languages = {
"Japanese":"ja",
"English":"en",
"Chinese":"zh",
"Arabic":"ar",
"Russian":"ru",
"French":"fr",
"German":"de",
"Spanish":"es",
"Portuguese":"pt",
"Italian":"it",
"Korean":"ko",
"Greek":"el",
"Dutch":"nl",
"Hindi":"hi",
"Turkish":"tr",
"Malay":"ms",
"Thai":"th",
"Vietnamese":"vi",
"Indonesian":"id",
"Hebrew":"he",
"Polish":"pl",
"Czech":"cs",
"Hungarian":"hu",
"Estonian":"et",
"Bulgarian":"bg",
"Danish":"da",
"Finnish":"fi",
"Romanian":"ro",
"Swedish":"sv",
"Slovenian":"sl",
"Persian/Farsi":"fa",
"Bosnian":"bs",
"Serbian":"sr",
"Fijian":"fj",
"Filipino":"tl",
"Haitiancreole":"ht",
"Catalan":"ca",
"Croatian":"hr",
"Latvian":"lv",
"Lithuanian":"lt",
"Urdu":"ur",
"Ukrainian":"uk",
"Welsh":"cy",
"Tahiti":"ty",
"Tongan":"to",
"Swahili":"sw",
"Samoan":"sm",
"Slovak":"sk",
"Afrikaans":"af",
"Norwegian":"no",
"Bengali":"bn",
"Malagasy":"mg",
"Maltese":"mt",
"Queretaro otomi":"otq",
"Klingon/tlhingan Hol":"tlh",
"Gujarati":"gu",
"Tamil":"ta",
"Telugu":"te",
"Punjabi":"pa",
"Irish":"ga"
}
translation_lang["Bing(web)"] = {
"source":dict_bing_web_languages,
"target":dict_bing_web_languages,
}

View File

@@ -0,0 +1,68 @@
from deepl import Translator as deepl_Translator
from deepl_translate import translate as deepl_web_Translator
from translators import translate_text as other_web_Translator
from .translation_languages import translatorEngine, translation_lang
# Translator
class Translator():
def __init__(self):
self.translator_status = {}
for translator in translatorEngine:
self.translator_status[translator] = False
self.deepl_client = None
def authentication(self, translator_name, authkey=None):
result = False
try:
if translator_name == "DeepL(web)":
self.translator_status["DeepL(web)"] = True
result = True
elif translator_name == "DeepL(auth)":
self.deepl_client = deepl_Translator(authkey)
self.deepl_client.translate_text(" ", target_lang="EN-US")
self.translator_status["DeepL(auth)"] = True
result = True
elif translator_name == "Google(web)":
self.translator_status["Google(web)"] = True
result = True
elif translator_name == "Bing(web)":
self.translator_status["Bing(web)"] = True
result = True
except:
pass
return result
def translate(self, translator_name, source_language, target_language, message):
result = ""
try:
source_language=translation_lang[translator_name]["source"][source_language]
target_language=translation_lang[translator_name]["target"][target_language]
if translator_name == "DeepL(web)":
result = deepl_web_Translator(
source_language=source_language,
target_language=target_language,
text=message
)
elif translator_name == "DeepL(auth)":
result = self.deepl_client.translate_text(
message,
source_lang=source_language,
target_lang=target_language,
).text
elif translator_name == "Google(web)":
result = other_web_Translator(
query_text=message,
translator="google",
from_language=source_language,
to_language=target_language,
)
elif translator_name == "Bing(web)":
result = other_web_Translator(
query_text=message,
translator="bing",
from_language=source_language,
to_language=target_language,
)
except:
pass
return result

View File

@@ -0,0 +1,72 @@
# ###########################################################################################################################
# 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=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:
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)
response = sock.sendto(msg_str.encode("utf-8"), endpoint)
sock.close()
return response
def notification_xsoverlay_for_vrct(content:str="") -> int:
response = notification_xsoverlay(
title="VRCT",
content=content,
useBase64Icon=True,
icon="./img/xsoverlay.png",
sourceApp="VRCT"
)
return response
if __name__ == "__main__":
notification_xsoverlay_for_vrct(content="notification test")