Add commands exec eval level and some fixes

This commit is contained in:
octospacc 2023-07-07 18:14:18 +02:00
parent a54ebb61f2
commit fcd444bf0f
5 changed files with 223 additions and 96 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
Database.json
Dump.txt
Config.py Config.py
*.pyc *.pyc

View File

@ -1,13 +1,13 @@
{ {
"start": [ "start": [
"Hi {user.mention_markdown_v2()}!" "*Hi* {user.mention_markdown_v2()}*!*"
], ],
"help": [ "help": [
"There's no one around to help (yet)." "*There's no one around to help (yet).*"
], ],
"echo": { "echo": {
"empty": [ "empty": [
"Echo what? Give me something to repeat." "*Echo what? Give me something to repeat.*"
] ]
}, },
"wish": { "wish": {
@ -15,7 +15,7 @@
"*You wished for nothing! ✨*\n\n_Nothing happens..._" "*You wished for nothing! ✨*\n\n_Nothing happens..._"
], ],
"done": [ "done": [
"*Your wish has been cast! ✨*\n\n_Chance of success: {0}%_" "*Your wish has been cast! ✨*\n\n_Chance of success: *{Percent}%*._"
] ]
}, },
"hug": { "hug": {
@ -27,5 +27,22 @@
"others": [ "others": [
"*{0} hugs {1} tightly... :3*" "*{0} hugs {1} tightly... :3*"
] ]
} },
} "level": {
"empty": [
"Check what's your level of something.\n\n*Usage*: {Cmd} <Thing>."
],
"done": [
"_Your level of *{Thing}* is... *{Percent}%*._"
]
},
"hash": [
"*Usage*: {0} <Algorithm> <Text to Hash>.\n\n*Available algorithms*: {1}."
],
"eval": [
"This feature is not implemented [Security Issue]."
],
"time": [
"Local time: *{0}*."
]
}

View File

@ -1,6 +1,6 @@
{ {
"start": [ "start": [
"Ciao {user.mention_markdown_v2()}!" "*Ciao* {0}*!*"
], ],
"help": [ "help": [
"*Non c'è nessuno qui ad aiutarti (per ora).*" "*Non c'è nessuno qui ad aiutarti (per ora).*"
@ -15,7 +15,15 @@
"*Non hai desiderato nulla! ✨*\n\n_Non succede niente..._" "*Non hai desiderato nulla! ✨*\n\n_Non succede niente..._"
], ],
"done": [ "done": [
"*Il tuo desiderio è stato espresso! ✨*\n\n_Probabilità che si avveri: {0}%_" "*Il tuo desiderio è stato espresso! ✨*\n\n_Probabilità che si avveri: *{Percent}%*._"
]
},
"level": {
"empty": [
"Controlla il tuo livello di qualcosa.\n\n*Uso*: {Cmd} <Cosa>."
],
"done": [
"_Il tuo livello di *{Thing}* è... *{Percent}%*._"
] ]
}, },
"hug": { "hug": {

7
StartWinDog Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
ScriptPath=$(realpath $0)
ScriptDir=$(dirname $ScriptPath)
cd $ScriptDir
python3 WinDog.py

267
WinDog.py
View File

@ -1,36 +1,82 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# =================================== # # ================================== #
# WinDog multi-purpose chatbot # WinDog multi-purpose chatbot #
# Licensed under AGPLv3 by OctoSpacc # Licensed under AGPLv3 by OctoSpacc #
# =================================== # # ================================== #
import json import json, hashlib, re, time, subprocess
from os import listdir
from random import choice, randint from random import choice, randint
from types import SimpleNamespace
from telegram import Update, ForceReply, Bot from telegram import Update, ForceReply, Bot
from telegram.utils.helpers import escape_markdown from telegram.utils.helpers import escape_markdown
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext
from Config import * from Config import *
Private = {} Db = {"Chats": {}}
Locale = {} Locale = {"Fallback": {}}
def CharEscape(String, Escape=''): def SetupDb() -> None:
global Db
try:
with open('Database.json', 'r') as File:
Db = json.load(File)
except Exception:
pass
def SetupLocale() -> None:
global Locale
for File in listdir('./Locale'):
Lang = File.split('.')[0]
try:
with open(f'./Locale/{File}') as File:
Locale[Lang] = json.load(File)
except Exception:
print(f'Cannot load {Lang} locale, exiting.')
raise
exit(1)
for Key in Locale[DefaultLang]:
Locale['Fallback'][Key] = Locale[DefaultLang][Key]
for Lang in Locale:
for Key in Locale[Lang]:
if not Key in Locale['Fallback']:
Locale['Fallback'][Key] = Locale[Lang][Key]
def __(Key:str, Lang:str=DefaultLang):
Set = None
Key = Key.split('.')
try:
Set = Locale.Locale[Lang]
for El in Key:
Set = Set[El]
except Exception:
Set = Locale.Locale['Fallback']
for El in Key:
Set = Set[El]
return Set
Locale['__'] = __
Locale['Locale'] = Locale
Locale = SimpleNamespace(**Locale)
def CharEscape(String, Escape='') -> str:
if Escape == 'MARKDOWN': if Escape == 'MARKDOWN':
return escape_markdown(String, version=2) return escape_markdown(String, version=2)
elif Escape == 'MARKDOWN_SPEECH':
for c in '.!_()[]<>':
String = String.replace(c, '\\'+c)
return String
else: else:
if Escape == 'MARKDOWN_SPEECH':
Escape = '+-_.!()[]{}<>'
elif Escape == 'MARKDOWN_SPEECH_FORMAT':
Escape = '+-_.!()[]<>'
for c in Escape: for c in Escape:
String = String.replace(c, '\\'+c) String = String.replace(c, '\\'+c)
return String return String
def CommandFilter(Message): def GetRawTokens(Text:str) -> list:
return Message.lower().split(' ')[0][1:].split('@')[0] return Text.strip().replace('\t', ' ').replace(' ', ' ').replace(' ', ' ').split(' ')
def RandPercent(): def CmdFilter(Msg) -> str:
return Msg.lower().split(' ')[0][1:].split('@')[0]
def RandPercent() -> int:
Num = randint(0,100) Num = randint(0,100)
if Num == 100: if Num == 100:
Num = str(Num) + '\.00' Num = str(Num) + '\.00'
@ -38,77 +84,85 @@ def RandPercent():
Num = str(Num) + '\.' + str(randint(0,9)) + str(randint(0,9)) Num = str(Num) + '\.' + str(randint(0,9)) + str(randint(0,9))
return Num return Num
def start(update:Update, context:CallbackContext) -> None: def cStart(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update): if CmdRestrict(update):
user = update.effective_user user = update.effective_user
update.message.reply_markdown_v2( update.message.reply_markdown_v2(
fr'Hi {user.mention_markdown_v2()}\!', CharEscape(choice(Locale.__('start')), 'MARKDOWN_SPEECH').format(user.mention_markdown_v2()),
#reply_markup=ForceReply(selective=True),
)
def help(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update):
update.message.reply_markdown_v2(
CharEscape(choice(Locale[Lang]['help']), '.!()'),
reply_to_message_id=update.message.message_id) reply_to_message_id=update.message.message_id)
def echo(update:Update, context:CallbackContext) -> None: def cHelp(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update): if CmdRestrict(update):
Message = update.message.text update.message.reply_markdown_v2(
if len(Message.split(' ')) < 2: CharEscape(choice(Locale.__('help')), 'MARKDOWN_SPEECH'),
Text = CharEscape(choice(Locale[Lang]['echo']['empty']), '.!') reply_to_message_id=update.message.message_id)
update.message.reply_markdown_v2(
Text, def cConfig(update:Update, context:CallbackContext) -> None:
reply_to_message_id=update.message.message_id) pass
else:
Text = Message[len(Message.split(' ')[0])+1:] def cEcho(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update):
Msg = update.message.text
if len(Msg.split(' ')) >= 2:
Text = Msg[len(Msg.split(' ')[0])+1:]
update.message.reply_text( update.message.reply_text(
Text, Text,
reply_to_message_id=update.message.message_id) reply_to_message_id=update.message.message_id)
else:
Text = CharEscape(choice(Locale.__('echo.empty')), '.!')
update.message.reply_markdown_v2(
Text,
reply_to_message_id=update.message.message_id)
def ping(update:Update, context:CallbackContext) -> None: def cPing(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update): if CmdRestrict(update):
update.message.reply_markdown_v2( update.message.reply_markdown_v2(
'*Pong\!*', '*Pong\!*',
reply_to_message_id=update.message.message_id) reply_to_message_id=update.message.message_id)
def wish(update:Update, context:CallbackContext) -> None: def percenter(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update): if CmdRestrict(update):
if len(update.message.text.split(' ')) < 2: Msg = update.message.text
Text = choice(Locale[Lang]['wish']['empty']) Key = CmdFilter(Msg)
Toks = GetRawTokens(Msg)
Thing = Key.join(Msg.split(Key)[1:]).strip()
if len(Toks) >= 2:
Text = choice(Locale.__(f'{Key}.done'))
else: else:
Text = choice(Locale[Lang]['wish']['done']) Text = choice(Locale.__(f'{Key}.empty'))
update.message.reply_markdown_v2( update.message.reply_markdown_v2(
CharEscape(Text, '.!').format(RandPercent()), CharEscape(Text, '.!').format(Cmd=Toks[0], Percent=RandPercent(), Thing=Thing),
reply_to_message_id=update.message.message_id) reply_to_message_id=update.message.message_id)
def multifun(update:Update, context:CallbackContext) -> None: def multifun(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update): if CmdRestrict(update):
Key = CommandFilter(update.message.text) Key = CmdFilter(update.message.text)
ReplyToMessage = update.message.message_id ReplyToMsg = update.message.message_id
if update.message.reply_to_message: if update.message.reply_to_message:
ReplyFromUID = update.message.reply_to_message.from_user.id ReplyFromUID = update.message.reply_to_message.from_user.id
if ReplyFromUID == TGID and 'bot' in Locale[Lang][Key]: if ReplyFromUID == TGID and 'bot' in Locale.__(Key):
Text = CharEscape(choice(Locale[Lang][Key]['bot']), 'MARKDOWN_SPEECH') Text = CharEscape(choice(Locale.__(f'{Key}.bot')), 'MARKDOWN_SPEECH')
elif ReplyFromUID == update.message.from_user.id and 'self' in Locale[Lang][Key]: elif ReplyFromUID == update.message.from_user.id and 'self' in Locale.__(Key):
FromUName = CharEscape(update.message.from_user.first_name, 'MARKDOWN') FromUName = CharEscape(update.message.from_user.first_name, 'MARKDOWN')
Text = CharEscape(choice(Locale[Lang][Key]['self']), 'MARKDOWN_SPEECH').format(FromUName) Text = CharEscape(choice(Locale.__(f'{Key}.self')), 'MARKDOWN_SPEECH').format(FromUName)
else: else:
if 'others' in Locale[Lang][Key]: if 'others' in Locale.__(Key):
FromUName = CharEscape(update.message.from_user.first_name, 'MARKDOWN') FromUName = CharEscape(update.message.from_user.first_name, 'MARKDOWN')
ToUName = CharEscape(update.message.reply_to_message.from_user.first_name, 'MARKDOWN') ToUName = CharEscape(update.message.reply_to_message.from_user.first_name, 'MARKDOWN')
Text = CharEscape(choice(Locale[Lang][Key]['others']), 'MARKDOWN_SPEECH').format(FromUName,ToUName) Text = CharEscape(choice(Locale.__(f'{Key}.others')), 'MARKDOWN_SPEECH').format(FromUName,ToUName)
ReplyToMessage = update.message.reply_to_message.message_id ReplyToMsg = update.message.reply_to_message.message_id
else: else:
if 'empty' in Locale[Lang][Key]: if 'empty' in Locale.__(Key):
Text = CharEscape(choice(Locale[Lang][Key]['empty']), 'MARKDOWN_SPEECH') Text = CharEscape(choice(Locale.__(f'{Key}.empty')), 'MARKDOWN_SPEECH')
update.message.reply_markdown_v2( update.message.reply_markdown_v2(Text, reply_to_message_id=ReplyToMsg)
Text,
reply_to_message_id=ReplyToMessage)
def cUnsplash(update:Update, context:CallbackContext) -> None:
pass
def filters(update:Update, context:CallbackContext) -> None: def filters(update:Update, context:CallbackContext) -> None:
pass if Debug and Dumper:
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}] {update.message.text}\n')
''' '''
if CmdRestrict(update): if CmdRestrict(update):
ChatID = update.message.chat.id ChatID = update.message.chat.id
@ -130,51 +184,90 @@ def setfilter(update:Update, context:CallbackContext) -> None:
Private['Chats'][ChatID]['Filters'][update.message.text] = {'Text':0} Private['Chats'][ChatID]['Filters'][update.message.text] = {'Text':0}
''' '''
def CmdRestrict(update): def cTime(update:Update, context:CallbackContext) -> None:
update.message.reply_markdown_v2(
CharEscape(choice(Locale.__('time')).format(time.ctime().replace(' ', ' ')), 'MARKDOWN_SPEECH'),
reply_to_message_id=update.message.message_id)
def cHash(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update):
Msg = update.message.text
Toks = GetRawTokens(Msg)
if len(Toks) >= 3 and Toks[1] in hashlib.algorithms_available:
Alg = Toks[1]
Caption = hashlib.new(Alg, Alg.join(Msg.split(Alg)[1:]).strip().encode()).hexdigest()
else:
Caption = CharEscape(choice(Locale.__('hash')).format(Toks[0], hashlib.algorithms_available), 'MARKDOWN_SPEECH')
update.message.reply_markdown_v2(Caption, reply_to_message_id=update.message.message_id)
def cEval(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update):
update.message.reply_markdown_v2(
CharEscape(choice(Locale.__('eval')), 'MARKDOWN_SPEECH'),
reply_to_message_id=update.message.message_id)
def cExec(update:Update, context:CallbackContext) -> None:
if CmdRestrict(update):
Toks = GetRawTokens(update.message.text)
if len(Toks) >= 2 and Toks[1].lower() in ('date', 'neofetch', 'uptime'):
Caption = '```' + CharEscape(re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])').sub('', subprocess.run(('sh', '-c', Toks[1].lower()), stdout=subprocess.PIPE).stdout.decode()) , 'MARKDOWN') + '```',
update.message.reply_markdown_v2(
# <https://stackoverflow.com/a/14693789>
'```' + CharEscape( re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])').sub('', subprocess.run(('sh', '-c', Toks[1].lower()),
stdout=subprocess.PIPE).stdout.decode()) , 'MARKDOWN') + '```',
reply_to_message_id=update.message.message_id)
else:
update.message.reply_markdown_v2(
CharEscape(choice(Locale.__('eval')), 'MARKDOWN_SPEECH'),
reply_to_message_id=update.message.message_id)
#def CmdArgs(Msg:str, Cfg:tuple=None):
# Args = []
# Msg = Msg.strip().replace('\t', ' ')
# if Cfg:
# for i in Cfg:
# Args += [Msg.replace(' ', ' ').replace(' ', ' ').split(' ')[:i]]
# Msg = Msg
# else:
# return Msg.replace(' ', ' ').replace(' ', ' ').split(' ')
def CmdRestrict(update) -> bool:
if not TGRestrict: if not TGRestrict:
return True return True
else: else:
if TGRestrict == 'Whitelist': if TGRestrict.lower() == 'whitelist':
if update.message.chat.id in TGWhitelist: if update.message.chat.id in TGWhitelist:
return True return True
return False return False
def main() -> None: #def SendMsg(Data, context):
global Private, Locale # pass
try: def Main() -> None:
with open('Private.json', 'r') as File: SetupDb()
Private = json.load(File) SetupLocale()
except Exception:
Private = {}
if 'Chats' not in Private:
Private['Chats'] = {}
try:
with open('Locale/{0}.json'.format(Lang)) as File:
Locale[Lang] = json.load(File)
except Exception:
print('Cannot load {0} locale, exiting'.format(Lang))
raise
exit(1)
#Private['Chats'].update({update.message.chat.id:{}}) #Private['Chats'].update({update.message.chat.id:{}})
updater = Updater(TGToken) updater = Updater(TGToken)
dispatcher = updater.dispatcher dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler('start', start)) dispatcher.add_handler(CommandHandler('start', cStart))
dispatcher.add_handler(CommandHandler('help', help)) dispatcher.add_handler(CommandHandler('config', cConfig))
dispatcher.add_handler(CommandHandler('echo', echo)) dispatcher.add_handler(CommandHandler('help', cHelp))
dispatcher.add_handler(CommandHandler('ping', ping)) dispatcher.add_handler(CommandHandler('echo', cEcho))
dispatcher.add_handler(CommandHandler('wish', wish)) dispatcher.add_handler(CommandHandler('ping', cPing))
dispatcher.add_handler(CommandHandler('hug', multifun)) dispatcher.add_handler(CommandHandler('time', cTime))
dispatcher.add_handler(CommandHandler('pat', multifun)) dispatcher.add_handler(CommandHandler('hash', cHash))
dispatcher.add_handler(CommandHandler('poke', multifun)) dispatcher.add_handler(CommandHandler('eval', cEval))
dispatcher.add_handler(CommandHandler('cuddle', multifun)) dispatcher.add_handler(CommandHandler('exec', cExec))
dispatcher.add_handler(CommandHandler('floor', multifun)) dispatcher.add_handler(CommandHandler('unsplash', cUnsplash))
dispatcher.add_handler(CommandHandler('hands', multifun))
dispatcher.add_handler(CommandHandler('sessocto', multifun)) for Cmd in ('wish', 'level'):
dispatcher.add_handler(CommandHandler(Cmd, percenter))
for Cmd in ('hug', 'pat', 'poke', 'cuddle', 'floor', 'hands', 'sessocto'):
dispatcher.add_handler(CommandHandler(Cmd, multifun))
#dispatcher.add_handler(CommandHandler('setfilter', setfilter)) #dispatcher.add_handler(CommandHandler('setfilter', setfilter))
dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, filters)) dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, filters))
@ -183,5 +276,5 @@ def main() -> None:
updater.idle() updater.idle()
if __name__ == '__main__': if __name__ == '__main__':
main() Main()
print('Closing WinDog...') print('Closing WinDog...')