forked from dymik739/modular-bot-framework-for-telegram
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 08672bdbbe | |||
| 11acdb6fd4 | |||
| e830bae282 | |||
| 2a9bd28d65 | |||
| 2b8105d2a8 | |||
| a7bbb1c1cc | |||
| e002dc46a2 | |||
| 51307b5234 | |||
| ec22c72afb | |||
| 79a307a7b5 | |||
| 3e38c113d9 | |||
| 7d0d816ca8 | |||
| 376ffd4957 | |||
| a530272408 | |||
| 807dee5af1 | |||
| f591c8d54a | |||
| 48e672a7b0 | |||
| b5a37acecb | |||
| 187d990d2b | |||
| 151107aa81 | |||
| 2446a20a5b | |||
| 4502e7fbe1 | |||
| 34439e944b | |||
| dc8056abed | |||
| 9bdf8d0775 | |||
| 34f9b83a95 | |||
| 87928df3f7 | |||
| baf815e74d |
148
main.py
148
main.py
@@ -11,7 +11,12 @@ import traceback
|
|||||||
|
|
||||||
# global variables
|
# global variables
|
||||||
STOP_REQUESTED = False
|
STOP_REQUESTED = False
|
||||||
|
DEBUG_MODE = False
|
||||||
|
DELAY_AFTER_RESPONSE = 3
|
||||||
|
DELAY_AFTER_MESSAGE = 0.1
|
||||||
|
DELAY_AFTER_IDLE = 1.0
|
||||||
|
|
||||||
|
lock = threading.Lock()
|
||||||
|
|
||||||
# some functions that increase readability of the code
|
# some functions that increase readability of the code
|
||||||
def readfile(filename):
|
def readfile(filename):
|
||||||
@@ -44,6 +49,8 @@ class ModuleV1:
|
|||||||
|
|
||||||
def set_predefine(self):
|
def set_predefine(self):
|
||||||
try:
|
try:
|
||||||
|
if DEBUG_MODE:
|
||||||
|
print(f"Predefine on module v1 {self.alias} ({self.path})")
|
||||||
exec(self.predefine)
|
exec(self.predefine)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" "
|
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" "
|
||||||
@@ -55,11 +62,13 @@ class ModuleV1:
|
|||||||
|
|
||||||
self.MESSAGE = msg
|
self.MESSAGE = msg
|
||||||
try:
|
try:
|
||||||
|
if DEBUG_MODE:
|
||||||
|
print(f"Calling module v1 {self.alias} ({self.path})")
|
||||||
exec(self.code)
|
exec(self.code)
|
||||||
return self.RESPONSE, self.FORMAT
|
return self.RESPONSE, self.FORMAT
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
|
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
|
||||||
print(f"[ERROR] module v1: traceback:\ntraceback.format_exc()")
|
print(f"[ERROR] module v1: traceback:\n{traceback.format_exc()}")
|
||||||
return "", None
|
return "", None
|
||||||
|
|
||||||
|
|
||||||
@@ -75,6 +84,8 @@ class ModuleV2:
|
|||||||
# running the module
|
# running the module
|
||||||
def process(self, msg):
|
def process(self, msg):
|
||||||
try:
|
try:
|
||||||
|
if DEBUG_MODE:
|
||||||
|
print(f"Calling module v2 {self.alias} ({self.path})")
|
||||||
return self.obj.process(msg, self.path)
|
return self.obj.process(msg, self.path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] module v2: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
|
print(f"[ERROR] module v2: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
|
||||||
@@ -166,16 +177,19 @@ def queue_processor():
|
|||||||
try:
|
try:
|
||||||
if len(message_queue) > 0:
|
if len(message_queue) > 0:
|
||||||
msg = message_queue[0]
|
msg = message_queue[0]
|
||||||
|
del message_queue[0]
|
||||||
print("[DEBUG] queue_processor: {}".format(msg)) # debug
|
print("[DEBUG] queue_processor: {}".format(msg)) # debug
|
||||||
|
|
||||||
# check for control commands
|
# check for control commands
|
||||||
if msg["chat"]["id"] == 575246355:
|
if msg.chat.id == 575246355:
|
||||||
if msg["text"][0] == "$":
|
if msg["text"][0] == "$":
|
||||||
command = msg["text"][1:].split(" ")
|
command = msg["text"][1:].split()
|
||||||
|
|
||||||
if len(command) >= 2 and command[0] == "module":
|
if len(command) >= 2 and command[0] == "module":
|
||||||
if command[1] == "reload":
|
if command[1] == "reload":
|
||||||
print("[INFO] Module reloading triggered by a command")
|
if len(command) == 2:
|
||||||
|
print("[INFO] Full module reloading triggered by a command")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"Reloading all modules...")
|
||||||
|
|
||||||
# properly reload all v2 modules
|
# properly reload all v2 modules
|
||||||
for mod in mcu.modules:
|
for mod in mcu.modules:
|
||||||
@@ -184,55 +198,153 @@ def queue_processor():
|
|||||||
|
|
||||||
del mcu.modules[:]
|
del mcu.modules[:]
|
||||||
mcu.reload_modules()
|
mcu.reload_modules()
|
||||||
|
else:
|
||||||
|
# TO DO: make it possible to reload individual modules by their
|
||||||
|
# alias or containing folder
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif command[1] == "enable" and len(command) == 3:
|
||||||
|
if command[2] == "all":
|
||||||
|
for mod in mcu.modules:
|
||||||
|
mod.enabled = True
|
||||||
|
print(f"[INFO] module {mod.alias} was enabled")
|
||||||
|
else:
|
||||||
|
for mod in mcu.modules:
|
||||||
|
if mod.alias == command[2]:
|
||||||
|
mod.enabled = True
|
||||||
|
print(f"[INFO] module {mod.alias} was enabled")
|
||||||
|
|
||||||
|
elif command[1] == "disable" and len(command) == 3:
|
||||||
|
if command[2] == "all":
|
||||||
|
for mod in mcu.modules:
|
||||||
|
mod.enabled = False
|
||||||
|
print(f"[INFO] module {mod.alias} was disabled")
|
||||||
|
else:
|
||||||
|
for mod in mcu.modules:
|
||||||
|
if mod.alias == command[2]:
|
||||||
|
mod.enabled = False
|
||||||
|
print(f"[INFO] module {mod.alias} was disabled")
|
||||||
|
|
||||||
|
elif command[1] == "status" and len(command) == 3:
|
||||||
|
if command[2] == "all":
|
||||||
|
for mod in mcu.modules:
|
||||||
|
print(f"[INFO] module {mod.alias} is {mod.enabled}")
|
||||||
|
else:
|
||||||
|
for mod in mcu.modules:
|
||||||
|
if mod.alias == command[2]:
|
||||||
|
print(f"[INFO] module {mod.alias} is {mod.enabled}")
|
||||||
|
|
||||||
|
elif (2 <= len(command) <= 3) and command[0] == "delay":
|
||||||
|
l = len(command)
|
||||||
|
|
||||||
|
if command[1] == "response":
|
||||||
|
if l == 3:
|
||||||
|
try:
|
||||||
|
new_value = float(command[2])
|
||||||
|
global DELAY_AFTER_RESPONSE
|
||||||
|
DELAY_AFTER_RESPONSE = new_value
|
||||||
|
updater.bot.send_message(msg.chat.id, f"Set DELAY_AFTER_RESPONSE to {command[2]}")
|
||||||
|
except:
|
||||||
|
print(f"[WARN]: Cannot set DELAY_AFTER_RESPONSE to non-float value of {command[2]}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_RESPONSE to non-float value of {command[2]}")
|
||||||
|
elif l == 2:
|
||||||
|
print(f"[INFO]: DELAY_AFTER_RESPONSE = {DELAY_AFTER_RESPONSE}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_RESPONSE = {DELAY_AFTER_RESPONSE}")
|
||||||
|
|
||||||
|
elif command[1] == "message":
|
||||||
|
if l == 3:
|
||||||
|
try:
|
||||||
|
new_value = float(command[2])
|
||||||
|
global DELAY_AFTER_MESSAGE
|
||||||
|
DELAY_AFTER_MESSAGE = new_value
|
||||||
|
updater.bot.send_message(msg.chat.id, f"Set DELAY_AFTER_MESSAGE to {command[2]}")
|
||||||
|
except:
|
||||||
|
print("[WARN]: Cannot set DELAY_AFTER_MESSAGE to non-float value of {command[2]}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_MESSAGE to non-float value of {command[2]}")
|
||||||
|
elif l == 2:
|
||||||
|
print(f"[INFO]: DELAY_AFTER_MESSAGE = {DELAY_AFTER_MESSAGE}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_MESSAGE = {DELAY_AFTER_MESSAGE}")
|
||||||
|
|
||||||
|
elif command[1] == "idle":
|
||||||
|
if l == 3:
|
||||||
|
try:
|
||||||
|
new_value = float(command[2])
|
||||||
|
global DELAY_AFTER_IDLE
|
||||||
|
DELAY_AFTER_IDLE = new_value
|
||||||
|
except:
|
||||||
|
print("[WARN]: Cannot set DELAY_AFTER_IDLE to non-float value of {command[2]}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_MESSAGE to non-float value of {command[2]}")
|
||||||
|
elif l == 2:
|
||||||
|
print(f"[INFO]: DELAY_AFTER_IDLE = {DELAY_AFTER_IDLE}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_IDLE = {DELAY_AFTER_IDLE}")
|
||||||
|
|
||||||
|
elif len(command) == 2 and command[0] == "queue":
|
||||||
|
if command[1] == "size":
|
||||||
|
print(f"[INFO]: Queue length is {len(message_queue)}")
|
||||||
|
updater.bot.send_message(msg.chat.id, f"[INFO]: Queue length is {len(message_queue)}")
|
||||||
|
|
||||||
|
elif len(command) == 2 and command[0] == "debug":
|
||||||
|
global DEBUG_MODE
|
||||||
|
if command[1] == "on":
|
||||||
|
DEBUG_MODE = True
|
||||||
|
else:
|
||||||
|
DEBUG_MODE = False
|
||||||
|
|
||||||
del message_queue[0]
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# modules are used in here
|
# modules are used in here
|
||||||
for mod in mcu.modules:
|
for mod in mcu.modules:
|
||||||
if mod.enabled:
|
if mod.enabled:
|
||||||
if mod.version in [1, 2]:
|
if mod.version in [1, 2]:
|
||||||
|
try:
|
||||||
response, formatting = mod.process(msg)
|
response, formatting = mod.process(msg)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module {mod.alias} ({mod.path}) failed to do a proper return, skipping...")
|
||||||
|
continue
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
if formatting == None:
|
if not formatting:
|
||||||
|
print(f"Responding using module {mod.path} ({mod.alias}) with text: {response}")
|
||||||
updater.bot.send_message(chat_id=msg.chat.id, text=response,
|
updater.bot.send_message(chat_id=msg.chat.id, text=response,
|
||||||
disable_web_page_preview=True)
|
disable_web_page_preview=True)
|
||||||
print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
|
time.sleep(DELAY_AFTER_RESPONSE)
|
||||||
break
|
break
|
||||||
|
|
||||||
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
|
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
|
||||||
|
print(f"Responding using module {mod.path} ({mod.alias}) with text (using {formatting}): {response}")
|
||||||
updater.bot.send_message(chat_id=msg.chat.id, text=response,
|
updater.bot.send_message(chat_id=msg.chat.id, text=response,
|
||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
parse_mode=formatting)
|
parse_mode=formatting)
|
||||||
print(f"Responded using module {mod.path} ({mod.alias}) with text (using {formatting}): {response}")
|
time.sleep(DELAY_AFTER_RESPONSE)
|
||||||
break
|
break
|
||||||
|
|
||||||
del message_queue[0]
|
time.sleep(DELAY_AFTER_MESSAGE)
|
||||||
|
|
||||||
time.sleep(0.1)
|
|
||||||
else:
|
else:
|
||||||
if STOP_REQUESTED:
|
if STOP_REQUESTED:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
time.sleep(1)
|
time.sleep(DELAY_AFTER_IDLE)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] queue_processor: current message queue: {message_queue}")
|
print(f"[ERROR] queue_processor: current message queue: {message_queue}")
|
||||||
print(f"[ERROR] Traceback:\n{traceback.format_exc()}")
|
print(f"[ERROR] Traceback:\n{traceback.format_exc()}")
|
||||||
print(f"[ERROR] queue_processor: error while processing message ({e}), trying to delete it...")
|
print(f"[ERROR] queue_processor: error while processing message ({e})...")
|
||||||
try:
|
print("[INFO] queue_processor: skipped broken message")
|
||||||
del message_queue[0]
|
|
||||||
print("[INFO] queue_processor: deleted broken message from the queue")
|
|
||||||
except:
|
|
||||||
print("[WARN] queue_processor: message seems absent, whatever")
|
|
||||||
|
|
||||||
print("[INFO] queue_processor thread stops successfully")
|
print("[INFO] queue_processor thread stops successfully")
|
||||||
|
|
||||||
|
|
||||||
# telegram bot processor
|
# telegram bot processor
|
||||||
def message_handler(update, context):
|
def message_handler(update, context):
|
||||||
|
global lock
|
||||||
|
with lock:
|
||||||
|
if update.message and update.message.text.__class__ == str and update.message.text.startswith("$"):
|
||||||
|
print("[DEBUG] Received new message with high priority") # just for testing
|
||||||
|
message_queue.insert(0, update.message)
|
||||||
|
elif update.message:
|
||||||
print("[DEBUG] Received new message") # just for testing
|
print("[DEBUG] Received new message") # just for testing
|
||||||
message_queue.append(update.message)
|
message_queue.append(update.message)
|
||||||
|
else:
|
||||||
|
print(f"[DEBUG] Received {update.message} instead of a message")
|
||||||
|
|
||||||
|
|
||||||
# --- Final stage ---
|
# --- Final stage ---
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ def queue_processor():
|
|||||||
response, formatting = mod.process(msg)
|
response, formatting = mod.process(msg)
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
if formatting == None:
|
if not formatting:
|
||||||
print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
|
print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
|
||||||
break
|
break
|
||||||
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
|
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Психологія",
|
"name": "Психологія",
|
||||||
"teacher": "Волянюк Н. Ю.",
|
"teacher": "Волянюк Н. Ю.",
|
||||||
"link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT0",
|
"link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
},
|
},
|
||||||
@@ -44,10 +44,9 @@
|
|||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Інженерія програмного забезпечення",
|
"name": "Інженерія програмного забезпечення",
|
||||||
"teacher": "Васильєва Марія Давидівна",
|
"teacher": "Васильєва Марія Давидівна",
|
||||||
"link": "https://zoom.us/wc/88696149166/join?from=join&_x_zm_rtaid=qhdJKhYLQNakh-zwxMG4lg.1693903841334.ad606145c892a54a4b450526e2394cbe&_x_zm_rhtaid=531",
|
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
|
||||||
"type": "lab",
|
"type": "lab",
|
||||||
"selectable": false,
|
"selectable": false
|
||||||
"notice": "Код: 4VHkdw"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"14:15": {
|
"14:15": {
|
||||||
@@ -77,7 +76,7 @@
|
|||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Інженерія програмного забезпечення",
|
"name": "Інженерія програмного забезпечення",
|
||||||
"teacher": "Васильєва Марія Давидівна",
|
"teacher": "Васильєва Марія Давидівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
}
|
}
|
||||||
@@ -86,14 +85,14 @@
|
|||||||
"10:25": {
|
"10:25": {
|
||||||
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
||||||
"teacher": "Стаматієва Вікторія В'ячеславівна",
|
"teacher": "Стаматієва Вікторія В'ячеславівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Практичний курс іноземної мови. Частина 2",
|
"name": "Практичний курс іноземної мови. Частина 2",
|
||||||
"teacher": "Шевченко Ольга Миколаївна",
|
"teacher": "Шевченко Ольга Миколаївна",
|
||||||
"link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh",
|
"link": "https://meet.google.com/tno-cxef-zyi",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
@@ -116,7 +115,7 @@
|
|||||||
"8:30": {
|
"8:30": {
|
||||||
"name": "Вступ до філософії",
|
"name": "Вступ до філософії",
|
||||||
"teacher": "Руденко Тамара Петрівна",
|
"teacher": "Руденко Тамара Петрівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
@@ -130,7 +129,7 @@
|
|||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
||||||
"teacher": "Овчар Раїса Федорівна",
|
"teacher": "Овчар Раїса Федорівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
}
|
}
|
||||||
@@ -142,14 +141,14 @@
|
|||||||
{
|
{
|
||||||
"name": "Психологія",
|
"name": "Психологія",
|
||||||
"teacher": "Сербова О. В.",
|
"teacher": "Сербова О. В.",
|
||||||
"link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09",
|
"link": "https://us05web.zoom.us/j/9299459744?pwd=Z3VQdWEvQ0tyc3pMbzl2bHN6Y1VlUT09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Психологія конфлікту",
|
"name": "Психологія конфлікту",
|
||||||
"teacher": "Кононець М. О.",
|
"teacher": "Кононець М. О.",
|
||||||
"link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09",
|
"link": "https://zoom.us/j/9953120638?pwd=WGZsYUhPK2hxbUc4YVJmT0lhdysyZz09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
}
|
}
|
||||||
@@ -159,14 +158,14 @@
|
|||||||
{
|
{
|
||||||
"name": "Політична наука: конфліктологічний підхід",
|
"name": "Політична наука: конфліктологічний підхід",
|
||||||
"teacher": "Северинчик О. П.",
|
"teacher": "Северинчик О. П.",
|
||||||
"link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09",
|
"link": "https://us04web.zoom.us/j/2279372490?pwd=bHR5QmpCT0tvQXJMLzRzaldHbFZ3dz09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Захист персональних даних: стандарти ЄС та Ради Європи",
|
"name": "Захист персональних даних: стандарти ЄС та Ради Європи",
|
||||||
"teacher": "Самчинська О. А.",
|
"teacher": "Самчинська О. А.",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://us04web.zoom.us/j/72149205587?pwd=Ld2Xj7RORYEwnUYauB5yEbATwwsNan.1",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
}
|
}
|
||||||
@@ -175,7 +174,7 @@
|
|||||||
"14:15": {
|
"14:15": {
|
||||||
"name": "Розумні міста",
|
"name": "Розумні міста",
|
||||||
"teacher": "Чукут Світлана Анатоліївна",
|
"teacher": "Чукут Світлана Анатоліївна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
}
|
}
|
||||||
@@ -184,7 +183,7 @@
|
|||||||
"10:25": {
|
"10:25": {
|
||||||
"name": "Вступ до філософії",
|
"name": "Вступ до філософії",
|
||||||
"teacher": "Руденко Тамара Петрівна",
|
"teacher": "Руденко Тамара Петрівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
@@ -214,14 +213,14 @@
|
|||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Інженерія програмного забезпечення",
|
"name": "Інженерія програмного забезпечення",
|
||||||
"teacher": "Васильєва Марія Давидівна",
|
"teacher": "Васильєва Марія Давидівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
"14:15": {
|
"14:15": {
|
||||||
"name": "Інженерія програмного забезпечення",
|
"name": "Інженерія програмного забезпечення",
|
||||||
"teacher": "Васильєва Марія Давидівна",
|
"teacher": "Васильєва Марія Давидівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
}
|
}
|
||||||
@@ -230,21 +229,21 @@
|
|||||||
"8:30": {
|
"8:30": {
|
||||||
"name": "Вступ до операційної системи Linux",
|
"name": "Вступ до операційної системи Linux",
|
||||||
"teacher": "Алєнін Олег Ігорович",
|
"teacher": "Алєнін Олег Ігорович",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://us04web.zoom.us/j/4122071690?pwd=bANFi3fk9pWvRu9TSBRGzfxFHuEkZC.1",
|
||||||
"type": "lab",
|
"type": "lab",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
"10:25": {
|
"10:25": {
|
||||||
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
||||||
"teacher": "Стаматієва Вікторія В'ячеславівна",
|
"teacher": "Стаматієва Вікторія В'ячеславівна",
|
||||||
"link": "(старе посилання!) https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09",
|
"link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Практичний курс іноземної мови. Частина 2",
|
"name": "Практичний курс іноземної мови. Частина 2",
|
||||||
"teacher": "Шевченко Ольга Миколаївна",
|
"teacher": "Шевченко Ольга Миколаївна",
|
||||||
"link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh",
|
"link": "https://meet.google.com/tno-cxef-zyi",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
},
|
},
|
||||||
@@ -258,8 +257,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Розумні міста",
|
"name": "Розумні міста",
|
||||||
"teacher": "Чукут С. А.",
|
"teacher": "Чукут Світлана Анатоліївна",
|
||||||
"link": "(посилання відсутні!)",
|
"link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09",
|
||||||
"type": "prac",
|
"type": "prac",
|
||||||
"selectable": true
|
"selectable": true
|
||||||
}
|
}
|
||||||
@@ -276,7 +275,7 @@
|
|||||||
"12:20": {
|
"12:20": {
|
||||||
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
|
||||||
"teacher": "Овчар Раїса Федорівна",
|
"teacher": "Овчар Раїса Федорівна",
|
||||||
"link": "(посилання відсутнє!)",
|
"link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09",
|
||||||
"type": "lec",
|
"type": "lec",
|
||||||
"selectable": false
|
"selectable": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,51 +5,51 @@
|
|||||||
"14:15": {"name": "Основи електронного урядування (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
|
"14:15": {"name": "Основи електронного урядування (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"12:20": {"name": "Інженерія програмного забезпечення (лабораторна)", "teacher": "Васильєва Марія Давидівна", "link": "https://zoom.us/wc/88696149166/join?from=join&_x_zm_rtaid=qhdJKhYLQNakh-zwxMG4lg.1693903841334.ad606145c892a54a4b450526e2394cbe&_x_zm_rhtaid=531"},
|
"12:20": {"name": "Інженерія програмного забезпечення (лабораторна)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"},
|
||||||
"14:15": {"name": "Теорія електричних кіл та сигналів (лабораторна)", "teacher": "Лободзинський В. Ю. & Ілліна О. О.", "link": "https://meet.google.com/gwx-sshq-sqb"}
|
"14:15": {"name": "Теорія електричних кіл та сигналів (лабораторна)", "teacher": "Лободзинський В. Ю. & Ілліна О. О.", "link": "https://meet.google.com/gwx-sshq-sqb"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"},
|
"8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"},
|
||||||
"10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"},
|
"10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"},
|
||||||
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"}
|
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "(посилання відсутнє!)"},
|
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"},
|
||||||
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh"},
|
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "https://meet.google.com/tno-cxef-zyi"},
|
||||||
"14:15": {"name": "Соціальна психологія (практика)", "teacher": "Блохіна Ірина Олександрівна", "link": "(посилання відсутнє!)"},
|
"14:15": {"name": "Соціальна психологія (практика)", "teacher": "Блохіна Ірина Олександрівна", "link": "(посилання відсутнє!)"},
|
||||||
"16:10": {"name": "Основи електронного урядування (практика)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
|
"16:10": {"name": "Основи електронного урядування (практика)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"8:30": {"name": "Вступ до філософії (лекція)", "teacher": "Руденко Тамара Петрівна", "link": "(посилання відсутнє!)"},
|
"8:30": {"name": "Вступ до філософії (лекція)", "teacher": "Руденко Тамара Петрівна", "link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09"},
|
||||||
"10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
|
"10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
|
||||||
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "(посилання відсутнє!)"}
|
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09"}
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"10:25": {"name": "Психологія & Психологія конфлікту (практики)", "teacher": "Сербова О. В. & Кононець М. О.", "link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09 & https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09"},
|
"10:25": {"name": "Психологія (практика) & Психологія конфлікту (лекція)", "teacher": "Сербова О. В. & Кононець М. О.", "link": "https://us05web.zoom.us/j/9299459744?pwd=Z3VQdWEvQ0tyc3pMbzl2bHN6Y1VlUT09 & https://zoom.us/j/9953120638?pwd=WGZsYUhPK2hxbUc4YVJmT0lhdysyZz09"},
|
||||||
"12:20": {"name": "Політична наука: конфліктологічний підхід & Захист персональних даних: стандарти ЄС та Ради Європи (практики)", "teacher": "Северинчик О. П. & Самчинська О. А.", "link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09 & (посилання відсутнє!)"},
|
"12:20": {"name": "Політична наука: конфліктологічний підхід & Захист персональних даних: стандарти ЄС та Ради Європи (практики)", "teacher": "Северинчик О. П. & Самчинська О. А.", "link": "(посилання відсутнє!) & https://us04web.zoom.us/j/72149205587?pwd=Ld2Xj7RORYEwnUYauB5yEbATwwsNan.1"},
|
||||||
"14:15": {"name": "Розумні міста (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
|
"14:15": {"name": "Розумні міста (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"10:25": {"name": "Вступ до філософії (практика)", "teacher": "Руденко Тамара Петрівна", "link": "(посилання відсутнє!)"},
|
"10:25": {"name": "Вступ до філософії (практика)", "teacher": "Руденко Тамара Петрівна", "link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09"},
|
||||||
"14:15": {"name": "Теорія ймовірності та математична статистика (практика)", "teacher": "Марковський Олександр Петрович", "link": "(посилання відсутнє!)"}
|
"14:15": {"name": "Теорія ймовірності та математична статистика (практика)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"},
|
"8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"},
|
||||||
"10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"},
|
"10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"},
|
||||||
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"},
|
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"},
|
||||||
"14:15": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"}
|
"14:15": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"8:30": {"name": "Вступ до операційної системи Linux (лабораторна)", "teacher": "Алєнін Олег Ігорович", "link": "(посилання відсутнє!)"},
|
"8:30": {"name": "Вступ до операційної системи Linux (лабораторна)", "teacher": "Алєнін Олег Ігорович", "link": "https://us04web.zoom.us/j/4122071690?pwd=bANFi3fk9pWvRu9TSBRGzfxFHuEkZC.1"},
|
||||||
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "(старе посилання!) https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"},
|
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"},
|
||||||
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh"},
|
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "https://meet.google.com/tno-cxef-zyi"},
|
||||||
"14:15": {"name": "Соціальна психологія (лекція) & Розумні міста (практика)", "teacher": "Винославська О. В. & Чукут С. А.", "link": "(посилання відсутні!)"}
|
"14:15": {"name": "Соціальна психологія (лекція) & Розумні міста (практика)", "teacher": "Винославська О. В. & Чукут С. А.", "link": "(посилання відсутнє!) & https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
|
"10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
|
||||||
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "(посилання відсутнє!)"}
|
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09"}
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
{}
|
{}
|
||||||
|
|||||||
6
modules/generic-command-processor/data.json
Normal file
6
modules/generic-command-processor/data.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"s": "Головна сторінка сервера: http://10.1.1.1:12010/",
|
||||||
|
"ss": "Головна сторінка сервера: http://10.1.1.1:12010/",
|
||||||
|
"пари_для_артема": "🧐",
|
||||||
|
"пари_для_артема_хоч_і_не_на_завтра": "🤨"
|
||||||
|
}
|
||||||
6
modules/generic-command-processor/index.py
Normal file
6
modules/generic-command-processor/index.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
command_storage = json.loads(open(self.path + "data.json").read())
|
||||||
|
|
||||||
|
received_command = self.MESSAGE.text[1:]
|
||||||
|
|
||||||
|
if received_command.lower() in command_storage:
|
||||||
|
self.RESPONSE = command_storage[received_command.lower()]
|
||||||
6
modules/generic-command-processor/meta.json
Normal file
6
modules/generic-command-processor/meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"index_file": "index.py",
|
||||||
|
"start_on_boot": true,
|
||||||
|
"alias": "generic-command-processor"
|
||||||
|
}
|
||||||
5
modules/help/db/hardsub.txt
Normal file
5
modules/help/db/hardsub.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Usage: !hardsub [event_name]
|
||||||
|
|
||||||
|
Permanently subscribes to [event_name]. If blank, uses "default".
|
||||||
|
To unsubscribe, use !hardunsub
|
||||||
|
For one-time subscriptions, use !sub
|
||||||
5
modules/help/db/hardunsub.txt
Normal file
5
modules/help/db/hardunsub.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Usage: !hardunsub [event_name]
|
||||||
|
|
||||||
|
Remove permanent subscription to [event_name]. If blank, uses "default".
|
||||||
|
To remove one-time subscription, use !unsub
|
||||||
|
To add permanent subscription, use !hardsub
|
||||||
5
modules/help/db/schedule-ctl.txt
Normal file
5
modules/help/db/schedule-ctl.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Usage:
|
||||||
|
!schedule-ctl list - see all settings
|
||||||
|
!schedule-ctl get <setting> - see specific personal setting
|
||||||
|
!schedule-ctl set <setting> <value> - change <setting> to <value>
|
||||||
|
!schedule-ctl clear <setting> - restore <setting> to default value
|
||||||
7
modules/help/db/sub.txt
Normal file
7
modules/help/db/sub.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Usage: !sub [event_name]
|
||||||
|
|
||||||
|
Soft-subscribes to [event_name]. If black, uses "default".
|
||||||
|
If you want to remove soft substription, use !unsub
|
||||||
|
|
||||||
|
Soft subscription is automatically removed after the event is triggered once.
|
||||||
|
If you want to subscribe permanently, use !hardsub
|
||||||
5
modules/help/db/unsub.txt
Normal file
5
modules/help/db/unsub.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Usage: !unsub [event_name]
|
||||||
|
|
||||||
|
Removes one-time subscription to [event_name]. If blank, uses "default".
|
||||||
|
Does not affect hard subscriptions. To remove hard subscription, use !hardunsub
|
||||||
|
To add one-time supscription, use !sub
|
||||||
54
modules/help/index.py
Normal file
54
modules/help/index.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
module_path = ""
|
||||||
|
|
||||||
|
def readfile(filename):
|
||||||
|
if os.path.exists(module_path + filename):
|
||||||
|
return open(module_path + filename).read()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def list_entries(search_query):
|
||||||
|
files = []
|
||||||
|
for p, d, f in os.walk(module_path + "db/"):
|
||||||
|
for i in f:
|
||||||
|
entry_name = f"{p.split('/', 3)[3]}/{i}"
|
||||||
|
if search_query in entry_name:
|
||||||
|
files.append(f"{p.split('/', 3)[3]}/{i}".rsplit(".", 1)[0].replace("/", ".").lstrip("."))
|
||||||
|
|
||||||
|
files.sort()
|
||||||
|
return files
|
||||||
|
|
||||||
|
def process(message, path):
|
||||||
|
if message.text[:5] != "!help":
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
global module_path
|
||||||
|
module_path = path
|
||||||
|
|
||||||
|
cmd = message.text[1:].split()
|
||||||
|
|
||||||
|
if len(cmd) == 1:
|
||||||
|
return "Usage:\n```\n!help show <entry> - displays specified manual entry\n!help list [query] - lists out available entries (optionally, filtered by [query])```", "Markdown"
|
||||||
|
|
||||||
|
elif cmd[1] == "list":
|
||||||
|
if len(cmd) == 2:
|
||||||
|
return "Available entries:\n" + "\n".join(list_entries("")), None
|
||||||
|
else:
|
||||||
|
return f"Found entries for {cmd[2]}:\n" + "\n".join(list_entries(cmd[2])), None
|
||||||
|
|
||||||
|
elif cmd[1] == "show":
|
||||||
|
if len(cmd) >= 3:
|
||||||
|
result = ""
|
||||||
|
for entry_name in cmd[2:]:
|
||||||
|
data = readfile("db/" + entry_name.replace(".", "/") + ".txt")
|
||||||
|
|
||||||
|
if data:
|
||||||
|
result += f"Manual page for {entry_name}:\n```\n{data}```\n"
|
||||||
|
else:
|
||||||
|
result += f"No manual found for {entry_name}\n\n"
|
||||||
|
|
||||||
|
return result, "Markdown"
|
||||||
|
else:
|
||||||
|
return "Usage: !help show <entry> - displays specified manual entry", None
|
||||||
6
modules/help/meta.json
Normal file
6
modules/help/meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"start_on_boot": true,
|
||||||
|
"alias": "help",
|
||||||
|
"version": 2,
|
||||||
|
"index_file": "index.py"
|
||||||
|
}
|
||||||
129
modules/pingtools/index.py
Normal file
129
modules/pingtools/index.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
msg = self.MESSAGE.text.lower()
|
||||||
|
|
||||||
|
if msg == "!ping":
|
||||||
|
current_time = time.time()
|
||||||
|
delay = current_time - 7200 - float(self.MESSAGE.date.strftime('+%s'))
|
||||||
|
self.RESPONSE = f"Pong in {delay} seconds"
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "scoreboard/"):
|
||||||
|
os.mkdir(self.path + "scoreboard/")
|
||||||
|
|
||||||
|
def append_score(path, name, data):
|
||||||
|
open(path + f"scoreboard/{name}", "a").write(data)
|
||||||
|
|
||||||
|
user_id = self.MESSAGE.from_user.id
|
||||||
|
chat_id = self.MESSAGE.chat.id
|
||||||
|
first_name = self.MESSAGE.from_user.first_name
|
||||||
|
last_name = self.MESSAGE.from_user.last_name
|
||||||
|
username = self.MESSAGE.from_user.username
|
||||||
|
|
||||||
|
append_score(self.path, self.MESSAGE.from_user.id, f"{current_time} {user_id} {chat_id} {first_name} {last_name} {username} {delay}\n")
|
||||||
|
|
||||||
|
elif msg == "!pong":
|
||||||
|
current_time = time.time()
|
||||||
|
delay = current_time - 7200 - float(self.MESSAGE.date.strftime('+%s'))
|
||||||
|
self.RESPONSE = f"Ping in {delay} seconds"
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "pong-scoreboard/"):
|
||||||
|
os.mkdir(self.path + "pong-scoreboard/")
|
||||||
|
|
||||||
|
def append_score(path, name, data):
|
||||||
|
open(path + f"pong-scoreboard/{name}", "a").write(data)
|
||||||
|
|
||||||
|
user_id = self.MESSAGE.from_user.id
|
||||||
|
chat_id = self.MESSAGE.chat.id
|
||||||
|
first_name = self.MESSAGE.from_user.first_name
|
||||||
|
last_name = self.MESSAGE.from_user.last_name
|
||||||
|
username = self.MESSAGE.from_user.username
|
||||||
|
|
||||||
|
append_score(self.path, self.MESSAGE.from_user.id, f"{current_time} {user_id} {chat_id} {first_name} {last_name} {username} {delay}\n")
|
||||||
|
|
||||||
|
elif msg == "!pingtop":
|
||||||
|
def read_score(path, name):
|
||||||
|
if os.path.exists(path + f"scoreboard/{name}"):
|
||||||
|
return open(path + f"scoreboard/{name}").read()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "scoreboard/"):
|
||||||
|
os.mkdir(self.path + "scoreboard/")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for name in os.listdir(self.path + "scoreboard/"):
|
||||||
|
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
|
||||||
|
data.sort(key = lambda x: float(x.split()[6]))
|
||||||
|
results.append(data[0].split())
|
||||||
|
|
||||||
|
print(results)
|
||||||
|
|
||||||
|
results.sort(key = lambda x: float(x[6]))
|
||||||
|
self.RESPONSE = "<u>Ping top</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
|
||||||
|
self.FORMAT = "HTML"
|
||||||
|
|
||||||
|
elif msg == "!pongtop":
|
||||||
|
def read_score(path, name):
|
||||||
|
if os.path.exists(path + f"pong-scoreboard/{name}"):
|
||||||
|
return open(path + f"pong-scoreboard/{name}").read()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "pong-scoreboard/"):
|
||||||
|
os.mkdir(self.path + "pong-scoreboard/")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for name in os.listdir(self.path + "pong-scoreboard/"):
|
||||||
|
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
|
||||||
|
data.sort(key = lambda x: float(x.split()[6]))
|
||||||
|
results.append(data[0].split())
|
||||||
|
|
||||||
|
print(results)
|
||||||
|
|
||||||
|
results.sort(key = lambda x: float(x[6]))
|
||||||
|
self.RESPONSE = "<u>Pong top</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
|
||||||
|
self.FORMAT = "HTML"
|
||||||
|
|
||||||
|
elif msg == "!pingantitop":
|
||||||
|
def read_score(path, name):
|
||||||
|
if os.path.exists(path + f"scoreboard/{name}"):
|
||||||
|
return open(path + f"scoreboard/{name}").read()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "scoreboard/"):
|
||||||
|
os.mkdir(self.path + "scoreboard/")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for name in os.listdir(self.path + "scoreboard/"):
|
||||||
|
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
|
||||||
|
data.sort(key = lambda x: float(x.split()[6]))
|
||||||
|
results.append(data[-1].split())
|
||||||
|
|
||||||
|
print(results)
|
||||||
|
|
||||||
|
results.sort(key = lambda x: float(x[6]))
|
||||||
|
results = results[::-1]
|
||||||
|
self.RESPONSE = "<u>Ping antitop</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
|
||||||
|
self.FORMAT = "HTML"
|
||||||
|
|
||||||
|
elif msg == "!pongantitop":
|
||||||
|
def read_score(path, name):
|
||||||
|
if os.path.exists(path + f"pong-scoreboard/{name}"):
|
||||||
|
return open(path + f"pong-scoreboard/{name}").read()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not os.path.exists(self.path + "pong-scoreboard/"):
|
||||||
|
os.mkdir(self.path + "pong-scoreboard/")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for name in os.listdir(self.path + "pong-scoreboard/"):
|
||||||
|
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
|
||||||
|
data.sort(key = lambda x: float(x.split()[6]))
|
||||||
|
results.append(data[-1].split())
|
||||||
|
|
||||||
|
print(results)
|
||||||
|
|
||||||
|
results.sort(key = lambda x: float(x[6]))
|
||||||
|
results = results[::-1]
|
||||||
|
self.RESPONSE = "<u>Pong antitop</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
|
||||||
|
self.FORMAT = "HTML"
|
||||||
6
modules/pingtools/meta.json
Normal file
6
modules/pingtools/meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"start_on_boot": true,
|
||||||
|
"alias": "pingtools",
|
||||||
|
"version": 1,
|
||||||
|
"index_file": "index.py"
|
||||||
|
}
|
||||||
133
modules/tag-sub/index.py
Normal file
133
modules/tag-sub/index.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
for i in ["sub-storage"]:
|
||||||
|
if not os.path.exists(module_path + i):
|
||||||
|
os.mkdir(module_path + i)
|
||||||
|
|
||||||
|
def load_group(group_name):
|
||||||
|
if os.path.exists(module_path + f"sub-storage/{group_name}.json"):
|
||||||
|
return json.loads(open(module_path + f"sub-storage/{group_name}.json").read())
|
||||||
|
else:
|
||||||
|
return {"hard": [], "soft": []}
|
||||||
|
|
||||||
|
def save_group(group_name, existing_group):
|
||||||
|
with open(module_path + f"sub-storage/{group_name}.json", "w") as f:
|
||||||
|
f.write(json.dumps(existing_group))
|
||||||
|
|
||||||
|
def sub_to_group(group_name, tag, persistence = "soft"):
|
||||||
|
for i in ["..", "/", "\\"]:
|
||||||
|
if i in group_name:
|
||||||
|
return False
|
||||||
|
|
||||||
|
existing_group = load_group(group_name)
|
||||||
|
|
||||||
|
if tag not in existing_group[persistence]:
|
||||||
|
existing_group[persistence].append(tag)
|
||||||
|
|
||||||
|
save_group(group_name, existing_group)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unsub_from_group(group_name, tag, persistence = "soft"):
|
||||||
|
for i in ["..", "/", "\\"]:
|
||||||
|
if i in group_name:
|
||||||
|
return False
|
||||||
|
|
||||||
|
existing_group = load_group(group_name)
|
||||||
|
|
||||||
|
if tag in existing_group[persistence]:
|
||||||
|
existing_group[persistence].remove(tag)
|
||||||
|
|
||||||
|
save_group(group_name, existing_group)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_group(cmd):
|
||||||
|
if len(cmd) == 1:
|
||||||
|
return "default"
|
||||||
|
else:
|
||||||
|
return cmd[1]
|
||||||
|
|
||||||
|
def clear_subs_in(group_name, category = "soft"):
|
||||||
|
existing_group = load_group(group_name)
|
||||||
|
existing_group[category] = []
|
||||||
|
save_group(group_name, existing_group)
|
||||||
|
|
||||||
|
module_path = ""
|
||||||
|
setup()
|
||||||
|
|
||||||
|
def process(message, path):
|
||||||
|
global module_path
|
||||||
|
module_path = path
|
||||||
|
|
||||||
|
if not message.text[0] == "!":
|
||||||
|
return "", None
|
||||||
|
|
||||||
|
msg = message.text.lower()
|
||||||
|
cmd = [i for i in msg[1:].split(" ", 2) if i]
|
||||||
|
|
||||||
|
chosen_group_name = get_group(cmd)
|
||||||
|
|
||||||
|
if cmd[0] == "sub":
|
||||||
|
if message.from_user.username:
|
||||||
|
if sub_to_group(chosen_group_name, message.from_user.username):
|
||||||
|
return f"Subscribed {message.from_user.username} to the {chosen_group_name} event", None
|
||||||
|
else:
|
||||||
|
return f"Failed to subscribe {message.from_user.username} to the \"{chosen_group_name}\" event (event name violation)", None
|
||||||
|
else:
|
||||||
|
return f"Failed to subscribe {message.from_user.id} to the \"{chosen_group_name}\" event (no username available)", None
|
||||||
|
|
||||||
|
if cmd[0] == "hardsub":
|
||||||
|
if message.from_user.username:
|
||||||
|
if sub_to_group(chosen_group_name, message.from_user.username, persistence = "hard"):
|
||||||
|
return f"Hard-subscribed {message.from_user.username} to the {chosen_group_name} event", None
|
||||||
|
else:
|
||||||
|
return f"Failed to hard-subscribe {message.from_user.username} to the \"{chosen_group_name}\" event (event name violation)", None
|
||||||
|
else:
|
||||||
|
return f"Failed to hard-subscribe {message.from_user.id} to the \"{chosen_group_name}\" event (no username available)", None
|
||||||
|
|
||||||
|
elif cmd[0] == "unsub":
|
||||||
|
if message.from_user.username:
|
||||||
|
if unsub_from_group(chosen_group_name, message.from_user.username):
|
||||||
|
return f"Unsubscribed {message.from_user.username} from the {chosen_group_name} event", None
|
||||||
|
else:
|
||||||
|
return f"Failed to unsubscribe {message.from_user.username} from the \"{chosen_group_name}\" event (event name violation)", None
|
||||||
|
else:
|
||||||
|
return f"Failed to unsubscribe {message.from_user.id} from the \"{chosen_group_name}\" event (no username available)", None
|
||||||
|
|
||||||
|
elif cmd[0] == "hardunsub":
|
||||||
|
if message.from_user.username:
|
||||||
|
if unsub_from_group(chosen_group_name, message.from_user.username, persistence = "hard"):
|
||||||
|
return f"Unsubscribed {message.from_user.username} from the {chosen_group_name} event", None
|
||||||
|
else:
|
||||||
|
return f"Failed to unsubscribe {message.from_user.username} from the \"{chosen_group_name}\" event (event name violation)", None
|
||||||
|
else:
|
||||||
|
return f"Failed to unsubscribe {message.from_user.id} from the \"{chosen_group_name}\" event (no username available)", None
|
||||||
|
|
||||||
|
elif cmd[0] == "call":
|
||||||
|
group_data = load_group(chosen_group_name)
|
||||||
|
tags = set()
|
||||||
|
|
||||||
|
for subs in group_data.values():
|
||||||
|
tags |= set([f"@{i}" for i in subs if i])
|
||||||
|
|
||||||
|
ping_string = " ".join(tags)
|
||||||
|
clear_subs_in(chosen_group_name)
|
||||||
|
|
||||||
|
if len(cmd) == 3:
|
||||||
|
return f"{message.from_user.username} calls \"{chosen_group_name}\": {cmd[2]}\n{ping_string}", None
|
||||||
|
else:
|
||||||
|
return f"{message.from_user.username} calls \"{chosen_group_name}\"\n{ping_string}", None
|
||||||
|
|
||||||
|
|
||||||
|
elif cmd[0] == "sublist":
|
||||||
|
group_data = load_group(chosen_group_name)
|
||||||
|
responce = f"Subscribers for group \"{chosen_group_name}\":\n"
|
||||||
|
|
||||||
|
for name, subs in group_data.items():
|
||||||
|
responce += f"{name}: {', '.join(subs)}\n"
|
||||||
|
|
||||||
|
return responce, None
|
||||||
|
|
||||||
6
modules/tag-sub/meta.json
Normal file
6
modules/tag-sub/meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"start_on_boot": true,
|
||||||
|
"alias": "tag-sub",
|
||||||
|
"version": 2,
|
||||||
|
"index_file": "index.py"
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ if (command[0] in self.aliases) and (1 <= command_length <= 3):
|
|||||||
"target": target,
|
"target": target,
|
||||||
"format": "text"}
|
"format": "text"}
|
||||||
|
|
||||||
res = requests.post("http://127.0.0.1:5000/translate", data = data)
|
res = requests.post("http://10.1.1.1:5010/translate", data = data)
|
||||||
result = json.loads(res.text)
|
result = json.loads(res.text)
|
||||||
|
|
||||||
if source == "auto":
|
if source == "auto":
|
||||||
|
|||||||
@@ -4,8 +4,14 @@ command_length = len(command)
|
|||||||
def escaped_string(unescaped_string):
|
def escaped_string(unescaped_string):
|
||||||
result_string = str(unescaped_string)
|
result_string = str(unescaped_string)
|
||||||
|
|
||||||
for i in ["<", ">"]:
|
escaping_rules = {
|
||||||
result_string = result_string.replace(i, f"\\{i}")
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
'"': """
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in escaping_rules.items():
|
||||||
|
result_string = result_string.replace(i[0], i[1])
|
||||||
|
|
||||||
return result_string
|
return result_string
|
||||||
|
|
||||||
@@ -31,7 +37,7 @@ if (command[0] in self.aliases) and (1 <= command_length <= 3):
|
|||||||
f"{', '.join(list(models.keys()))}"
|
f"{', '.join(list(models.keys()))}"
|
||||||
else:
|
else:
|
||||||
for i in models[chosen_model]:
|
for i in models[chosen_model]:
|
||||||
decoded_text = decoded_text.replace(i[0], i[1])
|
decoded_text = decoded_text.replace(i[0].lower(), i[1].lower())
|
||||||
decoded_text = decoded_text.replace(i[0].capitalize(), i[1].capitalize())
|
decoded_text = decoded_text.replace(i[0].capitalize(), i[1].capitalize())
|
||||||
decoded_text = decoded_text.replace(i[0].upper(), i[1].upper())
|
decoded_text = decoded_text.replace(i[0].upper(), i[1].upper())
|
||||||
|
|
||||||
|
|||||||
@@ -75,5 +75,57 @@
|
|||||||
["$", ";"],
|
["$", ";"],
|
||||||
["^", ":"],
|
["^", ":"],
|
||||||
["&", "?"]
|
["&", "?"]
|
||||||
|
],
|
||||||
|
"en-men": [
|
||||||
|
["a", "4"],
|
||||||
|
["b", "8"],
|
||||||
|
["c", "("],
|
||||||
|
["d", "|)"],
|
||||||
|
["e", "3"],
|
||||||
|
["f", "|="],
|
||||||
|
["g", "6"],
|
||||||
|
["h", "#"],
|
||||||
|
["i", "!"],
|
||||||
|
["j", "|_"],
|
||||||
|
["k", "|<"],
|
||||||
|
["l", "1"],
|
||||||
|
["m", "//N"],
|
||||||
|
["o", "0"],
|
||||||
|
["p", "|D"],
|
||||||
|
["q", "(,)"],
|
||||||
|
["r", "|2"],
|
||||||
|
["s", "5"],
|
||||||
|
["t", "7"],
|
||||||
|
["u", "|_|"],
|
||||||
|
["w", "//"],
|
||||||
|
["v", "/"],
|
||||||
|
["x", "><"],
|
||||||
|
["y", "`/"]
|
||||||
|
],
|
||||||
|
"men-en": [
|
||||||
|
["4", "a"],
|
||||||
|
["8", "b"],
|
||||||
|
["(,)", "q"],
|
||||||
|
["(", "c"],
|
||||||
|
["|)", "d"],
|
||||||
|
["3", "e"],
|
||||||
|
["|=", "f"],
|
||||||
|
["6", "g"],
|
||||||
|
["#", "h"],
|
||||||
|
["!", "i"],
|
||||||
|
["|_|", "u"],
|
||||||
|
["|_", "j"],
|
||||||
|
["|<", "k"],
|
||||||
|
["1", "l"],
|
||||||
|
["//N", "m"],
|
||||||
|
["0", "o"],
|
||||||
|
["|D", "p"],
|
||||||
|
["|2", "r"],
|
||||||
|
["5", "s"],
|
||||||
|
["7", "t"],
|
||||||
|
["//", "w"],
|
||||||
|
["`/", "y"],
|
||||||
|
["/", "v"],
|
||||||
|
["><", "x"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
3
modules/troll-spelling-corrector/index.py
Normal file
3
modules/troll-spelling-corrector/index.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
def process(message, path):
|
||||||
|
if "силк" in message.text.lower() or "лінк" in message.text.lower():
|
||||||
|
return "*посилання 🌚", None
|
||||||
6
modules/troll-spelling-corrector/meta.json
Normal file
6
modules/troll-spelling-corrector/meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"start_on_boot": true,
|
||||||
|
"alias": "troll-spelling-corrector",
|
||||||
|
"version": 2,
|
||||||
|
"index_file": "index.py"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user