36 Commits
master ... dev

Author SHA1 Message Date
b0ea33cfff PEP8 autoformat and message formatting changes. 2023-09-06 20:06:18 +03:00
e9bec0159f auto-schedule-pro-v2: change spacing between schedule lookup parts 2023-09-06 17:39:58 +03:00
5dc78b8cb0 auto-schedule-pro-v2: fix HTML escaping 2023-09-06 17:36:18 +03:00
67b3c4278b auto-schedule-pro-v2: fix date showing up twice during schedule lookup 2023-09-06 17:33:12 +03:00
0497cbf9b7 add support for parse_mode selection in all module APIs and update modules to respect these changes 2023-09-06 17:22:26 +03:00
2b9ac41ced improve error reporting system, switch to schedule-v2 format in auto-schedule-pro-v2 2023-09-05 20:40:57 +03:00
fc450f633e update .gitignore to not track __pycache__ folders 2023-09-05 19:22:49 +03:00
1070362bc6 auto-schedule-pro-v2: prepare for migration from schedule-v1 to schedule-v2 format 2023-09-05 19:13:52 +03:00
d2915c10e2 auto-schedule-pro: update schedule.json 2023-09-05 19:07:45 +03:00
ebdae6256e main.py: disable MarkdownV2 to avoid errors 2023-09-05 13:22:11 +03:00
8cc68080e8 auto-schedule-pro: update schedule.json 2023-09-05 13:17:15 +03:00
94275048bb auto-schedule-pro: updated schedule.json 2023-09-05 11:47:34 +03:00
1504e03e13 main.py: added temporary fix for MarkdownV2 support 2023-09-05 11:46:59 +03:00
87424c8786 transliteration-decoder: add support for MarkdownV2 2023-09-04 21:36:13 +03:00
b21b16b817 auto-schedule-pro-v2: add initial support for MarkdownV2 2023-09-04 21:34:33 +03:00
12ee02cee0 main.py: enable MarkdownV2 formatting 2023-09-04 21:33:23 +03:00
ba353a3609 auto-schedule-pro: update schedule.json 2023-09-03 07:56:45 +03:00
69cb179d87 auto-schedule-pro: update schedule for 3 semester 2023-08-08 18:18:46 +03:00
1bd7fc2ef1 auto-schedule-pro-v2: improve holiday exclusive easter egg (triggered at !пара) 2023-08-07 23:32:45 +03:00
535087fae1 auto-schedule-pro-v2: temporary change responce to !пара (holidays exclusive) 2023-08-07 22:58:32 +03:00
e8a61a9e36 auto-schedule-pro: commit last additions.json edit as of 2 semester 2023-08-07 22:33:37 +03:00
5d7f89cff0 auto-schedule-pro: fix issues related to reading links from containers 2023-08-07 22:32:10 +03:00
763cc4d131 add new module: translator 2023-08-01 12:09:35 +03:00
bd22e8e9b6 hotfix: make bot core API v1 respect recent change from self.RESPONCE to self.RESPONSE 2023-06-29 13:46:44 +03:00
44628a3021 qna-basic: fix broken database file after code refactoring 2023-06-27 16:01:42 +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
23 changed files with 805 additions and 141 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
config/* config/*
modules/irc-bridge/error.log modules/irc-bridge/error.log
__pycache__/

83
main.py
View File

@@ -7,20 +7,23 @@ import sys
import os import os
import threading import threading
import importlib import importlib
import traceback
# 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):
@@ -36,13 +39,15 @@ class ModuleV1:
# set environmental variables # set environmental variables
def set_env(self): def set_env(self):
self.RESPONCE = "" self.RESPONSE = ""
self.FORMAT = ""
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):
@@ -51,10 +56,12 @@ class ModuleV1:
self.MESSAGE = msg self.MESSAGE = msg
try: try:
exec(self.code) exec(self.code)
return self.RESPONCE return self.RESPONSE, self.FORMAT
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 "" print(f"[ERROR] module v1: traceback:\ntraceback.format_exc()")
return "", None
class ModuleV2: class ModuleV2:
def __init__(self, path, index_file, enabled, alias): def __init__(self, path, index_file, enabled, alias):
@@ -68,11 +75,11 @@ 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) return self.obj.process(msg, self.path)
return responce
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 print(f"[ERROR] module v2: traceback:\ntraceback.format_exc()")
return None, None
# module control unit # module control unit
@@ -88,10 +95,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:
@@ -99,7 +106,7 @@ 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("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder))
continue continue
@@ -119,9 +126,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 +149,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
@@ -187,11 +191,22 @@ def queue_processor():
# 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 == 1 or mod.version == 2: if mod.version in [1, 2]:
responce = mod.process(msg) response, formatting = mod.process(msg)
if responce:
updater.bot.send_message(chat_id = msg.chat.id, text = responce, disable_web_page_preview = True) if response:
print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}") if formatting == None:
updater.bot.send_message(chat_id=msg.chat.id, text=response,
disable_web_page_preview=True)
print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
break
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
updater.bot.send_message(chat_id=msg.chat.id, text=response,
disable_web_page_preview=True,
parse_mode=formatting)
print(
f"Responded using module {mod.path} ({mod.alias}) with text (using {formatting}): {response}")
break break
del message_queue[0] del message_queue[0]
@@ -203,8 +218,9 @@ def queue_processor():
else: else:
time.sleep(1) time.sleep(1)
except Exception as e: except Exception as e:
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(f"[ERROR] Traceback:\n{traceback.format_exc()}")
print(f"[ERROR] queue_processor: error while processing message ({e}), trying to delete it...")
try: try:
del message_queue[0] del message_queue[0]
print("[INFO] queue_processor: deleted broken message from the queue") print("[INFO] queue_processor: deleted broken message from the queue")
@@ -229,10 +245,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()
# connecting to Telegram servers and listening for messages # connecting to Telegram servers and listening for messages
TOKEN = readfile("config/token") TOKEN = readfile("config/token")
@@ -241,7 +256,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

@@ -6,22 +6,25 @@ import sys
import os import os
import threading import threading
import importlib import importlib
import traceback
from telegram import Message, Chat 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 +40,15 @@ class ModuleV1:
# set environmental variables # set environmental variables
def set_env(self): def set_env(self):
self.RESPONCE = "" self.RESPONSE = ""
self.FORMAT = ""
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,10 +57,11 @@ class ModuleV1:
self.MESSAGE = msg self.MESSAGE = msg
try: try:
exec(self.code) exec(self.code)
return self.RESPONCE return self.RESPONSE, self.FORMAT
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 "" print(f"[ERROR] module v1: traceback:\ntraceback.format_exc()")
return "", None
class ModuleV2: class ModuleV2:
@@ -70,11 +76,11 @@ 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) return self.obj.process(msg, self.path)
return responce
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 print(f"[ERROR] module v2: traceback:\n{traceback.format_exc()}")
return None, None
# module control unit # module control unit
@@ -90,10 +96,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 +107,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 +127,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 +150,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():
@@ -190,10 +191,15 @@ def queue_processor():
# 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 == 1 or mod.version == 2: if mod.version in [1, 2]:
responce = mod.process(msg) response, formatting = mod.process(msg)
if responce:
print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}") if response:
if formatting == None:
print(f"Responded using module {mod.path} ({mod.alias}) with text: {response}")
break
elif formatting in ["Markdown", "MarkdownV2", "HTML"]:
print(f"Responded using module {mod.path} ({mod.alias}) with text (using {formatting}): {response}")
break break
del message_queue[0] del message_queue[0]
@@ -203,8 +209,9 @@ 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(f"[ERROR] Traceback:\n{traceback.format_exc()}")
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 +231,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 +241,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,26 @@
[
{
},
{
},
{
},
{
},
{
},
{},
{},
{
},
{
},
{
},
{
},
{
},
{},
{}
]

View File

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

View File

@@ -0,0 +1,264 @@
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 = ["цього понеділка", "цього вівторка", "цієї середи", "цього четверга", "цієї п'ятниці",
"цієї суботи", "цієї неділі"]
lesson_types_to_strings = {
"lec": "лекція",
"prac": "практика",
"lab": "лабораторна"
}
# global variables
module_path = ""
def escaped_string_markdownV2(input_string):
result_string = input_string
symbols_to_escape = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!']
for symbol in symbols_to_escape:
result_string = result_string.replace(symbol, f"\\{symbol}")
return result_string
def escaped_string_html(input_string):
result_string = input_string
symbols_to_escape = ['<', '>']
for symbol in symbols_to_escape:
result_string = result_string.replace(symbol, f"\\{symbol}")
return result_string
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 get_name_of_lesson_type(lesson_type):
if lesson_type in lesson_types_to_strings:
return lesson_types_to_strings[lesson_type]
def generate_lesson_description(lesson, start_datetime, end_datetime, current_day, current_week, overrides={},
custom_name_prefix="<b>Назва</b>"):
output_settings = {"name": True, "date": True, "teacher": True, "link": True, "comment": True}
output_settings.update(overrides)
result = ""
if output_settings['name']:
result += f"<b>{escaped_string_html(lesson['name'])}<b> ({escaped_string_html(get_name_of_lesson_type(lesson['type']))})\n"
if output_settings['date']:
human_readable_date = get_human_readable_date(start_datetime, end_datetime,
current_day, current_week)
result += f"<i>Дата</ii>: {escaped_string_html(human_readable_date)}\n"
if output_settings['teacher']:
result += f"<i>Викладач</i>: {escaped_string_html(lesson['teacher'])}\n"
if output_settings['link']:
result += f"<i>Посилання</i>: {escaped_string_html(lesson['link'])}\n"
if output_settings['comment'] and 'comment' in lesson:
result += f"<i>Примітка</i>: {escaped_string_html(lesson['comment'])}\n"
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 = raw_schedule[day_number][lesson_time]
item_source = filename.split(".json")[0]
if new_record.__class__ == list:
for item in new_record:
item["source"] = item_source
else:
new_record["source"] = item_source
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={},
custom_name_prefix="<b>Назва</b>", force_date_at_top=False):
lesson_record = schedule[lesson_time]
lesson_start_datetime = datetime.fromtimestamp(reference_time + lesson_time)
lesson_end_datetime = datetime.fromtimestamp(reference_time + lesson_time + 5400)
if lesson_record.__class__ == dict:
if force_date_at_top:
user_defined_overrides = dict(overrides)
internal_overrides = dict(overrides)
internal_overrides['date'] = False
description = generate_lesson_description(lesson_record, lesson_start_datetime, lesson_end_datetime,
current_day,
current_week, overrides=internal_overrides)
if 'date' in user_defined_overrides and not user_defined_overrides['date']:
return description
else:
human_readable_date = get_human_readable_date(lesson_start_datetime, lesson_end_datetime,
current_day, current_week)
return f"<b><u>{human_readable_date.capitalize()}</u></b>:\n" + description
else:
return generate_lesson_description(lesson_record, lesson_start_datetime, lesson_end_datetime, current_day,
current_week, overrides=overrides)
elif lesson_record.__class__ == list:
user_defined_overrides = dict(overrides)
internal_overrides = dict(overrides)
internal_overrides['date'] = False
descriptions = [generate_lesson_description(i, lesson_start_datetime, lesson_end_datetime, current_day,
current_week, overrides=internal_overrides,
custom_name_prefix=custom_name_prefix) for i in lesson_record]
if 'date' in user_defined_overrides and not user_defined_overrides['date']:
return "\n".join(descriptions)
else:
human_readable_date = get_human_readable_date(lesson_start_datetime, lesson_end_datetime,
current_day, current_week)
return f"<b><u>{human_readable_date.capitalize()}</u></b>:\n" + "\n".join(descriptions)
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 None, None
global module_path
module_path = path
schedule = get_schedule_data_from("schedule-v2.json")
schedule.update(get_schedule_data_from("additions-v2.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 == "!пара":
study_begin_ts = int(datetime(year=2023, month=9, day=4).strftime("%s"))
current_ts = int(datetime.now().strftime("%s"))
if -3600 * 4 < study_begin_ts - current_ts < 0:
return "Навчання незабаром розпочнеться!", None
elif 0 <= study_begin_ts - current_ts < 1209600:
return f"До навчання залишилося {study_begin_ts - current_ts} секунд...", None
elif study_begin_ts - current_ts >= 1209600:
return "Ви маєте законне право відпочити, пари почнуться не скоро", None
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, custom_name_prefix="<b>Актуальна пара</b>"), "HTML"
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,
custom_name_prefix="<b>Назва</b>", force_date_at_top=True)
for lesson_time in lesson_list]
return f"<b><u>Пари у {WEEKDAYS_ACCUSATIVE[selected_day % 7]}</u></b>:\n\n\n" + "\n\n".join(
lesson_descriptions_list), "HTML"

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,286 @@
[
{
"8:30": {
"name": "Політична наука: конфліктологічний підхід",
"teacher": "Багінський Андрій Владиславович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
"10:25": [
{
"name": "Захист персональних даних: стандарти ЄС та Ради Європи",
"teacher": "Дубняк М. В.",
"link": "https://us04web.zoom.us/j/7423381732?pwd=c1pJclU2ZDRUWDgyUE10dmhJUDhiZz09",
"type": "lec",
"selectable": true
},
{
"name": "Психологія",
"teacher": "Волянюк Н. Ю.",
"link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT0",
"type": "lec",
"selectable": true
},
{
"name": "Психологія конфлікту",
"teacher": "Москаленко О. В.",
"link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09",
"type": "prac",
"selectable": true
}
],
"14:15": {
"name": "Основи електронного урядування",
"teacher": "Чукут Світлана Анатоліївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
}
},
{
"12:20": {
"name": "Інженерія програмного забезпечення",
"teacher": "Васильєва Марія Давидівна",
"link": "https://zoom.us/wc/88696149166/join?from=join&_x_zm_rtaid=qhdJKhYLQNakh-zwxMG4lg.1693903841334.ad606145c892a54a4b450526e2394cbe&_x_zm_rhtaid=531",
"type": "lab",
"selectable": false,
"notice": "Код: 4VHkdw"
},
"14:15": {
"name": "Теорія електричних кіл та сигналів",
"teacher": "Лободзинський В. Ю. & Ілліна О. О.",
"link": "https://meet.google.com/gwx-sshq-sqb",
"type": "lab",
"selectable": false
}
},
{
"8:30": {
"name": "Теорія ймовірності та математична статистика",
"teacher": "Марковський Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc",
"type": "lec",
"selectable": false
},
"10:25": {
"name": "Вступ до операційної системи Linux",
"teacher": "Роковий Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Інженерія програмного забезпечення",
"teacher": "Васильєва Марія Давидівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
}
},
{
"10:25": {
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
"teacher": "Стаматієва Вікторія В'ячеславівна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": false
},
"12:20": {
"name": "Практичний курс іноземної мови. Частина 2",
"teacher": "Шевченко Ольга Миколаївна",
"link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh",
"type": "prac",
"selectable": false
},
"14:15": {
"name": "Соціальна психологія",
"teacher": "Блохіна Ірина Олександрівна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
},
"16:10": {
"name": "Основи електронного урядування",
"teacher": "Чукут Світлана Анатоліївна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
}
},
{
"8:30": {
"name": "Вступ до філософії",
"teacher": "Руденко Тамара Петрівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
},
"10:25": {
"name": "Теорія електричних кіл та сигналів",
"teacher": "Лободзинський Вадим Юрійович",
"link": "https://meet.google.com/gwx-sshq-sqb",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
"teacher": "Овчар Раїса Федорівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
}
},
{},
{},
{
"10:25": [
{
"name": "Психологія",
"teacher": "Сербова О. В.",
"link": "https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09",
"type": "prac",
"selectable": true
},
{
"name": "Психологія конфлікту",
"teacher": "Кононець М. О.",
"link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09",
"type": "lec",
"selectable": true
}
],
"12:20": [
{
"name": "Політична наука: конфліктологічний підхід",
"teacher": "Северинчик О. П.",
"link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09",
"type": "prac",
"selectable": true
},
{
"name": "Захист персональних даних: стандарти ЄС та Ради Європи",
"teacher": "Самчинська О. А.",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
}
],
"14:15": {
"name": "Розумні міста",
"teacher": "Чукут Світлана Анатоліївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
}
},
{
"10:25": {
"name": "Вступ до філософії",
"teacher": "Руденко Тамара Петрівна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": false
},
"14:15": {
"name": "Теорія ймовірності та математична статистика",
"teacher": "Марковський Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc",
"type": "prac",
"selectable": false
}
},
{
"8:30": {
"name": "Теорія ймовірності та математична статистика",
"teacher": "Марковський Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc",
"type": "lec",
"selectable": false
},
"10:25": {
"name": "Вступ до операційної системи Linux",
"teacher": "Роковий Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Інженерія програмного забезпечення",
"teacher": "Васильєва Марія Давидівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
},
"14:15": {
"name": "Інженерія програмного забезпечення",
"teacher": "Васильєва Марія Давидівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
}
},
{
"8:30": {
"name": "Вступ до операційної системи Linux",
"teacher": "Алєнін Олег Ігорович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": false
},
"10:25": {
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
"teacher": "Стаматієва Вікторія В'ячеславівна",
"link": "(старе посилання!) https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09",
"type": "prac",
"selectable": false
},
"12:20": {
"name": "Практичний курс іноземної мови. Частина 2",
"teacher": "Шевченко Ольга Миколаївна",
"link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh",
"type": "prac",
"selectable": false
},
"14:15": [
{
"name": "Соціальна психологія",
"teacher": "Винославська О. В.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Розумні міста",
"teacher": "Чукут С. А.",
"link": "(посилання відсутні!)",
"type": "prac",
"selectable": true
}
]
},
{
"10:25": {
"name": "Теорія електричних кіл та сигналів",
"teacher": "Лободзинський Вадим Юрійович",
"link": "https://meet.google.com/gwx-sshq-sqb",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення",
"teacher": "Овчар Раїса Федорівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false
}
},
{},
{}
]

View File

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

View File

@@ -1,6 +1,5 @@
[ [
{ {
"12:20": {"name": "Культура мовлення та ділове мовлення", "teacher": "Кушлаба М. П.", "link": "https://bbb.comsys.kpi.ua/b/myk-0iw-red-p01"}
}, },
{ {
}, },

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,55 @@
[ [
{ {
"8:30": {"name": "Дискретна математика (лекція)", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"}, "8:30": {"name": "Політична наука: конфліктологічний підхід (лекція)", "teacher": "Багінський Андрій Владиславович", "link": "(посилання відсутнє!)"},
"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://us04web.zoom.us/j/7423381732?pwd=c1pJclU2ZDRUWDgyUE10dmhJUDhiZz09 & https://us04web.zoom.us/j/6762396563?pwd=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09 & https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09"},
"12:20": {"name": "Культура мовлення та ділове мовлення (лекція)", "teacher": "Онуфрієнко О. П.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"} "14:15": {"name": "Основи електронного урядування (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
}, },
{ {
"12:20": {"name": "Англійська мова I (практика)", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"}, "12:20": {"name": "Інженерія програмного забезпечення (лабораторна)", "teacher": "Васильєва Марія Давидівна", "link": "https://zoom.us/wc/88696149166/join?from=join&_x_zm_rtaid=qhdJKhYLQNakh-zwxMG4lg.1693903841334.ad606145c892a54a4b450526e2394cbe&_x_zm_rhtaid=531"},
"14:15": {"name": "Фізика (лабораторна)", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"} "14:15": {"name": "Теорія електричних кіл та сигналів (лабораторна)", "teacher": "Лободзинський В. Ю. & Ілліна О. О.", "link": "https://meet.google.com/gwx-sshq-sqb"}
}, },
{ {
"8:30": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лабораторна)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}, "8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"},
"10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"},
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"}
}, },
{ {
"10:25": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "(посилання відсутнє!)"},
"12:20": {"name": "Фізика (лекція)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лекція)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"} "14:15": {"name": "Соціальна психологія (практика)", "teacher": "Блохіна Ірина Олександрівна", "link": "(посилання відсутнє!)"},
"16:10": {"name": "Основи електронного урядування (практика)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
}, },
{ {
"10:25": {"name": "Фізика (практика)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "8:30": {"name": "Вступ до філософії (лекція)", "teacher": "Руденко Тамара Петрівна", "link": "(посилання відсутнє!)"},
"12:20": {"name": "Дискретна математика (лабораторна)", "teacher": "Пономаренко А. М.", "link": "https://us05web.zoom.us/j/7089075754?pwd=TWRlZmxyVlFiTWU1UGlVVU1XcFE0Zz09"}, "10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
"14:15": {"name": "Основи здорового способу життя (практика)", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"} "12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "(посилання відсутнє!)"}
}, },
{}, {},
{}, {},
{ {
"8:30": {"name": "Дискретна математика (лекція)", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"}, "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://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"}, "12:20": {"name": "Політична наука: конфліктологічний підхід & Захист персональних даних: стандарти ЄС та Ради Європи (практики)", "teacher": "Северинчик О. П. & Самчинська О. А.", "link": "https://zoom.us/j/5175581158?pwd=UlhFY3lBOUUrNG9pclRVNndTNTZzQT09 & (посилання відсутнє!)"},
"12:20": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "14:15": {"name": "Розумні міста (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
}, },
{ {
"8:30": {"name": "Комп'ютерна логіка (лабораторна)", "teacher": "Верба О. А.", "link": "https://us04web.zoom.us/j/7382214783?pwd=RnZ3SWgwK1JoVkZtNndnKzdPZjFGdz09"}, "10:25": {"name": "Вступ до філософії (практика)", "teacher": "Руденко Тамара Петрівна", "link": "(посилання відсутнє!)"},
"10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "14:15": {"name": "Теорія ймовірності та математична статистика (практика)", "teacher": "Марковський Олександр Петрович", "link": "(посилання відсутнє!)"}
"12:20": {"name": "Англійська мова I (практика)", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Фізика (лабораторна)", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"10:25": {"name": "Вища математика (практика)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"} "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"},
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"},
"14:15": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "(посилання відсутнє!)"}
}, },
{ {
"10:25": {"name": "Вища математика (лекція)", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}, "8:30": {"name": "Вступ до операційної системи Linux (лабораторна)", "teacher": "Алєнін Олег Ігорович", "link": "(посилання відсутнє!)"},
"12:20": {"name": "Фізика (лекція)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "(старе посилання!) https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"},
"14:15": {"name": "Програмування II. Об'єктно-орієнтоване програмування (лекція)", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"} "12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "(старе посилання!) https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Соціальна психологія (лекція) & Розумні міста (практика)", "teacher": "Винославська О. В. & Чукут С. А.", "link": "(посилання відсутні!)"}
}, },
{ {
"10:25": {"name": "Фізика (практика)", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"}, "10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"},
"12:20": {"name": "Культура мовлення та ділове мовлення (практика)", "teacher": "Кушлаба М. П.", "link": "https://bbb.comsys.kpi.ua/b/myk-0iw-red-p01"}, "12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "(посилання відсутнє!)"}
"14:15": {"name": "Основи здорового способу життя (практика)", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"}
}, },
{}, {},
{} {}

View File

@@ -1,5 +1,6 @@
import datetime import datetime
import json import json
import time
import os import os
current_time = datetime.datetime.now() current_time = datetime.datetime.now()
@@ -84,7 +85,7 @@ if next_pair_time == None:
#print("test3.1.5") #print("test3.1.5")
if 'container_id' in p: if 'container_id' in p:
try: try:
cont = json.decode(open(f"../containers/{p['container_id']}", 'r').read()) cont = json.loads(open(f"../containers/{p['container_id']}", 'r').read())
if (time.time() - cont['update_ts']) > 43200: if (time.time() - cont['update_ts']) > 43200:
if ("QUERY_STRING" in os.environ) and ("force" in os.environ['QUERY_STRING'].lower()): if ("QUERY_STRING" in os.environ) and ("force" in os.environ['QUERY_STRING'].lower()):
print(f"Location: {cont['link']}\n\n", end = '') print(f"Location: {cont['link']}\n\n", end = '')
@@ -102,7 +103,7 @@ if next_pair_time == None:
new_seed = os.environ['REMOTE_ADDR'] + datetime.datetime.now().replace(minute = 0, second = 0).strftime("%s") new_seed = os.environ['REMOTE_ADDR'] + datetime.datetime.now().replace(minute = 0, second = 0).strftime("%s")
random.seed(new_seed) random.seed(new_seed)
surprise_pool = ["Йой!", "От халепа!", "Ой лишенько!"] surprise_pool = ["Йой!", "От халепа!", "Ой лишенько!"]
print(f"Content-Type: text/html; charset=UTF-8\n\n<h2>{random.choice(surprise_pool)}</h2><br><p>Під час спроби отримання посилання на пару {p['name']} сталася непередбачена помилка. Ви можете оновлювати сторінку, поки проблема не зникне (перенаправлення відбудеться, щойно все запрацює), або пошукати посилання де-інде.</p><p>Вибачте за тимчасові незручності(</p>") print(f"Content-Type: text/html; charset=UTF-8\n\n<h2>{random.choice(surprise_pool)}</h2><br><p>Під час спроби отримання посилання на пару {p['name']} сталася непередбачена помилка. Ви можете оновлювати сторінку, поки проблема не зникне (перенаправлення відбудеться, щойно все запрацює), або пошукати посилання де-інде.</p><p>Вибачте за тимчасові незручності(</p><p>(технічна інформація про помилку: {e}</p>")
else: else:
print(f"Location: {p['link'].split()[0]}\n\n", end = '') print(f"Location: {p['link'].split()[0]}\n\n", end = '')
@@ -139,7 +140,7 @@ else:
if 'container_id' in p: if 'container_id' in p:
try: try:
cont = json.decode(open(f"../containers/{p['container_id']}", 'r').read()) cont = json.loads(open(f"../containers/{p['container_id']}", 'r').read())
if (time.time() - cont['update_ts']) > 43200: if (time.time() - cont['update_ts']) > 43200:
if ("QUERY_STRING" in os.environ) and ("force" in os.environ['QUERY_STRING'].lower()): if ("QUERY_STRING" in os.environ) and ("force" in os.environ['QUERY_STRING'].lower()):
print(f"Location: {cont['link']}\n\n", end = '') print(f"Location: {cont['link']}\n\n", end = '')
@@ -157,7 +158,7 @@ else:
new_seed = os.environ['REMOTE_ADDR'] + datetime.datetime.now().replace(minute = 0, second = 0).strftime("%s") new_seed = os.environ['REMOTE_ADDR'] + datetime.datetime.now().replace(minute = 0, second = 0).strftime("%s")
random.seed(new_seed) random.seed(new_seed)
surprise_pool = ["Йой!", "От халепа!", "Ой лишенько!"] surprise_pool = ["Йой!", "От халепа!", "Ой лишенько!"]
print(f"Content-Type: text/html; charset=UTF-8\n\n<h2>{random.choice(surprise_pool)}</h2><br><p>Під час спроби отримання посилання на пару {p['name']} сталася непередбачена помилка. Ви можете оновлювати сторінку, поки проблема не зникне (перенаправлення відбудеться, щойно все запрацює), або пошукати посилання де-інде.</p><p>Вибачте за тимчасові незручності(</p>") print(f"Content-Type: text/html; charset=UTF-8\n\n<h2>{random.choice(surprise_pool)}</h2><br><p>Під час спроби отримання посилання на пару {p['name']} сталася непередбачена помилка. Ви можете оновлювати сторінку, поки проблема не зникне (перенаправлення відбудеться, щойно все запрацює), або пошукати посилання де-інде.</p><p>Вибачте за тимчасові незручності(</p><p>(технічна інформація про помилку: {e}</p>")
else: else:
print(f"Location: {p['link'].split()[0]}\n\n", end = '') print(f"Location: {p['link'].split()[0]}\n\n", end = '')

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

@@ -13,4 +13,6 @@ def get_num():
def process(message, path): def process(message, path):
if message.text == "!v2-testing": if message.text == "!v2-testing":
return f"Testing successful - call number {get_num()}" return f"Testing successful - call number {get_num()}", None
else:
return None, None

View File

@@ -2,5 +2,5 @@
"trigger_lists": [ "trigger_lists": [
["коли", "тест", "обж"] ["коли", "тест", "обж"]
], ],
"responce_text": "Тести з ОБЖ необхідно проходити лише тим студентам, які не були на практичному занятті. Якщо Ви були на практиці, але все одно пройдете тест, то ризикуєте отримати нижчу оцінку та знизити свій загальний бал" "response_text": "Тести з ОБЖ необхідно проходити лише тим студентам, які не були на практичному занятті. Якщо Ви були на практиці, але все одно пройдете тест, то ризикуєте отримати нижчу оцінку та знизити свій загальний бал"
} }

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

@@ -0,0 +1,34 @@
command = self.MESSAGE['text'].split(" ", 2)
command_length = len(command)
if (command[0] in self.aliases) and (1 <= command_length <= 3):
try:
import requests
if command_length == 1:
chosen_model = "auto-uk"
else:
chosen_model = command[1]
source, target = chosen_model.split("-")
if command_length == 3:
text_to_translate = command[2]
else:
text_to_translate = self.MESSAGE['reply_to_message']['text']
data = {"q": text_to_translate,
"source": source,
"target": target,
"format": "text"}
res = requests.post("http://127.0.0.1:5000/translate", data = data)
result = json.loads(res.text)
if source == "auto":
self.RESPONSE = f"Результат ({result['detectedLanguage']['language']} - {result['detectedLanguage']['confidence']}%): {result['translatedText']}"
else:
self.RESPONSE = f"Результат: {result['translatedText']}"
except Exception as e:
print(f"[translit-decoder] Got exception: {e}")

View File

@@ -0,0 +1,7 @@
{
"version": 1,
"index_file": "index.py",
"start_on_boot": true,
"alias": "translator",
"predefine": "predefine.py"
}

View File

@@ -0,0 +1 @@
self.aliases = ["!translate", "!t"]

View File

@@ -1,6 +1,14 @@
command = self.MESSAGE['text'].split(" ", 2) command = self.MESSAGE['text'].split(" ", 2)
command_length = len(command) command_length = len(command)
def escaped_string(unescaped_string):
result_string = str(unescaped_string)
for i in ["/", "<", ">"]:
result_string = result_string.replace(i, f"\\{i}")
return result_string
if (command[0] in self.aliases) and (1 <= command_length <= 3): if (command[0] in self.aliases) and (1 <= command_length <= 3):
try: try:
models = json.loads(readfile(self.path + "translate_models.json")) models = json.loads(readfile(self.path + "translate_models.json"))
@@ -17,14 +25,16 @@ 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"<b><u>Результат</u></b>\n{escaped_string(decoded_text)}"
self.FORMAT = "HTML"
except Exception as e: except Exception as e:
print(f"[translit-decoder] Got exception: {e}") print(f"[translit-decoder] Got exception: {e}")