modular-bot-framework-for-t.../modules/auto-schedule-pro-v2/main.py

265 lines
11 KiB
Python
Raw Normal View History

from datetime import datetime
import json
2023-05-08 10:22:23 +03:00
def readfile(filename):
with open(module_path + filename) as f:
return f.read()
2023-05-08 10:22:23 +03:00
# global constants
# Accusative - znahidnyj
2023-05-08 10:22:23 +03:00
WEEKDAYS_ACCUSATIVE = ["понеділок", "вівторок", "середу", "четвер", "п'ятницю", "суботу", "неділю"]
# Genitive - rodovyj
2023-05-08 10:22:23 +03:00
WEEKDAYS_GENITIVE_NEXT = ["наступного понеділка", "наступного вівторка", "наступної середи", "наступного четверга",
"наступної п'ятниці", "наступної суботи", "наступної неділі"]
2023-05-08 10:22:23 +03:00
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
2023-05-08 10:22:23 +03:00
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 = ""
2023-05-08 12:27:39 +03:00
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
2023-05-08 10:22:23 +03:00
def get_schedule_data_from(filename):
raw_schedule = json.loads(readfile(filename))
baked_schedule = {}
2023-05-08 10:22:23 +03:00
for day_number, lesson_times in enumerate(raw_schedule):
for lesson_time in lesson_times:
2023-05-08 10:22:23 +03:00
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
2023-05-08 10:22:23 +03:00
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()
2023-05-08 10:22:23 +03:00
# 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()
2023-05-08 10:22:23 +03:00
current_week = current_time.isocalendar()[1] % 2
current_day = current_time.weekday()
2023-05-08 10:22:23 +03:00
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
2023-05-08 10:22:23 +03:00
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)
2023-05-08 10:22:23 +03:00
return get_lesson_description(schedule, reference_time, closest_lesson_time, current_day,
current_week, custom_name_prefix="<b>Актуальна пара</b>"), "HTML"
elif base_command == "!пари":
2023-05-08 10:22:23 +03:00
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
2023-05-08 10:22:23 +03:00
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"