✨ 8 major features: trafilatura, digest, ntfy actions, templates, FTS5 search, backup/restore, proxy, RSS reader
build-and-push / docker (push) Has been cancelled
build-and-push / docker (push) Has been cancelled
- Full article extraction via trafilatura (fetch_full_article)
- Digest mode with configurable period (digest_enabled, digest_period_hours)
- ntfy Actions buttons (Open article, Open feed)
- Notification templates with {title}, {body}, {link}, {source}, {image_url}
- FTS5 full-text search in notification history
- Database backup/restore (download/upload .db)
- HTTP/SOCKS proxy for RSS feed fetching (proxy_url setting)
- Built-in RSS reader tab with categories, unread counts, article detail view
- Auto-category 'Общее' for feeds without a category
- Article storage (Article table) for reader
- DigestEntry model for pending digest entries
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+112
-3
@@ -5,7 +5,9 @@
|
||||
<div class="brand"><span class="logo">📡</span> RSS → ntfy</div>
|
||||
<nav class="tabs">
|
||||
<button class="tab active" data-tab="feeds" data-i18n="nav.feeds">Ленты</button>
|
||||
<button class="tab" data-tab="reader" data-i18n="nav.reader">Чтение</button>
|
||||
<button class="tab" data-tab="history" data-i18n="nav.history">История</button>
|
||||
<button class="tab admin-only" data-tab="categories" data-i18n="nav.categories">Категории</button>
|
||||
<button class="tab admin-only" data-tab="users" data-i18n="nav.users">Пользователи</button>
|
||||
<button class="tab admin-only" data-tab="settings" data-i18n="nav.settings">Настройки</button>
|
||||
</nav>
|
||||
@@ -39,6 +41,9 @@
|
||||
<div class="panel-head-actions">
|
||||
<button class="btn ghost" id="check-all" data-i18n="feeds.checkAll">↻ Проверить все</button>
|
||||
<button class="btn ghost admin-only" id="import-btn" data-i18n="feeds.import">⬆ Импорт OPML</button>
|
||||
<button class="btn ghost admin-only" id="backup-btn" data-i18n="feeds.backup">💾 Бэкап</button>
|
||||
<button class="btn ghost admin-only" id="restore-btn" data-i18n="feeds.restore">📥 Восстановить</button>
|
||||
<input type="file" id="restore-file" accept=".db" hidden>
|
||||
<button class="btn ghost" id="export-btn" data-i18n="feeds.export">⬇ Экспорт OPML</button>
|
||||
<button class="btn primary admin-only" id="add-feed" data-i18n="feeds.add">+ Добавить ленту</button>
|
||||
<input type="file" id="opml-file" accept=".opml,.xml,text/xml" hidden>
|
||||
@@ -51,7 +56,30 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== HISTORY ===================== -->
|
||||
<!-- ===================== READER ===================== -->
|
||||
<section id="tab-reader" class="tab-panel">
|
||||
<div class="reader-layout">
|
||||
<aside class="reader-sidebar">
|
||||
<div class="reader-cats" id="reader-cat-list">
|
||||
<div class="reader-cat active" data-cat="all" data-i18n="reader.all">Все</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="reader-main">
|
||||
<div class="panel-head">
|
||||
<h2 data-i18n="nav.reader">Чтение</h2>
|
||||
<button class="btn ghost" id="reader-mark-all" data-i18n="reader.markAll">Отметить все прочитанными</button>
|
||||
</div>
|
||||
<div id="reader-list"></div>
|
||||
<div id="reader-detail" class="hidden"></div>
|
||||
<div id="reader-empty" class="empty hidden">
|
||||
<div class="empty-icon">📖</div>
|
||||
<p data-i18n="reader.empty">Статей пока нет. Добавьте ленты, чтобы начать читать.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== HISTORY ===================== -->
|
||||
<section id="tab-history" class="tab-panel">
|
||||
<div class="panel-head">
|
||||
<h2 data-i18n="history.heading">История уведомлений</h2>
|
||||
@@ -72,7 +100,20 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== USERS ===================== -->
|
||||
<!-- ===================== CATEGORIES ===================== -->
|
||||
<section id="tab-categories" class="tab-panel">
|
||||
<div class="panel-head">
|
||||
<h2 data-i18n="categories.heading">Категории</h2>
|
||||
<button class="btn primary" id="add-category" data-i18n="categories.add">+ Добавить категорию</button>
|
||||
</div>
|
||||
<div id="categories-list" class="cards"></div>
|
||||
<div id="categories-empty" class="empty hidden">
|
||||
<div class="empty-icon">🏷️</div>
|
||||
<p data-i18n="categories.empty">Категорий пока нет.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== USERS ===================== -->
|
||||
<section id="tab-users" class="tab-panel">
|
||||
<div class="panel-head">
|
||||
<h2 data-i18n="users.heading">Пользователи</h2>
|
||||
@@ -108,13 +149,40 @@
|
||||
<button type="button" class="btn ghost" id="test-btn" data-i18n="settings.testBtn">Отправить тест</button>
|
||||
</div>
|
||||
|
||||
<h3 data-i18n="settings.check">Проверка</h3>
|
||||
<label><span data-i18n="settings.proxyUrl">URL прокси</span> <small class="muted" data-i18n="settings.proxyHint"></small>
|
||||
<input type="text" name="proxy_url" placeholder="http://proxy:8080"></label>
|
||||
|
||||
<h3 data-i18n="settings.template">Шаблон уведомлений</h3>
|
||||
<label><span data-i18n="settings.templateHint">Переменные: {title}, {body}, {link}, {source}, {image_url}</span>
|
||||
<textarea name="notification_template" rows="3" style="width:100%;margin-top:4px;padding:8px;background:var(--bg-soft);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:monospace;font-size:13px;resize:vertical"></textarea></label>
|
||||
|
||||
<h3 data-i18n="settings.check">Проверка</h3>
|
||||
<label><span data-i18n="settings.interval">Интервал проверки по умолчанию (минуты)</span>
|
||||
<input type="number" name="check_interval" min="1" value="5">
|
||||
<small class="muted" data-i18n="settings.intervalHint"></small>
|
||||
</label>
|
||||
|
||||
<h3 data-i18n="settings.telegram">Telegram</h3>
|
||||
<h3 data-i18n="settings.feedDefaults">Значения по умолчанию для новых лент</h3>
|
||||
<div class="grid-2">
|
||||
<label><span data-i18n="feed.priority">Приоритет</span>
|
||||
<select name="default_priority">
|
||||
<option value="1" data-i18n="feed.p1"></option>
|
||||
<option value="2" data-i18n="feed.p2"></option>
|
||||
<option value="3" selected data-i18n="feed.p3"></option>
|
||||
<option value="4" data-i18n="feed.p4"></option>
|
||||
<option value="5" data-i18n="feed.p5"></option>
|
||||
</select>
|
||||
</label>
|
||||
<label><span data-i18n="feed.intervalMin">Интервал, мин</span> <small class="muted" data-i18n="feed.intervalHint"></small>
|
||||
<input type="number" name="default_interval" min="0" value="0"></label>
|
||||
</div>
|
||||
<label><span data-i18n="feed.tags">Теги / эмодзи</span> <small class="muted" data-i18n="feed.commaHint"></small>
|
||||
<input type="text" name="default_tags" placeholder="newspaper,fire"></label>
|
||||
<label class="switch-row"><span data-i18n="feed.attach">Прикреплять картинку</span>
|
||||
<input type="checkbox" name="default_attach_image" class="switch" checked></label>
|
||||
|
||||
<h3 data-i18n="settings.telegram">Telegram</h3>
|
||||
<label class="switch-row"><span data-i18n="settings.tgEnable">Включить доставку в Telegram</span>
|
||||
<input type="checkbox" name="telegram_enabled" class="switch"></label>
|
||||
<div class="grid-2">
|
||||
@@ -169,6 +237,11 @@
|
||||
<label><span data-i18n="feed.title">Название</span> <small class="muted" data-i18n="feed.titleOpt"></small>
|
||||
<input type="text" name="title">
|
||||
</label>
|
||||
<label><span data-i18n="feed.category">Категория</span>
|
||||
<select name="category_id">
|
||||
<option value="" data-i18n="feed.categoryNone">— без категории —</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="grid-2">
|
||||
<label><span data-i18n="feed.server">Сервер ntfy</span> <small class="muted" data-i18n="feed.serverHint"></small>
|
||||
<input type="text" name="ntfy_server" placeholder="https://ntfy.sh"></label>
|
||||
@@ -201,6 +274,15 @@
|
||||
<label><span data-i18n="feed.intervalMin">Интервал, мин</span> <small class="muted" data-i18n="feed.intervalHint"></small>
|
||||
<input type="number" name="interval" min="0" value="0"></label>
|
||||
</div>
|
||||
|
||||
<details class="adv">
|
||||
<summary data-i18n="feed.digest">Дайджест</summary>
|
||||
<label class="switch-row"><span data-i18n="feed.digestEnable">Накапливать записи (дайджест)</span>
|
||||
<input type="checkbox" name="digest_enabled" class="switch"></label>
|
||||
<label><span data-i18n="feed.digestPeriod">Период дайджеста (часы)</span>
|
||||
<input type="number" name="digest_period_hours" min="1" value="24"></label>
|
||||
</details>
|
||||
|
||||
<label><span data-i18n="feed.tags">Теги / эмодзи</span> <small class="muted" data-i18n="feed.commaHint"></small>
|
||||
<input type="text" name="tags" placeholder="newspaper,fire"></label>
|
||||
|
||||
@@ -214,6 +296,12 @@
|
||||
<div class="switch-grid">
|
||||
<label class="switch-row"><span data-i18n="feed.attach">Прикреплять картинку</span>
|
||||
<input type="checkbox" name="attach_image" class="switch" checked></label>
|
||||
<label class="switch-row"><span data-i18n="feed.fetchArticle">Загружать полную статью (trafilatura)</span>
|
||||
<input type="checkbox" name="fetch_full_article" class="switch"></label>
|
||||
<small class="muted" data-i18n="feed.fetchArticleHint" style="margin-top:-8px;display:block">Загружает страницу статьи и извлекает основной текст.</small>
|
||||
<label class="switch-row"><span data-i18n="feed.fullContent">Отправлять полный контент</span>
|
||||
<input type="checkbox" name="send_full_content" class="switch"></label>
|
||||
<small class="muted" data-i18n="feed.fullContentHint" style="margin-top:-8px;display:block">Весь текст, все картинки и видео. Для ntfy — Markdown.</small>
|
||||
<label class="switch-row"><span data-i18n="feed.dupTg">Дублировать в Telegram</span>
|
||||
<input type="checkbox" name="to_telegram" class="switch"></label>
|
||||
<label class="switch-row"><span data-i18n="feed.toWebhook">Отправлять в webhook</span>
|
||||
@@ -234,6 +322,27 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- ===================== CATEGORY MODAL ===================== -->
|
||||
<div id="cat-modal" class="modal-backdrop hidden">
|
||||
<form class="modal" id="cat-form">
|
||||
<div class="modal-head">
|
||||
<h3 id="cat-modal-title" data-i18n="cat.addTitle">Добавить категорию</h3>
|
||||
<button type="button" class="icon-btn" id="cat-modal-close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="id">
|
||||
<label><span data-i18n="cat.name">Название *</span>
|
||||
<input type="text" name="name" required></label>
|
||||
<label><span data-i18n="cat.sortOrder">Порядок сортировки</span>
|
||||
<input type="number" name="sort_order" min="0" value="0"></label>
|
||||
</div>
|
||||
<div class="modal-foot">
|
||||
<button type="button" class="btn ghost" id="cat-modal-cancel" data-i18n="modal.cancel">Отмена</button>
|
||||
<button type="submit" class="btn primary" data-i18n="modal.save">Сохранить</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- ===================== USER MODAL ===================== -->
|
||||
<div id="user-modal" class="modal-backdrop hidden">
|
||||
<form class="modal" id="user-form">
|
||||
|
||||
Reference in New Issue
Block a user