diff --git a/dtek_notif/main.py b/dtek_notif/main.py
index 6637257..3896473 100644
--- a/dtek_notif/main.py
+++ b/dtek_notif/main.py
@@ -1,10 +1,3 @@
-# Раздел "ТВАРИ, ЧИТАТЕ ВНИМАТЕЛЬНО!"
-
-# Когда обновят сайт -- расскоментровать 641-646 и закоментировать 647.
-# Поменять комменты 671 и 672 местами.
-
-
-
import requests
import json
import asyncio
@@ -89,7 +82,7 @@ def get_day_statistics(day_blocks: List[Dict]) -> Dict[str, int]:
# ============================================================================
def parse_html(html: str) -> List[Dict]:
- """Парсит HTML с графиком отключений (нова логіка)"""
+ """Парсит HTML с графиком отключений (логика от 15.11.2024)"""
soup = BeautifulSoup(html, "html.parser")
cells = soup.select(".disconnection-detailed-table-cell.cell")
@@ -103,56 +96,71 @@ def parse_html(html: str) -> List[Dict]:
cell_classes = cell.get('class', [])
- # Перевіряємо чи вся година вимкнена
+ # ПРоверка статуса отключения на весь час
full_hour_off = 'has_disconnection' in cell_classes and 'full_hour' in cell_classes
- no_disconnection = 'no_disconnection' in cell_classes
+ no_disconnection_cell = 'no_disconnection' in cell_classes
hour_block = cell.select_one(".hour_block")
if not hour_block:
continue
- # Визначаємо статус та підтвердження для всієї години
- confirmed = None
+ # Проверка подтверждённости отключения для всего часа
+ cell_confirmed = None
if 'confirm_1' in cell_classes:
- confirmed = True
+ cell_confirmed = True
elif 'confirm_0' in cell_classes:
- confirmed = False
+ cell_confirmed = False
- # Шукаємо часткові відключення через div.fill
- fill_divs = hour_block.select(".fill")
+ # Проверка половин часа
+ left = hour_block.select_one(".half.left")
+ right = hour_block.select_one(".half.right")
- first_half_data = {"status": "on", "queue": None, "confirmed": None}
- second_half_data = {"status": "on", "queue": None, "confirmed": None}
+ def parse_half(half, is_full_hour_off: bool) -> Dict:
+ """Парсит половину часа"""
+ if not half:
+ return {"status": "on", "queue": None, "confirmed": None}
+
+ half_classes = half.get('class', [])
+
+ # Если вся ячейка full_hour - используем статус ячейки
+ if is_full_hour_off:
+ return {"status": "off", "queue": None, "confirmed": cell_confirmed}
+
+ # Определяем статус половины
+ if 'has_disconnection' in half_classes:
+ status = "off"
+ elif 'no_disconnection' in half_classes:
+ status = "on"
+ else:
+ status = "on" # По умолчанию считаем включенным
+
+ # Если выключено - ищем подробности
+ queue = None
+ confirmed = None
+
+ if status == "off":
+ disconnection_div = half.select_one(".disconnection")
+ if disconnection_div:
+ # Ищем номер черги в title
+ if disconnection_div.has_attr("title"):
+ title = disconnection_div["title"]
+ if "Номер черги" in title or "Номер черги:" in title:
+ try:
+ queue = title.split(":")[-1].strip()
+ except:
+ pass
+
+ # Определяем подтверждение
+ disc_classes = disconnection_div.get('class', [])
+ if 'disconnection_confirm_1' in disc_classes:
+ confirmed = True
+ elif 'disconnection_confirm_0' in disc_classes:
+ confirmed = False
+
+ return {"status": status, "queue": queue, "confirmed": confirmed}
- if full_hour_off:
- # Вся година вимкнена
- first_half_data = {"status": "off", "queue": None, "confirmed": confirmed}
- second_half_data = {"status": "off", "queue": None, "confirmed": confirmed}
- elif no_disconnection and not fill_divs:
- # Вся година ввімкнена
- first_half_data = {"status": "on", "queue": None, "confirmed": None}
- second_half_data = {"status": "on", "queue": None, "confirmed": None}
- else:
- # Перевіряємо часткові відключення
- for fill_div in fill_divs:
- title = fill_div.get('title', '')
- style = fill_div.get('style', '')
- fill_classes = fill_div.get('class', [])
-
- # Визначаємо підтвердження
- fill_confirmed = None
- if 'confirmed' in fill_classes:
- fill_confirmed = True
- elif 'possible' in fill_classes:
- fill_confirmed = False
-
- # Парсимо стиль для визначення часу
- # --start:0;--size:50 означає 0-30 хвилин (перша половина)
- # --start:50;--size:50 означає 30-60 хвилин (друга половина)
- if '--start:0' in style or title.endswith(':00—' + f'{current_hour:02d}:30'):
- first_half_data = {"status": "off", "queue": None, "confirmed": fill_confirmed}
- elif '--start:50' in style or (f'{current_hour:02d}:30' in title and title.endswith(':00')):
- second_half_data = {"status": "off", "queue": None, "confirmed": fill_confirmed}
+ first_half_data = parse_half(left, full_hour_off)
+ second_half_data = parse_half(right, full_hour_off)
schedule.append({
"hour": current_hour,
@@ -168,6 +176,7 @@ def parse_html(html: str) -> List[Dict]:
return schedule
+
def get_voe_html(city_id: int, street_id: int, house_id: int) -> str:
"""Получает HTML с сайта VOE"""
url = "https://www.voe.com.ua/disconnection/detailed?ajax_form=1&_wrapper_format=drupal_ajax"
@@ -582,7 +591,12 @@ async def cmd_info(message: Message):
await message.answer(
"ℹ️ Про бота\n\n"
- "🚀 Версія: 2.1 (Оптимізована)\n"
+ "🚀 Версія: 2.2 (Стабільна)\n\n"
+ "📝 Реліз-ноути:\n"
+ "├ 15.11.2024: Адаптація під оновлену логіку сайту VOE\n"
+ "├ Виправлено парсинг half.left та half.right\n"
+ "├ Покращено визначення підтвердження відключень\n"
+ "└ Оптимізовано обробку статусу для всієї години\n\n"
"⚡ Функціональність:\n"
"├ Моніторинг графіку 24/7\n"
"├ Сповіщення за 5 хвилин\n"
@@ -645,21 +659,18 @@ async def cmd_tomorrow(message: Message):
return
try:
- # """Закоментировал до лучших времен"""
- # await message.answer("⏳ Завантаження графіку завтра...")
- # html = get_voe_html(VOE_CITY_ID, VOE_STREET_ID, VOE_HOUSE_ID)
- # schedule = parse_html(html)
- # text = format_single_day_schedule(schedule, 1)
- # await message.answer(text, parse_mode="HTML", reply_markup=get_main_keyboard())
- await message.answer("❌ Функція тимчасово недоступна. Чекаємо на оновлення сайту", parse_mode="HTML", reply_markup=get_main_keyboard())
+ await message.answer("⏳ Завантаження графіку завтра...")
+ html = get_voe_html(VOE_CITY_ID, VOE_STREET_ID, VOE_HOUSE_ID)
+ schedule = parse_html(html)
+ text = format_single_day_schedule(schedule, 1)
+ await message.answer(text, parse_mode="HTML", reply_markup=get_main_keyboard())
+ # await message.answer("❌ Функція тимчасово недоступна. Чекаємо на оновлення сайту", parse_mode="HTML", reply_markup=get_main_keyboard())
except Exception as e:
await message.answer(
f"❌ Помилка: {str(e)}",
parse_mode="HTML",
reply_markup=get_main_keyboard()
)
-# Когда обновят сайт -- расскоментровать 641-646 и закоментировать 647.
-# Поменять комменты 671 и 672 местами.
@dp.message(Command("check"))
@@ -675,8 +686,7 @@ async def cmd_check(message: Message):
new_schedule = parse_html(html)
prefix = "✅ Знайдено зміни!\n\n" if schedules_differ(last_schedule, new_schedule) else "✓ Графік без змін\n\n"
- # result = prefix + format_schedule_message(new_schedule, days_to_show=2)
- result = prefix + format_schedule_message(new_schedule, days_to_show=1)
+ result = prefix + format_schedule_message(new_schedule, days_to_show=2)
await message.answer(result, parse_mode="HTML", reply_markup=get_main_keyboard())
except Exception as e:
@@ -703,9 +713,9 @@ async def handle_text(message: Message):
elif text == "📅 Сьогодні":
await cmd_today(message)
- # # Кнопка "Завтра"
- # elif text == "📅 Завтра":
- # await cmd_tomorrow(message)
+ # Кнопка "Завтра"
+ elif text == "📅 Завтра":
+ await cmd_tomorrow(message)
# Кнопка "Оновити"
elif text == "🔄 Оновити":
@@ -733,7 +743,7 @@ async def handle_text(message: Message):
async def main():
"""Главная функция"""
logger.info("=" * 50)
- logger.info("🚀 ЗАПУСК БОТА V2.1 (ОПТИМІЗОВАНА ВЕРСІЯ)")
+ logger.info("ЗАПУСК БОТА V2.2 (stable 2.2, 15.11.2025)")
logger.info("=" * 50)
if not TELEGRAM_TOKEN or TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN", "YOUR_TOKEN_HERE")
@@ -744,7 +754,7 @@ async def main():
logger.error("❌ ALLOWED_CHAT_IDS не конфігуровані! Напишіть ID в .env файл")
return
- logger.info(f"🔌 Дозволені чати: {ALLOWED_CHAT_IDS}")
+ logger.info(f"📌 Allowed chat ids: {ALLOWED_CHAT_IDS}")
logger.info(f"⏱ Інтервал перевірки: {CHECK_INTERVAL} сек")
logger.info("=" * 50)