feat: telegram commands, app settings, bot polling, webhook handling, UI improvements
Adds telegram bot command system with 13 commands (search, latest, random, etc.), webhook/polling handlers, rate limiting, app settings page, and various UI/UX improvements across all entity pages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,8 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from notify_bridge_core.models.events import ServiceEvent
|
||||
from notify_bridge_core.notifications.dispatcher import NotificationDispatcher, TargetConfig
|
||||
from notify_bridge_core.providers.immich import ImmichServiceProvider
|
||||
from notify_bridge_core.notifications.telegram.cache import TelegramFileCache
|
||||
from notify_bridge_core.storage import JsonFileBackend
|
||||
|
||||
from ..database.engine import get_engine
|
||||
from ..database.models import (
|
||||
@@ -28,6 +29,29 @@ from ..database.models import (
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Module-level Telegram file caches — shared across dispatches for reuse
|
||||
_url_cache: TelegramFileCache | None = None
|
||||
_asset_cache: TelegramFileCache | None = None
|
||||
|
||||
|
||||
async def _get_telegram_caches() -> tuple[TelegramFileCache | None, TelegramFileCache | None]:
|
||||
"""Lazily initialize shared Telegram file caches using NOTIFY_BRIDGE_DATA_DIR."""
|
||||
global _url_cache, _asset_cache
|
||||
if _url_cache is not None:
|
||||
return _url_cache, _asset_cache
|
||||
import os
|
||||
from pathlib import Path
|
||||
data_dir = os.environ.get("NOTIFY_BRIDGE_DATA_DIR")
|
||||
if not data_dir:
|
||||
return None, None
|
||||
cache_dir = Path(data_dir) / "cache"
|
||||
_url_cache = TelegramFileCache(JsonFileBackend(cache_dir / "telegram_url_cache.json"))
|
||||
_asset_cache = TelegramFileCache(JsonFileBackend(cache_dir / "telegram_asset_cache.json"))
|
||||
await _url_cache.async_load()
|
||||
await _asset_cache.async_load()
|
||||
_LOGGER.info("Initialized Telegram file caches in %s", cache_dir)
|
||||
return _url_cache, _asset_cache
|
||||
|
||||
|
||||
def _in_quiet_hours(start: str | None, end: str | None) -> bool:
|
||||
"""Check if the current UTC time is within the quiet hours window."""
|
||||
@@ -131,6 +155,7 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
new_state: dict[str, Any] = {}
|
||||
|
||||
if provider_type == "immich":
|
||||
from notify_bridge_core.providers.immich import ImmichServiceProvider
|
||||
async with aiohttp.ClientSession() as http_session:
|
||||
immich = ImmichServiceProvider(
|
||||
http_session,
|
||||
@@ -208,7 +233,8 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
)
|
||||
|
||||
if events and link_data:
|
||||
dispatcher = NotificationDispatcher()
|
||||
url_cache, asset_cache = await _get_telegram_caches()
|
||||
dispatcher = NotificationDispatcher(url_cache=url_cache, asset_cache=asset_cache)
|
||||
for event in events:
|
||||
_LOGGER.info(
|
||||
"Dispatching event %s for %s (added=%d removed=%d)",
|
||||
@@ -239,7 +265,7 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
config=ld["target_config"],
|
||||
template_slots=slots,
|
||||
date_format=tmpl.date_format if tmpl else "%d.%m.%Y, %H:%M UTC",
|
||||
date_only_format=tmpl.date_only_format if tmpl and hasattr(tmpl, "date_only_format") else "%d.%m.%Y",
|
||||
date_only_format=tmpl.date_only_format if tmpl and tmpl.date_only_format else "%d.%m.%Y",
|
||||
provider_api_key=provider_config.get("api_key"),
|
||||
provider_internal_url=provider_config.get("url", ""),
|
||||
provider_external_url=provider_config.get("external_domain", ""),
|
||||
|
||||
Reference in New Issue
Block a user