Add months-old local changes, restructure platforms api and some modules, fix some bugs

This commit is contained in:
2024-06-15 02:08:09 +02:00
parent 2512df4f98
commit b7eb53e6a7
13 changed files with 393 additions and 332 deletions

205
WinDog.py
View File

@ -4,36 +4,34 @@
# Licensed under AGPLv3 by OctoSpacc #
# ==================================== #
import json, hashlib, re, time, subprocess
import json, re, time, subprocess
from binascii import hexlify
from magic import Magic
from os import listdir
from os.path import isfile
from os.path import isfile, isdir
from random import choice, randint
from types import SimpleNamespace
#from traceback import format_exc as TraceText
import mastodon, telegram
from bs4 import BeautifulSoup
from html import unescape as HtmlUnescape
from markdown import markdown
from telegram import Update, ForceReply, Bot
from telegram.utils.helpers import escape_markdown
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext
from urllib import parse as UrlParse
from urllib.request import urlopen, Request
# <https://daringfireball.net/projects/markdown/syntax#backslash>
MdEscapes = '\\`*_{}[]()<>#+-.!|='
Db = { "Rooms": {}, "Users": {}, }
Locale = { "Fallback": {}, }
Db = {"Rooms": {}, "Users": {}}
Locale = {"Fallback": {}}
Platforms = {}
Commands = {}
for Dir in ('Mod', 'Lib'):
for File in listdir(f'./{Dir}WinDog'):
File = f'./{Dir}WinDog/{File}'
if isfile(File):
with open(File, 'r') as File:
exec(File.read())
for dir in ("LibWinDog/Platforms", "ModWinDog"):
for path in listdir(f"./{dir}"):
path = f"./{dir}/{path}"
if isfile(path):
exec(open(path, 'r').read())
elif isdir(path):
exec(open(f"{path}/mod.py", 'r').read())
exec(open("./LibWinDog/Config.py", 'r').read())
def SetupLocale() -> None:
global Locale
@ -94,18 +92,18 @@ def CharEscape(String:str, Escape:str='') -> str:
String = String.replace(c, '\\'+c)
return String
def InferMdEscape(Raw:str, Plain:str) -> str:
Chs = ''
for Ch in MdEscapes:
if Ch in Raw and Ch in Plain:
Chs += Ch
return Chs
def InferMdEscape(raw:str, plain:str) -> str:
chars = ''
for char in MdEscapes:
if char in raw and char in plain:
chars += char
return chars
def MarkdownCode(Text:str, Block:bool) -> str:
return '```\n' + Text.strip().replace('`', '\`') + '\n```'
def MarkdownCode(text:str, block:bool) -> str:
return '```\n' + text.strip().replace('`', '\`') + '\n```'
def MdToTxt(Md:str) -> str:
return BeautifulSoup(markdown(Md), 'html.parser').get_text(' ')
def MdToTxt(md:str) -> str:
return BeautifulSoup(markdown(md), 'html.parser').get_text(' ')
def HtmlEscapeFull(Raw:str) -> str:
New = ''
@ -114,78 +112,29 @@ def HtmlEscapeFull(Raw:str) -> str:
New += f'&#x{Hex[i] + Hex[i+1]};'
return New
def CmdAllowed(update) -> bool:
if not TelegramRestrict:
return True
else:
if TelegramRestrict.lower() == 'whitelist':
if update.message.chat.id in TelegramWhitelist:
return True
return False
def GetRawTokens(text:str) -> list:
return text.strip().replace('\t', ' ').replace(' ', ' ').replace(' ', ' ').split(' ')
def HandleCmd(update):
TelegramQueryHandle(update)
if CmdAllowed(update):
return ParseCmd(update.message.text)
else:
return False
def ParseCmd(msg) -> dict|None:
name = msg.lower().split(' ')[0][1:].split('@')[0]
if not name:
return
return SimpleNamespace(**{
"Name": name,
"Body": name.join(msg.split(name)[1:]).strip(),
"Tokens": GetRawTokens(msg),
"User": None,
"Quoted": None,
})
def GetRawTokens(Text:str) -> list:
return Text.strip().replace('\t', ' ').replace(' ', ' ').replace(' ', ' ').split(' ')
def ParseCmd(Msg) -> dict:
Name = Msg.lower().split(' ')[0][1:].split('@')[0]
if Name:
return SimpleNamespace(**{
"Name": Name,
"Body": Name.join(Msg.split(Name)[1:]).strip(),
"Tokens": GetRawTokens(Msg),
"User": None,
"Quoted": None,
})
def TelegramQueryHandle(update:Update, context:CallbackContext=None) -> None:
if update and update.message:
Cmd = ParseCmd(update.message.text)
if Cmd and Cmd.Tokens[0][0] in CmdPrefixes and Cmd.Name in Endpoints:
Cmd.User = {
"Name": update.message.from_user.first_name,
"Tag": update.message.from_user.username,
"Id": f'{update.message.from_user.id}@telegram',
}
if update.message.reply_to_message:
Cmd.Quoted = {
"Body": update.message.reply_to_message.text,
"User": {
"Name": update.message.reply_to_message.from_user.first_name,
"Tag": update.message.reply_to_message.from_user.username,
"Id": f'{update.message.reply_to_message.from_user.id}@telegram',
},
}
Endpoints[Cmd.Name]({ "Event": update, "Manager": context }, Cmd)
if Debug and Dumper:
Text = update.message.text
Text = (Text.replace('\n', '\\n') if Text else '')
with open('Dump.txt', 'a') as File:
File.write(f'[{time.ctime()}] [{int(time.time())}] [{update.message.chat.id}] [{update.message.message_id}] [{update.message.from_user.id}] {Text}\n')
'''
if CmdAllowed(update):
ChatID = update.message.chat.id
if ChatID in Private['Chats'] and 'Filters' in Private['Chats'][ChatID]:
for f in Private['Chats'][ChatID]['Filters']:
if f in update.message.text:
update.message.reply_text(
Private['Chats'][ChatID]['Filters'][f],
reply_to_message_id=update.message.message_id)
'''
def GetWeightedText(texts:tuple) -> str:
for text in texts:
if text:
return text
def RandPercent() -> int:
Num = randint(0,100)
if Num == 100:
Num = f'{Num}.00'
else:
Num = f'{Num}.{randint(0,9)}{randint(0,9)}'
return Num
num = randint(0,100)
return (f'{num}.00' if num == 100 else f'{num}.{randint(0,9)}{randint(0,9)}')
def RandHexStr(Len:int) -> str:
Hex = ''
@ -193,16 +142,12 @@ def RandHexStr(Len:int) -> str:
Hex += choice('0123456789abcdef')
return Hex
def HttpGet(Url:str):
return urlopen(Request(Url, headers={"User-Agent": WebUserAgent}))
def SendMsg(Context, Data, Destination=None) -> None:
if type(Context) == dict:
Event = Context['Event'] if 'Event' in Context else None
Manager = Context['Manager'] if 'Manager' in Context else None
else:
[Event, Manager] = [Context, Context]
if InDict(Data, 'TextPlain') or InDict(Data, 'TextMarkdown'):
TextPlain = InDict(Data, 'TextPlain')
TextMarkdown = InDict(Data, 'TextMarkdown')
@ -212,62 +157,20 @@ def SendMsg(Context, Data, Destination=None) -> None:
# our old system attemps to always receive Markdown and retransform when needed
TextPlain = MdToTxt(Data['Text'])
TextMarkdown = CharEscape(HtmlUnescape(Data['Text']), InferMdEscape(HtmlUnescape(Data['Text']), TextPlain))
if isinstance(Manager, mastodon.Mastodon):
if InDict(Data, 'Media'):
Media = Manager.media_post(Data['Media'], Magic(mime=True).from_buffer(Data['Media']))
while Media['url'] == 'null':
Media = Manager.media(Media)
if TextPlain:
Manager.status_post(
status=(TextPlain + '\n\n@' + Event['account']['acct']),
media_ids=(Media if InDict(Data, 'Media') else None),
in_reply_to_id=Event['status']['id'],
visibility=('direct' if Event['status']['visibility'] == 'direct' else 'unlisted'),
)
elif isinstance(Event, telegram.Update):
if Destination:
Manager.bot.send_message(Destination, text=TextPlain)
else:
if InDict(Data, 'Media'):
Event.message.reply_photo(
Data['Media'],
caption=(TextMarkdown if TextMarkdown else TextPlain if TextPlain else None),
parse_mode=('MarkdownV2' if TextMarkdown else None),
reply_to_message_id=Event.message.message_id,
)
elif TextMarkdown:
Event.message.reply_markdown_v2(TextMarkdown, reply_to_message_id=Event.message.message_id)
elif TextPlain:
Event.message.reply_text(TextPlain,reply_to_message_id=Event.message.message_id)
for platform in Platforms:
platform = Platforms[platform]
if ("eventClass" in platform and isinstance(Event, platform["eventClass"])) \
or ("managerClass" in platform and isinstance(Manager, platform["managerClass"])):
platform["sender"](Event, Manager, Data, Destination, TextPlain, TextMarkdown)
def Main() -> None:
SetupDb()
SetupLocale()
if TelegramToken:
updater = Updater(TelegramToken)
dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler('config', cConfig))
for Cmd in ('hug', 'pat', 'poke', 'cuddle', 'floor', 'hands', 'sessocto'):
dispatcher.add_handler(CommandHandler(Cmd, multifun))
dispatcher.add_handler(MessageHandler(Filters.text | Filters.command, TelegramQueryHandle))
updater.start_polling()
if MastodonUrl and MastodonToken:
Mastodon = mastodon.Mastodon(api_base_url=MastodonUrl, access_token=MastodonToken)
class MastodonListener(mastodon.StreamListener):
def on_notification(self, Event):
if Event['type'] == 'mention':
Msg = BeautifulSoup(Event['status']['content'], 'html.parser').get_text(' ').strip().replace('\t', ' ')
if not Msg.split('@')[0]:
Msg = ' '.join('@'.join(Msg.split('@')[1:]).strip().split(' ')[1:]).strip()
if Msg[0] in CmdPrefixes:
Cmd = ParseCmd(Msg)
if Cmd.Name in Endpoints:
Endpoints[Cmd.Name]({"Event": Event, "Manager": Mastodon}, Cmd)
Mastodon.stream_user(MastodonListener())
TelegramMain()
MastodonMain()
#MatrixMain()
#for platform in Platforms:
# Platforms[platform]["main"]()
while True:
time.sleep(9**9)
@ -276,7 +179,7 @@ if __name__ == '__main__':
from Config import *
except Exception:
pass
print('Starting WinDog...')
Main()
print('Closing WinDog...')