mirror of
https://gitlab.com/octospacc/WinDog.git
synced 2025-06-05 22:09:20 +02:00
Move all new strings to YAML, basic working Matrix backend with text messages
This commit is contained in:
@ -1,3 +1,8 @@
|
|||||||
|
# ================================== #
|
||||||
|
# WinDog multi-purpose chatbot #
|
||||||
|
# Licensed under AGPLv3 by OctoSpacc #
|
||||||
|
# ================================== #
|
||||||
|
|
||||||
from peewee import *
|
from peewee import *
|
||||||
from LibWinDog.Types import *
|
from LibWinDog.Types import *
|
||||||
|
|
||||||
|
@ -17,58 +17,60 @@
|
|||||||
# end windog config # """
|
# end windog config # """
|
||||||
|
|
||||||
MatrixUrl, MatrixUsername, MatrixPassword, MatrixToken = None, None, None, None
|
MatrixUrl, MatrixUsername, MatrixPassword, MatrixToken = None, None, None, None
|
||||||
|
MatrixClient = None
|
||||||
|
|
||||||
from asyncio import run as asyncio_run
|
from asyncio import run as asyncio_run, create_task as asyncio_create_task
|
||||||
import nio
|
import nio
|
||||||
#from nio import AsyncClient, MatrixRoom, RoomMessageText
|
|
||||||
#import simplematrixbotlib as MatrixBotLib
|
|
||||||
|
|
||||||
async def MatrixMessageHandler(room:nio.MatrixRoom, event:nio.RoomMessage) -> None:
|
def MatrixMain() -> bool:
|
||||||
data = MatrixMakeInputMessageData(room, event)
|
if not (MatrixUrl and MatrixUsername and (MatrixPassword or MatrixToken)):
|
||||||
|
return False
|
||||||
|
def upgrade_username(new:str):
|
||||||
|
global MatrixUsername
|
||||||
|
MatrixUsername = new
|
||||||
|
async def client_main() -> None:
|
||||||
|
global MatrixClient
|
||||||
|
MatrixClient = nio.AsyncClient(MatrixUrl, MatrixUsername)
|
||||||
|
login = await MatrixClient.login(password=MatrixPassword, token=MatrixToken)
|
||||||
|
if MatrixPassword and (not MatrixToken) and (token := ObjGet(login, "access_token")):
|
||||||
|
open("./Config.py", 'a').write(f'\n# Added automatically #\nMatrixToken = "{token}"\n')
|
||||||
|
if (bot_id := ObjGet(login, "user_id")):
|
||||||
|
upgrade_username(bot_id) # ensure username is fully qualified for the API
|
||||||
|
await MatrixClient.sync(30000) # resync old messages first to "skip read ones"
|
||||||
|
MatrixClient.add_event_callback(MatrixMessageHandler, nio.RoomMessage)
|
||||||
|
await MatrixClient.sync_forever(timeout=30000)
|
||||||
|
Thread(target=lambda:asyncio_run(client_main())).start()
|
||||||
|
return True
|
||||||
|
|
||||||
def MatrixMakeInputMessageData(room:nio.MatrixRoom, event:nio.RoomMessage) -> InputMessageData:
|
def MatrixMakeInputMessageData(room:nio.MatrixRoom, event:nio.RoomMessage) -> InputMessageData:
|
||||||
data = InputMessageData(
|
data = InputMessageData(
|
||||||
message_id = f"matrix:{event.event_id}",
|
message_id = f"matrix:{event.event_id}",
|
||||||
|
datetime = event.server_timestamp,
|
||||||
|
text_plain = event.body,
|
||||||
|
text_html = event.formatted_body, # note: this could be None
|
||||||
room = SafeNamespace(
|
room = SafeNamespace(
|
||||||
id = f"matrix:{room.room_id}",
|
id = f"matrix:{room.room_id}",
|
||||||
name = room.display_name,
|
name = room.display_name,
|
||||||
),
|
),
|
||||||
user = SafeNamespace(
|
user = SafeNamespace(
|
||||||
id = f"matrix:{event.sender}",
|
id = f"matrix:{event.sender}",
|
||||||
)
|
#name = , # TODO name must be get via a separate API request (and so maybe we should cache it)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
print(data)
|
data.command = ParseCommand(data.text_plain)
|
||||||
|
data.user.settings = (GetUserSettings(data.user.id) or SafeNamespace())
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def MatrixMain() -> bool:
|
async def MatrixMessageHandler(room:nio.MatrixRoom, event:nio.RoomMessage) -> None:
|
||||||
if not (MatrixUrl and MatrixUsername and (MatrixPassword or MatrixToken)):
|
if MatrixUsername == event.sender:
|
||||||
return False
|
return # ignore messages that come from the bot itself
|
||||||
#MatrixBot = MatrixBotLib.Bot(MatrixBotLib.Creds(MatrixUrl, MatrixUsername, MatrixPassword))
|
data = MatrixMakeInputMessageData(room, event)
|
||||||
##@MatrixBot.listener.on_message_event
|
OnMessageParsed(data)
|
||||||
#@MatrixBot.listener.on_custom_event(nio.RoomMessageText)
|
if (command := ObjGet(data, "command.name")):
|
||||||
#async def MatrixMessageListener(room, message, event) -> None:
|
CallEndpoint(command, EventContext(platform="matrix", event=SafeNamespace(room=room, event=event), manager=MatrixClient), data)
|
||||||
# print(message)
|
|
||||||
# #match = MatrixBotLib.MessageMatch(room, message, MatrixBot)
|
|
||||||
# #OnMessageParsed()
|
|
||||||
# #if match.is_not_from_this_bot() and match.command("windogtest"):
|
|
||||||
# # pass #await MatrixBot.api.send_text_message(room.room_id, " ".join(arg for arg in match.args()))
|
|
||||||
#@MatrixBot.listener.on_custom_event(nio.RoomMessageFile)
|
|
||||||
#async def MatrixMessageFileListener(room, event):
|
|
||||||
# print(event)
|
|
||||||
#Thread(target=lambda:MatrixBot.run()).start()
|
|
||||||
async def client() -> None:
|
|
||||||
client = nio.AsyncClient(MatrixUrl, MatrixUsername)
|
|
||||||
login = await client.login(password=MatrixPassword, token=MatrixToken)
|
|
||||||
if MatrixPassword and (not MatrixToken) and (token := ObjGet(login, "access_token")):
|
|
||||||
open("./Config.py", 'a').write(f'\n# Added automatically #\nMatrixToken = "{token}"\n')
|
|
||||||
await client.sync(30000) # resync old messages first to "skip read ones"
|
|
||||||
client.add_event_callback(MatrixMessageHandler, nio.RoomMessage)
|
|
||||||
await client.sync_forever(timeout=30000)
|
|
||||||
Thread(target=lambda:asyncio_run(client())).start()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def MatrixSender() -> None:
|
def MatrixSender(context:EventContext, data:OutputMessageData, destination) -> None:
|
||||||
pass
|
asyncio_create_task(context.manager.room_send(room_id=context.event.room.room_id, message_type="m.room.message", content={"msgtype": "m.text", "body": data.text_plain}))
|
||||||
|
|
||||||
#RegisterPlatform(name="Matrix", main=MatrixMain, sender=MatrixSender)
|
RegisterPlatform(name="Matrix", main=MatrixMain, sender=MatrixSender)
|
||||||
|
|
||||||
|
@ -1,2 +1 @@
|
|||||||
matrix-nio
|
matrix-nio
|
||||||
simplematrixbotlib
|
|
||||||
|
@ -35,22 +35,23 @@ def TelegramMakeInputMessageData(message:telegram.Message) -> InputMessageData:
|
|||||||
# return None
|
# return None
|
||||||
data = InputMessageData(
|
data = InputMessageData(
|
||||||
message_id = f"telegram:{message.message_id}",
|
message_id = f"telegram:{message.message_id}",
|
||||||
|
datetime = int(time.mktime(message.date.timetuple())),
|
||||||
text_plain = message.text,
|
text_plain = message.text,
|
||||||
text_markdown = message.text_markdown_v2,
|
text_markdown = message.text_markdown_v2,
|
||||||
|
user = SafeNamespace(
|
||||||
|
id = f"telegram:{message.from_user.id}",
|
||||||
|
tag = message.from_user.username,
|
||||||
|
name = message.from_user.first_name,
|
||||||
|
),
|
||||||
|
room = SafeNamespace(
|
||||||
|
id = f"telegram:{message.chat.id}",
|
||||||
|
tag = message.chat.username,
|
||||||
|
name = (message.chat.title or message.chat.first_name),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
data.text_auto = GetWeightedText(data.text_markdown, data.text_plain)
|
data.text_auto = GetWeightedText(data.text_markdown, data.text_plain)
|
||||||
data.command = ParseCommand(data.text_plain)
|
data.command = ParseCommand(data.text_plain)
|
||||||
data.user = SafeNamespace(
|
|
||||||
id = f"telegram:{message.from_user.id}",
|
|
||||||
tag = message.from_user.username,
|
|
||||||
name = message.from_user.first_name,
|
|
||||||
)
|
|
||||||
data.user.settings = (GetUserSettings(data.user.id) or SafeNamespace())
|
data.user.settings = (GetUserSettings(data.user.id) or SafeNamespace())
|
||||||
data.room = SafeNamespace(
|
|
||||||
id = f"telegram:{message.chat.id}",
|
|
||||||
tag = message.chat.username,
|
|
||||||
name = (message.chat.title or message.chat.first_name),
|
|
||||||
)
|
|
||||||
linked = TelegramLinker(data)
|
linked = TelegramLinker(data)
|
||||||
data.message_url = linked.message
|
data.message_url = linked.message
|
||||||
data.room.url = linked.room
|
data.room.url = linked.room
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
# ================================== #
|
||||||
|
# WinDog multi-purpose chatbot #
|
||||||
|
# Licensed under AGPLv3 by OctoSpacc #
|
||||||
|
# ================================== #
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
class SafeNamespace(SimpleNamespace):
|
class SafeNamespace(SimpleNamespace):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# ==================================== #
|
# ================================== #
|
||||||
# WinDog multi-purpose chatbot #
|
# WinDog multi-purpose chatbot #
|
||||||
# Licensed under AGPLv3 by OctoSpacc #
|
# Licensed under AGPLv3 by OctoSpacc #
|
||||||
# ==================================== #
|
# ================================== #
|
||||||
|
|
||||||
def cSource(context:EventContext, data:InputMessageData) -> None:
|
def cSource(context:EventContext, data:InputMessageData) -> None:
|
||||||
SendMessage(context, {"TextPlain": ("""\
|
SendMessage(context, {"TextPlain": ("""\
|
||||||
@ -28,7 +28,10 @@ def cConfig(context:EventContext, data:InputMessageData) -> None:
|
|||||||
# ... userdata: import, export, delete
|
# ... userdata: import, export, delete
|
||||||
|
|
||||||
def cPing(context:EventContext, data:InputMessageData) -> None:
|
def cPing(context:EventContext, data:InputMessageData) -> None:
|
||||||
SendMessage(context, {"Text": "*Pong!*"})
|
# nice experiment, but it won't work with Telegram since time is not to milliseconds (?)
|
||||||
|
#time_diff = (time_now := int(time.time())) - (time_sent := data.datetime)
|
||||||
|
#SendMessage(context, OutputMessageData(text_html=f"<b>Pong!</b>\n\n{time_sent} → {time_now} = {time_diff}"))
|
||||||
|
SendMessage(context, OutputMessageData(text_html="<b>Pong!</b>"))
|
||||||
|
|
||||||
#def cTime(update:Update, context:CallbackContext) -> None:
|
#def cTime(update:Update, context:CallbackContext) -> None:
|
||||||
# update.message.reply_markdown_v2(
|
# update.message.reply_markdown_v2(
|
||||||
@ -39,12 +42,12 @@ def cEval(context:EventContext, data:InputMessageData) -> None:
|
|||||||
SendMessage(context, {"Text": choice(Locale.__('eval'))})
|
SendMessage(context, {"Text": choice(Locale.__('eval'))})
|
||||||
|
|
||||||
RegisterModule(name="Base", endpoints=[
|
RegisterModule(name="Base", endpoints=[
|
||||||
SafeNamespace(names=["source"], summary="Provides a copy of the bot source codes and/or instructions on how to get it.", handler=cSource),
|
SafeNamespace(names=["source"], handler=cSource),
|
||||||
SafeNamespace(names=["config"], handler=cConfig, arguments={
|
SafeNamespace(names=["config"], handler=cConfig, arguments={
|
||||||
"get": True,
|
"get": True,
|
||||||
}),
|
}),
|
||||||
#SafeNamespace(names=["gdpr"], summary="Operations for european citizens regarding your personal data.", handler=cGdpr),
|
#SafeNamespace(names=["gdpr"], summary="Operations for european citizens regarding your personal data.", handler=cGdpr),
|
||||||
SafeNamespace(names=["ping"], summary="Responds pong, useful for testing messaging latency.", handler=cPing),
|
SafeNamespace(names=["ping"], handler=cPing),
|
||||||
#SafeNamespace(names=["eval"], summary="Execute a Python command (or safe literal operation) in the current context. Currently not implemented.", handler=cEval),
|
#SafeNamespace(names=["eval"], summary="Execute a Python command (or safe literal operation) in the current context. Currently not implemented.", handler=cEval),
|
||||||
#SafeNamespace(names=["format"], summary="Reformat text using an handful of rules. Not yet implemented.", handler=cFormat),
|
#SafeNamespace(names=["format"], summary="Reformat text using an handful of rules. Not yet implemented.", handler=cFormat),
|
||||||
#SafeNamespace(names=["frame"], summary="Frame someone's message into a platform-styled image. Not yet implemented.", handler=cFrame),
|
#SafeNamespace(names=["frame"], summary="Frame someone's message into a platform-styled image. Not yet implemented.", handler=cFrame),
|
||||||
|
8
ModWinDog/Base/Base.yaml
Normal file
8
ModWinDog/Base/Base.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
endpoints:
|
||||||
|
source:
|
||||||
|
summary:
|
||||||
|
en: Provides a copy of the bot source codes and/or instructions on how to get it.
|
||||||
|
ping:
|
||||||
|
summary:
|
||||||
|
en: Responds pong, useful for testing messaging latency.
|
||||||
|
|
@ -13,7 +13,7 @@ def cBroadcast(context:EventContext, data:InputMessageData) -> None:
|
|||||||
SendMessage(context, {"TextPlain": "Executed."})
|
SendMessage(context, {"TextPlain": "Executed."})
|
||||||
|
|
||||||
RegisterModule(name="Broadcast", endpoints=[
|
RegisterModule(name="Broadcast", endpoints=[
|
||||||
SafeNamespace(names=["broadcast"], summary="Sends an admin message over to any chat destination.", handler=cBroadcast, arguments={
|
SafeNamespace(names=["broadcast"], handler=cBroadcast, arguments={
|
||||||
"destination": True,
|
"destination": True,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
5
ModWinDog/Broadcast/Broadcast.yaml
Normal file
5
ModWinDog/Broadcast/Broadcast.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
endpoints:
|
||||||
|
broadcast:
|
||||||
|
summary:
|
||||||
|
en: Sends an admin message over to any chat destination.
|
||||||
|
|
@ -17,7 +17,7 @@ def cGpt(context:EventContext, data:InputMessageData) -> None:
|
|||||||
output += (completion.choices[0].delta.content or "")
|
output += (completion.choices[0].delta.content or "")
|
||||||
return SendMessage(context, {"TextPlain": f"[🤖️ GPT]\n\n{output}"})
|
return SendMessage(context, {"TextPlain": f"[🤖️ GPT]\n\n{output}"})
|
||||||
|
|
||||||
RegisterModule(name="ChatGPT", endpoints=[
|
RegisterModule(name="GPT", endpoints=[
|
||||||
SafeNamespace(names=["gpt", "chatgpt"], summary="Sends a message to GPT to get back a response. Note: conversations are not yet supported, and this is more standard GPT than ChatGPT, and in general there are many bugs!", handler=cGpt),
|
SafeNamespace(names=["gpt", "chatgpt"], handler=cGpt),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
6
ModWinDog/GPT/GPT.yaml
Normal file
6
ModWinDog/GPT/GPT.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
endpoints:
|
||||||
|
gpt:
|
||||||
|
summary:
|
||||||
|
en: >
|
||||||
|
Sends a message to GPT to get back a response. Note: conversations are not yet supported, and this is more standard GPT than ChatGPT, and in general there are many bugs!
|
||||||
|
|
@ -8,7 +8,7 @@ def cHelp(context:EventContext, data:InputMessageData) -> None:
|
|||||||
module_list = ''
|
module_list = ''
|
||||||
language = data.user.settings.language
|
language = data.user.settings.language
|
||||||
for module in Modules:
|
for module in Modules:
|
||||||
summary = Modules[module].get_string("summary", language)#summary
|
summary = Modules[module].get_string("summary", language)
|
||||||
endpoints = Modules[module].endpoints
|
endpoints = Modules[module].endpoints
|
||||||
module_list += (f"\n\n{module}" + (f": {summary}" if summary else ''))
|
module_list += (f"\n\n{module}" + (f": {summary}" if summary else ''))
|
||||||
for endpoint in endpoints:
|
for endpoint in endpoints:
|
||||||
|
@ -136,14 +136,14 @@ def cSafebooru(context:EventContext, data:InputMessageData) -> None:
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
RegisterModule(name="Internet", summary="Tools and toys related to the Internet.", endpoints=[
|
RegisterModule(name="Internet", endpoints=[
|
||||||
SafeNamespace(names=["embedded"], summary="Rewrites a link, trying to bypass embed view protection.", handler=cEmbedded),
|
SafeNamespace(names=["embedded"], handler=cEmbedded),
|
||||||
SafeNamespace(names=["web"], summary="Provides results of a DuckDuckGo search.", handler=cWeb),
|
SafeNamespace(names=["web"], handler=cWeb),
|
||||||
SafeNamespace(names=["translate"], summary="Returns the received message after translating it in another language.", handler=cTranslate, arguments={
|
SafeNamespace(names=["translate"], handler=cTranslate, arguments={
|
||||||
"language_to": True,
|
"language_to": True,
|
||||||
"language_from": False,
|
"language_from": False,
|
||||||
}),
|
}),
|
||||||
#SafeNamespace(names=["unsplash"], summary="Sends a picture sourced from Unsplash.", handler=cUnsplash),
|
#SafeNamespace(names=["unsplash"], summary="Sends a picture sourced from Unsplash.", handler=cUnsplash),
|
||||||
SafeNamespace(names=["safebooru"], summary="Sends a picture sourced from Safebooru.", handler=cSafebooru),
|
SafeNamespace(names=["safebooru"], handler=cSafebooru),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
16
ModWinDog/Internet/Internet.yaml
Normal file
16
ModWinDog/Internet/Internet.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
summary:
|
||||||
|
en: Tools and toys related to the Internet.
|
||||||
|
endpoints:
|
||||||
|
embedded:
|
||||||
|
summary:
|
||||||
|
en: Rewrite a link, bypassing embed view protections for known sites.
|
||||||
|
web:
|
||||||
|
summary:
|
||||||
|
en: Provides results of a DuckDuckGo search.
|
||||||
|
translate:
|
||||||
|
summary:
|
||||||
|
en: Returns the received message after translating it in another language.
|
||||||
|
safebooru:
|
||||||
|
summary:
|
||||||
|
en: Sends a picture sourced from Safebooru.
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
# ==================================== #
|
# ================================== #
|
||||||
# WinDog multi-purpose chatbot #
|
# WinDog multi-purpose chatbot #
|
||||||
# Licensed under AGPLv3 by OctoSpacc #
|
# Licensed under AGPLv3 by OctoSpacc #
|
||||||
# ==================================== #
|
# ================================== #
|
||||||
|
|
||||||
def mMultifun(context:EventContext, data:InputMessageData) -> None:
|
def mMultifun(context:EventContext, data:InputMessageData) -> None:
|
||||||
cmdkey = data.command.name
|
cmdkey = data.command.name
|
||||||
@ -23,6 +23,6 @@ def mMultifun(context:EventContext, data:InputMessageData) -> None:
|
|||||||
SendMessage(context, {"Text": Text, "ReplyTo": replyToId})
|
SendMessage(context, {"Text": Text, "ReplyTo": replyToId})
|
||||||
|
|
||||||
RegisterModule(name="Multifun", endpoints=[
|
RegisterModule(name="Multifun", endpoints=[
|
||||||
SafeNamespace(names=["hug", "pat", "poke", "cuddle", "hands", "floor", "sessocto"], summary="Provides fun trough preprogrammed-text-based toys.", handler=mMultifun),
|
SafeNamespace(names=["hug", "pat", "poke", "cuddle", "hands", "floor", "sessocto"], handler=mMultifun),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
3
ModWinDog/Multifun/Multifun.yaml
Normal file
3
ModWinDog/Multifun/Multifun.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
summary:
|
||||||
|
en: Provides fun trough preprogrammed text-based toys.
|
||||||
|
|
@ -8,6 +8,6 @@ def mPercenter(context:EventContext, data:InputMessageData) -> None:
|
|||||||
Cmd=data.command.tokens[0], Percent=RandPercent(), Thing=data.command.body)})
|
Cmd=data.command.tokens[0], Percent=RandPercent(), Thing=data.command.body)})
|
||||||
|
|
||||||
RegisterModule(name="Percenter", endpoints=[
|
RegisterModule(name="Percenter", endpoints=[
|
||||||
SafeNamespace(names=["wish", "level"], summary="Provides fun trough percentage-based toys.", handler=mPercenter),
|
SafeNamespace(names=["wish", "level"], handler=mPercenter),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
3
ModWinDog/Percenter/Percenter.yaml
Normal file
3
ModWinDog/Percenter/Percenter.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
summary:
|
||||||
|
en: Provides fun trough percentage-based toys.
|
||||||
|
|
@ -119,7 +119,7 @@ def cCraiyonSelenium(context:EventContext, data:InputMessageData) -> None:
|
|||||||
closeSelenium(driver_index, driver)
|
closeSelenium(driver_index, driver)
|
||||||
|
|
||||||
RegisterModule(name="Scrapers", endpoints=[
|
RegisterModule(name="Scrapers", endpoints=[
|
||||||
SafeNamespace(names=["dalle"], summary="Sends an AI-generated picture from DALL-E 3 via Microsoft Bing.", handler=cDalleSelenium),
|
SafeNamespace(names=["dalle"], handler=cDalleSelenium),
|
||||||
SafeNamespace(names=["craiyon", "crayion"], summary="Sends an AI-generated picture from Craiyon.com.", handler=cCraiyonSelenium),
|
SafeNamespace(names=["craiyon", "crayion"], handler=cCraiyonSelenium),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
8
ModWinDog/Scrapers/Scrapers.yaml
Normal file
8
ModWinDog/Scrapers/Scrapers.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
endpoints:
|
||||||
|
dalle:
|
||||||
|
summary:
|
||||||
|
en: Sends an AI-generated picture from DALL-E 3 via Microsoft Bing.
|
||||||
|
craiyon:
|
||||||
|
summary:
|
||||||
|
en: Sends an AI-generated picture from Craiyon.com.
|
||||||
|
|
@ -52,7 +52,7 @@ end)()"""))
|
|||||||
Log(textOutput := ("Lua Error: " + str(error)))
|
Log(textOutput := ("Lua Error: " + str(error)))
|
||||||
SendMessage(context, {"TextPlain": textOutput})
|
SendMessage(context, {"TextPlain": textOutput})
|
||||||
|
|
||||||
RegisterModule(name="Scripting", group="Geek", summary="Tools for programming the bot and expanding its features.", endpoints=[
|
RegisterModule(name="Scripting", group="Geek", endpoints=[
|
||||||
SafeNamespace(names=["lua"], summary="Execute a Lua snippet and get its output.", handler=cLua),
|
SafeNamespace(names=["lua"], handler=cLua),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
7
ModWinDog/Scripting/Scripting.yaml
Normal file
7
ModWinDog/Scripting/Scripting.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
summary:
|
||||||
|
en: Tools for programming the bot and expanding its features.
|
||||||
|
endpoints:
|
||||||
|
lua:
|
||||||
|
summary:
|
||||||
|
en: Execute a Lua snippet and get its output.
|
||||||
|
|
17
WinDog.py
17
WinDog.py
@ -165,7 +165,7 @@ def GetUserSettings(user_id:str) -> SafeNamespace|None:
|
|||||||
except EntitySettings.DoesNotExist:
|
except EntitySettings.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# TODO handle @ characters attached to command, e.g. on telegram
|
# TODO ignore tagged commands when they are not directed to the bot's username
|
||||||
def ParseCommand(text:str) -> SafeNamespace|None:
|
def ParseCommand(text:str) -> SafeNamespace|None:
|
||||||
if not text:
|
if not text:
|
||||||
return None
|
return None
|
||||||
@ -176,8 +176,8 @@ def ParseCommand(text:str) -> SafeNamespace|None:
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
command = SafeNamespace()
|
command = SafeNamespace()
|
||||||
command.tokens = text.replace("\r", " ").replace("\n", " ").replace("\t", " ").replace(" ", " ").replace(" ", " ").split(" ")
|
command.tokens = text.split()
|
||||||
command.name = command.tokens[0][1:].lower()
|
command.name = command.tokens[0][1:].lower().split('@')[0]
|
||||||
command.body = text[len(command.tokens[0]):].strip()
|
command.body = text[len(command.tokens[0]):].strip()
|
||||||
if command.name not in Endpoints:
|
if command.name not in Endpoints:
|
||||||
return command
|
return command
|
||||||
@ -244,9 +244,10 @@ def SendMessage(context:EventContext, data:OutputMessageData, destination=None)
|
|||||||
#data.text_html = ???
|
#data.text_html = ???
|
||||||
if data.media:
|
if data.media:
|
||||||
data.media = SureArray(data.media)
|
data.media = SureArray(data.media)
|
||||||
for platform in Platforms.values():
|
#for platform in Platforms.values():
|
||||||
if isinstanceSafe(context.event, platform.eventClass) or isinstanceSafe(context.manager, platform.managerClass):
|
# if isinstanceSafe(context.event, platform.eventClass) or isinstanceSafe(context.manager, platform.managerClass):
|
||||||
return platform.sender(context, data, destination)
|
# return platform.sender(context, data, destination)
|
||||||
|
return Platforms[context.platform].sender(context, data, destination)
|
||||||
|
|
||||||
def SendNotice(context:EventContext, data) -> None:
|
def SendNotice(context:EventContext, data) -> None:
|
||||||
pass
|
pass
|
||||||
@ -255,10 +256,10 @@ def DeleteMessage(context:EventContext, data) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def RegisterPlatform(name:str, main:callable, sender:callable, linker:callable=None, *, eventClass=None, managerClass=None) -> None:
|
def RegisterPlatform(name:str, main:callable, sender:callable, linker:callable=None, *, eventClass=None, managerClass=None) -> None:
|
||||||
Platforms[name] = SafeNamespace(main=main, sender=sender, linker=linker, eventClass=eventClass, managerClass=managerClass)
|
Platforms[name.lower()] = SafeNamespace(main=main, sender=sender, linker=linker, eventClass=eventClass, managerClass=managerClass)
|
||||||
Log(f"{name}, ", inline=True)
|
Log(f"{name}, ", inline=True)
|
||||||
|
|
||||||
def RegisterModule(name:str, endpoints:dict, *, group:str|None=None, summary:str|None=None) -> None:
|
def RegisterModule(name:str, endpoints:dict, *, group:str|None=None) -> None:
|
||||||
module = SafeNamespace(group=group, endpoints=endpoints, get_string=(lambda query, lang=None, /: None))
|
module = SafeNamespace(group=group, endpoints=endpoints, get_string=(lambda query, lang=None, /: None))
|
||||||
if isfile(file := f"./ModWinDog/{name}/{name}.yaml"):
|
if isfile(file := f"./ModWinDog/{name}/{name}.yaml"):
|
||||||
module.strings = yaml_load(open(file, 'r').read().replace("\t", " "), Loader=yaml_BaseLoader)
|
module.strings = yaml_load(open(file, 'r').read().replace("\t", " "), Loader=yaml_BaseLoader)
|
||||||
|
Reference in New Issue
Block a user