17 Commits

Author SHA1 Message Date
8cf9208a29 PEP8 autoformat. 2023-09-04 23:34:16 +03:00
1ea0ab35e3 Changed accusative list for weekdays. 2023-09-04 23:32:46 +03:00
91748be435 Testing MARKDOVN_V2 parsing. 2023-09-04 20:58:17 +03:00
72c5b0b4a9 Minor changes. 2023-05-08 12:45:02 +03:00
efac73776f Minor changes. 2023-05-08 12:27:39 +03:00
d1f7019f89 Typos and cosmetics. 2023-05-08 10:28:26 +03:00
8debb0b3d5 Typos. 2023-05-08 10:23:06 +03:00
2206bf6319 Typos. 2023-05-08 10:22:23 +03:00
38d8674bbd Typos. 2023-05-08 10:14:28 +03:00
7bca26e07c Edited according to PEP8 and added f-strings. 2023-05-08 09:59:07 +03:00
1f9212c033 Понедулок. 2023-05-06 20:09:20 +03:00
d0cd483b73 auto-schedule-pro-v2: fix negative day shifts being interpreted as positive ones 2023-05-06 18:25:00 +03:00
edfcc6e1be auto-schedule-pro-v2, auto-schedule-pro: switch to calling new module by default 2023-05-06 18:14:53 +03:00
56e57c4d7f auto-schedule-pro-v2: add new module as a successor of auto-schedule-pro rewritten to utilize ModuleV2 API 2023-05-06 18:03:01 +03:00
ae1225ceee Merge pull request 'Added lesson type.' (#6) from Rhinemann/modular-bot-framework-for-telegram:master
Reviewed-on: dymik739/modular-bot-framework-for-telegram#6
2023-05-04 21:48:07 +03:00
bf79f3903d Slight naming tweaks. 2023-05-04 21:42:13 +03:00
59b547d9fa Added lesson type. 2023-05-04 21:20:03 +03:00
13 changed files with 299 additions and 114 deletions

52
main.py
View File

@@ -1,4 +1,5 @@
from telegram.ext import Updater, MessageHandler, Filters from telegram.ext import Updater, MessageHandler, Filters
from telegram.constants import ParseMode
import datetime import datetime
import codecs import codecs
import time import time
@@ -11,16 +12,18 @@ import importlib
# global variables # global variables
STOP_REQUESTED = False STOP_REQUESTED = False
# some functions that increase readability of the code # some functions that increase readability of the code
def readfile(filename): def readfile(filename):
try: try:
return codecs.open(filename, encoding = "utf-8").read() return codecs.open(filename, encoding="utf-8").read()
except FileNotFoundError: except FileNotFoundError:
return False return False
except Exception as e: except Exception as e:
print( "[ERROR] Unexpected error occured in readfile() ({0})".format(e) ) print(f"[ERROR] Unexpected error occurred in readfile() ({e})")
return False return False
# module object classes # module object classes
class ModuleV1: class ModuleV1:
def __init__(self, path, code, enabled, alias, predefine): def __init__(self, path, code, enabled, alias, predefine):
@@ -42,7 +45,8 @@ class ModuleV1:
try: try:
exec(self.predefine) exec(self.predefine)
except Exception as e: except Exception as e:
print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\" during predefine stage, disabling it...".format(self.path, self.alias, e)) print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" "
f"during predefine stage, disabling it...")
# running the module # running the module
def process(self, msg): def process(self, msg):
@@ -53,9 +57,10 @@ class ModuleV1:
exec(self.code) exec(self.code)
return self.RESPONCE return self.RESPONCE
except Exception as e: except Exception as e:
print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\"".format(self.path, self.alias, e)) print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
return "" return ""
class ModuleV2: class ModuleV2:
def __init__(self, path, index_file, enabled, alias): def __init__(self, path, index_file, enabled, alias):
self.version = 2 self.version = 2
@@ -68,8 +73,8 @@ class ModuleV2:
# running the module # running the module
def process(self, msg): def process(self, msg):
try: try:
responce = self.obj.process(msg, self.path) response = self.obj.process(msg, self.path)
return responce return response
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}\"")
return None return None
@@ -88,7 +93,7 @@ class ModuleControlUnit:
try: try:
meta_raw = readfile("modules/{}/meta.json".format(folder)) meta_raw = readfile("modules/{}/meta.json".format(folder))
if not meta_raw: if not meta_raw:
print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(folder)) print(f"[WARN] module_loader: no meta.json found in module folder \"{folder}\"")
continue continue
meta = json.loads( meta_raw ) meta = json.loads( meta_raw )
@@ -119,9 +124,10 @@ class ModuleControlUnit:
else: else:
predefine = False predefine = False
self.modules.append( ModuleV1( "modules/{}/".format(folder), code, enabled, alias, predefine ) ) self.modules.append(ModuleV1(f"modules/{folder}/", code, enabled, alias, predefine))
print("[INFO] reload_modules: successfully loaded {} as {} (start_on_boot: {})".format(folder, alias, enabled)) print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} "
f"(start_on_boot: {enabled})")
elif meta["version"] == 2: elif meta["version"] == 2:
if "index_file" in meta: if "index_file" in meta:
@@ -141,19 +147,15 @@ class ModuleControlUnit:
self.modules.append(ModuleV2(f"modules/{folder}/", index_file, enabled, alias)) self.modules.append(ModuleV2(f"modules/{folder}/", index_file, enabled, alias))
print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} (start_on_boot: {enabled})") print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} "
f"(start_on_boot: {enabled})")
else: else:
print(f"[WARN] reload_modules: module {folder} requires unsupported version ({meta['version']} > 2), skipping...") print(f"[WARN] reload_modules: module {folder} requires unsupported version "
f"({meta['version']} > 2), skipping...")
except Exception as e: except Exception as e:
print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(folder, e)) print(f"[ERROR] module_loader: error while loading module \"{folder}\" ({e})")
# message queue object to go back to synchronous message processing
#class MessageQueue:
# def __init__(self):
# print("[INFO] Initializing the message queue...")
# self.queue = []
# synchronous message processor # synchronous message processor
@@ -190,7 +192,9 @@ def queue_processor():
if mod.version == 1 or mod.version == 2: if mod.version == 1 or mod.version == 2:
responce = mod.process(msg) responce = mod.process(msg)
if responce: if responce:
updater.bot.send_message(chat_id = msg.chat.id, text = responce, disable_web_page_preview = True) updater.bot.send_message(chat_id=msg.chat.id, text=responce,
disable_web_page_preview=True,
parse_mode=ParseMode.MARKDOWN_V2)
print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}") print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}")
break break
@@ -202,8 +206,8 @@ def queue_processor():
break break
else: else:
time.sleep(1) time.sleep(1)
except Exception as e: except Exception:
print("[ERROR] queue_processor: current message queue: {}".format(message_queue)) print(f"[ERROR] queue_processor: current message queue: {message_queue}")
print("[ERROR] queue_processor: error while processing message, trying to delete it...") print("[ERROR] queue_processor: error while processing message, trying to delete it...")
try: try:
del message_queue[0] del message_queue[0]
@@ -216,7 +220,7 @@ def queue_processor():
# telegram bot processor # telegram bot processor
def message_handler(update, context): def message_handler(update, context):
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)
@@ -229,7 +233,7 @@ message_queue = []
mcu = ModuleControlUnit() mcu = ModuleControlUnit()
processor_thread = threading.Thread( target = queue_processor, args = [] ) processor_thread = threading.Thread(target=queue_processor, args=[])
processor_thread.start() processor_thread.start()
@@ -241,7 +245,7 @@ if not TOKEN:
sys.exit(1) sys.exit(1)
# connect to Telegram servers # connect to Telegram servers
updater = Updater(TOKEN, use_context = True) updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher dispatcher = updater.dispatcher
# assign the handler for messages # assign the handler for messages

View File

@@ -12,16 +12,18 @@ from telegram import Message, Chat
# global variables # global variables
STOP_REQUESTED = False STOP_REQUESTED = False
# some functions that increase readability of the code # some functions that increase readability of the code
def readfile(filename): def readfile(filename):
try: try:
return codecs.open(filename, encoding = "utf-8").read() return codecs.open(filename, encoding="utf-8").read()
except FileNotFoundError: except FileNotFoundError:
return False return False
except Exception as e: except Exception as e:
print( "[ERROR] Unexpected error occured in readfile() ({0})".format(e) ) print(f"[ERROR] Unexpected error occurred in readfile() ({e})")
return False return False
# module object classes # module object classes
class ModuleV1: class ModuleV1:
def __init__(self, path, code, enabled, alias, predefine): def __init__(self, path, code, enabled, alias, predefine):
@@ -37,13 +39,14 @@ class ModuleV1:
# set environmental variables # set environmental variables
def set_env(self): def set_env(self):
self.RESPONCE = "" self.RESPONSE = ""
def set_predefine(self): def set_predefine(self):
try: try:
exec(self.predefine) exec(self.predefine)
except Exception as e: except Exception as e:
print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\" during predefine stage, disabling it...".format(self.path, self.alias, e)) print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" "
f"during predefine stage, disabling it...")
# running the module # running the module
def process(self, msg): def process(self, msg):
@@ -52,9 +55,9 @@ class ModuleV1:
self.MESSAGE = msg self.MESSAGE = msg
try: try:
exec(self.code) exec(self.code)
return self.RESPONCE return self.RESPONSE
except Exception as e: except Exception as e:
print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\"".format(self.path, self.alias, e)) print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
return "" return ""
@@ -90,10 +93,10 @@ class ModuleControlUnit:
try: try:
meta_raw = readfile("modules/{}/meta.json".format(folder)) meta_raw = readfile("modules/{}/meta.json".format(folder))
if not meta_raw: if not meta_raw:
print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(folder)) print(f"[WARN] module_loader: no meta.json found in module folder \"{folder}\"")
continue continue
meta = json.loads( meta_raw ) meta = json.loads(meta_raw)
if "version" in meta: if "version" in meta:
if meta["version"] == 1: if meta["version"] == 1:
if "index_file" in meta: if "index_file" in meta:
@@ -101,9 +104,9 @@ class ModuleControlUnit:
else: else:
index_file = "index.py" index_file = "index.py"
code = readfile( "modules/{}/{}".format(folder, index_file) ) code = readfile("modules/{}/{}".format(folder, index_file))
if not code: # False both when readfile() returns False and when the code string is empty if not code: # False both when readfile() returns False and when the code string is empty
print("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder)) print(f"[WARN] reload_modules: module {folder} does not have any code, skipping...")
continue continue
if "start_on_boot" in meta: if "start_on_boot" in meta:
@@ -121,9 +124,10 @@ class ModuleControlUnit:
else: else:
predefine = False predefine = False
self.modules.append( ModuleV1( "modules/{}/".format(folder), code, enabled, alias, predefine ) ) self.modules.append(ModuleV1(f"modules/{folder}/", code, enabled, alias, predefine))
print("[INFO] reload_modules: successfully loaded {} as {} (start_on_boot: {})".format(folder, alias, enabled)) print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} "
f"(start_on_boot: {enabled})")
elif meta["version"] == 2: elif meta["version"] == 2:
if "index_file" in meta: if "index_file" in meta:
@@ -143,21 +147,15 @@ class ModuleControlUnit:
self.modules.append(ModuleV2(f"modules/{folder}/", index_file, enabled, alias)) self.modules.append(ModuleV2(f"modules/{folder}/", index_file, enabled, alias))
print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} (start_on_boot: {enabled})") print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} "
f"(start_on_boot: {enabled})")
else: else:
print(f"[WARN] reload_modules: module {folder} requires unsupported version ({meta['version']} > 2), skipping...") print(f"[WARN] reload_modules: module {folder} requires unsupported version "
f"({meta['version']} > 2), skipping...")
except Exception as e: except Exception as e:
print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(folder, e)) print(f"[ERROR] module_loader: error while loading module \"{folder}\" ({e})")
# message queue object to go back to synchronous message processing
#class MessageQueue:
# def __init__(self):
# print("[INFO] Initializing the message queue...")
# self.queue = []
# synchronous message processor # synchronous message processor
def queue_processor(): def queue_processor():
@@ -165,7 +163,7 @@ def queue_processor():
try: try:
if len(message_queue) > 0: if len(message_queue) > 0:
msg = message_queue[0] msg = 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:
@@ -191,9 +189,9 @@ def queue_processor():
for mod in mcu.modules: for mod in mcu.modules:
if mod.enabled: if mod.enabled:
if mod.version == 1 or mod.version == 2: if mod.version == 1 or mod.version == 2:
responce = mod.process(msg) response = mod.process(msg)
if responce: if response:
print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}") print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
break break
del message_queue[0] del message_queue[0]
@@ -203,8 +201,8 @@ def queue_processor():
else: else:
time.sleep(1) time.sleep(1)
except Exception as e: except Exception:
print("[ERROR] queue_processor: current message queue: {}".format(message_queue)) print(f"[ERROR] queue_processor: current message queue: {message_queue}")
print("[ERROR] queue_processor: error while processing message, trying to delete it...") print("[ERROR] queue_processor: error while processing message, trying to delete it...")
try: try:
del message_queue[0] del message_queue[0]
@@ -224,10 +222,9 @@ message_queue = []
mcu = ModuleControlUnit() mcu = ModuleControlUnit()
processor_thread = threading.Thread( target = queue_processor, args = [] ) processor_thread = threading.Thread(target=queue_processor, args=[])
processor_thread.start() processor_thread.start()
print("Enter testing messages one by one, end with an empty line") print("Enter testing messages one by one, end with an empty line")
while True: while True:
@@ -235,4 +232,4 @@ while True:
if len(new_msg) == 0: if len(new_msg) == 0:
break break
message_queue.append(Message(9, round(time.time()), Chat(575246355, 'supergroup'), text = new_msg)) message_queue.append(Message(9, round(time.time()), Chat(575246355, 'supergroup'), text=new_msg))

View File

@@ -0,0 +1 @@
../auto-schedule-pro/additions.json

View File

@@ -0,0 +1,174 @@
from datetime import datetime
import json
def readfile(filename):
with open(module_path + filename) as f:
return f.read()
# global constants
# Accusative - znahidnyj
WEEKDAYS_ACCUSATIVE = ["в понеділок", "у вівторок", "в середу", "в четвер", "в п'ятницю", "в суботу", "в неділю"]
# Genitive - rodovyj
WEEKDAYS_GENITIVE_NEXT = ["наступного понеділка", "наступного вівторка", "наступної середи", "наступного четверга",
"наступної п'ятниці", "наступної суботи", "наступної неділі"]
WEEKDAYS_GENITIVE_THIS = ["цього понеділка", "цього вівторка", "цієї середи", "цього четверга", "цієї п'ятниці",
"цієї суботи", "цієї неділі"]
# global variables
module_path = ""
def get_human_readable_date(start_datetime, end_datetime,
current_day, current_week):
human_readable_date = ""
if ((current_day + 2) == int(start_datetime.strftime("%u"))) or \
((current_day == 6) and (start_datetime.strftime("%u") == "1")):
human_readable_date += "завтра "
elif current_week != int(start_datetime.strftime("%W")) % 2:
human_readable_date += f"{WEEKDAYS_GENITIVE_NEXT[int(start_datetime.strftime('%u')) - 1]} "
elif current_day != (int(start_datetime.strftime("%u")) - 1):
human_readable_date += f"{WEEKDAYS_GENITIVE_THIS[int(start_datetime.strftime('%u')) - 1]} "
else:
human_readable_date += "сьогодні "
human_readable_date += "з "
human_readable_date += start_datetime.strftime("%H:%M")
human_readable_date += " до "
human_readable_date += end_datetime.strftime("%H:%M")
return human_readable_date
def generate_lesson_description(lesson, start_datetime, end_datetime, current_day, current_week, overrides={}):
output_settings = {"name": True, "date": True, "teacher": True, "link": True}
output_settings.update(overrides)
result = ""
if output_settings['name']:
result += f"{lesson['name']}\n"
if output_settings['date']:
human_readable_date = get_human_readable_date(start_datetime, end_datetime,
current_day, current_week)
result += f"*Дата*: {human_readable_date}\n"
if output_settings['teacher']:
result += f"*Викладач*: {lesson['teacher']}\n"
if output_settings['link']:
result += f"*Посилання*: {lesson['link']}"
return result
def get_schedule_data_from(filename):
raw_schedule = json.loads(readfile(filename))
baked_schedule = {}
for day_number, lesson_times in enumerate(raw_schedule):
for lesson_time in lesson_times:
timestamp = day_number * 86400 + int(lesson_time.split(":")[0]) * 3600 \
+ int(lesson_time.split(":")[1]) * 60
new_record = dict(raw_schedule[day_number][lesson_time])
new_record["source"] = filename.split(".json")[0]
baked_schedule[timestamp] = new_record
return baked_schedule
def process_arguments(args, base_day):
selected_day = int(base_day)
preferences = {}
for arg in args:
if arg[0] == "-":
if arg[1:].isdigit():
selected_day -= int(arg[1:])
else:
preferences[arg[1:]] = False
elif arg[0] == "+":
if arg[1:].isdigit():
selected_day += int(arg[1:])
else:
preferences[arg[1:]] = True
selected_day = selected_day % 14
return preferences, selected_day
def get_lesson_description(schedule, reference_time, lesson_time, current_day, current_week, overrides={}):
lesson_record = schedule[lesson_time]
lesson_start_datetime = datetime.fromtimestamp(reference_time + lesson_time)
lesson_end_datetime = datetime.fromtimestamp(reference_time + lesson_time + 5400)
return generate_lesson_description(lesson_record, lesson_start_datetime, lesson_end_datetime, current_day,
current_week, overrides=overrides)
def process(message, path):
message_text = message["text"]
full_command = message_text.split()
# there is no need to check if the full_command list if empty as it
# never will be - Telegram requires all messages to have at least
# one printable symbol, so this is already protected
base_command = full_command[0].lower()
if base_command not in ["!пара", "!пари"]:
return ""
global module_path
module_path = path
schedule = get_schedule_data_from("schedule.json")
schedule.update(get_schedule_data_from("additions.json"))
current_time = datetime.now()
current_week = current_time.isocalendar()[1] % 2
current_day = current_time.weekday()
current_seconds = current_week * 604800 + current_day * 86400 + current_time.hour * 3600 + current_time.minute \
* 60 + current_time.second
reference_time = int(current_time.strftime("%s")) - current_seconds
if base_command == "!пара":
upcoming_lessons = [timestamp for timestamp in schedule if timestamp > current_seconds - 5400]
if len(upcoming_lessons) > 0:
closest_lesson_time = min(upcoming_lessons)
else:
closest_lesson_time = min(schedule)
return "*Актуальна пара*: " + get_lesson_description(schedule, reference_time, closest_lesson_time, current_day,
current_week)
elif base_command == "!пари":
base_day = current_week * 7 + current_day
if len(full_command) >= 2:
args = [i for i in full_command[1:] if len(i) > 1]
preferences, selected_day = process_arguments(args, base_day)
else:
preferences = {}
selected_day = base_day
lesson_list = [i for i in schedule if selected_day * 86400 <= i < (selected_day + 1) * 86400]
lesson_descriptions_list = ["*Назва*: " + get_lesson_description(schedule, reference_time, lesson_time,
current_day, current_week,
overrides=preferences)
for lesson_time in lesson_list]
return f"__Пари {WEEKDAYS_ACCUSATIVE[selected_day % 7]}__\n" + "\n\n".join(lesson_descriptions_list)

View File

@@ -0,0 +1,6 @@
{
"version": 2,
"index_file": "main.py",
"start_on_boot": true,
"alias": "auto-schedule-pro-v2"
}

View File

@@ -0,0 +1 @@
../auto-schedule-pro/schedule.json

View File

@@ -1,5 +1,5 @@
## code ## ## code ##
if (self.MESSAGE["text"].lower() == "!пара" or self.MESSAGE["text"].lower().split()[0] == "!пари"): if (self.MESSAGE["text"].lower() == "!пара-old2" or self.MESSAGE["text"].lower().split()[0] == "!пари-old2"):
#getting current time #getting current time
current_time = datetime.datetime.now() current_time = datetime.datetime.now()
@@ -31,7 +31,7 @@ if (self.MESSAGE["text"].lower() == "!пара" or self.MESSAGE["text"].lower().
full_schedule = dict(list(schedule.items()) + list(additions.items())) full_schedule = dict(list(schedule.items()) + list(additions.items()))
if self.MESSAGE["text"].lower() == "!пара": if self.MESSAGE["text"].lower() == "!пара-old2":
print("test1") print("test1")
print(f"Full schedule printout: {full_schedule}") print(f"Full schedule printout: {full_schedule}")
print(f"Current delta_time: {current_seconds}") print(f"Current delta_time: {current_seconds}")
@@ -79,10 +79,10 @@ if self.MESSAGE["text"].lower() == "!пара":
human_readable_date += " до " human_readable_date += " до "
human_readable_date += dt_lesson_finish.strftime("%H:%M") human_readable_date += dt_lesson_finish.strftime("%H:%M")
self.RESPONCE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link']) self.RESPONSE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link'])
print("test3.1.5") print("test3.1.5")
else: else:
self.RESPONCE = "Пар немає взагалі. Ми вільні!" self.RESPONSE = "Пар немає взагалі. Ми вільні!"
else: else:
print("test3.2") print("test3.2")
@@ -106,9 +106,9 @@ if self.MESSAGE["text"].lower() == "!пара":
human_readable_date += " до " human_readable_date += " до "
human_readable_date += dt_lesson_finish.strftime("%H:%M") human_readable_date += dt_lesson_finish.strftime("%H:%M")
self.RESPONCE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link']) self.RESPONSE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link'])
if self.MESSAGE["text"].lower().split()[0] == "!пари": if self.MESSAGE["text"].lower().split()[0] == "!пари-old2":
command = self.MESSAGE["text"].lower().split() command = self.MESSAGE["text"].lower().split()
preferences = {"name": True, "date": True, "teacher": True, "link": True} preferences = {"name": True, "date": True, "teacher": True, "link": True}
@@ -183,4 +183,4 @@ if self.MESSAGE["text"].lower().split()[0] == "!пари":
result_text += "\n" result_text += "\n"
self.RESPONCE = result_text self.RESPONSE = result_text

View File

@@ -1,52 +1,52 @@
[ [
{ {
"8:30": {"name": "Дискретна математика", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"}, "8:30": {"name": "Дискретна математика (лекція)", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"},
"10:25": {"name": "Комп'ютерна логіка", "teacher": "Жабін В. І.", "link": "https://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"}, "10:25": {"name": "Комп'ютерна логіка (лекція)", "teacher": "Жабін В. І.", "link": "https://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"},
"12:20": {"name": "Культура мовлення та ділове мовлення", "teacher": "Онуфрієнко О. П.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"} "12:20": {"name": "Культура мовлення та ділове мовлення (лекція)", "teacher": "Онуфрієнко О. П.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"12:20": {"name": "Практичний курс іноземної мови. Частина 1", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"}, "12:20": {"name": "Англійська мова I (практика)", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Фізика", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"} "14:15": {"name": "Фізика (лабораторна)", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"8:30": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}, "8:30": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лабораторна)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"},
"10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}
}, },
{ {
"10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "10:25": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"},
"12:20": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "12:20": {"name": "Фізика (лекція)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"14:15": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"} "14:15": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лекція)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}
}, },
{ {
"10:25": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "10:25": {"name": "Фізика (практика)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"12:20": {"name": "Дискретна математика", "teacher": "Пономаренко А. М.", "link": "https://us05web.zoom.us/j/7089075754?pwd=TWRlZmxyVlFiTWU1UGlVVU1XcFE0Zz09"}, "12:20": {"name": "Дискретна математика (лабораторна)", "teacher": "Пономаренко А. М.", "link": "https://us05web.zoom.us/j/7089075754?pwd=TWRlZmxyVlFiTWU1UGlVVU1XcFE0Zz09"},
"14:15": {"name": "Основи здорового способу життя", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"} "14:15": {"name": "Основи здорового способу життя (практика)", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"}
}, },
{}, {},
{}, {},
{ {
"8:30": {"name": "Дискретна математика", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"}, "8:30": {"name": "Дискретна математика (лекція)", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"},
"10:25": {"name": "Комп'ютерна логіка", "teacher": "Жабін В. І.", "link": "https://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"}, "10:25": {"name": "Комп'ютерна логіка (лекція)", "teacher": "Жабін В. І.", "link": "https://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"},
"12:20": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "12:20": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}
}, },
{ {
"8:30": {"name": "Комп'ютерна логіка", "teacher": "Верба О. А.", "link": "https://us04web.zoom.us/j/7382214783?pwd=RnZ3SWgwK1JoVkZtNndnKzdPZjFGdz09"}, "8:30": {"name": "Комп'ютерна логіка (лабораторна)", "teacher": "Верба О. А.", "link": "https://us04web.zoom.us/j/7382214783?pwd=RnZ3SWgwK1JoVkZtNndnKzdPZjFGdz09"},
"10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"},
"12:20": {"name": "Практичний курс іноземної мови. Частина 1", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"}, "12:20": {"name": "Англійська мова I (практика)", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Фізика", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"} "14:15": {"name": "Фізика (лабораторна)", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}
}, },
{ {
"10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "10:25": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"},
"12:20": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "12:20": {"name": "Фізика (лекція)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"14:15": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"} "14:15": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лекція)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}
}, },
{ {
"10:25": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "10:25": {"name": "Фізика (практика)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"12:20": {"name": "Культура мовлення та ділове мовлення", "teacher": "Кушлаба М. П.", "link": "https://bbb.comsys.kpi.ua/b/myk-0iw-red-p01"}, "12:20": {"name": "Культура мовлення та ділове мовлення (практика)", "teacher": "Кушлаба М. П.", "link": "https://bbb.comsys.kpi.ua/b/myk-0iw-red-p01"},
"14:15": {"name": "Основи здорового способу життя", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"} "14:15": {"name": "Основи здорового способу життя (практика)", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"}
}, },
{}, {},
{} {}

View File

@@ -24,7 +24,7 @@ if self.MESSAGE["text"].lower() == "!пара-old":
pair_found = True pair_found = True
break break
self.RESPONCE = f"Сьогодні вихідний, тому пар немає)\n"\ self.RESPONSE = f"Сьогодні вихідний, тому пар немає)\n"\
f"Наступна пара - {next_pair['subject']} ({next_pair['lector']}) о {self.reverse_timetable[int(j)]} у {self.days_rod[day]}\n"\ f"Наступна пара - {next_pair['subject']} ({next_pair['lector']}) о {self.reverse_timetable[int(j)]} у {self.days_rod[day]}\n"\
f"Посилання (якщо воно чомусь треба): {next_pair['link']}" f"Посилання (якщо воно чомусь треба): {next_pair['link']}"
else: else:
@@ -33,13 +33,13 @@ if self.MESSAGE["text"].lower() == "!пара-old":
print("[DEBUG] Looking up a relevant pair...") print("[DEBUG] Looking up a relevant pair...")
try: try:
relevant_pair = schedule[current_week][current_day][str(self.timetable[i])] relevant_pair = schedule[current_week][current_day][str(self.timetable[i])]
self.RESPONCE = f"Актуальна пара: {relevant_pair['subject']} ({relevant_pair['lector']}), початок о {self.reverse_timetable[self.timetable[i]]}\n"\ self.RESPONSE = f"Актуальна пара: {relevant_pair['subject']} ({relevant_pair['lector']}), початок о {self.reverse_timetable[self.timetable[i]]}\n"\
f"Посилання: {relevant_pair['link']}" f"Посилання: {relevant_pair['link']}"
break break
except Exception as e: except Exception as e:
print(f"[WARN] module: auto-schedule: exception {e} while looking up the pair") print(f"[WARN] module: auto-schedule: exception {e} while looking up the pair")
else: else:
self.RESPONCE = "Сьогодні більше немає пар" self.RESPONSE = "Сьогодні більше немає пар"
except Exception as e: except Exception as e:
print(f"[WARN] module: auto-schedule: failed to process schedule.json ({e})") print(f"[WARN] module: auto-schedule: failed to process schedule.json ({e})")

View File

@@ -1,2 +1,2 @@
if msg.chat["type"] == "private": if msg.chat["type"] == "private":
self.RESPONCE = self.MESSAGE["text"] self.RESPONSE = self.MESSAGE["text"]

View File

@@ -9,4 +9,5 @@ if "%" in self.MESSAGE["text"]:
tagged_users |= self.tag_sets[i] tagged_users |= self.tag_sets[i]
if tagging_issued: if tagging_issued:
self.RESPONCE = "Користувач використав масовий тег з повідомленням: {}\n\n{}".format(self.MESSAGE["text"], " ".join(tagged_users)) self.RESPONSE = f"Користувач використав масовий тег з повідомленням: {self.MESSAGE['text']}\n\n" \
f"{' '.join(tagged_users)}"

View File

@@ -1,24 +1,24 @@
msg = self.MESSAGE["text"].lower() msg = self.MESSAGE["text"].lower()
responce_given = False response_given = False
for file in os.listdir(self.path + "db/"): for file in os.listdir(self.path + "db/"):
if responce_given: if response_given:
break break
try: try:
criteria = json.loads( readfile(self.path + "db/" + file) ) criteria = json.loads(readfile(self.path + "db/" + file))
for wordset in criteria["trigger_lists"]: for word_set in criteria["trigger_lists"]:
all_words_in = True all_words_in = True
for word in wordset: for word in word_set:
if word not in msg: if word not in msg:
all_words_in = False all_words_in = False
break break
if all_words_in: if all_words_in:
self.RESPONCE = criteria["responce_text"] self.RESPONSE = criteria["response_text"]
responce_given = True response_given = True
break break
except Exception as e: except Exception as e:

View File

@@ -17,14 +17,15 @@ if (command[0] in self.aliases) and (1 <= command_length <= 3):
decoded_text = text_to_decode decoded_text = text_to_decode
if chosen_model not in models: if chosen_model not in models:
self.RESPONCE = f"Такого варіанту транслітерації не існує. Доступні варіанти: {', '.join(list(models.keys()))}" self.RESPONSE = f"Такого варіанту транслітерації не існує. Доступні варіанти: " \
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], i[1])
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())
self.RESPONCE = f"Результат: {decoded_text}" self.RESPONSE = f"__Результат__\n{decoded_text}"
except Exception as e: except Exception as e:
print(f"[translit-decoder] Got exception: {e}") print(f"[translit-decoder] Got exception: {e}")