Initial commit
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# tg-watchbot environment
|
||||
# Create a bot with @BotFather, then put the token here.
|
||||
TELEGRAM_BOT_TOKEN=
|
||||
|
||||
# Telegram numeric chat id that receives monitor notifications and user messages.
|
||||
ADMIN_CHAT_ID=
|
||||
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
# Web admin panel. Bind to localhost by default; use a reverse proxy / Cloudflare Tunnel if exposing it.
|
||||
WEB_PANEL_ENABLED=true
|
||||
WEB_PANEL_HOST=127.0.0.1
|
||||
WEB_PANEL_PORT=8765
|
||||
WEB_PANEL_USER=admin
|
||||
WEB_PANEL_PASSWORD=change-me
|
||||
WEB_PANEL_SESSION_SECRET=
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.env
|
||||
config.yaml
|
||||
memory.md
|
||||
*.log
|
||||
*.sqlite3
|
||||
*.sqlite3-*
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.DS_Store
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,287 @@
|
||||
# tg-watchbot
|
||||
|
||||
tg-watchbot 是一个轻量级 Python 服务,把 **Telegram 双向客服机器人** 和 **Web/RSS 监控推送** 合在一起:
|
||||
|
||||
- 普通用户私聊 Bot,消息会转发给管理员;
|
||||
- 管理员可以直接回复、主动发文字/图片、封禁/备注用户;
|
||||
- 后台定时监控 RSS 或网页,命中关键词、新条目、价格/库存变化后推送给管理员;
|
||||
- 自带一个 Web 管理面板,可配置监控目标、编辑 YAML、查看收件箱和日志。
|
||||
|
||||
项目为单文件应用,适合个人服务器、NAT 小鸡、轻量 VPS 直接用 systemd 跑。
|
||||
|
||||
## 功能
|
||||
|
||||
### Telegram 双向机器人
|
||||
|
||||
- 使用官方 Telegram Bot API,不做 userbot/selfbot。
|
||||
- `/start` 建立用户和管理员之间的联系。
|
||||
- 用户消息先写入 SQLite,再转发给管理员,避免转发失败时丢消息。
|
||||
- 管理员可通过“回复转发消息”直接回给原用户。
|
||||
- 支持显式命令:
|
||||
- `/reply <user_id> <内容>`:给指定用户发文字;
|
||||
- `/sendpic <user_id> [说明]`:给指定用户发图片;
|
||||
- `/block <user_id>`:封禁用户;
|
||||
- `/unblock <user_id>`:解封用户;
|
||||
- `/note <user_id> <备注>`:给用户加备注;
|
||||
- `/who <user_id>`:查看用户信息;
|
||||
- `/cancel`:取消待发送图片。
|
||||
- 普通用户有简单限流,防止刷屏。
|
||||
|
||||
### Web/RSS 监控
|
||||
|
||||
- 支持两类监控:
|
||||
- `rss`:解析 RSS/Atom 条目;
|
||||
- `web`:用 CSS selector 抓网页条目、标题、链接、价格、库存。
|
||||
- 支持触发条件:
|
||||
- 关键词命中;
|
||||
- 新条目;
|
||||
- 价格变化;
|
||||
- 库存变化。
|
||||
- 支持论坛 RSS 增强字段:作者、分类、tags、摘要。
|
||||
- 支持去重,避免同一条反复推送。
|
||||
- 支持屏蔽词、作者、分类过滤(YAML 高级配置)。
|
||||
- 默认最低监控间隔为 60 秒。
|
||||
|
||||
### Web 管理面板
|
||||
|
||||
- 登录页 + HttpOnly session cookie,不使用丑陋的浏览器 Basic Auth。
|
||||
- 监控列表、新增、编辑、删除、手动检查、预览。
|
||||
- NodeSeek / Linux.do RSS 模板。
|
||||
- 批量新增监控。
|
||||
- YAML 高级编辑。
|
||||
- Bot Token / 管理员 ID / 面板账号配置页。
|
||||
- 收件箱页面,可查看用户消息和重试转发。
|
||||
- 主动发消息页面 `/send`,发送成功后会在页面显示结果,并给管理员聊天发送确认提醒。
|
||||
- 自动清理监控/RSS/网站状态数据;不会删除用户、收件箱、双向对话消息。
|
||||
- 日志页面和健康检查 `/health`。
|
||||
|
||||
## 借鉴 / 使用的开源库
|
||||
|
||||
本项目的业务逻辑为自写,主要使用并参考了以下开源库的公开 API 和常见用法:
|
||||
|
||||
- [`aiogram`](https://github.com/aiogram/aiogram):Telegram Bot API、命令、消息处理、复制/发送消息。
|
||||
- [`FastAPI`](https://github.com/fastapi/fastapi):Web 管理面板、表单、路由、中间件。
|
||||
- [`Uvicorn`](https://github.com/encode/uvicorn):ASGI 服务运行。
|
||||
- [`APScheduler`](https://github.com/agronholm/apscheduler):异步定时监控任务。
|
||||
- [`httpx`](https://github.com/encode/httpx):异步 HTTP 抓取。
|
||||
- [`feedparser`](https://github.com/kurtmckee/feedparser):RSS/Atom 解析。
|
||||
- [`Beautiful Soup`](https://www.crummy.com/software/BeautifulSoup/):HTML 解析和 CSS selector 抽取。
|
||||
- [`PyYAML`](https://pyyaml.org/):`config.yaml` 配置读写。
|
||||
- [`python-dotenv`](https://github.com/theskumar/python-dotenv):读取 `.env`。
|
||||
- Python 标准库 `sqlite3`:消息、用户、去重、监控状态持久化。
|
||||
|
||||
## 安全 / 脱敏说明
|
||||
|
||||
- 仓库不包含真实 `TELEGRAM_BOT_TOKEN`、`ADMIN_CHAT_ID`、面板密码、Session Secret、数据库、日志。
|
||||
- 真实配置放在 `.env`,不要提交。
|
||||
- `.gitignore` 已忽略 `.env`、SQLite、日志、虚拟环境和缓存。
|
||||
- 如果要把面板暴露到公网,建议使用 Cloudflare Access / 反代鉴权,并使用强密码。
|
||||
- Bot 只能给“已经主动私聊过 Bot 的用户”发消息,这是 Telegram Bot API 的限制。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
git clone <YOUR_REPO_URL> tg-watchbot
|
||||
cd tg-watchbot
|
||||
python3 -m venv .venv
|
||||
./.venv/bin/pip install -U pip
|
||||
./.venv/bin/pip install -r requirements.txt
|
||||
cp .env.example .env
|
||||
cp config.example.yaml config.yaml
|
||||
nano .env
|
||||
```
|
||||
|
||||
至少填写:
|
||||
|
||||
```dotenv
|
||||
TELEGRAM_BOT_TOKEN=<your_bot_token>
|
||||
ADMIN_CHAT_ID=<your_admin_chat_id>
|
||||
WEB_PANEL_USER=admin
|
||||
WEB_PANEL_PASSWORD=<strong_password>
|
||||
```
|
||||
|
||||
启动:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python app.py
|
||||
```
|
||||
|
||||
打开面板:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:8765
|
||||
```
|
||||
|
||||
如果只是先配置面板、还没有 Telegram Token:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python app.py --panel-only
|
||||
```
|
||||
|
||||
手动跑一次监控:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python app.py --run-once
|
||||
```
|
||||
|
||||
## systemd 部署
|
||||
|
||||
推荐部署到 `/opt/tg-watchbot`:
|
||||
|
||||
```bash
|
||||
sudo useradd --system --no-create-home --shell /usr/sbin/nologin tg-watchbot || true
|
||||
sudo mkdir -p /opt/tg-watchbot
|
||||
sudo chown -R "$USER:$USER" /opt/tg-watchbot
|
||||
|
||||
cd /opt/tg-watchbot
|
||||
git clone <YOUR_REPO_URL> .
|
||||
python3 -m venv .venv
|
||||
./.venv/bin/pip install -U pip
|
||||
./.venv/bin/pip install -r requirements.txt
|
||||
cp .env.example .env
|
||||
cp config.example.yaml config.yaml
|
||||
nano .env
|
||||
|
||||
sudo chown -R tg-watchbot:tg-watchbot /opt/tg-watchbot
|
||||
sudo chmod 600 /opt/tg-watchbot/.env
|
||||
sudo cp systemd/tg-watchbot.service /etc/systemd/system/tg-watchbot.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now tg-watchbot
|
||||
sudo journalctl -u tg-watchbot -f
|
||||
```
|
||||
|
||||
健康检查:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8765/health
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### `.env`
|
||||
|
||||
| 变量 | 说明 |
|
||||
|---|---|
|
||||
| `TELEGRAM_BOT_TOKEN` | BotFather 创建的 Telegram Bot Token |
|
||||
| `ADMIN_CHAT_ID` | 管理员 Telegram 数字 chat id,用于接收用户消息和监控通知 |
|
||||
| `LOG_LEVEL` | 日志级别,默认 `INFO` |
|
||||
| `WEB_PANEL_ENABLED` | 是否启用 Web 面板,默认 `true` |
|
||||
| `WEB_PANEL_HOST` | 面板监听地址,默认 `127.0.0.1` |
|
||||
| `WEB_PANEL_PORT` | 面板端口,默认 `8765` |
|
||||
| `WEB_PANEL_USER` | 面板用户名 |
|
||||
| `WEB_PANEL_PASSWORD` | 面板密码 |
|
||||
| `WEB_PANEL_SESSION_SECRET` | Session Secret,留空会自动生成并写回 `.env` |
|
||||
|
||||
### `config.yaml`
|
||||
|
||||
监控数据自动清理示例:
|
||||
|
||||
```yaml
|
||||
cleanup:
|
||||
enabled: true
|
||||
interval_minutes: 60 # 每多少分钟执行一次清理
|
||||
monitor_retention_minutes: 1440 # RSS/网站监控状态保留多久
|
||||
```
|
||||
|
||||
清理范围只包括:
|
||||
|
||||
- `monitor_state`:网站/RSS 条目状态、价格/库存状态;
|
||||
- `sent_events`:监控推送去重记录。
|
||||
|
||||
不会删除:
|
||||
|
||||
- `users`;
|
||||
- `message_map`;
|
||||
- `inbox_messages`;
|
||||
- 任何双向对话/客服消息记录。
|
||||
|
||||
RSS 示例:
|
||||
|
||||
```yaml
|
||||
monitors:
|
||||
- name: NodeSeek 新帖
|
||||
type: rss
|
||||
url: https://rss.nodeseek.com/
|
||||
interval_seconds: 60
|
||||
keywords:
|
||||
- VPS
|
||||
- 优惠
|
||||
exclude_keywords:
|
||||
- 出号
|
||||
authors: []
|
||||
categories: []
|
||||
notify_on:
|
||||
keyword_match: true
|
||||
new_item: true
|
||||
price_change: false
|
||||
stock_change: false
|
||||
forum: true
|
||||
```
|
||||
|
||||
网页示例:
|
||||
|
||||
```yaml
|
||||
monitors:
|
||||
- name: Example Deals
|
||||
type: web
|
||||
url: https://example.com/deals
|
||||
interval_seconds: 300
|
||||
keywords:
|
||||
- discount
|
||||
selectors:
|
||||
item: article, .deal, li
|
||||
title: h1, h2, h3, a
|
||||
link: a
|
||||
price: .price
|
||||
stock: .stock
|
||||
notify_on:
|
||||
keyword_match: true
|
||||
new_item: true
|
||||
price_change: true
|
||||
stock_change: true
|
||||
```
|
||||
|
||||
## 管理命令
|
||||
|
||||
管理员在 Telegram 里可用:
|
||||
|
||||
```text
|
||||
/reply <user_id> <内容>
|
||||
/sendpic <user_id> [图片说明]
|
||||
/block <user_id>
|
||||
/unblock <user_id>
|
||||
/note <user_id> <备注>
|
||||
/who <user_id>
|
||||
/cancel
|
||||
```
|
||||
|
||||
也可以直接“回复 Bot 转发给管理员的用户消息”,Bot 会按映射把回复发回原用户。
|
||||
|
||||
## 面板路由
|
||||
|
||||
| 路由 | 说明 |
|
||||
|---|---|
|
||||
| `/` | 监控列表 |
|
||||
| `/monitor/new` | 新增监控 |
|
||||
| `/monitor/templates` | 论坛模板 |
|
||||
| `/monitor/bulk` | 批量新增 |
|
||||
| `/monitor/{idx}/preview` | 预览抓取结果,不写入状态、不推送 |
|
||||
| `/monitor/{idx}/run` | 手动检查单个监控 |
|
||||
| `/run-once` | 手动检查全部监控 |
|
||||
| `/yaml` | YAML 高级编辑 |
|
||||
| `/settings` | `.env` 设置和监控清理策略 |
|
||||
| `/send` | 主动发消息给已私聊过 Bot 的用户 |
|
||||
| `/inbox` | 收件箱 |
|
||||
| `/logs` | 日志 |
|
||||
| `/health` | 健康检查 |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- Telegram Bot 不能主动私聊陌生人;对方必须先给 Bot 发过 `/start` 或任意消息。
|
||||
- 对公网暴露 Web 面板前,务必改默认密码。
|
||||
- RSS 监控建议 60 秒起步;网页监控建议更保守,避免对目标站造成压力。
|
||||
- 媒体消息当前只保证记录文本/说明和转发状态;转发失败后的媒体补发需要额外做本地附件存储。
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,47 @@
|
||||
http:
|
||||
timeout_seconds: 20
|
||||
user_agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
|
||||
Chrome/124.0 Safari/537.36 tg-watchbot/1.0
|
||||
bot:
|
||||
rate_limit:
|
||||
window_seconds: 10
|
||||
max_messages: 3
|
||||
monitors:
|
||||
- name: NodeSeek 新帖
|
||||
type: rss
|
||||
url: https://rss.nodeseek.com/
|
||||
interval_seconds: 60
|
||||
keywords:
|
||||
- VPS
|
||||
- 优惠
|
||||
- 免费
|
||||
exclude_keywords: []
|
||||
authors: []
|
||||
categories: []
|
||||
notify_on:
|
||||
keyword_match: true
|
||||
new_item: true
|
||||
price_change: false
|
||||
stock_change: false
|
||||
forum: true
|
||||
- name: Linux.do 最新
|
||||
type: rss
|
||||
url: https://linux.do/latest.rss
|
||||
interval_seconds: 60
|
||||
keywords:
|
||||
- API
|
||||
- 教程
|
||||
- 开源
|
||||
exclude_keywords: []
|
||||
authors: []
|
||||
categories: []
|
||||
notify_on:
|
||||
keyword_match: true
|
||||
new_item: true
|
||||
price_change: false
|
||||
stock_change: false
|
||||
forum: true
|
||||
cleanup:
|
||||
enabled: true
|
||||
interval_minutes: 60
|
||||
monitor_retention_minutes: 1440
|
||||
@@ -0,0 +1,10 @@
|
||||
aiogram==3.22.0
|
||||
APScheduler==3.11.1
|
||||
beautifulsoup4==4.14.3
|
||||
fastapi==0.136.1
|
||||
feedparser==6.0.12
|
||||
httpx==0.28.1
|
||||
python-dotenv==1.2.1
|
||||
python-multipart==0.0.20
|
||||
PyYAML==6.0.3
|
||||
uvicorn[standard]==0.38.0
|
||||
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=tg-watchbot
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/tg-watchbot
|
||||
EnvironmentFile=/opt/tg-watchbot/.env
|
||||
ExecStart=/opt/tg-watchbot/.venv/bin/python /opt/tg-watchbot/app.py
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
User=tg-watchbot
|
||||
Group=tg-watchbot
|
||||
UMask=0077
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
ReadWritePaths=/opt/tg-watchbot
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user