Compare commits

..

No commits in common. "master" and "modulev2" have entirely different histories.

62 changed files with 181 additions and 3102 deletions

2
.gitignore vendored
View File

@ -1,4 +1,2 @@
config/* config/*
modules/irc-bridge/error.log modules/irc-bridge/error.log
__pycache__/
modules/auto-schedule-pro-v2/preference-db

247
main.py
View File

@ -7,28 +7,20 @@ 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
DEBUG_MODE = False
DELAY_AFTER_RESPONSE = 3
DELAY_AFTER_MESSAGE = 0.1
DELAY_AFTER_IDLE = 1.0
lock = threading.Lock()
# some functions that increase readability of the code # some functions that increase readability of the code
def readfile(filename): def readfile(filename):
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(f"[ERROR] Unexpected error occurred in readfile() ({e})") print( "[ERROR] Unexpected error occured in readfile() ({0})".format(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):
@ -44,17 +36,13 @@ class ModuleV1:
# set environmental variables # set environmental variables
def set_env(self): def set_env(self):
self.RESPONSE = "" self.RESPONCE = ""
self.FORMAT = ""
def set_predefine(self): def set_predefine(self):
try: try:
if DEBUG_MODE:
print(f"Predefine on module v1 {self.alias} ({self.path})")
exec(self.predefine) exec(self.predefine)
except Exception as e: except Exception as e:
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" " print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\" during predefine stage, disabling it...".format(self.path, self.alias, e))
f"during predefine stage, disabling it...")
# running the module # running the module
def process(self, msg): def process(self, msg):
@ -62,15 +50,11 @@ class ModuleV1:
self.MESSAGE = msg self.MESSAGE = msg
try: try:
if DEBUG_MODE:
print(f"Calling module v1 {self.alias} ({self.path})")
exec(self.code) exec(self.code)
return self.RESPONSE, self.FORMAT return self.RESPONCE
except Exception as e: except Exception as e:
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"") print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\"".format(self.path, self.alias, e))
print(f"[ERROR] module v1: traceback:\n{traceback.format_exc()}") return ""
return "", None
class ModuleV2: class ModuleV2:
def __init__(self, path, index_file, enabled, alias): def __init__(self, path, index_file, enabled, alias):
@ -84,13 +68,11 @@ class ModuleV2:
# running the module # running the module
def process(self, msg): def process(self, msg):
try: try:
if DEBUG_MODE: responce = self.obj.process(msg, self.path)
print(f"Calling module v2 {self.alias} ({self.path})") return responce
return self.obj.process(msg, self.path)
except Exception as e: except Exception as e:
print(f"[ERROR] module v2: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"") print(f"[ERROR] module v2: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"")
print(f"[ERROR] module v2: traceback:\ntraceback.format_exc()") return None
return None, None
# module control unit # module control unit
@ -104,9 +86,9 @@ class ModuleControlUnit:
def reload_modules(self): def reload_modules(self):
for folder in os.listdir("modules/"): for folder in os.listdir("modules/"):
try: try:
meta_raw = readfile(f"modules/{folder}/meta.json") meta_raw = readfile("modules/{}/meta.json".format(folder))
if not meta_raw: if not meta_raw:
print(f"[WARN] module_loader: no meta.json found in module folder \"{folder}\"") print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(folder))
continue continue
meta = json.loads( meta_raw ) meta = json.loads( meta_raw )
@ -117,9 +99,9 @@ class ModuleControlUnit:
else: else:
index_file = "index.py" index_file = "index.py"
code = readfile(f"modules/{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(f"[WARN] reload_modules: module {folder} does not have any code, skipping...") print("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder))
continue continue
if "start_on_boot" in meta: if "start_on_boot" in meta:
@ -133,14 +115,13 @@ class ModuleControlUnit:
alias = None alias = None
if "predefine" in meta: if "predefine" in meta:
predefine = readfile(f"modules/{folder}/{meta['predefine']}") predefine = readfile("modules/{}/{}".format(folder, meta["predefine"]))
else: else:
predefine = False predefine = False
self.modules.append(ModuleV1(f"modules/{folder}/", code, enabled, alias, predefine)) self.modules.append( ModuleV1( "modules/{}/".format(folder), code, enabled, alias, predefine ) )
print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} " print("[INFO] reload_modules: successfully loaded {} as {} (start_on_boot: {})".format(folder, alias, enabled))
f"(start_on_boot: {enabled})")
elif meta["version"] == 2: elif meta["version"] == 2:
if "index_file" in meta: if "index_file" in meta:
@ -160,15 +141,19 @@ 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} " print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} (start_on_boot: {enabled})")
f"(start_on_boot: {enabled})")
else: else:
print(f"[WARN] reload_modules: module {folder} requires unsupported version " print(f"[WARN] reload_modules: module {folder} requires unsupported version ({meta['version']} > 2), skipping...")
f"({meta['version']} > 2), skipping...")
except Exception as e: except Exception as e:
print(f"[ERROR] module_loader: error while loading module \"{folder}\" ({e})") print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(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
@ -177,180 +162,62 @@ def queue_processor():
try: try:
if len(message_queue) > 0: if len(message_queue) > 0:
msg = message_queue[0] msg = message_queue[0]
del message_queue[0] print("[DEBUG] queue_processor: {}".format(msg)) # debug
print(f"[DEBUG] queue_processor: {msg}") # debug
# check for control commands # check for control commands
if msg.from_user.id == 575246355: if msg["chat"]["id"] == 575246355:
if msg["text"][0] == "$": if msg["text"][0] == "$":
command = msg["text"][1:].split() command = msg["text"][1:].split(" ")
if len(command) >= 2 and command[0] == "module": if len(command) >= 2 and command[0] == "module":
if command[1] == "reload": if command[1] == "reload":
if len(command) == 2: print("[INFO] Module reloading triggered by a command")
print("[INFO] Full module reloading triggered by a command")
updater.bot.send_message(msg.chat.id, f"Reloading all modules...")
# properly reload all v2 modules # properly reload all v2 modules
for mod in mcu.modules: for mod in mcu.modules:
if mod.version == 2: if mod.version == 2:
importlib.reload(mod.obj) importlib.reload(mod.obj)
del mcu.modules[:] del mcu.modules[:]
mcu.reload_modules() mcu.reload_modules()
else:
# TO DO: make it possible to reload individual modules by their
# alias or containing folder
pass
elif command[1] == "enable" and len(command) == 3:
if command[2] == "all":
for mod in mcu.modules:
mod.enabled = True
print(f"[INFO] module {mod.alias} was enabled")
else:
for mod in mcu.modules:
if mod.alias == command[2]:
mod.enabled = True
print(f"[INFO] module {mod.alias} was enabled")
elif command[1] == "disable" and len(command) == 3:
if command[2] == "all":
for mod in mcu.modules:
mod.enabled = False
print(f"[INFO] module {mod.alias} was disabled")
else:
for mod in mcu.modules:
if mod.alias == command[2]:
mod.enabled = False
print(f"[INFO] module {mod.alias} was disabled")
elif command[1] == "status" and len(command) == 3:
if command[2] == "all":
for mod in mcu.modules:
print(f"[INFO] module {mod.alias} is {mod.enabled}")
else:
for mod in mcu.modules:
if mod.alias == command[2]:
print(f"[INFO] module {mod.alias} is {mod.enabled}")
elif (2 <= len(command) <= 3) and command[0] == "delay":
l = len(command)
if command[1] == "response":
if l == 3:
try:
new_value = float(command[2])
global DELAY_AFTER_RESPONSE
DELAY_AFTER_RESPONSE = new_value
print(f"[INFO]: Set DELAY_AFTER_RESPONSE to {command[2]}")
updater.bot.send_message(msg.chat.id, f"Set DELAY_AFTER_RESPONSE to {command[2]}")
except:
print(f"[WARN]: Cannot set DELAY_AFTER_RESPONSE to non-float value of {command[2]}")
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_RESPONSE to non-float value of {command[2]}")
elif l == 2:
print(f"[INFO]: DELAY_AFTER_RESPONSE = {DELAY_AFTER_RESPONSE}")
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_RESPONSE = {DELAY_AFTER_RESPONSE}")
elif command[1] == "message":
if l == 3:
try:
new_value = float(command[2])
global DELAY_AFTER_MESSAGE
DELAY_AFTER_MESSAGE = new_value
print(f"[INFO]: Set DELAY_AFTER_MESSAGE to {command[2]}")
updater.bot.send_message(msg.chat.id, f"Set DELAY_AFTER_MESSAGE to {command[2]}")
except:
print("[WARN]: Cannot set DELAY_AFTER_MESSAGE to non-float value of {command[2]}")
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_MESSAGE to non-float value of {command[2]}")
elif l == 2:
print(f"[INFO]: DELAY_AFTER_MESSAGE = {DELAY_AFTER_MESSAGE}")
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_MESSAGE = {DELAY_AFTER_MESSAGE}")
elif command[1] == "idle":
if l == 3:
try:
new_value = float(command[2])
global DELAY_AFTER_IDLE
DELAY_AFTER_IDLE = new_value
print(f"[INFO]: Set DELAY_AFTER_IDLE to {command[2]}")
updater.bot.send_message(msg.chat.id, f"Set DELAY_AFTER_IDLE to {command[2]}")
except:
print("[WARN]: Cannot set DELAY_AFTER_IDLE to non-float value of {command[2]}")
updater.bot.send_message(msg.chat.id, f"[WARN]: Cannot set DELAY_AFTER_IDLE to non-float value of {command[2]}")
elif l == 2:
print(f"[INFO]: DELAY_AFTER_IDLE = {DELAY_AFTER_IDLE}")
updater.bot.send_message(msg.chat.id, f"[INFO]: DELAY_AFTER_IDLE = {DELAY_AFTER_IDLE}")
elif len(command) == 2 and command[0] == "queue":
if command[1] == "size":
print(f"[INFO]: Queue length is {len(message_queue)}")
updater.bot.send_message(msg.chat.id, f"[INFO]: Queue length is {len(message_queue)}")
elif len(command) == 2 and command[0] == "debug":
global DEBUG_MODE
if command[1] == "on":
print("[INFO] Debug mode is enabled")
DEBUG_MODE = True
else:
print("[INFO] Debug mode is disabled")
DEBUG_MODE = False
del message_queue[0]
continue continue
# modules are used in here # modules are used in here
for mod in mcu.modules: for mod in mcu.modules:
if mod.enabled: if mod.enabled:
if mod.version in [1, 2]: if mod.version == 1 or mod.version == 2:
try: responce = mod.process(msg)
response, formatting = mod.process(msg) if responce:
except Exception as e: updater.bot.send_message(chat_id = msg.chat.id, text = responce, disable_web_page_preview = True)
print(f"Module {mod.alias} ({mod.path}) failed to do a proper return, skipping...") print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}")
continue break
if response: del message_queue[0]
if not formatting:
print(f"Responding using module {mod.path} ({mod.alias}) with text: {response}")
updater.bot.send_message(chat_id=msg.chat.id, text=response,
disable_web_page_preview=True)
time.sleep(DELAY_AFTER_RESPONSE)
break
elif formatting in ["Markdown", "MarkdownV2", "HTML"]: time.sleep(0.1)
print(f"Responding using module {mod.path} ({mod.alias}) with text (using {formatting}): {response}")
updater.bot.send_message(chat_id=msg.chat.id, text=response,
disable_web_page_preview=True,
parse_mode=formatting)
time.sleep(DELAY_AFTER_RESPONSE)
break
time.sleep(DELAY_AFTER_MESSAGE)
else: else:
if STOP_REQUESTED: if STOP_REQUESTED:
break break
else: else:
time.sleep(DELAY_AFTER_IDLE) time.sleep(1)
except Exception as e: except Exception as e:
print(f"[ERROR] queue_processor: current message queue: {message_queue}") print("[ERROR] queue_processor: current message queue: {}".format(message_queue))
print(f"[ERROR] Traceback:\n{traceback.format_exc()}") print("[ERROR] queue_processor: error while processing message, trying to delete it...")
print(f"[ERROR] queue_processor: error while processing message ({e})...") try:
print("[INFO] queue_processor: skipped broken message") del message_queue[0]
print("[INFO] queue_processor: deleted broken message from the queue")
except:
print("[WARN] queue_processor: message seems absent, whatever")
print("[INFO] queue_processor thread stops successfully") print("[INFO] queue_processor thread stops successfully")
# telegram bot processor # telegram bot processor
def message_handler(update, context): def message_handler(update, context):
global lock print("[DEBUG] Received new message") # just for testing
with lock: message_queue.append(update.message)
if update.message and update.message.text.__class__ == str and update.message.text.startswith("$"):
print("[DEBUG] Received new message with high priority") # just for testing
message_queue.insert(0, update.message)
elif update.message:
print("[DEBUG] Received new message") # just for testing
message_queue.append(update.message)
else:
print(f"[DEBUG] Received {update.message} instead of a message")
# --- Final stage --- # --- Final stage ---
@ -362,7 +229,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()
@ -374,7 +241,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,25 +6,22 @@ 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(f"[ERROR] Unexpected error occurred in readfile() ({e})") print( "[ERROR] Unexpected error occured in readfile() ({0})".format(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):
@ -40,15 +37,13 @@ class ModuleV1:
# set environmental variables # set environmental variables
def set_env(self): def set_env(self):
self.RESPONSE = "" self.RESPONCE = ""
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(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\" " print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\" during predefine stage, disabling it...".format(self.path, self.alias, e))
f"during predefine stage, disabling it...")
# running the module # running the module
def process(self, msg): def process(self, msg):
@ -57,11 +52,10 @@ class ModuleV1:
self.MESSAGE = msg self.MESSAGE = msg
try: try:
exec(self.code) exec(self.code)
return self.RESPONSE, self.FORMAT return self.RESPONCE
except Exception as e: except Exception as e:
print(f"[ERROR] module v1: module \"{self.path}\" ({self.alias}) raised exception \"{e}\"") print("[ERROR] module v1: module \"{}\" ({}) raised exception \"{}\"".format(self.path, self.alias, e))
print(f"[ERROR] module v1: traceback:\n{traceback.format_exc()}") return ""
return "", None
class ModuleV2: class ModuleV2:
@ -76,11 +70,11 @@ class ModuleV2:
# running the module # running the module
def process(self, msg): def process(self, msg):
try: try:
return self.obj.process(msg, self.path) responce = 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}\"")
print(f"[ERROR] module v2: traceback:\n{traceback.format_exc()}") return None
return None, None
# module control unit # module control unit
@ -96,10 +90,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(f"[WARN] module_loader: no meta.json found in module folder \"{folder}\"") print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(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:
@ -107,9 +101,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(f"[WARN] reload_modules: module {folder} does not have any code, skipping...") print("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder))
continue continue
if "start_on_boot" in meta: if "start_on_boot" in meta:
@ -127,10 +121,9 @@ class ModuleControlUnit:
else: else:
predefine = False predefine = False
self.modules.append(ModuleV1(f"modules/{folder}/", code, enabled, alias, predefine)) self.modules.append( ModuleV1( "modules/{}/".format(folder), code, enabled, alias, predefine ) )
print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} " print("[INFO] reload_modules: successfully loaded {} as {} (start_on_boot: {})".format(folder, alias, enabled))
f"(start_on_boot: {enabled})")
elif meta["version"] == 2: elif meta["version"] == 2:
if "index_file" in meta: if "index_file" in meta:
@ -150,15 +143,21 @@ 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} " print(f"[INFO] reload_modules: successfully loaded {folder} as {alias} (start_on_boot: {enabled})")
f"(start_on_boot: {enabled})")
else: else:
print(f"[WARN] reload_modules: module {folder} requires unsupported version " print(f"[WARN] reload_modules: module {folder} requires unsupported version ({meta['version']} > 2), skipping...")
f"({meta['version']} > 2), skipping...")
except Exception as e: except Exception as e:
print(f"[ERROR] module_loader: error while loading module \"{folder}\" ({e})") print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(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():
@ -166,7 +165,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,16 +190,11 @@ 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 in [1, 2]: if mod.version == 1 or mod.version == 2:
response, formatting = mod.process(msg) responce = mod.process(msg)
if responce:
if response: print(f"Responded using module {mod.path} ({mod.alias}) with text: {responce}")
if not formatting: break
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
del message_queue[0] del message_queue[0]
else: else:
@ -209,9 +203,8 @@ def queue_processor():
else: else:
time.sleep(1) time.sleep(1)
except Exception: except Exception as e:
print(f"[ERROR] queue_processor: current message queue: {message_queue}") print("[ERROR] queue_processor: current message queue: {}".format(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]
@ -231,9 +224,10 @@ 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:
@ -241,4 +235,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

@ -1,26 +0,0 @@
[
{
},
{
},
{
},
{
},
{
},
{},
{},
{
},
{
},
{
},
{
},
{
},
{},
{}
]

View File

@ -1,477 +0,0 @@
from datetime import datetime
import json
import os
def readfile(filename):
with open(module_path + filename) as f:
return f.read()
def writefile(filename, data):
with open(module_path + filename, 'w') as f:
f.write(data)
# global constants
# Accusative - znahidnyj
WEEKDAYS_ACCUSATIVE = ["понеділок", "вівторок", "середу", "четвер", "п'ятницю", "суботу", "неділю"]
# Genitive - rodovyj
WEEKDAYS_GENITIVE_NEXT = ["наступного понеділка", "наступного вівторка", "наступної середи", "наступного четверга",
"наступної п'ятниці", "наступної суботи", "наступної неділі"]
WEEKDAYS_GENITIVE_THIS = ["цього понеділка", "цього вівторка", "цієї середи", "цього четверга", "цієї п'ятниці",
"цієї суботи", "цієї неділі"]
lesson_types_to_strings = {
"lec": "лекція",
"prac": "практика",
"lab": "лабораторна",
"con": "консультація"
}
color_code_mapping = {
"lec": "🔵",
"prac": "🟡",
"lab": "🔴",
"con": "🟢"
}
# global variables
module_path = ""
def get_preference_by_id(user_id, name):
if not os.path.exists(module_path + f"preference-db/{user_id}.json"):
return None
raw_prefs = readfile(f"preference-db/{user_id}.json")
try:
preferences = json.loads(raw_prefs)
except Exception as e:
return None
if not name in preferences:
return None
return preferences[name]
def get_all_preferences_by_id(user_id):
user_preferences = {
"output-style": "legacy-vibrant",
"output-style-lesson": "None",
"output-style-lookup": "None"
}
# label defaults as defaults and let custom settings override these labels
for i in user_preferences:
user_preferences[i] += " <i>(default)</i>"
for i in user_preferences:
override = get_preference_by_id(user_id, i)
if override != None:
user_preferences[i] = override
return user_preferences
def set_preference_by_id(user_id, name, value):
if not os.path.exists(module_path + "preference-db/"):
os.mkdir(module_path + "preference-db/")
preferences = {}
if os.path.exists(module_path + f"preference-db/{user_id}.json"):
try:
raw_prefs = readfile(f"preference-db/{user_id}.json")
preferences = json.loads(raw_prefs)
except Exception as e:
preferences = {}
else:
preferences = {}
preferences[name] = value
final_data = json.dumps(preferences)
writefile(f"preference-db/{user_id}.json", final_data)
def clear_preference_by_id(user_id, name):
if not os.path.exists(module_path + "preference-db/"):
os.mkdir(module_path + "preference-db/")
preferences = {}
if os.path.exists(module_path + f"preference-db/{user_id}.json"):
try:
raw_prefs = readfile(f"preference-db/{user_id}.json")
preferences = json.loads(raw_prefs)
except Exception as e:
preferences = {}
else:
preferences = {}
if name in preferences:
del preferences[name]
final_data = json.dumps(preferences)
writefile(f"preference-db/{user_id}.json", final_data)
def load_template(template, part):
return readfile(f"templates/{template}/{part}.msg")
def get_color_code(lesson_type):
return color_code_mapping[lesson_type]
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="Назва", template="legacy-vibrant", force_date_at_top=False):
if lesson.__class__ == dict:
if force_date_at_top:
total_result = load_template(template, "date")
human_readable_date = get_human_readable_date(start_datetime, end_datetime,
current_day, current_week)
total_result = total_result.replace("%DATE%", human_readable_date)
if "full" in overrides and overrides["full"]:
total_result += load_template(template, "multiple")
else:
total_result += load_template(template, "multiple-short")
for i in ['name', 'teacher']:
total_result = total_result.replace(f"%{i.upper()}%", lesson[i])
total_result = total_result.replace("%DATE%", human_readable_date)
total_result = total_result.replace("%TYPE%", get_name_of_lesson_type(lesson['type']))
total_result = total_result.replace("%NAME_PREFIX%", custom_name_prefix)
total_result = total_result.replace("%COLOR_CODE%", get_color_code(lesson['type']))
if ('nolink' not in lesson) or (not lesson['nolink']):
total_result = total_result.replace("%LINK%", lesson['link'])
else:
total_result = total_result.replace("%LINK%", "#")
if 'comment' in lesson:
total_result += load_template(template, "comment")
total_result = total_result.replace("%COMMENT%", lesson["comment"])
if "full" in overrides and overrides["full"]:
total_result += "\n"
return total_result
else:
active_template = load_template(template, "single")
for i in ['name', 'teacher']:
active_template = active_template.replace(f"%{i.upper()}%", lesson[i])
human_readable_date = get_human_readable_date(start_datetime, end_datetime,
current_day, current_week)
active_template = active_template.replace("%DATE%", human_readable_date)
active_template = active_template.replace("%TYPE%", get_name_of_lesson_type(lesson['type']))
active_template = active_template.replace("%NAME_PREFIX%", custom_name_prefix)
active_template = active_template.replace("%COLOR_CODE%", get_color_code(lesson['type']))
if ('nolink' not in lesson) or (not lesson['nolink']):
active_template = active_template.replace("%LINK%", lesson['link'])
else:
active_template = active_template.replace("%LINK%", "#")
if 'comment' in lesson:
active_template += load_template(template, "comment")
active_template = active_template.replace("%COMMENT%", lesson["comment"])
return active_template
elif lesson.__class__ == list:
total_result = load_template(template, "date")
human_readable_date = get_human_readable_date(start_datetime, end_datetime,
current_day, current_week)
total_result = total_result.replace("%DATE%", human_readable_date)
for l in lesson:
if "full" in overrides and overrides["full"]:
active_template = load_template(template, "multiple")
else:
active_template = load_template(template, "multiple-short")
for i in ['name', 'teacher']:
active_template = active_template.replace(f"%{i.upper()}%", l[i])
active_template = active_template.replace("%DATE%", human_readable_date)
active_template = active_template.replace("%TYPE%", get_name_of_lesson_type(l['type']))
active_template = active_template.replace("%NAME_PREFIX%", custom_name_prefix)
active_template = active_template.replace("%COLOR_CODE%", get_color_code(l['type']))
if ('nolink' not in lesson) or (not lesson['nolink']):
active_template = active_template.replace("%LINK%", l['link'])
else:
active_template = active_template.replace("%LINK%", "#")
if 'comment' in lesson:
active_template += load_template(template, "comment")
active_template = active_template.replace("%COMMENT%", lesson["comment"])
if "full" in overrides and overrides["full"]:
active_template += "\n"
total_result += active_template
return total_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="Назва", template="legacy-vibrant", 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)
return generate_lesson_description(lesson_record, lesson_start_datetime, lesson_end_datetime, current_day,
current_week, overrides=overrides, custom_name_prefix=custom_name_prefix, template=template,
force_date_at_top=force_date_at_top)
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 ["!пара", "!пари", "!schedule-ctl",
"!para", "!pary"]:
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 in ["!пара", "!para"]:
# easter egg
study_begin_ts = int(datetime(year=2024, month=9, day=2).strftime("%s"))
current_ts = int(datetime.now().strftime("%s"))
until_study_day = study_begin_ts - current_ts
if -3600*4 < until_study_day < 0:
return "Навчання от-от розпочнеться!", None
elif 0 <= until_study_day < 3600*24*28:
return f"До навчання залишилося {until_study_day} секунд..." \
f" ({round(until_study_day/3600, 4)} годин," \
f" {round(until_study_day/3600/24, 4)} діб)", None
elif until_study_day >= 3600*24*14:
return "Ви маєте законне право відпочити, пари почнуться не скоро", None
# actual lesson finding code
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)
# shifting lesson pointer if requested to do so
if len(full_command) >= 2:
possible_times = list(schedule.keys())
current_pointer_position = possible_times.index(closest_lesson_time)
total_list_length = len(possible_times)
if len(full_command[1]) > 1 and full_command[1][1:].isdigit():
if full_command[1][0] == "+":
current_pointer_position = (current_pointer_position + int(full_command[1][1:])) % total_list_length
else:
current_pointer_position = (current_pointer_position - int(full_command[1][1:])) % total_list_length
closest_lesson_time = possible_times[current_pointer_position]
# getting corrent style
output_style_preference = "legacy-vibrant"
general_output_style_preference = get_preference_by_id(message.from_user.id, "output-style")
if general_output_style_preference != None:
output_style_preference = general_output_style_preference
specific_output_style_preference = get_preference_by_id(message.from_user.id, "output-style-lesson")
if specific_output_style_preference != None:
output_style_preference = specific_output_style_preference
# returning generated pair description
return get_lesson_description(schedule, reference_time, closest_lesson_time, current_day,
current_week, custom_name_prefix="Актуальна пара", template=output_style_preference), "HTML"
elif base_command in ["!пари", "!pary"]:
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]
output_style_preference = "legacy-vibrant"
general_output_style_preference = get_preference_by_id(message.from_user.id, "output-style")
if general_output_style_preference != None:
output_style_preference = general_output_style_preference
specific_output_style_preference = get_preference_by_id(message.from_user.id, "output-style-lookup")
if specific_output_style_preference != None:
output_style_preference = specific_output_style_preference
lesson_descriptions_list = [get_lesson_description(schedule, reference_time, lesson_time, current_day,
current_week, overrides=preferences, custom_name_prefix="Назва", template=output_style_preference, 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".join(lesson_descriptions_list), "HTML"
elif base_command == "!schedule-ctl" and len(full_command) >= 2:
if full_command[1] == "list":
prefs = get_all_preferences_by_id(message.from_user.id)
return "Ваші персональні налаштування:\n" + '\n'.join([f"- {k} = {v}" for k, v in prefs.items()]), "HTML"
elif full_command[1] == "set" and len(full_command) == 4:
prefs = get_all_preferences_by_id(message.from_user.id)
if full_command[2] in prefs:
if full_command[2] in ["output-style", "output-style-lesson", "output-style-lookup"]:
if full_command[3] not in os.listdir(module_path + "templates/"):
return f"Стилю {full_command[3]} не існує; доступні варіанти: " \
+ ', '.join(os.listdir(module_path + "templates/")), "HTML"
previous_value = prefs[full_command[2]]
prefs[full_command[2]] = full_command[3]
set_preference_by_id(message.from_user.id, full_command[2], full_command[3])
return f"Змінено значення {full_command[2]}: {previous_value} -> {full_command[3]}", "HTML"
else:
return f"Такого налаштування не існує; переглянути наявні налаштування можна за допомогою команди <u>!schedule-ctl list</u>", "HTML"
elif full_command[1] == "get" and len(full_command) == 3:
requested_preference = get_preference_by_id(message.from_user.id, full_command[2])
return f"Налаштування {full_command[2]} має значення {requested_preference}", "HTML"
elif full_command[1] == "clear" and len(full_command) == 3:
clear_preference_by_id(message.from_user.id, full_command[2])
return f"Очищено значення для налаштування {full_command[2]}, надалі для нього використовуватиметься стандартне значення", "HTML"
else:
return "Такої команди не існує (або був використаний помилковий синтаксис)", "HTML"

View File

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

View File

@ -1,26 +0,0 @@
[
{
},
{
},
{
},
{
},
{
},
{},
{},
{
},
{
},
{
},
{
},
{
},
{},
{}
]

View File

@ -1,54 +0,0 @@
[
{
},
{
},
{
},
{
"9:00": {
"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (ЕКЗАМЕН)",
"teacher": "Овчар Раїса Федорівна",
"link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09",
"type": "prac",
"selectable": false
}
},
{
},
{},
{},
{
"9:00": {
"name": "Інженерія програмного забезпечення (ЕКЗАМЕН)",
"teacher": "Васильєва Марія Давидівна",
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
"type": "prac",
"selectable": false
}
},
{
},
{
},
{
"16:30": {
"name": "Теорія електричних кіл та сигналів",
"teacher": "Лободзинський Вадим Юрійович",
"link": "https://meet.google.com/gwx-sshq-sqb",
"type": "con",
"selectable": false
}
},
{
"9:00": {
"name": "Теорія електричних кіл та сигналів (ЕКЗАМЕН)",
"teacher": "Лободзинський Вадим Юрійович",
"link": "https://meet.google.com/gwx-sshq-sqb",
"type": "prac",
"selectable": false
}
},
{},
{}
]

View File

@ -1,307 +0,0 @@
[
{
"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=L1EvTmpFZHBSdkRHUjZyRG95SFl4QT09",
"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://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
"type": "lab",
"selectable": false
},
"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": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
"type": "lec",
"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/tno-cxef-zyi",
"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": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09",
"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": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09",
"type": "lec",
"selectable": false
}
},
{
"10:00": {
"name": "Теорія ймовірності та математична статистика",
"teacher": "Марковський Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc",
"type": "con",
"selectable": false
}
},
{},
{
"10:25": [
{
"name": "Психологія",
"teacher": "Сербова О. В.",
"link": "https://us05web.zoom.us/j/9299459744?pwd=Z3VQdWEvQ0tyc3pMbzl2bHN6Y1VlUT09",
"type": "prac",
"selectable": true
},
{
"name": "Психологія конфлікту",
"teacher": "Кононець М. О.",
"link": "https://zoom.us/j/9953120638?pwd=WGZsYUhPK2hxbUc4YVJmT0lhdysyZz09",
"type": "lec",
"selectable": true
}
],
"12:20": [
{
"name": "Політична наука: конфліктологічний підхід",
"teacher": "Северинчик О. П.",
"link": "https://us04web.zoom.us/j/2279372490?pwd=bHR5QmpCT0tvQXJMLzRzaldHbFZ3dz09",
"type": "prac",
"selectable": true
},
{
"name": "Захист персональних даних: стандарти ЄС та Ради Європи",
"teacher": "Самчинська О. А.",
"link": "https://us04web.zoom.us/j/72149205587?pwd=Ld2Xj7RORYEwnUYauB5yEbATwwsNan.1",
"type": "prac",
"selectable": true
}
],
"14:15": {
"name": "Розумні міста",
"teacher": "Чукут Світлана Анатоліївна",
"link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09",
"type": "lec",
"selectable": true
}
},
{
"10:25": {
"name": "Вступ до філософії",
"teacher": "Руденко Тамара Петрівна",
"link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09",
"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": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
"type": "lec",
"selectable": false
},
"14:15": {
"name": "Інженерія програмного забезпечення",
"teacher": "Васильєва Марія Давидівна",
"link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039",
"type": "lec",
"selectable": false
}
},
{
"8:30": {
"name": "Вступ до операційної системи Linux",
"teacher": "Алєнін Олег Ігорович",
"link": "https://us04web.zoom.us/j/4122071690?pwd=bANFi3fk9pWvRu9TSBRGzfxFHuEkZC.1",
"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/tno-cxef-zyi",
"type": "prac",
"selectable": false
},
"14:15": [
{
"name": "Соціальна психологія",
"teacher": "Винославська О. В.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Розумні міста",
"teacher": "Чукут Світлана Анатоліївна",
"link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09",
"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": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09",
"type": "lec",
"selectable": false
}
},
{
"10:00": {
"name": "Теорія ймовірності та математична статистика",
"teacher": "Марковський Олександр Петрович",
"link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc",
"type": "con",
"selectable": false
}
},
{}
]

View File

@ -1,51 +0,0 @@
[
{
},
{
},
{
"9:00": {
"name": "Системне програмування",
"teacher": "Порєв Віктор Миколайович",
"link": "https://us02web.zoom.us/j/2256183863?pwd=Q3FmZGVSbW5xUnFQZERpdlcxSElrUT09",
"type": "prac",
"selectable": false,
"comment": "Екзамен!"
}
},
{
},
{
},
{},
{},
{
"14:00": {
"name": "Комп'ютерна електроніка",
"teacher": "Виноградов Юрій Миколайович",
"link": "https://bbb.comsys.kpi.ua/b/x2g-dqc-6fg",
"type": "lab",
"selectable": false,
"comment": "Екзамен! Деталі: https://t.me/c/1856295652/522"
}
},
{
},
{
},
{
},
{
"9:00": {
"name": "Архітектура комп'ютерів. Частина 1. Арифметичні та управляючі пристрої",
"teacher": "Жабін Валерій Іванович",
"link": "https://bbb.comsys.kpi.ua/rooms/jwe-mmp-lb5-jf2/join",
"type": "prac",
"selectable": false,
"comment": "Екзамен!"
}
},
{},
{}
]

View File

@ -1,348 +0,0 @@
[
{
"10:25": {
"name": "Алгоритми та методи обчислень",
"teacher": "Новотарський Михайло Анатолійович",
"link": "https://us02web.zoom.us/j/85323196480?pwd=aXRONTh2SUxmdFZ5M1N5NU5VcGVlZz09",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Комп'ютерна електроніка",
"teacher": "Виноградов Юрій Миколайович",
"link": "https://bbb.comsys.kpi.ua/b/x2g-dqc-6fg",
"type": "lec",
"selectable": false
}
},
{
"10:25": {
"name": "Практичний курс іноземної мови. Частина 2",
"teacher": "Шевченко Ольга Миколаївна",
"link": "https://meet.google.com/tno-cxef-zyi",
"type": "prac",
"selectable": false
},
"12:20": {
"name": "Комп'ютерна електроніка",
"teacher": "Виноградов Юрій Миколайович",
"link": "https://bbb.comsys.kpi.ua/b/x2g-dqc-6fg",
"type": "lab",
"selectable": false
},
"14:15": {
"name": "Стратегія охорони навколишнього середовища",
"teacher": "Романюкіна Ірина Юріївна",
"link": "https://us05web.zoom.us/j/84713917316?pwd=MR0w0aDdxnka2H64qqCpVcUgfuhaQP.1",
"type": "prac",
"selectable": false
}
},
{
"8:30": [
{
"name": "Естетика промислового дизайну",
"teacher": "Кузіна Ольга Юріївна",
"link": "https://us05web.zoom.us/j/87803902417?pwd=64D8BbLeLkvweVlWlY2lX95UaA0XMG.1",
"type": "lec",
"selectable": true
},
{
"name": "Logic",
"teacher": "Казаков Мстислав Андрійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Дизайн презентації для професійної діяльності",
"teacher": "Іщенко Олександр Анатолійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Стилі в образотворчому мистецтві",
"teacher": "Оляніна Світлана Валеріївна",
"link": "https://us05web.zoom.us/j/85408874003?pwd=UGdyRWNwSytSM0Zhc3dMTG4yek9sdz09",
"type": "lec",
"selectable": true
}
],
"10:25": [
{
"name": "Основи підприємницької діяльності",
"teacher": "Марченко Валентина Миколаївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Корпоративна культура та діловий етикет",
"teacher": "Цимбаленко Яна Юріївна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
},
{
"name": "Дизайн презентації для професійної діяльності",
"teacher": "Іщенко Олександр Анатолійович",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
}
],
"12:20": [
{
"name": "Логіка",
"teacher": "Піхорович Василь Дмитрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Корпоративна культура та діловий етикет",
"teacher": "Тимошенко Наталія Леонідівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true
},
{
"name": "Циклічні види спорту",
"teacher": "Черевичко Олександр Геннадійович",
"link": "https://us05web.zoom.us/j/84221628555?pwd=ZjVDV3lDTjRES0lOdkk4cUlUaWp0UT09",
"type": "prac",
"selectable": true
}
],
"14:15": [
{
"name": "Єдиноборства",
"teacher": "Назимок Віктор Васильович",
"link": "https://us04web.zoom.us/j/2276337141?pwd=ejNrUkpPQk9iQlhMMnprOEg3UHNnZz09",
"type": "prac",
"selectable": true
},
{
"name": "Ігрові види спорту",
"teacher": "Сироватко З. В.",
"link": "https://us05web.zoom.us/j/7112676497?pwd=SzEySzRGUzh6NGcxdXZtQ2ovYzhCUT09",
"type": "prac",
"selectable": true
},
{
"name": "Силові види спорту",
"teacher": "Корюкаєв Микола Миколайович",
"link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09",
"type": "prac",
"selectable": true
},
{
"name": "Складно-координаційні види спорту",
"teacher": "Козлова Тетяна Георгіївна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
}
]
},
{
"8:30": {
"name": "Алгоритми та методи обчислень",
"teacher": "Порєв Віктор Миколайович",
"link": "https://us02web.zoom.us/j/2256183863?pwd=Q3FmZGVSbW5xUnFQZERpdlcxSElrUT09",
"type": "lab",
"selectable": false
},
"10:25": {
"name": "Організація баз даних",
"teacher": "Болдак Андрій Олександрович",
"link": "https://us04web.zoom.us/j/5439063374?pwd=VG1iODU0WmpCNTlCVXJJTitYU2Nmdz09",
"type": "lab",
"selectable": false
}
},
{
"8:30": {
"name": "Системне програмування",
"teacher": "Порєв Віктор Миколайович",
"link": "https://us02web.zoom.us/j/2256183863?pwd=Q3FmZGVSbW5xUnFQZERpdlcxSElrUT09",
"type": "lec",
"selectable": false
},
"10:25": {
"name": "Організація баз даних",
"teacher": "Болдак Андрій Олександрович",
"link": "https://us04web.zoom.us/j/5439063374?pwd=VG1iODU0WmpCNTlCVXJJTitYU2Nmdz09",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Архітектура комп'ютерів. Частина 1. Арифметичні та управляючі пристрої",
"teacher": "Жабін Валерій Іванович",
"link": "https://bbb.comsys.kpi.ua/rooms/jwe-mmp-lb5-jf2/join",
"type": "lec",
"selectable": false
},
"14:15": {
"name": "Стратегія охорони навколишнього середовища",
"teacher": "Романюкіна Ірина Юріївна",
"link": "https://us05web.zoom.us/j/84674156408?pwd=BoZcB13bbA82SxL503YaQgabjUiqC9.1",
"type": "lec",
"selectable": false
}
},
{},
{},
{
"10:25": {
"name": "Алгоритми та методи обчислень",
"teacher": "Новотарський Михайло Анатолійович",
"link": "https://us02web.zoom.us/j/85323196480?pwd=aXRONTh2SUxmdFZ5M1N5NU5VcGVlZz09",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Комп'ютерна електроніка",
"teacher": "Виноградов Юрій Миколайович",
"link": "https://bbb.comsys.kpi.ua/b/x2g-dqc-6fg",
"type": "lec",
"selectable": false
}
},
{
"8:30": {
"name": "Архітектура комп'ютерів. Частина 1. Арифметичні та управляючі пристрої",
"teacher": "Верба Олександр Андрійович",
"link": "https://us04web.zoom.us/j/7382214783?pwd=RnZ3SWgwK1JoVkZtNndnKzdPZjFGdz09",
"type": "lab",
"selectable": false
},
"10:25": {
"name": "Практичний курс іноземної мови. Частина 2",
"teacher": "Шевченко Ольга Миколаївна",
"link": "https://meet.google.com/tno-cxef-zyi",
"type": "prac",
"selectable": false
}
},
{
"12:20": [
{
"name": "Стилі в образотворчому мистецтві",
"teacher": "Оляніна Світлана Валеріївна",
"link": "https://us05web.zoom.us/j/85408874003?pwd=UGdyRWNwSytSM0Zhc3dMTG4yek9sdz09",
"type": "prac",
"selectable": true
},
{
"name": "Естетика промислового дизайну",
"teacher": "Кузіна Ольга Юріївна",
"link": "https://us05web.zoom.us/j/87803902417?pwd=64D8BbLeLkvweVlWlY2lX95UaA0XMG.1",
"type": "prac",
"selectable": true
},
{
"name": "Логіка",
"teacher": "Сторожик Марина Іванівна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
},
{
"name": "Logic",
"teacher": "Казаков Мстислав Андрійович",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
},
{
"name": "Циклічні види спорту",
"teacher": "Черевичко Олександр Геннадійович",
"link": "https://us05web.zoom.us/j/84221628555?pwd=ZjVDV3lDTjRES0lOdkk4cUlUaWp0UT09",
"type": "prac",
"selectable": true
}
],
"14:15": [
{
"name": "Єдиноборства",
"teacher": "Назимок Віктор Васильович",
"link": "https://us04web.zoom.us/j/2276337141?pwd=ejNrUkpPQk9iQlhMMnprOEg3UHNnZz09",
"type": "prac",
"selectable": true
},
{
"name": "Ігрові види спорту",
"teacher": "Сироватко З. В.",
"link": "https://us05web.zoom.us/j/7112676497?pwd=SzEySzRGUzh6NGcxdXZtQ2ovYzhCUT09",
"type": "prac",
"selectable": true
},
{
"name": "Силові види спорту",
"teacher": "Корюкаєв Микола Миколайович",
"link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09",
"type": "prac",
"selectable": true
},
{
"name": "Складно-координаційні види спорту",
"teacher": "Козлова Тетяна Георгіївна",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true
}
]
},
{
"8:30": {
"name": "Системне програмування",
"teacher": "Порєв Віктор Миколайович",
"link": "https://us02web.zoom.us/j/2256183863?pwd=Q3FmZGVSbW5xUnFQZERpdlcxSElrUT09",
"type": "lab",
"selectable": false
}
},
{
"8:30": {
"name": "Системне програмування",
"teacher": "Порєв Віктор Миколайович",
"link": "https://us02web.zoom.us/j/2256183863?pwd=Q3FmZGVSbW5xUnFQZERpdlcxSElrUT09",
"type": "lec",
"selectable": false
},
"10:25": {
"name": "Організація баз даних",
"teacher": "Болдак Андрій Олександрович",
"link": "https://us04web.zoom.us/j/5439063374?pwd=VG1iODU0WmpCNTlCVXJJTitYU2Nmdz09",
"type": "lec",
"selectable": false
},
"12:20": {
"name": "Архітектура комп'ютерів. Частина 1. Арифметичні та управляючі пристрої",
"teacher": "Жабін Валерій Іванович",
"link": "https://bbb.comsys.kpi.ua/rooms/jwe-mmp-lb5-jf2/join",
"type": "lec",
"selectable": false
}
},
{},
{}
]

View File

@ -1,699 +0,0 @@
[
{
},
{
"8:30": {
"name": "Архітектура комп'ютерів. Частина 2. Процесори",
"teacher": "Клименко Ірина Анатоліївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"10:25": {
"name": "Паралельне програмування",
"teacher": "Корочкін Олександр Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"12:20": {
"name": "Комп'ютерна схемотехніка",
"teacher": "Ткаченко Валентина Василівна & Старовєров Костянтин Сергійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"14:15": {
"name": "Правознавство",
"teacher": "Попов Костянтин Леонідович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"16:10": [
{
"name": "Вступ до штучного інтелекту",
"teacher": "Таран Владислав Ігорович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології програмування користувацьких інтерфейсів (Front-end)",
"teacher": "Алещенко Олексій Вадимович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології розроблення серверного програмного забезпечення (Back-end)",
"teacher": "Валько В. .",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
]
},
{
"8:30": [
{
"name": "Життєвий цикл розробки програмного забезпечення",
"teacher": "Галушко Дмитро Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Комп’ютерна графіка та мультимедіа",
"teacher": "Родіонов Павло Юрійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Методи та технології штучного інтелекту",
"teacher": "Шимкович Володимир Миколайович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка програмного забезпечення на платформі Java",
"teacher": "Ковальчук Олександр Миронович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології та засоби розробки комп'ютерної графіки та мультимедіа",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"10:25": [
{
"name": "AGILE методологія розробки програмного забезпечення (Авторський курс компаніїї SoftServe)",
"teacher": "Шевело Олексій Павлович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Linux",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Основи Front-end технологій",
"teacher": "Жереб К. А.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка мобільних застосувань під iOS",
"teacher": "Храмченко Микола Сергійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розроблення застосунків з використанням Spring Framework",
"teacher": "Букасов Максим Михайлович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технологія блокчейн",
"teacher": "Яланецький Валерій Анатолійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"12:20": [
{
"name": "Методи та технології штучного інтелекту",
"teacher": "Шимкович Володимир Миколайович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Комп’ютерна графіка та мультимедіа",
"teacher": "Родіонов Павло Юрійович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Технології Computer Vision",
"teacher": "Баран Данило Романович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Життєвий цикл розробки програмного забезпечення",
"teacher": "Альбрехт Йосип Омелянович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Розробка програмного забезпечення на платформі Java",
"teacher": "Ковальчук Олександр Миронович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Технології та засоби розробки комп'ютерної графіки та мультимедіа",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
}
],
"18:30": {
"name": "Технології Computer Vision",
"teacher": "Писарчук О О",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
},
{
"8:30": {
"name": "Правознавство",
"teacher": "Тихонюк Ольга Володимирівна",
"link": "(посиланя відсутнє!)",
"type": "prac",
"selectable": false,
"nolink": true
},
"10:25": {
"name": "Комп'ютерна схемотехніка",
"teacher": "Нікольський С С",
"link": "(посиланя відсутнє!)",
"type": "lab",
"selectable": false,
"nolink": true
},
"12:20": {
"name": "Практичний курс іноземної мови професійного спрямування. Частина 1",
"teacher": "Шевченко Ольга Миколаївна",
"link": "https://meet.google.com/tno-cxef-zyi",
"type": "prac",
"selectable": false,
"nolink": false
},
"14:15": {
"name": "Вступ до штучного інтелекту",
"teacher": "Кочура Юрій Петрович",
"link": "(посилання відсутнє!)",
"type": "prac",
"selectable": true,
"nolink": true
}
},
{
"8:30": [
{
"name": "Мова програмування Java",
"teacher": "Орленко С. П.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка програмного забезпечення на платформі Node.JS",
"teacher": "Нечай Дмитро Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Системне програмування С і С++",
"teacher": "Ковальов Микола Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань мовою програмування PHP",
"teacher": "Ковтунець Олесь Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань на платформі Java",
"teacher": "Іванова Любов Миколаївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології програмування на С/Embedded (Сертифікатна програма)",
"teacher": "Каплунов Артем Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"10:25": {
"name": "Системне програмування С і С++",
"teacher": "Густера Олег Михайлович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"12:20": {
"name": "Технології програмування на С/Embedded (Сертифікатна програма)",
"teacher": "Каплунов Артем Володимирович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"14:15": {
"name": "Розроблення застосунків з використанням Spring Framework",
"teacher": "Нікітін Валерій Андрійович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"16:10": {
"name": "Технології програмування користувацьких інтерфейсів (Front-end)",
"teacher": "Ковальчук Олександр Миронович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"18:30": {
"name": "Сучасні технології розробки WEB-застосувань на платформі Microsoft.NET",
"teacher": "Крамар Юлія Михайлівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
},
{},
{},
{
},
{
"8:30": {
"name": "Архітектура комп'ютерів. Частина 2. Процесори",
"teacher": "Клименко Ірина Анатоліївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"10:25": {
"name": "Паралельне програмування",
"teacher": "Корочкін Олександр Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"12:20": {
"name": "Комп'ютерна схемотехніка",
"teacher": "Ткаченко Валентина Василівна & Старовєров Костянтин Сергійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": false,
"nolink": true
},
"14:15": {
"name": "Технології розроблення серверного програмного забезпечення (Back-end)",
"teacher": "Валько В. .",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"16:10": [
{
"name": "Вступ до штучного інтелекту",
"teacher": "Гордієнко Юрій Григорович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології програмування користувацьких інтерфейсів (Front-end)",
"teacher": "Алещенко Олексій Вадимович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології розроблення серверного програмного забезпечення (Back-end)",
"teacher": "Валько В. .",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
]
},
{
"8:30": [
{
"name": "Життєвий цикл розробки програмного забезпечення",
"teacher": "Галушко Дмитро Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Комп’ютерна графіка та мультимедіа",
"teacher": "Родіонов Павло Юрійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Методи та технології штучного інтелекту",
"teacher": "Шимкович Володимир Миколайович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка програмного забезпечення на платформі Java",
"teacher": "Ковальчук Олександр Миронович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології та засоби розробки комп'ютерної графіки та мультимедіа",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"10:25": [
{
"name": "AGILE методологія розробки програмного забезпечення (Авторський курс компаніїї SoftServe)",
"teacher": "Шевело Олексій Павлович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Linux",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Основи Front-end технологій",
"teacher": "Жереб К. А.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка мобільних застосувань під iOS",
"teacher": "Храмченко Микола Сергійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розроблення застосунків з використанням Spring Framework",
"teacher": "Букасов Максим Михайлович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технологія блокчейн",
"teacher": "Яланецький Валерій Анатолійович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"12:20": [
{
"name": "Основи Front-end технологій",
"teacher": "Жереб К. А.",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Технологія блокчейн",
"teacher": "Яланецький Валерій Анатолійович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Linux",
"teacher": "Хмелюк Марина Сергіївна",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Розробка мобільних застосувань під iOS",
"teacher": "Храмченко Микола Сергійович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "AGILE методологія розробки програмного забезпечення (Авторський курс компаніїї SoftServe)",
"teacher": "Шевело Олексій Павлович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
}
],
"18:30": {
"name": "Технології Computer Vision",
"teacher": "Писарчук О О",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
},
{
"8:30": {
"name": "Архітектура комп'ютерів. Частина 2. Процесори",
"teacher": "Каплунов Артем Володимирович",
"link": "(посиланя відсутнє!)",
"type": "lab",
"selectable": false,
"nolink": true
},
"10:25": {
"name": "Паралельне програмування",
"teacher": "Корочкін Олександр Володимирович",
"link": "(посиланя відсутнє!)",
"type": "lab",
"selectable": false,
"nolink": true
},
"12:20": {
"name": "Практичний курс іноземної мови професійного спрямування. Частина 1",
"teacher": "Шевченко Ольга Миколаївна",
"link": "https://meet.google.com/tno-cxef-zyi",
"type": "prac",
"selectable": false,
"nolink": false
}
},
{
"8:30": [
{
"name": "Мова програмування Java",
"teacher": "Орленко С. П.",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Розробка програмного забезпечення на платформі Node.JS",
"teacher": "Нечай Дмитро Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Системне програмування С і С++",
"teacher": "Ковальов Микола Олександрович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань мовою програмування PHP",
"teacher": "Ковтунець Олесь Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань на платформі Java",
"teacher": "Іванова Любов Миколаївна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
},
{
"name": "Технології програмування на С/Embedded (Сертифікатна програма)",
"teacher": "Каплунов Артем Володимирович",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
],
"10:25": [
{
"name": "Сучасні технології розробки WEB-застосувань на платформі Microsoft.NET",
"teacher": "Крамар Юлія Михайлівна",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань на платформі Java",
"teacher": "Іванова Любов Миколаївна",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
{
"name": "Сучасні технології розробки WEB-застосувань мовою програмування PHP",
"teacher": "Ковтунець Олесь Володимирович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
}
],
"12:20": {
"name": "Розробка програмного забезпечення на платформі Node.JS",
"teacher": "Нечай Дмитро Олександрович",
"link": "(посилання відсутнє!)",
"type": "lab",
"selectable": true,
"nolink": true
},
"18:30": {
"name": "Сучасні технології розробки WEB-застосувань на платформі Microsoft.NET",
"teacher": "Крамар Юлія Михайлівна",
"link": "(посилання відсутнє!)",
"type": "lec",
"selectable": true,
"nolink": true
}
},
{},
{}
]

View File

@ -1 +0,0 @@
schedule-v2-term5.json

View File

@ -1 +0,0 @@
<b>Коментар</b>: %COMMENT%

View File

@ -1 +0,0 @@
<b><u>%DATE%</u></b>:

View File

@ -1 +0,0 @@
<b><a href="%LINK%">%COLOR_CODE% %NAME%</a></b>

View File

@ -1,3 +0,0 @@
<b>%NAME_PREFIX%</b>: %NAME% (%TYPE%)
<b>Викладач</b>: %TEACHER%
<b>Посилання</b>: %LINK%

View File

@ -1,4 +0,0 @@
<b>%NAME_PREFIX%</b>: %NAME% (%TYPE%)
<b>Дата</b>: %DATE%
<b>Викладач</b>: %TEACHER%
<b>Посилання</b>: %LINK%

View File

@ -1 +0,0 @@
Коментар: %COMMENT%

View File

@ -1 +0,0 @@
<u>%DATE%</u>:

View File

@ -1 +0,0 @@
<a href="%LINK%">%COLOR_CODE% %NAME%</a>

View File

@ -1,3 +0,0 @@
%NAME_PREFIX%: %NAME% (%TYPE%)
Викладач: %TEACHER%
Посилання: %LINK%

View File

@ -1,4 +0,0 @@
%NAME_PREFIX%: %NAME% (%TYPE%)
Дата: %DATE%
Викладач: %TEACHER%
Посилання: %LINK%

View File

@ -1 +0,0 @@
<i>Коментар</i>: %COMMENT%

View File

@ -1 +0,0 @@
<b><u>%DATE%</u></b>:

View File

@ -1 +0,0 @@
<b><a href="%LINK%">%COLOR_CODE% %NAME%</a></b>

View File

@ -1,3 +0,0 @@
<b>%NAME%</b> (%TYPE%)
<i>Викладач</i>: %TEACHER%
<i>Посилання</i>: %LINK%

View File

@ -1,4 +0,0 @@
<b>%NAME%</b> (%TYPE%)
<i>Дата</i>: %DATE%
<i>Викладач</i>: %TEACHER%
<i>Посилання</i>: %LINK%

View File

@ -1,5 +1,6 @@
[ [
{ {
"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() == "!пара-old2" or self.MESSAGE["text"].lower().split()[0] == "!пари-old2"): if (self.MESSAGE["text"].lower() == "!пара" or self.MESSAGE["text"].lower().split()[0] == "!пари"):
#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() == "!пара-old2" or self.MESSAGE["text"].low
full_schedule = dict(list(schedule.items()) + list(additions.items())) full_schedule = dict(list(schedule.items()) + list(additions.items()))
if self.MESSAGE["text"].lower() == "!пара-old2": if self.MESSAGE["text"].lower() == "!пара":
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() == "!пара-old2":
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.RESPONSE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link']) self.RESPONCE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link'])
print("test3.1.5") print("test3.1.5")
else: else:
self.RESPONSE = "Пар немає взагалі. Ми вільні!" self.RESPONCE = "Пар немає взагалі. Ми вільні!"
else: else:
print("test3.2") print("test3.2")
@ -106,9 +106,9 @@ if self.MESSAGE["text"].lower() == "!пара-old2":
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.RESPONSE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link']) self.RESPONCE = "Актуальна пара: {}\nДата: {}\nВикладач: {}\nПосилання на пару: {}".format(p['name'], human_readable_date, p['teacher'], p['link'])
if self.MESSAGE["text"].lower().split()[0] == "!пари-old2": if self.MESSAGE["text"].lower().split()[0] == "!пари":
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] == "!пари-old2":
result_text += "\n" result_text += "\n"
self.RESPONSE = result_text self.RESPONCE = result_text

View File

@ -1,55 +1,52 @@
[ [
{ {
"8:30": {"name": "Політична наука: конфліктологічний підхід (лекція)", "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/7423381732?pwd=c1pJclU2ZDRUWDgyUE10dmhJUDhiZz09 & 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"},
"14:15": {"name": "Основи електронного урядування (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"} "12:20": {"name": "Культура мовлення та ділове мовлення", "teacher": "Онуфрієнко О. П.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"12:20": {"name": "Інженерія програмного забезпечення (лабораторна)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"}, "12:20": {"name": "Практичний курс іноземної мови. Частина 1", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Теорія електричних кіл та сигналів (лабораторна)", "teacher": "Лободзинський В. Ю. & Ілліна О. О.", "link": "https://meet.google.com/gwx-sshq-sqb"} "14:15": {"name": "Фізика", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"8:30": {"name": "Теорія ймовірності та математична статистика (лекція)", "teacher": "Марковський Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-9ru-7vc"}, "8:30": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"},
"10:25": {"name": "Вступ до операційної системи Linux (лекція)", "teacher": "Роковий Олександр Петрович", "link": "https://bbb.comsys.kpi.ua/b/ole-knq-z9h-pyl"}, "10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}
"12:20": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"}
}, },
{ {
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"}, "10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"},
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "https://meet.google.com/tno-cxef-zyi"}, "12:20": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"14:15": {"name": "Соціальна психологія (практика)", "teacher": "Блохіна Ірина Олександрівна", "link": "(посилання відсутнє!)"}, "14:15": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}
"16:10": {"name": "Основи електронного урядування (практика)", "teacher": "Чукут Світлана Анатоліївна", "link": "(посилання відсутнє!)"}
}, },
{ {
"8:30": {"name": "Вступ до філософії (лекція)", "teacher": "Руденко Тамара Петрівна", "link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09"}, "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://us05web.zoom.us/j/7089075754?pwd=TWRlZmxyVlFiTWU1UGlVVU1XcFE0Zz09"},
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09"} "14:15": {"name": "Основи здорового способу життя", "teacher": "Соболенко А. І.", "link": "https://zoom.us/j/2035574145?pwd=bk1wTVhGbjJsQTR4WmVQMlROWFBCZz09"}
}, },
{}, {},
{}, {},
{ {
"10:25": {"name": "Психологія (практика) & Психологія конфлікту (лекція)", "teacher": "Сербова О. В. & Кононець М. О.", "link": "https://us05web.zoom.us/j/9299459744?pwd=Z3VQdWEvQ0tyc3pMbzl2bHN6Y1VlUT09 & https://zoom.us/j/9953120638?pwd=WGZsYUhPK2hxbUc4YVJmT0lhdysyZz09"}, "8:30": {"name": "Дискретна математика", "teacher": "Новотарський М. А.", "link": "https://us02web.zoom.us/j/87578307057?pwd=UGwyVGlwc3M4Q0Q0Q0NLWUt6bmVpUT09"},
"12:20": {"name": "Політична наука: конфліктологічний підхід & Захист персональних даних: стандарти ЄС та Ради Європи (практики)", "teacher": "Северинчик О. П. & Самчинська О. А.", "link": "(посилання відсутнє!) & https://us04web.zoom.us/j/72149205587?pwd=Ld2Xj7RORYEwnUYauB5yEbATwwsNan.1"}, "10:25": {"name": "Комп'ютерна логіка", "teacher": "Жабін В. І.", "link": "https://bbb.comsys.kpi.ua/b/val-2vb-o7w-y5y АБО https://bbb.ugrid.org/b/val-osi-lup-ou8"},
"14:15": {"name": "Розумні міста (лекція)", "teacher": "Чукут Світлана Анатоліївна", "link": "https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09"} "12:20": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"}
}, },
{ {
"10:25": {"name": "Вступ до філософії (практика)", "teacher": "Руденко Тамара Петрівна", "link": "https://zoom.us/j/9358038101?pwd=d0pwUHRDY0dxbngrU09PYll6UXpNZz09"}, "8:30": {"name": "Комп'ютерна логіка", "teacher": "Верба О. А.", "link": "https://us04web.zoom.us/j/7382214783?pwd=RnZ3SWgwK1JoVkZtNndnKzdPZjFGdz09"},
"14:15": {"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"},
"12:20": {"name": "Практичний курс іноземної мови. Частина 1", "teacher": "Шевченко О. М.", "link": "https://meet.google.com/bwg-pdnr-evh"},
"14:15": {"name": "Фізика", "teacher": "Федотов В. В. & Іванова І. М.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!"}
}, },
{ {
"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": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"},
"14:15": {"name": "Інженерія програмного забезпечення (лекція)", "teacher": "Васильєва Марія Давидівна", "link": "https://do.ipo.kpi.ua/mod/bigbluebuttonbn/view.php?id=171039"}
}, },
{ {
"8:30": {"name": "Вступ до операційної системи Linux (лабораторна)", "teacher": "Алєнін Олег Ігорович", "link": "https://us04web.zoom.us/j/4122071690?pwd=bANFi3fk9pWvRu9TSBRGzfxFHuEkZC.1"}, "10:25": {"name": "Вища математика", "teacher": "Ординська З. П.", "link": "https://us04web.zoom.us/j/2684350438?pwd=kiOi3BrgbJHeYvkrx7qaSxa08J8m8O.1"},
"10:25": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (практика)", "teacher": "Стаматієва Вікторія В'ячеславівна", "link": "https://us04web.zoom.us/j/2313886209?pwd=dnZHanV3cU9LUXJBVWYyYVArUFg5dz09"}, "12:20": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"12:20": {"name": "Практичний курс іноземної мови. Частина 2 (практика)", "teacher": "Шевченко Ольга Миколаївна", "link": "https://meet.google.com/tno-cxef-zyi"}, "14:15": {"name": "Програмування. Частина 2. Об'єктно-орієнтоване програмування", "teacher": "Алещенко О. В.", "link": "https://us02web.zoom.us/j/2711546637?pwd=Ry82RHp3SjV6WTZRMXl6WUNod25hUT09"}
"14:15": {"name": "Соціальна психологія (лекція) & Розумні міста (практика)", "teacher": "Винославська О. В. & Чукут С. А.", "link": "(посилання відсутнє!) & https://zoom.us/j/5439919039?pwd=Um8wWHV4ZjZpallCWkpVQ08wZGNzdz09"}
}, },
{ {
"10:25": {"name": "Теорія електричних кіл та сигналів (лекція)", "teacher": "Лободзинський Вадим Юрійович", "link": "https://meet.google.com/gwx-sshq-sqb"}, "10:25": {"name": "Фізика", "teacher": "Русаков В. Ф.", "link": "В житті не буває нічого вічного. Життя мінливе, як і посилання на кожну нову пару. Щасти вам його віднайти!", "container_id": "1"},
"12:20": {"name": "Вища математика. Частина 3. Ряди. Теорія функцій комплексної змінної. Операційне числення (лекція)", "teacher": "Овчар Раїса Федорівна", "link": "https://us02web.zoom.us/j/84532519615?pwd=eDFRMWtJTkxKcklpa1JUSjFmZHNyUT09"} "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"}
}, },
{}, {},
{} {}

View File

@ -1,6 +1,5 @@
import datetime import datetime
import json import json
import time
import os import os
current_time = datetime.datetime.now() current_time = datetime.datetime.now()
@ -85,7 +84,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.loads(open(f"../containers/{p['container_id']}", 'r').read()) cont = json.decode(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 = '')
@ -103,7 +102,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><p>(технічна інформація про помилку: {e}</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>")
else: else:
print(f"Location: {p['link'].split()[0]}\n\n", end = '') print(f"Location: {p['link'].split()[0]}\n\n", end = '')
@ -140,7 +139,7 @@ else:
if 'container_id' in p: if 'container_id' in p:
try: try:
cont = json.loads(open(f"../containers/{p['container_id']}", 'r').read()) cont = json.decode(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 = '')
@ -158,7 +157,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><p>(технічна інформація про помилку: {e}</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>")
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.RESPONSE = f"Сьогодні вихідний, тому пар немає)\n"\ self.RESPONCE = 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.RESPONSE = f"Актуальна пара: {relevant_pair['subject']} ({relevant_pair['lector']}), початок о {self.reverse_timetable[self.timetable[i]]}\n"\ self.RESPONCE = 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.RESPONSE = "Сьогодні більше немає пар" self.RESPONCE = "Сьогодні більше немає пар"
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.RESPONSE = self.MESSAGE["text"] self.RESPONCE = self.MESSAGE["text"]

View File

@ -1,16 +0,0 @@
{
"s": "Головна сторінка сервера: http://10.1.1.1:12010/",
"ss": "Головна сторінка сервера: http://10.1.1.1:12010/",
"u": "Універсальне посилання: http://10.1.1.1:12025/?d=1",
"c": "Розклад навчального року: http://10.1.1.1:12042/general/year_schedule_2024_2025.png",
"r": "Записи пар (5 семестр): http://10.1.1.1:12046/cgi/main-full.py",
"d": "Навчальні дисципліни (5-8 семестри): http://10.1.1.1:12022/generic/disciplines-terms5-8.png",
"d1": "Навчальні дисципліни (1-4 семестри): http://10.1.1.1:12022/generic/disciplines-terms1-4.png",
"d2": "Навчальні дисципліни (5-8 семестри): http://10.1.1.1:12022/generic/disciplines-terms5-8.png",
"h": "Стисла довідка:\n!s - головна сторінка сервера\n!u - універсальне посилання\n!r - записи пар (4 семестр)\n!c - календар навчального року\n!d - перелік навчальних дисциплін\n@all [повідомлення] - тег усіх користувачів\nПовна довідка: http://10.1.1.1:12032/generic/bot-help/short-help.html",
"пари_для_артема": "🧐",
"пари_для_артема_хоч_іеаавтра": "🤨",
"перекур": "😮\u200d💨",
"fiot_free_vidrahuvannja": "😢",
"світло": "⚡️"
}

View File

@ -1,6 +0,0 @@
command_storage = json.loads(open(self.path + "data.json").read())
received_command = self.MESSAGE.text[1:]
if received_command.lower() in command_storage:
self.RESPONSE = command_storage[received_command.lower()]

View File

@ -1,6 +0,0 @@
{
"version": 1,
"index_file": "index.py",
"start_on_boot": true,
"alias": "generic-command-processor"
}

View File

@ -1,5 +0,0 @@
Usage: !hardsub [event_name]
Permanently subscribes to [event_name]. If blank, uses "default".
To unsubscribe, use !hardunsub
For one-time subscriptions, use !sub

View File

@ -1,5 +0,0 @@
Usage: !hardunsub [event_name]
Remove permanent subscription to [event_name]. If blank, uses "default".
To remove one-time subscription, use !unsub
To add permanent subscription, use !hardsub

View File

@ -1,5 +0,0 @@
Usage:
!schedule-ctl list - see all settings
!schedule-ctl get <setting> - see specific personal setting
!schedule-ctl set <setting> <value> - change <setting> to <value>
!schedule-ctl clear <setting> - restore <setting> to default value

View File

@ -1,7 +0,0 @@
Usage: !sub [event_name]
Soft-subscribes to [event_name]. If black, uses "default".
If you want to remove soft substription, use !unsub
Soft subscription is automatically removed after the event is triggered once.
If you want to subscribe permanently, use !hardsub

View File

@ -1,5 +0,0 @@
Usage: !unsub [event_name]
Removes one-time subscription to [event_name]. If blank, uses "default".
Does not affect hard subscriptions. To remove hard subscription, use !hardunsub
To add one-time supscription, use !sub

View File

@ -1,54 +0,0 @@
import json
import os
module_path = ""
def readfile(filename):
if os.path.exists(module_path + filename):
return open(module_path + filename).read()
else:
return False
def list_entries(search_query):
files = []
for p, d, f in os.walk(module_path + "db/"):
for i in f:
entry_name = f"{p.split('/', 3)[3]}/{i}"
if search_query in entry_name:
files.append(f"{p.split('/', 3)[3]}/{i}".rsplit(".", 1)[0].replace("/", ".").lstrip("."))
files.sort()
return files
def process(message, path):
if message.text[:5] != "!help":
return None, None
global module_path
module_path = path
cmd = message.text[1:].split()
if len(cmd) == 1:
return "Usage:\n```\n!help show <entry> - displays specified manual entry\n!help list [query] - lists out available entries (optionally, filtered by [query])```", "Markdown"
elif cmd[1] == "list":
if len(cmd) == 2:
return "Available entries:\n" + "\n".join(list_entries("")), None
else:
return f"Found entries for {cmd[2]}:\n" + "\n".join(list_entries(cmd[2])), None
elif cmd[1] == "show":
if len(cmd) >= 3:
result = ""
for entry_name in cmd[2:]:
data = readfile("db/" + entry_name.replace(".", "/") + ".txt")
if data:
result += f"Manual page for {entry_name}:\n```\n{data}```\n"
else:
result += f"No manual found for {entry_name}\n\n"
return result, "Markdown"
else:
return "Usage: !help show <entry> - displays specified manual entry", None

View File

@ -1,6 +0,0 @@
{
"start_on_boot": true,
"alias": "help",
"version": 2,
"index_file": "index.py"
}

View File

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

View File

@ -13,6 +13,4 @@ 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()}", None return f"Testing successful - call number {get_num()}"
else:
return None, None

View File

@ -1,129 +0,0 @@
msg = self.MESSAGE.text.lower()
if msg == "!ping":
current_time = time.time()
delay = current_time - 7200 - float(self.MESSAGE.date.strftime('+%s'))
self.RESPONSE = f"Pong in {delay} seconds"
if not os.path.exists(self.path + "scoreboard/"):
os.mkdir(self.path + "scoreboard/")
def append_score(path, name, data):
open(path + f"scoreboard/{name}", "a").write(data)
user_id = self.MESSAGE.from_user.id
chat_id = self.MESSAGE.chat.id
first_name = self.MESSAGE.from_user.first_name
last_name = self.MESSAGE.from_user.last_name
username = self.MESSAGE.from_user.username
append_score(self.path, self.MESSAGE.from_user.id, f"{current_time} {user_id} {chat_id} {first_name} {last_name} {username} {delay}\n")
elif msg == "!pong":
current_time = time.time()
delay = current_time - 7200 - float(self.MESSAGE.date.strftime('+%s'))
self.RESPONSE = f"Ping in {delay} seconds"
if not os.path.exists(self.path + "pong-scoreboard/"):
os.mkdir(self.path + "pong-scoreboard/")
def append_score(path, name, data):
open(path + f"pong-scoreboard/{name}", "a").write(data)
user_id = self.MESSAGE.from_user.id
chat_id = self.MESSAGE.chat.id
first_name = self.MESSAGE.from_user.first_name
last_name = self.MESSAGE.from_user.last_name
username = self.MESSAGE.from_user.username
append_score(self.path, self.MESSAGE.from_user.id, f"{current_time} {user_id} {chat_id} {first_name} {last_name} {username} {delay}\n")
elif msg == "!pingtop":
def read_score(path, name):
if os.path.exists(path + f"scoreboard/{name}"):
return open(path + f"scoreboard/{name}").read()
else:
return None
if not os.path.exists(self.path + "scoreboard/"):
os.mkdir(self.path + "scoreboard/")
results = []
for name in os.listdir(self.path + "scoreboard/"):
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
data.sort(key = lambda x: float(x.split()[6]))
results.append(data[0].split())
print(results)
results.sort(key = lambda x: float(x[6]))
self.RESPONSE = "<u>Ping top</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
self.FORMAT = "HTML"
elif msg == "!pongtop":
def read_score(path, name):
if os.path.exists(path + f"pong-scoreboard/{name}"):
return open(path + f"pong-scoreboard/{name}").read()
else:
return None
if not os.path.exists(self.path + "pong-scoreboard/"):
os.mkdir(self.path + "pong-scoreboard/")
results = []
for name in os.listdir(self.path + "pong-scoreboard/"):
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
data.sort(key = lambda x: float(x.split()[6]))
results.append(data[0].split())
print(results)
results.sort(key = lambda x: float(x[6]))
self.RESPONSE = "<u>Pong top</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
self.FORMAT = "HTML"
elif msg == "!pingantitop":
def read_score(path, name):
if os.path.exists(path + f"scoreboard/{name}"):
return open(path + f"scoreboard/{name}").read()
else:
return None
if not os.path.exists(self.path + "scoreboard/"):
os.mkdir(self.path + "scoreboard/")
results = []
for name in os.listdir(self.path + "scoreboard/"):
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
data.sort(key = lambda x: float(x.split()[6]))
results.append(data[-1].split())
print(results)
results.sort(key = lambda x: float(x[6]))
results = results[::-1]
self.RESPONSE = "<u>Ping antitop</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
self.FORMAT = "HTML"
elif msg == "!pongantitop":
def read_score(path, name):
if os.path.exists(path + f"pong-scoreboard/{name}"):
return open(path + f"pong-scoreboard/{name}").read()
else:
return None
if not os.path.exists(self.path + "pong-scoreboard/"):
os.mkdir(self.path + "pong-scoreboard/")
results = []
for name in os.listdir(self.path + "pong-scoreboard/"):
data = [i for i in read_score(self.path, name).split("\n") if i != ""]
data.sort(key = lambda x: float(x.split()[6]))
results.append(data[-1].split())
print(results)
results.sort(key = lambda x: float(x[6]))
results = results[::-1]
self.RESPONSE = "<u>Pong antitop</u>:\n" + "\n".join( [f"{i+1}. {v[3]} {v[4]} ({v[5]}) - {v[6]}" for i, v in enumerate(results[:10])] )
self.FORMAT = "HTML"

View File

@ -1,6 +0,0 @@
{
"start_on_boot": true,
"alias": "pingtools",
"version": 1,
"index_file": "index.py"
}

View File

@ -1,8 +0,0 @@
{
"trigger_lists": [
["fiot", "free", "sex"],
["fict", "free", "sex"],
["fice", "free", "sex"]
],
"response_text": "👀"
}

View File

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

View File

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

View File

@ -1,107 +0,0 @@
import random
module_path = ""
def extract_separators(text):
sequence_buf = ""
seps = []
for i in text:
if i in ["\n", " "]:
sequence_buf += i
elif sequence_buf:
seps.append(sequence_buf)
sequence_buf = ""
return seps
def process(message, path):
if not message.text.lower().startswith("!shuf"):
return "", None
global module_path
module_path = path
cmd = message.text.split()
print(cmd)
l = len(cmd)
# settings
split_by = "word"
shuf_individual_words = False
data_source = "reply"
only_spaces = False
shuf_data = []
i = 1
# parsing arguments
while i < l:
print("C", i, cmd[i])
if cmd[i][0] != "-" or cmd[i] == "--":
break
elif cmd[i] == "-i":
shuf_individual_words = True
elif cmd[i] == "-c":
split_by = "char"
elif cmd[i] == "-o":
only_spaces = True
i += 1
# parsing text (if any)
while i < l:
print("T", i, cmd[i])
data_source = "internal"
if split_by == "char":
for c in cmd[i]:
shuf_data.append(c)
shuf_data.append(" ")
elif split_by == "word":
if shuf_individual_words:
shuf_data.append(list(cmd[i]))
else:
shuf_data.append(cmd[i])
i += 1
if data_source == "reply":
seps = extract_separators(message['reply_to_message'].text)
else:
seps = extract_separators(message.text)
if data_source == "reply":
for w in message['reply_to_message'].text.split():
if split_by == "char":
for c in w:
shuf_data.append(c)
elif split_by == "word":
if shuf_individual_words:
shuf_data.append(list(w))
else:
shuf_data.append(w)
if split_by == "word":
if shuf_individual_words:
for w in shuf_data:
random.shuffle(w)
if only_spaces:
return " ".join(["".join(w) for w in shuf_data]), "HTML"
else:
return "".join([i[0] + i[1] for i in zip(["".join(w) for w in shuf_data], seps)]) + "".join(shuf_data[-1]), "HTML"
else:
random.shuffle(shuf_data)
if only_spaces:
return " ".join(shuf_data), "HTML"
else:
return "".join([i[0] + i[1] for i in zip(shuf_data, seps)]) + shuf_data[-1], "HTML"
elif split_by == "char":
if only_spaces:
shuf_data += [" " for i in seps]
else:
shuf_data += seps
random.shuffle(shuf_data)
return "".join(shuf_data), "HTML"

View File

@ -1,6 +0,0 @@
{
"start_on_boot": true,
"alias": "shuffle",
"version": 2,
"index_file": "index.py"
}

View File

@ -1,133 +0,0 @@
import os
import json
def setup():
for i in ["sub-storage"]:
if not os.path.exists(module_path + i):
os.mkdir(module_path + i)
def load_group(group_name):
if os.path.exists(module_path + f"sub-storage/{group_name}.json"):
return json.loads(open(module_path + f"sub-storage/{group_name}.json").read())
else:
return {"hard": [], "soft": []}
def save_group(group_name, existing_group):
with open(module_path + f"sub-storage/{group_name}.json", "w") as f:
f.write(json.dumps(existing_group))
def sub_to_group(group_name, tag, persistence = "soft"):
for i in ["..", "/", "\\"]:
if i in group_name:
return False
existing_group = load_group(group_name)
if tag not in existing_group[persistence]:
existing_group[persistence].append(tag)
save_group(group_name, existing_group)
return True
def unsub_from_group(group_name, tag, persistence = "soft"):
for i in ["..", "/", "\\"]:
if i in group_name:
return False
existing_group = load_group(group_name)
if tag in existing_group[persistence]:
existing_group[persistence].remove(tag)
save_group(group_name, existing_group)
return True
def get_group(cmd):
if len(cmd) == 1:
return "default"
else:
return cmd[1]
def clear_subs_in(group_name, category = "soft"):
existing_group = load_group(group_name)
existing_group[category] = []
save_group(group_name, existing_group)
module_path = ""
setup()
def process(message, path):
global module_path
module_path = path
if not message.text[0] == "!":
return "", None
msg = message.text.lower()
cmd = [i for i in msg[1:].split(" ", 2) if i]
chosen_group_name = get_group(cmd)
if cmd[0] == "sub":
if message.from_user.username:
if sub_to_group(chosen_group_name, message.from_user.username):
return f"Subscribed {message.from_user.username} to the {chosen_group_name} event", None
else:
return f"Failed to subscribe {message.from_user.username} to the \"{chosen_group_name}\" event (event name violation)", None
else:
return f"Failed to subscribe {message.from_user.id} to the \"{chosen_group_name}\" event (no username available)", None
if cmd[0] == "hardsub":
if message.from_user.username:
if sub_to_group(chosen_group_name, message.from_user.username, persistence = "hard"):
return f"Hard-subscribed {message.from_user.username} to the {chosen_group_name} event", None
else:
return f"Failed to hard-subscribe {message.from_user.username} to the \"{chosen_group_name}\" event (event name violation)", None
else:
return f"Failed to hard-subscribe {message.from_user.id} to the \"{chosen_group_name}\" event (no username available)", None
elif cmd[0] == "unsub":
if message.from_user.username:
if unsub_from_group(chosen_group_name, message.from_user.username):
return f"Unsubscribed {message.from_user.username} from the {chosen_group_name} event", None
else:
return f"Failed to unsubscribe {message.from_user.username} from the \"{chosen_group_name}\" event (event name violation)", None
else:
return f"Failed to unsubscribe {message.from_user.id} from the \"{chosen_group_name}\" event (no username available)", None
elif cmd[0] == "hardunsub":
if message.from_user.username:
if unsub_from_group(chosen_group_name, message.from_user.username, persistence = "hard"):
return f"Unsubscribed {message.from_user.username} from the {chosen_group_name} event", None
else:
return f"Failed to unsubscribe {message.from_user.username} from the \"{chosen_group_name}\" event (event name violation)", None
else:
return f"Failed to unsubscribe {message.from_user.id} from the \"{chosen_group_name}\" event (no username available)", None
elif cmd[0] == "call":
group_data = load_group(chosen_group_name)
tags = set()
for subs in group_data.values():
tags |= set([f"@{i}" for i in subs if i])
ping_string = " ".join(tags)
clear_subs_in(chosen_group_name)
if len(cmd) == 3:
return f"{message.from_user.username} calls \"{chosen_group_name}\": {cmd[2]}\n{ping_string}", None
else:
return f"{message.from_user.username} calls \"{chosen_group_name}\"\n{ping_string}", None
elif cmd[0] == "sublist":
group_data = load_group(chosen_group_name)
responce = f"Subscribers for group \"{chosen_group_name}\":\n"
for name, subs in group_data.items():
responce += f"{name}: {', '.join(subs)}\n"
return responce, None

View File

@ -1,6 +0,0 @@
{
"start_on_boot": true,
"alias": "tag-sub",
"version": 2,
"index_file": "index.py"
}

View File

@ -1,34 +0,0 @@
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://10.1.1.1:5010/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

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

View File

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

View File

@ -1,45 +1,30 @@
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)
escaping_rules = {
"<": "&lt;",
">": "&gt;",
'"': "&quot;"
}
for i in escaping_rules.items():
result_string = result_string.replace(i[0], i[1])
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):
models = json.loads(readfile(self.path + "translate_models.json")) try:
models = json.loads(readfile(self.path + "translate_models.json"))
if command_length == 1: if command_length == 1:
chosen_model = "cz-ua" chosen_model = "cz-ua"
else: else:
chosen_model = command[1] chosen_model = command[1]
if command_length == 3: if command_length == 3:
text_to_decode = command[2] text_to_decode = command[2]
else: else:
if self.MESSAGE['reply_to_message'].caption: text_to_decode = self.MESSAGE['reply_to_message']['text']
text_to_decode = self.MESSAGE['reply_to_message'].caption
elif self.MESSAGE['reply_to_message'].text:
text_to_decode = self.MESSAGE['reply_to_message'].text
decoded_text = text_to_decode decoded_text = text_to_decode
if chosen_model not in models: if chosen_model not in models:
self.RESPONSE = f"Такого варіанту транслітерації не існує. Доступні варіанти: " \ self.RESPONCE = f"Такого варіанту транслітерації не існує. Доступні варіанти: {', '.join(list(models.keys()))}"
f"{', '.join(list(models.keys()))}" else:
else: for i in models[chosen_model]:
for i in models[chosen_model]: decoded_text = decoded_text.replace(i[0], i[1])
decoded_text = decoded_text.replace(i[0].lower(), i[1].lower()) decoded_text = decoded_text.replace(i[0].capitalize(), i[1].capitalize())
decoded_text = decoded_text.replace(i[0].capitalize(), i[1].capitalize()) decoded_text = decoded_text.replace(i[0].upper(), i[1].upper())
decoded_text = decoded_text.replace(i[0].upper(), i[1].upper())
self.RESPONSE = f"<b><u>Результат</u></b>\n{escaped_string(decoded_text)}" self.RESPONCE = f"Результат: {decoded_text}"
self.FORMAT = "HTML"
except Exception as e:
print(f"[translit-decoder] Got exception: {e}")

View File

@ -75,57 +75,5 @@
["$", ";"], ["$", ";"],
["^", ":"], ["^", ":"],
["&", "?"] ["&", "?"]
],
"en-men": [
["a", "4"],
["b", "8"],
["c", "("],
["d", "|)"],
["e", "3"],
["f", "|="],
["g", "6"],
["h", "#"],
["i", "!"],
["j", "|_"],
["k", "|<"],
["l", "1"],
["m", "//N"],
["o", "0"],
["p", "|D"],
["q", "(,)"],
["r", "|2"],
["s", "5"],
["t", "7"],
["u", "|_|"],
["w", "//"],
["v", "/"],
["x", "><"],
["y", "`/"]
],
"men-en": [
["4", "a"],
["8", "b"],
["(,)", "q"],
["(", "c"],
["|)", "d"],
["3", "e"],
["|=", "f"],
["6", "g"],
["#", "h"],
["!", "i"],
["|_|", "u"],
["|_", "j"],
["|<", "k"],
["1", "l"],
["//N", "m"],
["0", "o"],
["|D", "p"],
["|2", "r"],
["5", "s"],
["7", "t"],
["//", "w"],
["`/", "y"],
["/", "v"],
["><", "x"]
] ]
} }

View File

@ -1,124 +0,0 @@
import re
''' Grammar reference
all_possible_match_strings = [
"силка", "силки",
"силки", "силок",
"силці", "силкам",
"силку", "силки",
"силкою", "силками",
"силці", "силках",
"силко", "силки",
"лінк", "лінка", "лінки",
"лінку", "лінки", "лінок",
"лінку", "лінці", "лінкам",
"лінк", "лінку", "лінки",
"лінком", "лінкою", "лінками",
"лінку", "лінці", "лінках",
"лінке", "лінко", "лінки"
]
'''
EXTRACT_PADDING = 11
EXTRACT_INCLUDE_WHOLE_WORDS = True
corrections = [ # IDs
"посилання", # 0
"посиланню", # 1
"посиланням", # 2
"на посиланні", # 3
"посилань", # 4
"посиланнями", # 5
"посиланнях" # 6
]
replacements = [
["силка", "силки", "силку", "силко",
"лінк", "лінка", "лінки", "лінку", "лінке", "лінко"],
["силці",
"лінку", "лінці"],
["силкам", "силкою",
"лінкам", "лінком", "лінкою"],
["на силці",
"на лінку", "на лінці"],
["силок",
"лінок"],
["силками",
"лінками"],
["силках",
"лінках"]
]
#unique_match_strings = set(all_possible_match_strings)
#ua_alphabet = "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя"
#regex_matchers = [re.compile(fr"((?<=[^{ua_alphabet}])|(?<=\b)|(?<=^)|(?<= )){i}((?=[^{ua_alphabet}])|(?=\b)|(?=$)|(?= ))", re.DEBUG)
# for i in unique_match_strings]
ua_alphabet = "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя"
for i, group in enumerate(replacements):
for j, match_word in enumerate(group):
#replacements[i][j] = re.compile(fr"((?<=[^{ua_alphabet}])|(?<=\b)|(?<=^)|(?<= )){i}((?=[^{ua_alphabet}])|(?=\b)|(?=$)|(?= ))")
replacements[i][j] = [match_word, re.compile(fr"((?<=[^{ua_alphabet}])|(?<=\b)|(?<=^)|(?<= )){match_word}((?=[^{ua_alphabet}])|(?=\b)|(?=$)|(?= ))")]
#print(replacements[i][j])
#_ = [print(fr"(?<=[^абвгґдеєжзиіїйклмнопрстуфхцчшщьюя]){i}(?=[^абвгґдеєжзиіїйклмнопрстуфхцчшщьюя])") for i in unique_match_strings]
def process(message, path):
lowercase_message = message.text.lower()
for correct_word_id, group in enumerate(replacements):
for match_word, matcher in group:
result = matcher.search(lowercase_message)
if result:
l = len(message.text)
mistake_start = result.start()
mistake_end = result.end()
print(mistake_start, mistake_end)
original_text_before = message.text[max(mistake_start-EXTRACT_PADDING,0):mistake_start]
original_text_after = message.text[mistake_end:min(mistake_end+EXTRACT_PADDING,l)]
original_text_mistake = message.text[mistake_start:mistake_end]
if EXTRACT_INCLUDE_WHOLE_WORDS:
while 0 <= mistake_start - EXTRACT_PADDING - 1 < l and \
message.text[mistake_start-EXTRACT_PADDING-1].isalnum():
mistake_start -= 1
original_text_before = message.text[max(mistake_start-EXTRACT_PADDING,0):result.start()]
while 0 <= mistake_end + EXTRACT_PADDING < l and \
message.text[mistake_end+EXTRACT_PADDING].isalnum():
mistake_end += 1
original_text_after = message.text[result.end():min(mistake_end+EXTRACT_PADDING,l)]
if len(message.text[:mistake_start]) > EXTRACT_PADDING:
original_text_before_continue = "..."
else:
original_text_before_continue = ""
if len(message.text[mistake_end:]) > EXTRACT_PADDING:
original_text_after_continue = "..."
else:
original_text_after_continue = ""
original_extract = original_text_before_continue + original_text_before \
+ original_text_mistake + original_text_after + original_text_after_continue
correct_word = corrections[correct_word_id]
if original_text_mistake == match_word.capitalize():
correct_word = corrections[correct_word_id].capitalize()
elif original_text_mistake == match_word.upper():
correct_word = corrections[correct_word_id].upper()
fixed_extract = original_text_before_continue + original_text_before \
+ correct_word + original_text_after + original_text_after_continue
return f'"{original_extract}" -> "{fixed_extract}" 🌚', None
else:
return "", None

View File

@ -1,6 +0,0 @@
{
"start_on_boot": false,
"alias": "troll-spelling-corrector",
"version": 2,
"index_file": "index.py"
}