RSS/Atom -> ntfy bridge with web UI, OPML import/export and RU/EN localization

Web-managed fork of nurefexc/rss-bridge-ntfy: Flask UI + REST API, background
sync engine (SQLite dedup, quiet hours, filters, flood protection, images),
OPML import/export and switchable interface/notification language.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-06 19:34:53 +08:00
commit 3f9b108482
15 changed files with 2076 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
# RSS → ntfy Bridge (с веб-интерфейсом)
Мост, который следит за RSS/Atom-лентами и отправляет новые записи как push-уведомления
в [ntfy](https://ntfy.sh). В отличие от
[оригинального проекта](https://github.com/nurefexc/rss-bridge-ntfy), где ленты
настраивались через JSON-файлы и переменные окружения, **здесь всё управление
происходит через веб-интерфейс** — добавление лент, топиков, расписаний и
глобальных настроек, запуск синхронизации, просмотр журнала и отправка тестовых
уведомлений.
Проект упакован в Docker и запускается одной командой.
---
## Возможности
- 🌐 **Полное управление через браузер** — фиды, топики, настройки, без правки файлов.
- 🔔 **Отправка в ntfy** с заголовком, ссылкой (Click), Markdown, иконкой и картинкой (Attach).
- 🧠 **Дедупликация** через SQLite (WAL) — одна запись не приходит дважды.
- 🌙 **Тихие часы** — пониженный приоритет в заданном интервале (напр. `22-7`).
- 🧹 **Фильтры** include/exclude по регулярным выражениям.
- 🌊 **Флуд-защита** — ступенчатая задержка доставки для записей с низким приоритетом.
- 🖼️ **Картинки и описание** автоматически извлекаются из HTML записи.
- 📜 **Живой журнал** и дашборд со статусом прямо в интерфейсе.
- ▶️ **Кнопки** «Синхронизировать сейчас», «Пауза/Возобновить», «Тестовое уведомление».
- 📥 **Импорт/экспорт OPML** — перенос списка лент между ридерами (с сохранением ntfy-параметров).
- 🌍 **Локализация интерфейса** — переключение языка (RU/EN) прямо в шапке; влияет и на текст уведомлений.
- 💾 **Все данные в одном томе** `./data` (настройки, фиды, история, логи).
---
## Быстрый старт (Docker Compose) — рекомендуется
Требуется установленный **Docker** и **Docker Compose**.
```bash
# 1. Перейти в каталог проекта
cd rss-bridge-ntfy
# 2. Собрать образ и запустить контейнер
docker compose up -d --build
# 3. Открыть веб-интерфейс
# http://localhost:8080
```
Готово. Откройте **http://localhost:8080**, перейдите на вкладку **«Фиды»** и
добавьте первую ленту.
Полезные команды:
```bash
docker compose logs -f # смотреть логи
docker compose restart # перезапустить
docker compose down # остановить и удалить контейнер (данные в ./data сохранятся)
```
### Настройка перед запуском (необязательно)
В файле `docker-compose.yml` можно поменять:
- **Порт.** `"8080:8080"` → например `"9000:8080"`, тогда интерфейс будет на `:9000`.
- **Часовой пояс.** `TZ: "Europe/Moscow"` — влияет на тихие часы и время в логах.
> Адрес ntfy-сервера и токен задаются **не здесь, а в самом интерфейсе**
> (вкладка «Настройки»). По умолчанию используется публичный `https://ntfy.sh`.
---
## Запуск через `docker run` (без Compose)
```bash
docker build -t rss-bridge-ntfy-web .
docker run -d \
--name rss-bridge-ntfy \
-p 8080:8080 \
-e TZ=Europe/Moscow \
-v "$(pwd)/data:/data" \
--restart unless-stopped \
rss-bridge-ntfy-web
```
---
## Запуск без Docker (для разработки)
Требуется **Python 3.11+**.
```bash
pip install -r requirements.txt
python main.py
# Интерфейс: http://localhost:8080
```
Переменные окружения (необязательно): `PORT` (по умолчанию `8080`),
`HOST` (`0.0.0.0`), `DATA_DIR` (`data`), `TZ` (`UTC`).
---
## Как пользоваться интерфейсом
Интерфейс состоит из трёх вкладок.
### 1. Дашборд
- Карточки со статистикой: число фидов, топиков, отправленных уведомлений, записей в истории.
- Состояние движка, время последней и следующей синхронизации.
- **Тестовое уведомление** — введите топик и текст, проверьте доставку в ntfy.
- **Журнал** работы в реальном времени и кнопка очистки истории дедупликации.
- В шапке: **«Синхронизировать»** (запустить цикл немедленно) и **«Пауза/Возобновить»**.
### 2. Фиды
Кнопка **«+ Добавить фид»** открывает форму. Поля:
| Поле | Описание |
|------|----------|
| **Название** | Подпись источника в уведомлении. |
| **URL фида*** | Ссылка на RSS/Atom. |
| **Топик ntfy*** | Топик, в который уйдут уведомления (напр. `news`). |
| **Приоритет** | 1–5 (базовый приоритет уведомления). |
| **Иконка (URL)** | Картинка-иконка уведомления (заголовок `Icon`). |
| **Тихие часы** | Интервал вида `22-7`; в это время используется приоритет ниже. |
| **Приоритет в тихие часы** | Какой приоритет применять в тихие часы (по умолчанию 1). |
| **Include regex** | Показывать только записи, совпадающие с выражением. |
| **Exclude regex** | Отбрасывать записи, совпадающие с выражением. |
| **Включён** | Переключатель активности фида. |
Кнопка **«Проверить фид»** в форме загружает ленту и показывает несколько свежих
заголовков — удобно убедиться, что URL рабочий, ещё до сохранения.
Каждую ленту в списке можно включить/выключить тумблером, отредактировать (✎) или удалить (🗑).
**Импорт/экспорт OPML.** В шапке вкладки «Фиды» есть кнопки:
- **Экспорт OPML** — скачивает файл `feeds.opml` со всеми лентами (ntfy-параметры —
топик, приоритет, тихие часы, фильтры — сохраняются в кастомных атрибутах `ntfy*`).
- **Импорт OPML** — загружает `.opml`-файл и добавляет ленты. Дубликаты (совпадение
по URL и топику) пропускаются. У стандартных OPML-файлов из других ридеров топик
берётся из родительской группы (или `rss`, если её нет), затем его можно поправить.
### Локализация
Язык интерфейса переключается выпадающим списком **RU/EN** в правом верхнем углу.
Выбор сохраняется в настройках на сервере и влияет также на язык ссылки
«Читать на сайте» / «Read on website» в самих уведомлениях.
### 3. Настройки (глобальные)
| Настройка | Описание |
|-----------|----------|
| **ntfy сервер (URL)** | Адрес сервера ntfy (по умолчанию `https://ntfy.sh`; можно указать свой self-hosted). |
| **ntfy токен** | Токен доступа (`Bearer`) для приватных серверов/топиков. Необязательно. |
| **Интервал синхронизации** | Как часто опрашивать ленты, в секундах (по умолчанию 600). |
| **Часовой пояс (IANA)** | Напр. `Europe/Moscow`. Используется для тихих часов. |
| **Лимит новых записей за цикл** | Максимум новых уведомлений на ленту за один проход (по умолчанию 3). |
| **Макс. длина описания** | До скольких символов обрезать текст уведомления. |
| **User-Agent** | Заголовок User-Agent при запросе лент. |
| **Флуд-защита** | Ступенчатые задержки доставки для записей с приоритетом < 4. |
| **Язык (RU/EN)** | Переключается в шапке; влияет на интерфейс и текст уведомлений. |
После сохранения настроек запускается синхронизация.
---
## Получение уведомлений на телефоне
1. Установите приложение **ntfy** ([Android](https://play.google.com/store/apps/details?id=io.heckel.ntfy) / [iOS](https://apps.apple.com/app/ntfy/id1625396347)) или откройте веб-клиент https://ntfy.sh/app.
2. Подпишитесь на топик, который вы указали у фида (например `news`).
3. Новые записи из ленты будут приходить push-уведомлениями.
> Топик в ntfy.sh — это, по сути, публичный канал. Используйте длинное,
> труднодоступное имя топика или собственный сервер ntfy с токеном для приватности.
---
## Где хранятся данные
Всё лежит в каталоге `./data` (примонтирован как том `/data` в контейнере):
| Файл | Назначение |
|------|------------|
| `settings.json` | Глобальные настройки. |
| `feeds.json` | Список лент и их параметры. |
| `history.db` | SQLite-база отправленных записей (дедупликация). |
| `bridge.log` | Файл журнала. |
Резервная копия = копия каталога `data/`. Удаление `history.db` приведёт к
повторной отправке последних записей.
---
## Структура проекта
```
rss-bridge-ntfy/
├── main.py # точка входа: поднимает движок и веб-сервер (waitress)
├── engine.py # ядро: парсинг лент, дедуп, фильтры, отправка в ntfy
├── store.py # потокобезопасное хранилище настроек и фидов (JSON)
├── webapp.py # Flask: REST API + отдача интерфейса
├── opml.py # импорт/экспорт OPML
├── templates/index.html
├── static/css/style.css
├── static/js/app.js
├── static/js/i18n.js # словарь локализации (RU/EN)
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
└── data/ # создаётся при запуске (том с данными)
```
---
## REST API
Интерфейс работает поверх простого API — им можно пользоваться и напрямую:
| Метод | Путь | Назначение |
|-------|------|------------|
| `GET` | `/api/status` | Статус движка и статистика. |
| `POST` | `/api/sync` | Запустить синхронизацию немедленно. |
| `POST` | `/api/engine` | `{"action":"pause"|"resume"}` — пауза/возобновление. |
| `GET` | `/api/logs` | Последние строки журнала. |
| `POST` | `/api/history/clear` | Очистить историю дедупликации. |
| `GET`/`PUT` | `/api/settings` | Получить/обновить глобальные настройки. |
| `GET`/`POST` | `/api/feeds` | Список фидов / создать фид. |
| `PUT`/`DELETE` | `/api/feeds/<id>` | Изменить / удалить фид. |
| `POST` | `/api/feeds/preview` | `{"url":"..."}` — проверить ленту. |
| `GET` | `/api/export/opml` | Скачать все ленты в формате OPML. |
| `POST` | `/api/import/opml` | Загрузить OPML (multipart `file` или тело запроса). |
| `POST` | `/api/test-notify` | `{"topic":"...","message":"..."}` — тест. |
---
## Лицензия
MIT. Основано на идее проекта
[nurefexc/rss-bridge-ntfy](https://github.com/nurefexc/rss-bridge-ntfy).