import gspread import requests from datetime import datetime, timedelta import json import random import time from util import find_in_list class Structure: def __init__(self): print("Подключение Google Sheets...", end=" ") gc = gspread.oauth() self.document = gc.open_by_key("1srtrHkwbTCfvxyeDtb_ca4RMx8W1kxgUQ-MAIumamVA") print("Готово.") print("Загрузка настроек...", end=" ") with open("settings.json", 'r', encoding='utf-8') as file: self.settings = json.load(file) print("Готово.") print("Загрузка списка преподавателей...", end=" ") self.teachers = list(map(lambda a: a["name"], self.get_json("teachers"))) print("Готово.") print("Загрузка списка дисциплин...", end=" ") self.disciplines = list(map(lambda a: a["name"], self.get_json("disciplines"))) print("Готово.") print("Загрузка расписания...", end=" ") self.calls = self.get_json("calls", "schedule") print("Готово.") print("Данные загружены!") def get_json(self, type, sub_type=None) -> dict: resp = requests.get(url="https://ulsu.ru/oto/api/production/internal/getEnterpriseData.php?type=" + type, params={}) return resp.json()[type if sub_type is None else sub_type] def get_week_number(self, target_date=None): if target_date is None: target_date = self.get_monday() target_date = datetime.strptime(target_date, "%Y-%m-%d") first_week_start_date = datetime.strptime(self.settings["first_week"], "%Y-%m-%d") return ((target_date - first_week_start_date).days // 7) % 2 + 1 def get_monday(self): today = datetime.today() days_until_next_monday = (7 - today.weekday()) % 7 # Если сегодня понедельник, days_until_next_monday будет 0, поэтому добавляем 7 дней # if days_until_next_monday == 0: # days_until_next_monday = 7 # Вычисляем дату следующего понедельника next_monday = today + timedelta(days=days_until_next_monday) # Возвращаем дату в формате "%Y-%m-%d" return next_monday.strftime("%Y-%m-%d") def get_worksheets(self): return self.document.worksheets() def get_document_data(self, worksheet, range_name=None, max_retries=5, initial_backoff=1, maximum_backoff=32): retries = 0 while retries < max_retries: try: if range_name is None: return worksheet.get_all_values() else: return worksheet.get(range_name) except gspread.exceptions.APIError as e: retries += 1 if retries == max_retries: raise e backoff = min(initial_backoff * (2 ** (retries - 1)) + random.random(), maximum_backoff) time.sleep(backoff) def find_range(self, worksheet, first_week=True): def check(cell): if first_week: return "1 неделя" in cell or "I неделя" in cell else: return "2 неделя" in cell or "II неделя" in cell all_values = self.get_document_data(worksheet) week_row = None for i, row in enumerate(all_values): for j, cell in enumerate(row): if check(cell): week_row = i + 1 break if week_row is not None: break for row in range(week_row, worksheet.row_count + 1): cell_value = all_values[row][0] if cell_value == "1": return "C%d:H%d" % (row+1, row+16) def get_lectures_from_range(self, worksheet, range_name): # Получаем название аудитории из названия листа auditorium = worksheet.title # Получаем данные из указанного диапазона data = self.get_document_data(worksheet, range_name) if len(data) < 2: return [] # Дни недели days_of_week = self.settings["week"] day_order = {day: idx for idx, day in enumerate(days_of_week)} # Словарь для порядка дней # Список для хранения лекций lectures = [] # Проходим по данным for row_index in range(0, len(data), 2): # Шаг 2, так как каждая пара строк — это одна пара в расписании lecture_row = data[row_index] # Строка с названием лекции teacher_row = data[row_index + 1] # Строка с преподавателем # Номер пары pair_number = (row_index // 2) + 1 # Проходим по дням недели (столбцам) for col_index, (lecture, teacher) in enumerate(zip(lecture_row, teacher_row)): if lecture.strip() and teacher.strip(): # Если есть и название лекции, и преподаватель day_of_week = days_of_week[col_index] # День недели lectures.append({ "auditorium": auditorium, "day_of_week": day_of_week, "pair_number": pair_number, "lecture": lecture, "teacher": teacher }) lectures = sorted(lectures, key=lambda x: (day_order[x["day_of_week"]], x["pair_number"])) return lectures def find_teachers(self, short_name): return find_in_list(short_name, self.teachers) def find_disciplines(self, short_name): return find_in_list(short_name, self.disciplines) def get_lecture_time(self, day_of_week, pair_number, monday=None): """ Возвращает время начала и окончания лекции для указанного дня недели и номера пары. :param day_of_week: День недели (0 - понедельник, 1 - вторник, ..., 6 - воскресенье). :param pair_number: Номер пары (начиная с 1). :return: Кортеж (start_time, end_time) в формате "2025-03-09T08:00:00.000+04:00". """ if monday is None: monday = datetime.strptime(self.get_monday(), "%Y-%m-%d") # Определяем дату для указанного дня недели target_date = monday + timedelta(days=self.settings["week"].index(day_of_week)) # Находим время для указанной пары for call in self.calls: if call["lesson"] == pair_number: start_time = datetime.fromisoformat("2025-01-01T" + call["start_time"]) end_time = datetime.fromisoformat("2025-01-01T" + call["end_time"]) # Объединяем дату и время start_datetime = target_date.replace( hour=start_time.hour, minute=start_time.minute, second=start_time.second, microsecond=0, tzinfo=start_time.tzinfo ) end_datetime = target_date.replace( hour=end_time.hour, minute=end_time.minute, second=end_time.second, microsecond=0, tzinfo=end_time.tzinfo ) # Форматируем результат return ( start_datetime.isoformat(timespec="milliseconds"), end_datetime.isoformat(timespec="milliseconds") ) # Если пара не найдена raise ValueError(f"Пара с номером {pair_number} не найдена.")