12 KiB
Tg-notify.bot
Фоновый Telegram-бот уведомлений о новых сериях и озвучках (long polling). Пользователь подписывается на сериал прямо из карточки Lampa, а бот сам отслеживает выход новых эпизодов и появление выбранной озвучки и шлёт уведомление в Telegram с обложкой, номером серии и описанием из TMDB.
Проект: Modules/Tg-notify.bot/. C#-namespace модуля — TelegramBot.
Бот объединяет три подсистемы:
- Трекер новых серий — Trakt API (приоритет) с фоллбэком на TMDB.
- Трекер озвучек — параллельный опрос балансеров Mirage, Collaps и VideoHub (поиск по названию или kinopoisk_id, мультиозвучка, чистый JSON). Берётся максимальный эпизод из всех источников — кто первым выложил серию в нужной озвучке, от того и уведомление.
- Клиентский плагин Lampa (
tg-notify.js) — вкладка «TG Подписки», перехват кнопки 🔔 в карточке, меню выбора озвучки.
Включение
- В шаблоне
config/base.confпри необходимости проверьте, чтоTelegramBotне попал вBaseModule.SkipModules(если попал — уберите имя из списка, иначе модуль не загрузится). manifest.json: выставьте"enable": true(в репозитории по умолчаниюfalse).init.conf: добавьте секциюTelegramBot. Пример —init.merge.example.json.- Перезапустите сервис:
systemctl restart lampac(или имя вашего systemd-юнита).
При enable: true и пустом bot_token long polling не стартует — в лог пишется предупреждение.
Конфигурация (секция init.conf)
"TelegramBot": {
"enable": true,
"bot_token": "ТОКЕН_ОТ_BOTFATHER",
"tmdb_api_key": "ВАШ_КЛЮЧ_TMDB",
"trakt_client_id": "",
"lampac_host": "http://127.0.0.1:9118",
"lampac_token": "",
"kp_api_key": "",
"check_interval_minutes": 60,
"tmdb_lang": "ru-RU",
"data_dir": "database/tgnotify"
}
| Поле | Назначение |
|---|---|
bot_token |
Токен бота от @BotFather. Обязателен. |
tmdb_api_key |
Ключ TMDB v3 — обложки, описания эпизодов, определение актуального сезона. |
trakt_client_id |
Client ID приложения Trakt. Если задан — основной источник новых серий; если пуст — используется только TMDB. |
lampac_host |
Базовый URL самого Lampac для запросов к балансерам (/lite/mirage, /lite/collaps). Обычно локальный: http://127.0.0.1:9118. |
lampac_token |
Токен accsdb. Обязателен, если у вас включена защита accsdb — без него балансеры вернут {"accsdb":true,"msg":"Войдите в аккаунт"}. |
kp_api_key |
Ключ kinopoiskapiunofficial.tech — резолвинг tmdb_id → kinopoisk_id по названию для источника VideoHub. Опционально: если пусто, kinopoisk_id берётся только из встроенного моста Lampac /externalids (покрытие ~40%); с ключом — фоллбэк через поиск по названию поднимает покрытие почти до полного. |
check_interval_minutes |
Период фоновой проверки подписок. По умолчанию 60. Первый прогон — через 2 минуты после старта. |
tmdb_lang |
Язык метаданных TMDB. По умолчанию ru-RU (с фоллбэком на en-US при пустом описании). |
data_dir |
Каталог хранения users.json / subscriptions.json. По умолчанию database/tgnotify. |
Зависимости
Telegram.Bot22.4.4 — кладётся вreferences/(для рантайм-компиляции Roslyn) и подтягивается черезPackageReferenceпри локальной сборке.- TMDB API — ключ v3 (
tmdb_api_key). - Trakt API (опционально) —
trakt_client_idдля более точного и быстрого трекинга выхода серий. - Балансеры Mirage, Collaps и VideoHub (
/lite/cdnvideohub) должны быть доступны поlampac_host. - kinopoiskapiunofficial.tech (опционально) —
kp_api_key. Нужен только для VideoHub: резолвитkinopoisk_idпо названию, когда встроенный мост Lampac его не знает.
Структура модуля
Tg-notify.bot/
├── manifest.json # dynamic:true, references+tree
├── Tg-notify.bot.csproj # только для локальной сборки; на сервере не используется
├── init.merge.example.json # пример секции init.conf
├── ModInit.cs # ядро: polling, трекинг серий, парсеры озвучек, HTTP API
├── Models/
│ └── TelegramBotConf.cs # конфиг (наследует ModuleBaseConf)
├── Controllers/
│ └── TgNotifyController.cs # HTTP API + раздача tg-notify.js
├── references/
│ └── Telegram.Bot.dll # 22.4.4
└── tg-notify.js # клиентский плагин Lampa
На сервере модуль компилируется рантайм-движком Roslyn по
manifest.json(dynamic: true) —.csprojнужен только для локальной разработки. Поляreferencesиtreeобязательны.
Как работает
Привязка аккаунта
UID пользователя определяется так же, как для закладок и тайм-кодов: плагин передаёт token, account_email и uid устройства, сервер берёт первое непустое (RequestInfo.getuid). Вошёл в аккаунт CUB — подписки общие для всех его устройств.
Из вкладки «TG Подписки» в Lampa пользователь получает deep-link на бота. Telegram пропускает в параметре только A-Za-z0-9_- (до 64 символов), поэтому UID вида email уходит как link64_{base64url(uid)}, остальные — как раньше, link_{uid}. Бот сохраняет связку chat_id ↔ lampac_uid (users.json), после чего подписки этого UID становятся «его». Привязка, сделанная раньше по uid устройства, продолжает работать: если под основным UID привязки нет, API ищет её по uid устройства.
Подписка
В карточке сериала плагин перехватывает кнопку 🔔 и показывает меню озвучек (/api/tg/voices → Mirage + Collaps + VideoHub). Выбор отправляется в /api/tg/subscribe и сохраняется в subscriptions.json.
Фоновый цикл CheckAll
Раз в check_interval_minutes (и вручную командой /check) по каждой подписке:
- Новые серии —
CheckNewEpisodes(Trakt → TMDB). Если у подписки не выбрана конкретная озвучка — уведомление шлётся о самом факте выхода серии. - Озвучки (если озвучка выбрана) — параллельно (
Task.WhenAll) опрашиваются Mirage, Collaps и VideoHub; берётся максимальный доступный эпизод; кто первый нашёл новую серию — от того уведомление. На каждую новую серию шлётся отдельное сообщение с инфой из TMDB.
VideoHub и kinopoisk_id. VideoHub ищет контент только по
kinopoisk_id, тогда как бот работает поtmdb_id. Резолвинг выполняется лениво и кешируется в самой подписке: сначала через встроенный мост Lampac/externalids, при неудаче — поиском по названию черезkp_api_key. Имя озвучки в запросе URL-кодируется (кириллица иначе даёт HTTP 400). Еслиkinopoisk_idне нашёлся, VideoHub для этой подписки молча пропускается — Mirage и Collaps продолжают работать.
Формат уведомления:
🎬 Название
🎙 Озвучка
📺 S05E08 — Название эпизода
Описание (до 300 символов)
С обложкой кадра (SendPhoto), если у эпизода есть still_path.
Команды бота
| Команда / кнопка | Действие |
|---|---|
/start |
Приветствие; /start link_{uid} или /start link64_{base64url(uid)} — привязка аккаунта |
/list · «📋 Подписки» |
Список активных подписок |
/check · «🔍 Проверить» |
Принудительная проверка (в фоне) |
/help · «📖 Помощь» |
Справка |
/unlink · «🔓 Отвязать» |
Отвязать аккаунт |
HTTP API (TgNotifyController : BaseController)
| Метод | Маршрут | Назначение |
|---|---|---|
GET |
/tg-notify.js |
Раздаёт клиентский плагин с автозаменой {localhost} → реальный хост. [AllowAnonymous] |
POST |
/api/tg/subscribe |
Подписка на сериал/озвучку |
POST |
/api/tg/unsubscribe |
Отписка |
GET |
/api/tg/status?tmdb_id= |
Статус подписки текущего пользователя |
GET |
/api/tg/voices?title=&year=&season=&tmdb_id= |
Список доступных озвучек |
GET |
/api/tg/link |
Ссылка привязки бота |
GET |
/api/tg/subscriptions |
Все подписки пользователя с метаданными |
Все маршруты, кроме /tg-notify.js и /api/tg/voices, требуют requestInfo.user_uid.
Клиентский плагин (tg-notify.js)
Подключается через customPlugins в init.conf либо раздаётся самим модулем по /tg-notify.js:
"LampaWeb": {
"customPlugins": [
{ "url": "{localhost}/tg-notify.js", "status": 1 }
]
}
Возможности: вкладка «TG Подписки» (сетка карточек с бейджем S5 E4), перехват кнопки 🔔 в полной карточке, меню выбора озвучки (Lampa.Select.show, метки Mirage [—] / Collaps [C] / VideoHub [V]), загрузка метаданных через Lampa.TMDB / Lampa.Network.silent с кешем. Хост подставляется через {localhost} — хардкода адресов нет.