miet-schedule-api 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Deka
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the Software), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: miet-schedule-api
3
+ Version: 0.1.0
4
+ Summary: Небольшая библиотека для получения расписания групп МИЭТ
5
+ Home-page: https://github.com/TheDIMONDK/miet_schedule_api
6
+ Author: Deka
7
+ Author-email: Deka <dka@disroot.org>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/TheDIMONDK/miet_schedule_api
10
+ Project-URL: Repository, https://github.com/TheDIMONDK/miet_schedule_api
11
+ Project-URL: Issues, https://github.com/TheDIMONDK/miet_schedule_api/issues
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.6
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: requests>=2.25.0
19
+ Dynamic: author
20
+ Dynamic: home-page
21
+ Dynamic: license-file
22
+ Dynamic: requires-python
23
+
24
+ # MIET Schedule API
25
+
26
+ Небольшая библиотека для получения и структурирования расписания указанных групп МИЭТ.
27
+
28
+
29
+ ## Возможности
30
+ - Получение расписания для любой группы из списка МИЭТ.
31
+ - Проверка существования группы перед запросом, используя официальное API.
32
+ - Получение расписания на одну дату или диапазон дат, формат: `ДД.ММ.ГГГГ` или `ДД.ММ.ГГГГ-ДД.ММ.ГГГГ`.
33
+ - Получение расписания на текущую, следующую или предыдущую неделю.
34
+ - Кэширование данных в едином файле `last_data.json`, чтобы не мучать API МИЭТ.
35
+ - Принудительное обновление кэша через параметр `force=True`.
36
+ - Пропуск дней, состоящих только из военной подготовки, управляется флагом `SKIP_MILITARY`.
37
+ - Автоматическое определение года начала семестра: если текущий месяц >= сентября, используется текущий год, иначе - предыдущий.
38
+ - Возможность явно установить дату начала семестра через функцию `set_semester_start()`.
39
+ - Возврат результата с мета-информацией: `isFromCache` источник данных, `data` само расписание и `meta` - метаинформация о неделях для каждой даты.
40
+ - Возврат в виде словаря или отформатированной строки JSON, это управляется параметрами `return_json` и `pretty`.
41
+
42
+ > Важно: библиотека пока не учитывает каникулы и праздничные дни.
43
+
44
+
45
+ ## Структура вывода
46
+ ```jsonc
47
+ {
48
+ "isFromCache": true, // Вывод был закэширован, или было прямое обращение к API?
49
+ "data": {
50
+ "01.09.2026": { // День
51
+ "1": {
52
+ "time": ["09:00", "10:20"],
53
+ "title": "Название",
54
+ "type": "Лекция",
55
+ "full_name": "Фамилия Имя Отчество",
56
+ "room": "1201"
57
+ },
58
+ ...
59
+ },
60
+ "02.09.2026": {...},
61
+ ...
62
+ },
63
+ "meta": {
64
+ "weeks": {
65
+ "01.09.2026": {
66
+ "number": 1, // Номер недели по счёту в этом дне
67
+ "type": 0, // Тип недели, 1-й/2-й числитель/знаменатель в виде простого ID
68
+ "typeString": "Числитель - 1" // Тоже самое, но уже приведённое к читаемому виду
69
+ },
70
+ "02.09.2026": {...},
71
+ ...
72
+ },
73
+ "total_weeks": 20 // Общее количество недель
74
+ }
75
+ }
76
+ ```
77
+
78
+
79
+ ## Установка
80
+ ### Локальная установка / для разработки
81
+ ```sh
82
+ pip install -e .
83
+ ```
84
+
85
+ ### Установка из PyPI
86
+ ```sh
87
+ pip install miet_schedule_api
88
+ ```
89
+
90
+ ### Установка из GitHub
91
+ ```sh
92
+ pip install git+https://github.com/TheDIMONDK/miet_schedule_api.git
93
+ ```
94
+
95
+ ## Использование
96
+ ```py
97
+ from miet_schedule_api import *
98
+
99
+ # Получить список всех существующих групп
100
+ groups = get_groups_list()
101
+ print(groups)
102
+
103
+ # Расписание на один день, смотрим на само расписание без метаданных
104
+ schedule = get_schedule(group="ИТД-11", date_str="01.09.2026")
105
+ print(schedule["data"])
106
+
107
+ # Диапазон дат, вдобавок возвращаем и красивую JSON-строку
108
+ schedule_json = get_schedule_range(
109
+ group="ИТД-11",
110
+ start_date_str="01.09.2026",
111
+ end_date_str="05.09.2026",
112
+ return_json=True,
113
+ pretty=True
114
+ )
115
+ print(schedule_json)
116
+
117
+ # Расписание+метаданные текущей недели с понедельника по воскресенье
118
+ current_week = get_current_week(group="ИТД-11", return_json=True, pretty=True)
119
+ print(current_week)
120
+
121
+ # Расписание+метаданные следующей недели относительно сегодня
122
+ next_week = get_next_week(group="ИТД-11", return_json=True, pretty=True)
123
+ print(next_week)
124
+
125
+ # Расписание+метаданные предыдущей недели относительно заданной даты
126
+ prev_week = get_previous_week(group="ИТД-11", date_str="15.09.2026", return_json=True, pretty=True)
127
+ print(prev_week)
128
+ ```
129
+
130
+
131
+ ## Параметры функций
132
+ - `group` (str, обязательный) - код группы.
133
+ - `return_json` (bool, default=False) - если True, возвращает строку JSON вместо словаря.
134
+ - `pretty` (bool, default=False) - если True и `return_json=True`, JSON выводится с отступами.
135
+ - `force` (bool, default=False) - принудительно запрашивает данные с сервера, игнорируя кэш.
136
+ - `date_str` (str) - дата в формате `ДД.ММ.ГГГГ`, для функций недели опциональна.
137
+ - `start_date_str`, `end_date_str` (str) - начальная и конечная даты диапазона.
138
+
139
+
140
+ ## Разработка
141
+ ### Сборка пакета
142
+ ```sh
143
+ pip install build
144
+ python -m build
145
+ ```
146
+
147
+ ## Конфигурация
148
+ Базовые настройки по умолчанию находятся в `miet_schedule_api/consts.py`:
149
+
150
+ - `API_URL` - URL для запроса расписания.
151
+ - `GROUPS_URL` - URL для получения списка групп.
152
+ - `TOTAL_WEEKS` - общее количество недель в семестре, по умолчанию 20.
153
+ - `SKIP_MILITARY` - пропускать ли дни с военной подготовкой.
154
+ - `SEMESTER_START` - автоматически вычисляется, но можно переопределить, если нужно.
155
+
156
+ ## Лицензия
157
+ MIT
@@ -0,0 +1,134 @@
1
+ # MIET Schedule API
2
+
3
+ Небольшая библиотека для получения и структурирования расписания указанных групп МИЭТ.
4
+
5
+
6
+ ## Возможности
7
+ - Получение расписания для любой группы из списка МИЭТ.
8
+ - Проверка существования группы перед запросом, используя официальное API.
9
+ - Получение расписания на одну дату или диапазон дат, формат: `ДД.ММ.ГГГГ` или `ДД.ММ.ГГГГ-ДД.ММ.ГГГГ`.
10
+ - Получение расписания на текущую, следующую или предыдущую неделю.
11
+ - Кэширование данных в едином файле `last_data.json`, чтобы не мучать API МИЭТ.
12
+ - Принудительное обновление кэша через параметр `force=True`.
13
+ - Пропуск дней, состоящих только из военной подготовки, управляется флагом `SKIP_MILITARY`.
14
+ - Автоматическое определение года начала семестра: если текущий месяц >= сентября, используется текущий год, иначе - предыдущий.
15
+ - Возможность явно установить дату начала семестра через функцию `set_semester_start()`.
16
+ - Возврат результата с мета-информацией: `isFromCache` источник данных, `data` само расписание и `meta` - метаинформация о неделях для каждой даты.
17
+ - Возврат в виде словаря или отформатированной строки JSON, это управляется параметрами `return_json` и `pretty`.
18
+
19
+ > Важно: библиотека пока не учитывает каникулы и праздничные дни.
20
+
21
+
22
+ ## Структура вывода
23
+ ```jsonc
24
+ {
25
+ "isFromCache": true, // Вывод был закэширован, или было прямое обращение к API?
26
+ "data": {
27
+ "01.09.2026": { // День
28
+ "1": {
29
+ "time": ["09:00", "10:20"],
30
+ "title": "Название",
31
+ "type": "Лекция",
32
+ "full_name": "Фамилия Имя Отчество",
33
+ "room": "1201"
34
+ },
35
+ ...
36
+ },
37
+ "02.09.2026": {...},
38
+ ...
39
+ },
40
+ "meta": {
41
+ "weeks": {
42
+ "01.09.2026": {
43
+ "number": 1, // Номер недели по счёту в этом дне
44
+ "type": 0, // Тип недели, 1-й/2-й числитель/знаменатель в виде простого ID
45
+ "typeString": "Числитель - 1" // Тоже самое, но уже приведённое к читаемому виду
46
+ },
47
+ "02.09.2026": {...},
48
+ ...
49
+ },
50
+ "total_weeks": 20 // Общее количество недель
51
+ }
52
+ }
53
+ ```
54
+
55
+
56
+ ## Установка
57
+ ### Локальная установка / для разработки
58
+ ```sh
59
+ pip install -e .
60
+ ```
61
+
62
+ ### Установка из PyPI
63
+ ```sh
64
+ pip install miet_schedule_api
65
+ ```
66
+
67
+ ### Установка из GitHub
68
+ ```sh
69
+ pip install git+https://github.com/TheDIMONDK/miet_schedule_api.git
70
+ ```
71
+
72
+ ## Использование
73
+ ```py
74
+ from miet_schedule_api import *
75
+
76
+ # Получить список всех существующих групп
77
+ groups = get_groups_list()
78
+ print(groups)
79
+
80
+ # Расписание на один день, смотрим на само расписание без метаданных
81
+ schedule = get_schedule(group="ИТД-11", date_str="01.09.2026")
82
+ print(schedule["data"])
83
+
84
+ # Диапазон дат, вдобавок возвращаем и красивую JSON-строку
85
+ schedule_json = get_schedule_range(
86
+ group="ИТД-11",
87
+ start_date_str="01.09.2026",
88
+ end_date_str="05.09.2026",
89
+ return_json=True,
90
+ pretty=True
91
+ )
92
+ print(schedule_json)
93
+
94
+ # Расписание+метаданные текущей недели с понедельника по воскресенье
95
+ current_week = get_current_week(group="ИТД-11", return_json=True, pretty=True)
96
+ print(current_week)
97
+
98
+ # Расписание+метаданные следующей недели относительно сегодня
99
+ next_week = get_next_week(group="ИТД-11", return_json=True, pretty=True)
100
+ print(next_week)
101
+
102
+ # Расписание+метаданные предыдущей недели относительно заданной даты
103
+ prev_week = get_previous_week(group="ИТД-11", date_str="15.09.2026", return_json=True, pretty=True)
104
+ print(prev_week)
105
+ ```
106
+
107
+
108
+ ## Параметры функций
109
+ - `group` (str, обязательный) - код группы.
110
+ - `return_json` (bool, default=False) - если True, возвращает строку JSON вместо словаря.
111
+ - `pretty` (bool, default=False) - если True и `return_json=True`, JSON выводится с отступами.
112
+ - `force` (bool, default=False) - принудительно запрашивает данные с сервера, игнорируя кэш.
113
+ - `date_str` (str) - дата в формате `ДД.ММ.ГГГГ`, для функций недели опциональна.
114
+ - `start_date_str`, `end_date_str` (str) - начальная и конечная даты диапазона.
115
+
116
+
117
+ ## Разработка
118
+ ### Сборка пакета
119
+ ```sh
120
+ pip install build
121
+ python -m build
122
+ ```
123
+
124
+ ## Конфигурация
125
+ Базовые настройки по умолчанию находятся в `miet_schedule_api/consts.py`:
126
+
127
+ - `API_URL` - URL для запроса расписания.
128
+ - `GROUPS_URL` - URL для получения списка групп.
129
+ - `TOTAL_WEEKS` - общее количество недель в семестре, по умолчанию 20.
130
+ - `SKIP_MILITARY` - пропускать ли дни с военной подготовкой.
131
+ - `SEMESTER_START` - автоматически вычисляется, но можно переопределить, если нужно.
132
+
133
+ ## Лицензия
134
+ MIT
@@ -0,0 +1,34 @@
1
+ """
2
+ Небольшая библиотека для получения расписания групп МИЭТ.
3
+ """
4
+
5
+ from .core import (
6
+ get_schedule,
7
+ get_schedule_range,
8
+ get_current_week,
9
+ get_next_week,
10
+ get_previous_week,
11
+ fetch_schedule,
12
+ get_groups_list,
13
+ validate_group,
14
+ load_cached_data,
15
+ save_cached_data,
16
+ set_semester_start,
17
+ set_skip_military,
18
+ )
19
+
20
+ __version__ = "0.1.0"
21
+ __all__ = [
22
+ "get_schedule",
23
+ "get_schedule_range",
24
+ "get_current_week",
25
+ "get_next_week",
26
+ "get_previous_week",
27
+ "fetch_schedule",
28
+ "get_groups_list",
29
+ "validate_group",
30
+ "load_cached_data",
31
+ "save_cached_data",
32
+ "set_semester_start",
33
+ "set_skip_military",
34
+ ]
@@ -0,0 +1,56 @@
1
+ """
2
+ Константы для скрипта расписания.
3
+ """
4
+
5
+ from datetime import datetime
6
+
7
+
8
+ # URL API расписания МИЭТ
9
+ API_URL = "https://miet.ru/schedule/data"
10
+
11
+ # URL API списка групп
12
+ GROUPS_URL = "https://miet.ru/schedule/groups"
13
+
14
+ # Общее количество недель в семестре
15
+ TOTAL_WEEKS = 20
16
+
17
+ # Если истина, дни, состоящие только из занятий "Военная подготовка",
18
+ # будут считаться свободными и возвращаться как {}
19
+ SKIP_MILITARY = True
20
+
21
+ # Внутренняя переменная для хранения даты начала семестра
22
+ _SEMESTER_START = None
23
+
24
+
25
+ def get_semester_start() -> str:
26
+ """
27
+ Функция для возврата даты начала семестра в формате ДД.ММ.ГГГГ.
28
+ Если дата не была установлена явно через сеттер,
29
+ она вычисляется автоматически на основе текущей даты:
30
+ - если текущий месяц >= 9 (сентябрь), то год текущий,
31
+ - иначе год предыдущий.
32
+ """
33
+
34
+ global _SEMESTER_START
35
+ if _SEMESTER_START is None:
36
+ _CURRENT_YEAR = datetime.now().year
37
+ _CURRENT_MONTH = datetime.now().month
38
+ if _CURRENT_MONTH >= 9:
39
+ _SEMESTER_START = f"01.09.{_CURRENT_YEAR}"
40
+
41
+ else:
42
+ _SEMESTER_START = f"01.09.{_CURRENT_YEAR - 1}"
43
+
44
+ return _SEMESTER_START
45
+
46
+
47
+ def set_semester_start(new_start: str):
48
+ """
49
+ Явно устанавливает дату начала семестра в формате ДД.ММ.ГГГГ.
50
+ """
51
+ global _SEMESTER_START
52
+ _SEMESTER_START = new_start
53
+
54
+
55
+ # Для обратной совместимости сохраняем константу, но она теперь вычисляется при первом обращении
56
+ SEMESTER_START = get_semester_start()
@@ -0,0 +1,303 @@
1
+ """
2
+ Основной модуль библиотеки для получения расписания.
3
+ Предоставляет функции для загрузки, кэширования и парсинга расписания.
4
+ """
5
+
6
+ import json
7
+ import os
8
+ import requests
9
+ from datetime import datetime, timedelta
10
+ from .consts import API_URL, GROUPS_URL, TOTAL_WEEKS, SKIP_MILITARY, get_semester_start, set_semester_start
11
+ from .parser import build_schedule_for_date, get_week_info
12
+
13
+ def get_groups_list() -> list:
14
+ """
15
+ Функция для получения списка всех доступных групп из API.
16
+ """
17
+ try:
18
+ response = requests.get(GROUPS_URL)
19
+ response.raise_for_status()
20
+
21
+ return response.json()
22
+
23
+ except requests.exceptions.RequestException as e:
24
+ raise RuntimeError(f"Ошибка при получении списка групп: {e}")
25
+
26
+
27
+ def validate_group(group: str) -> bool:
28
+ """
29
+ Функция для проверки, существует ли указанная группа.
30
+ """
31
+ groups = get_groups_list()
32
+ return group in groups
33
+
34
+
35
+ def fetch_schedule(group: str) -> dict:
36
+ """
37
+ Функция для выполнения POST-запроса к API расписания и получения самого расписания в виде JSON-ответа.
38
+ """
39
+ try:
40
+ response = requests.post(API_URL, data={"group": group})
41
+ response.raise_for_status()
42
+ return response.json()
43
+
44
+ except requests.exceptions.RequestException as e:
45
+ raise RuntimeError(f"Ошибка при запросе расписания для группы {group}: {e}")
46
+
47
+
48
+ def load_cached_data(group: str) -> dict | None:
49
+ """
50
+ Функция для загрузки данных для указанной группы из единого файла кэша.
51
+ Возвращает словарь с данными расписания или None, если группа не найдена.
52
+ """
53
+ cache_path = "last_data.json"
54
+ if not os.path.exists(cache_path):
55
+ return None
56
+
57
+ try:
58
+ with open(cache_path, "r", encoding="utf-8") as f:
59
+ all_data = json.load(f)
60
+ return all_data.get(group)
61
+
62
+ except (json.JSONDecodeError, IOError):
63
+ return None
64
+
65
+
66
+ def save_cached_data(group: str, data: dict):
67
+ """
68
+ Функция для сохранения данных для указанной группы в единый файл кэша.
69
+ Если файл существует, обновляет запись для группы, иначе, создаёт новый.
70
+ """
71
+ cache_path = "last_data.json"
72
+ all_data = {}
73
+ if os.path.exists(cache_path):
74
+ try:
75
+ with open(cache_path, "r", encoding="utf-8") as f:
76
+ all_data = json.load(f)
77
+
78
+ except (json.JSONDecodeError, IOError):
79
+ all_data = {}
80
+
81
+ all_data[group] = data
82
+
83
+ with open(cache_path, "w", encoding="utf-8") as f:
84
+ json.dump(all_data, f, ensure_ascii=False, indent=2)
85
+
86
+
87
+ def get_schedule(group: str, date_str: str, force: bool = False, return_json: bool = False, pretty: bool = False):
88
+ """
89
+ Функция для получения структурированного расписания для указанной группы и даты.
90
+
91
+ Аргументы:
92
+ group: код группы / обязательный параметр
93
+ date_str: дата в формате ДД.ММ.ГГГГ
94
+ force: если True, принудительно запрашивает данные с сервера
95
+ return_json: если True, возвращает строку JSON, иначе словарь
96
+ pretty: если True, форматирует JSON с отступами; работает только при return_json=True
97
+
98
+ Возвращает словарь или строку JSON.
99
+ """
100
+ if not validate_group(group):
101
+ raise ValueError(f"Группа '{group}' не найдена в списке доступных групп.")
102
+
103
+ is_from_cache = False
104
+ schedule_data = None
105
+
106
+ if not force:
107
+ cached = load_cached_data(group)
108
+ if cached is not None:
109
+ schedule_data = cached
110
+ is_from_cache = True
111
+
112
+ else:
113
+ schedule_data = fetch_schedule(group)
114
+ save_cached_data(group, schedule_data)
115
+
116
+ else:
117
+ schedule_data = fetch_schedule(group)
118
+ save_cached_data(group, schedule_data)
119
+
120
+ if schedule_data is None:
121
+ raise RuntimeError(f"Не удалось получить данные расписания для группы {group}.")
122
+
123
+ result_data = build_schedule_for_date(schedule_data, date_str)
124
+
125
+ week_info = get_week_info(date_str)
126
+ meta = {
127
+ "weeks": {date_str: week_info},
128
+ "total_weeks": TOTAL_WEEKS
129
+ }
130
+
131
+ result = {
132
+ "isFromCache": is_from_cache,
133
+ "data": result_data,
134
+ "meta": meta
135
+ }
136
+
137
+ if return_json:
138
+ indent = 2 if pretty else None
139
+ return json.dumps(result, ensure_ascii=False, indent=indent)
140
+
141
+ return result
142
+
143
+
144
+ def get_schedule_range(group: str, start_date_str: str, end_date_str: str, force: bool = False, return_json: bool = False, pretty: bool = False):
145
+ """
146
+ Функция для получения структурированного расписания для указанной группы и диапазона дат.
147
+
148
+ Аргументы:
149
+ group: код группы / обязательный параметр
150
+ start_date_str: начальная дата в формате ДД.ММ.ГГГГ
151
+ end_date_str: конечная дата в формате ДД.ММ.ГГГГ
152
+ force: если True, принудительно запрашивает данные с сервера
153
+ return_json: если True, возвращает строку JSON, иначе словарь
154
+ pretty: если True, форматирует JSON с отступами; работает только при return_json=True
155
+
156
+ Возвращает словарь или строку JSON.
157
+ """
158
+ if not validate_group(group):
159
+ raise ValueError(f"Группа '{group}' не найдена в списке доступных групп.")
160
+
161
+ start = datetime.strptime(start_date_str, "%d.%m.%Y")
162
+ end = datetime.strptime(end_date_str, "%d.%m.%Y")
163
+ if start > end:
164
+ start, end = end, start
165
+
166
+ is_from_cache = False
167
+ schedule_data = None
168
+
169
+ if not force:
170
+ cached = load_cached_data(group)
171
+ if cached is not None:
172
+ schedule_data = cached
173
+ is_from_cache = True
174
+
175
+ else:
176
+ schedule_data = fetch_schedule(group)
177
+ save_cached_data(group, schedule_data)
178
+
179
+ else:
180
+ schedule_data = fetch_schedule(group)
181
+ save_cached_data(group, schedule_data)
182
+
183
+ if schedule_data is None:
184
+ raise RuntimeError(f"Не удалось получить данные расписания для группы {group}.")
185
+
186
+ result_data = {}
187
+ weeks_info = {}
188
+ current = start
189
+ delta = timedelta(days=1)
190
+ while current <= end:
191
+ date_str = current.strftime("%d.%m.%Y")
192
+ day_result = build_schedule_for_date(schedule_data, date_str)
193
+ result_data.update(day_result)
194
+ weeks_info[date_str] = get_week_info(date_str)
195
+ current += delta
196
+
197
+ meta = {
198
+ "weeks": weeks_info,
199
+ "total_weeks": TOTAL_WEEKS
200
+ }
201
+
202
+ result = {
203
+ "isFromCache": is_from_cache,
204
+ "data": result_data,
205
+ "meta": meta
206
+ }
207
+
208
+ if return_json:
209
+ indent = 2 if pretty else None
210
+ return json.dumps(result, ensure_ascii=False, indent=indent)
211
+
212
+ return result
213
+
214
+
215
+ def get_current_week(group: str, date_str: str = None, force: bool = False, return_json: bool = False, pretty: bool = False):
216
+ """
217
+ Функция для получения расписания на текущую неделю / с понедельника по воскресенье,
218
+ относительно заданной даты или текущей даты, если date_str не указан.
219
+
220
+ Аргументы:
221
+ group: код группы / обязательный параметр
222
+ date_str: опционально, дата в формате ДД.ММ.ГГГГ, от которой вычисляется неделя; если не указана, используется сегодняшняя дата
223
+ force: если True, принудительно запрашивает данные с сервера
224
+ return_json: если True, возвращает строку JSON, иначе словарь
225
+ pretty: если True, форматирует JSON с отступами
226
+
227
+ Возвращает словарь или строку JSON с расписанием на неделю.
228
+ """
229
+ if date_str is None:
230
+ date_str = datetime.now().strftime("%d.%m.%Y")
231
+ dt = datetime.strptime(date_str, "%d.%m.%Y")
232
+ start_of_week = dt - timedelta(days=dt.weekday()) # понедельник
233
+ end_of_week = start_of_week + timedelta(days=6)
234
+ start_str = start_of_week.strftime("%d.%m.%Y")
235
+ end_str = end_of_week.strftime("%d.%m.%Y")
236
+ return get_schedule_range(group, start_str, end_str, force, return_json, pretty)
237
+
238
+
239
+ def get_next_week(group: str, date_str: str = None, force: bool = False, return_json: bool = False, pretty: bool = False):
240
+ """
241
+ Функция для получения расписания на следующую неделю / с понедельника по воскресенье
242
+ относительно заданной даты или текущей даты, если date_str не указан.
243
+
244
+ Аргументы:
245
+ group: код группы / обязательный параметр
246
+ date_str: опционально, дата в формате ДД.ММ.ГГГГ, от которой вычисляется неделя; если не указана, используется сегодняшняя дата
247
+ force: если True, принудительно запрашивает данные с сервера
248
+ return_json: если True, возвращает строку JSON, иначе словарь
249
+ pretty: если True, форматирует JSON с отступами
250
+
251
+ Возвращает словарь или строку JSON с расписанием на неделю.
252
+ """
253
+ if date_str is None:
254
+ date_str = datetime.now().strftime("%d.%m.%Y")
255
+ dt = datetime.strptime(date_str, "%d.%m.%Y")
256
+ start_of_week = dt - timedelta(days=dt.weekday()) + timedelta(days=7)
257
+ end_of_week = start_of_week + timedelta(days=6)
258
+ start_str = start_of_week.strftime("%d.%m.%Y")
259
+ end_str = end_of_week.strftime("%d.%m.%Y")
260
+ return get_schedule_range(group, start_str, end_str, force, return_json, pretty)
261
+
262
+ def get_previous_week(group: str, date_str: str = None, force: bool = False, return_json: bool = False, pretty: bool = False):
263
+ """
264
+ Метод для получения расписания на предыдущую неделю / с понедельника по воскресенье
265
+ относительно заданной даты или текущей даты, если date_str не указан.
266
+
267
+ Аргументы:
268
+ group: код группы / обязательный параметр
269
+ date_str: опционально, дата в формате ДД.ММ.ГГГГ, от которой вычисляется неделя; если не указана, используется сегодняшняя дата
270
+ force: если True, принудительно запрашивает данные с сервера
271
+ return_json: если True, возвращает строку JSON, иначе словарь
272
+ pretty: если True, форматирует JSON с отступами
273
+
274
+ Возвращает словарь или строку JSON с расписанием на неделю.
275
+ """
276
+ if date_str is None:
277
+ date_str = datetime.now().strftime("%d.%m.%Y")
278
+
279
+ dt = datetime.strptime(date_str, "%d.%m.%Y")
280
+ start_of_week = dt - timedelta(days=dt.weekday()) - timedelta(days=7)
281
+ end_of_week = start_of_week + timedelta(days=6)
282
+ start_str = start_of_week.strftime("%d.%m.%Y")
283
+ end_str = end_of_week.strftime("%d.%m.%Y")
284
+
285
+ return get_schedule_range(group, start_str, end_str, force, return_json, pretty)
286
+
287
+
288
+ def get_semester_start():
289
+ """Возвращает дату начала семестра."""
290
+ from .consts import get_semester_start as _get
291
+ return _get()
292
+
293
+
294
+ def set_semester_start(new_start: str):
295
+ """Устанавливает дату начала семестра."""
296
+ from .consts import set_semester_start as _set
297
+ _set(new_start)
298
+
299
+
300
+ def set_skip_military(value: bool):
301
+ """Включает или выключает пропуск дней военной подготовки."""
302
+ global SKIP_MILITARY
303
+ SKIP_MILITARY = value
@@ -0,0 +1,150 @@
1
+ """
2
+ Модуль парсинга расписания МИЭТ.
3
+ """
4
+
5
+ import re
6
+ from datetime import datetime
7
+ from .consts import get_semester_start, SKIP_MILITARY
8
+
9
+
10
+ def compute_week_type(date_str: str) -> int:
11
+ """
12
+ Функция для вычисления типа недели 0-3 на основе даты и начала семестра.
13
+ Формула: разница в днях % 28 // 7.
14
+ Дата и начало семестра ожидаются в формате ДД.ММ.ГГГГ.
15
+ """
16
+ date = datetime.strptime(date_str, "%d.%m.%Y").date()
17
+ semester_start = datetime.strptime(get_semester_start(), "%d.%m.%Y").date()
18
+ delta = (date - semester_start).days
19
+ if delta < 0:
20
+ return 0
21
+ return (delta % 28) // 7
22
+
23
+
24
+ def compute_week_number(date_str: str) -> int:
25
+ """
26
+ Функция для вычисления абсолютного номера недели, начиная с 1, на основе даты.
27
+ """
28
+ date = datetime.strptime(date_str, "%d.%m.%Y").date()
29
+ semester_start = datetime.strptime(get_semester_start(), "%d.%m.%Y").date()
30
+
31
+ delta = (date - semester_start).days
32
+ if delta < 0:
33
+ return 0
34
+
35
+ return delta // 7 + 1
36
+
37
+
38
+ def get_week_type_string(week_type: int) -> str:
39
+ """
40
+ Функция для преобразования числового типа недели (0-3) в строку.
41
+ """
42
+ mapping = {
43
+ 0: "Числитель - 1",
44
+ 1: "Знаменатель - 1",
45
+ 2: "Числитель - 2",
46
+ 3: "Знаменатель - 2",
47
+ }
48
+ return mapping.get(week_type, "Неизвестно")
49
+
50
+
51
+ def get_week_info(date_str: str) -> dict:
52
+ """
53
+ Функция для получения информации о неделе для заданной даты:
54
+ {
55
+ "number": номер недели, начиная с 1,
56
+ "type": числовой тип 0-3,
57
+ "typeString": строковое представление
58
+ }
59
+ """
60
+ week_type = compute_week_type(date_str)
61
+ week_number = compute_week_number(date_str)
62
+ type_string = get_week_type_string(week_type)
63
+ return {
64
+ "number": week_number,
65
+ "type": week_type,
66
+ "typeString": type_string
67
+ }
68
+
69
+
70
+ def extract_lesson_type(name: str) -> tuple:
71
+ """
72
+ Функция для извлечения типа занятия из строки названия и получения очищенного названия и типа.
73
+ Пример: "Ноксология [Лек]" -> ("Ноксология", "Лекция")
74
+ Типы: Лек -> Лекция, Пр -> Практика, Сем -> Семинар, Лаб -> Лабораторная.
75
+ Если тип не распознан, возвращается "Неизвестно".
76
+ """
77
+ match = re.search(r'\[(.*?)\]$', name)
78
+ if not match:
79
+ return name.strip(), "Неизвестно"
80
+
81
+ type_code = match.group(1).strip()
82
+ clean_name = re.sub(r'\s*\[.*?\]$', '', name).strip()
83
+
84
+ type_map = {
85
+ "Лек": "Лекция",
86
+ "Пр": "Практика",
87
+ "Сем": "Семинар",
88
+ "Лаб": "Лабораторная",
89
+ }
90
+ lesson_type = type_map.get(type_code, "Неизвестно")
91
+
92
+ return clean_name, lesson_type
93
+
94
+
95
+ def parse_time(time_str: str) -> str:
96
+ """
97
+ Функция для преобразования строки времени вида "0001-01-01T09:00:00" в формат "ЧЧ:ММ".
98
+ """
99
+ time_part = time_str.split('T')[1]
100
+ return time_part[:-3]
101
+
102
+
103
+ def build_schedule_for_date(schedule_data: dict, target_date_str: str) -> dict:
104
+ """
105
+ Функция для преобразования сырых данных расписания в словарь из JSON
106
+ в формате ДД.ММ.ГГГГ ведущие нули необязательны.
107
+ Возвращает структурированный сортированный словарь.
108
+
109
+ Если включён флаг SKIP_MILITARY и все занятия на эту дату являются
110
+ "Военная подготовка", возвращается {дата: {}}, как бы "выходной".
111
+ """
112
+ target_date_obj = datetime.strptime(target_date_str, "%d.%m.%Y").date()
113
+ formatted_date = target_date_obj.strftime("%d.%m.%Y")
114
+
115
+ day_of_week = target_date_obj.isoweekday()
116
+ week_type = compute_week_type(formatted_date)
117
+
118
+ lessons = []
119
+ for item in schedule_data.get("Data", []):
120
+ if item.get("Day") == day_of_week and item.get("DayNumber") == week_type:
121
+ lessons.append(item)
122
+
123
+ if SKIP_MILITARY and lessons:
124
+ all_military = all("Военная подготовка" in item["Class"]["Name"] for item in lessons)
125
+ if all_military:
126
+ return {formatted_date: {}}
127
+
128
+ lessons.sort(key=lambda x: x["Time"]["Code"])
129
+
130
+ result = {formatted_date: {}}
131
+ for lesson in lessons:
132
+ time_info = lesson["Time"]
133
+ class_info = lesson["Class"]
134
+ room_info = lesson["Room"]
135
+
136
+ pair_number = time_info["Code"]
137
+ time_from = parse_time(time_info["TimeFrom"])
138
+ time_to = parse_time(time_info["TimeTo"])
139
+
140
+ clean_title, lesson_type = extract_lesson_type(class_info["Name"])
141
+
142
+ result[formatted_date][pair_number] = {
143
+ "time": [time_from, time_to],
144
+ "title": clean_title,
145
+ "type": lesson_type,
146
+ "full_name": class_info["TeacherFull"],
147
+ "room": room_info["Name"]
148
+ }
149
+
150
+ return result
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: miet-schedule-api
3
+ Version: 0.1.0
4
+ Summary: Небольшая библиотека для получения расписания групп МИЭТ
5
+ Home-page: https://github.com/TheDIMONDK/miet_schedule_api
6
+ Author: Deka
7
+ Author-email: Deka <dka@disroot.org>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/TheDIMONDK/miet_schedule_api
10
+ Project-URL: Repository, https://github.com/TheDIMONDK/miet_schedule_api
11
+ Project-URL: Issues, https://github.com/TheDIMONDK/miet_schedule_api/issues
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.6
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: requests>=2.25.0
19
+ Dynamic: author
20
+ Dynamic: home-page
21
+ Dynamic: license-file
22
+ Dynamic: requires-python
23
+
24
+ # MIET Schedule API
25
+
26
+ Небольшая библиотека для получения и структурирования расписания указанных групп МИЭТ.
27
+
28
+
29
+ ## Возможности
30
+ - Получение расписания для любой группы из списка МИЭТ.
31
+ - Проверка существования группы перед запросом, используя официальное API.
32
+ - Получение расписания на одну дату или диапазон дат, формат: `ДД.ММ.ГГГГ` или `ДД.ММ.ГГГГ-ДД.ММ.ГГГГ`.
33
+ - Получение расписания на текущую, следующую или предыдущую неделю.
34
+ - Кэширование данных в едином файле `last_data.json`, чтобы не мучать API МИЭТ.
35
+ - Принудительное обновление кэша через параметр `force=True`.
36
+ - Пропуск дней, состоящих только из военной подготовки, управляется флагом `SKIP_MILITARY`.
37
+ - Автоматическое определение года начала семестра: если текущий месяц >= сентября, используется текущий год, иначе - предыдущий.
38
+ - Возможность явно установить дату начала семестра через функцию `set_semester_start()`.
39
+ - Возврат результата с мета-информацией: `isFromCache` источник данных, `data` само расписание и `meta` - метаинформация о неделях для каждой даты.
40
+ - Возврат в виде словаря или отформатированной строки JSON, это управляется параметрами `return_json` и `pretty`.
41
+
42
+ > Важно: библиотека пока не учитывает каникулы и праздничные дни.
43
+
44
+
45
+ ## Структура вывода
46
+ ```jsonc
47
+ {
48
+ "isFromCache": true, // Вывод был закэширован, или было прямое обращение к API?
49
+ "data": {
50
+ "01.09.2026": { // День
51
+ "1": {
52
+ "time": ["09:00", "10:20"],
53
+ "title": "Название",
54
+ "type": "Лекция",
55
+ "full_name": "Фамилия Имя Отчество",
56
+ "room": "1201"
57
+ },
58
+ ...
59
+ },
60
+ "02.09.2026": {...},
61
+ ...
62
+ },
63
+ "meta": {
64
+ "weeks": {
65
+ "01.09.2026": {
66
+ "number": 1, // Номер недели по счёту в этом дне
67
+ "type": 0, // Тип недели, 1-й/2-й числитель/знаменатель в виде простого ID
68
+ "typeString": "Числитель - 1" // Тоже самое, но уже приведённое к читаемому виду
69
+ },
70
+ "02.09.2026": {...},
71
+ ...
72
+ },
73
+ "total_weeks": 20 // Общее количество недель
74
+ }
75
+ }
76
+ ```
77
+
78
+
79
+ ## Установка
80
+ ### Локальная установка / для разработки
81
+ ```sh
82
+ pip install -e .
83
+ ```
84
+
85
+ ### Установка из PyPI
86
+ ```sh
87
+ pip install miet_schedule_api
88
+ ```
89
+
90
+ ### Установка из GitHub
91
+ ```sh
92
+ pip install git+https://github.com/TheDIMONDK/miet_schedule_api.git
93
+ ```
94
+
95
+ ## Использование
96
+ ```py
97
+ from miet_schedule_api import *
98
+
99
+ # Получить список всех существующих групп
100
+ groups = get_groups_list()
101
+ print(groups)
102
+
103
+ # Расписание на один день, смотрим на само расписание без метаданных
104
+ schedule = get_schedule(group="ИТД-11", date_str="01.09.2026")
105
+ print(schedule["data"])
106
+
107
+ # Диапазон дат, вдобавок возвращаем и красивую JSON-строку
108
+ schedule_json = get_schedule_range(
109
+ group="ИТД-11",
110
+ start_date_str="01.09.2026",
111
+ end_date_str="05.09.2026",
112
+ return_json=True,
113
+ pretty=True
114
+ )
115
+ print(schedule_json)
116
+
117
+ # Расписание+метаданные текущей недели с понедельника по воскресенье
118
+ current_week = get_current_week(group="ИТД-11", return_json=True, pretty=True)
119
+ print(current_week)
120
+
121
+ # Расписание+метаданные следующей недели относительно сегодня
122
+ next_week = get_next_week(group="ИТД-11", return_json=True, pretty=True)
123
+ print(next_week)
124
+
125
+ # Расписание+метаданные предыдущей недели относительно заданной даты
126
+ prev_week = get_previous_week(group="ИТД-11", date_str="15.09.2026", return_json=True, pretty=True)
127
+ print(prev_week)
128
+ ```
129
+
130
+
131
+ ## Параметры функций
132
+ - `group` (str, обязательный) - код группы.
133
+ - `return_json` (bool, default=False) - если True, возвращает строку JSON вместо словаря.
134
+ - `pretty` (bool, default=False) - если True и `return_json=True`, JSON выводится с отступами.
135
+ - `force` (bool, default=False) - принудительно запрашивает данные с сервера, игнорируя кэш.
136
+ - `date_str` (str) - дата в формате `ДД.ММ.ГГГГ`, для функций недели опциональна.
137
+ - `start_date_str`, `end_date_str` (str) - начальная и конечная даты диапазона.
138
+
139
+
140
+ ## Разработка
141
+ ### Сборка пакета
142
+ ```sh
143
+ pip install build
144
+ python -m build
145
+ ```
146
+
147
+ ## Конфигурация
148
+ Базовые настройки по умолчанию находятся в `miet_schedule_api/consts.py`:
149
+
150
+ - `API_URL` - URL для запроса расписания.
151
+ - `GROUPS_URL` - URL для получения списка групп.
152
+ - `TOTAL_WEEKS` - общее количество недель в семестре, по умолчанию 20.
153
+ - `SKIP_MILITARY` - пропускать ли дни с военной подготовкой.
154
+ - `SEMESTER_START` - автоматически вычисляется, но можно переопределить, если нужно.
155
+
156
+ ## Лицензия
157
+ MIT
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ requirements.txt
6
+ setup.py
7
+ miet_schedule_api/__init__.py
8
+ miet_schedule_api/consts.py
9
+ miet_schedule_api/core.py
10
+ miet_schedule_api/parser.py
11
+ miet_schedule_api.egg-info/PKG-INFO
12
+ miet_schedule_api.egg-info/SOURCES.txt
13
+ miet_schedule_api.egg-info/dependency_links.txt
14
+ miet_schedule_api.egg-info/requires.txt
15
+ miet_schedule_api.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ miet_schedule_api
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "miet-schedule-api"
7
+ version = "0.1.0"
8
+ description = "Небольшая библиотека для получения расписания групп МИЭТ"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "Deka", email = "dka@disroot.org"}
13
+ ]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ requires-python = ">=3.6"
20
+ dependencies = [
21
+ "requests>=2.25.0"
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/TheDIMONDK/miet_schedule_api"
26
+ Repository = "https://github.com/TheDIMONDK/miet_schedule_api"
27
+ Issues = "https://github.com/TheDIMONDK/miet_schedule_api/issues"
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from setuptools import setup, find_packages
4
+
5
+ with open("README.md", "r", encoding="utf-8") as fh:
6
+ long_description = fh.read()
7
+
8
+ setup(
9
+ name="miet-schedule-api",
10
+ version="0.1.0",
11
+ author="Deka",
12
+ author_email="dka@disroot.org",
13
+ description="Небольшая библиотека для получения расписания групп МИЭТ",
14
+ long_description=long_description,
15
+ long_description_content_type="text/markdown",
16
+ url="https://github.com/TheDIMONDK/miet_schedule_api",
17
+ packages=find_packages(),
18
+ classifiers=[
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ ],
23
+ python_requires=">=3.6",
24
+ install_requires=[
25
+ "requests>=2.25.0",
26
+ ],
27
+ )