# pixpulse **Repository Path**: zhaofu233/pixpulse ## Basic Information - **Project Name**: pixpulse - **Description**: 消息聚合源 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-13 - **Last Updated**: 2026-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # pixpulse > 自托管的信息聚合 API 服务,定位为 **RSSHub 的轻量替代品**。 > Go 单二进制 + PostgreSQL + Redis,给 pixGallery 等项目消费聚合后的数据。 ## 特性 - **Adapter 模式**:每个数据源独立实现,挂一个不影响其他 - **多源支持**:38 个内置源(热榜 / 科技 / 财经 / 视频 / 工具),分类清晰 - **多格式输出**:JSON / RSS 2.0 / Atom 1.0 / Markdown - **缓存优先**:外部调用全部走 Redis 缓存,毫秒级响应、0 触发抓取 - **稳健调度**:cron + worker pool + 同源节流 + 失败自动降频 - **调试面板**:Tailwind CDN 单页,启用开关 / 手动刷新 / 测试 / 批量操作 - **两阶段部署**:本地(无鉴权)/ 公网(JWT + 限速 + CORS 白名单) - **单二进制**:Go embed 静态资源,编译出来一个文件搞定 ## 快速开始 ### 前置 - Go 1.23+ - PostgreSQL 14+ - Redis 6+ ### 安装与启动 ```bash # 克隆 git clone pixpulse && cd pixpulse # 准备 PG 数据库(用现有 PG 实例) psql -U postgres -c "CREATE DATABASE pixpulse;" # 配置 cp .env.example .env # 编辑 .env,填 DATABASE_URL / REDIS_URL # 编译 + 启动 make build ./bin/pixpulse # 或 make run ``` 打开 `http://localhost:8686` 即可看到调试面板。 ### 启用源 调试面板默认所有源都是关闭状态(`enabled=false`)。两种启用方式: 1. **面板里勾选**:每个源后面的 checkbox 直接切换 2. **批量启用**:选择分类后点"启用当前分类"按钮(一键开启某分类下所有源) 3. **API 调用**: ```bash # 单源启用 curl -X PUT http://localhost:8686/api/v1/admin/sources/zhihu-hotlist \ -H "Content-Type: application/json" \ -d '{"enabled": true}' # 按分类批量启用 curl -X POST http://localhost:8686/api/v1/admin/sources/batch \ -H "Content-Type: application/json" \ -d '{"category": "tech", "enabled": true}' ``` 启用后调度器立即触发一次抓取,之后按 `fetch_interval` 周期性更新。 ## 内置数据源(38 个) | 分类 | 数量 | 源清单 | |---|---|---| | **hot** 热点 | 12 | GitHub Trending、知乎热榜、微博热搜、百度热搜、抖音热榜、百度贴吧、虎扑步行街、Readhub、微信、快手、懂车帝、汽车之家 | | **tech** 科技 | 9 | Hacker News、V2EX、少数派、36氪、掘金、IT之家、量子位、机器之心、开源中国 | | **finance** 财经 | 5 | 华尔街见闻、第一财经、新浪财经、虎嗅、雪球 | | **video** 视频/游戏 | 8 | B站(全站/科技/生活/知识 4 分区)、游研社、机核、3DM、QQ音乐 | | **tool** 工具 | 4 | 天气(和风/OpenWeather)、汇率(Frankfurter)、金价(新浪 hf_GC)、加密货币(Binance/CoinGecko) | ## HTTP API 详细文档见 [`docs/API.md`](docs/API.md)。 主要端点: ``` GET /api/v1/health 健康检查 GET /api/v1/dashboard?category=hot 按分类聚合(缓存) GET /api/v1/source/:slug/items 单源分页(缓存) GET /api/v1/feed/:slug?format=rss RSS/Atom feed(兼容传统阅读器) GET /api/v1/latest?format=markdown LLM 友好的纯文本 GET /api/v1/metrics?slugs=gold,crypto 工具卡片批量 POST /api/v1/source/:slug/refresh 手动同步刷新(触发抓取) # 管理(public 模式需 Bearer token) GET /api/v1/admin/sources 列出所有源 PUT /api/v1/admin/sources/:slug 更新单源(enabled/interval/config) POST /api/v1/admin/sources/batch 批量启用/禁用(按分类) POST /api/v1/admin/sources/:slug/test 测试性 fetch(不入缓存) GET /api/v1/admin/sources/:slug/errors 错误日志 ``` ## 架构概览 ``` ┌──────────────────────────────────────────────────────┐ │ pixpulse 二进制 │ ├──────────────────────────────────────────────────────┤ │ HTTP server (chi) │ │ ├─ /api/v1/* 公开+管理 API │ │ └─ / 调试面板(embed FS) │ ├──────────────────────────────────────────────────────┤ │ Scheduler (cron + worker pool) │ │ └─ 按 fetch_interval 触发 adapter.Fetch() │ ├──────────────────────────────────────────────────────┤ │ Adapter 层(38 个 .go 文件平铺) │ │ └─ 每个源一个 ListAdapter/MetricAdapter 实现 │ ├──────────────────────┬───────────────────────────────┤ │ PostgreSQL │ Redis │ │ - source 表(配置) │ - 最新数据缓存 │ │ - error_log │ - 状态机 (ok/stale/pending/…) │ └──────────────────────┴───────────────────────────────┘ ``` ### 关键设计决策 - **代码声明 vs DB 控制**:adapter 在 Go 代码里声明 slug+元信息,DB 控制 enabled/分类/配置——删 adapter 不会丢运营状态,加 adapter 自动出现在管理 UI - **失败不阻塞**:单源失败只写 `last_error`,Redis 旧数据继续服务到 TTL 到期 - **外部调用走缓存**:HTTP handler 全部读 Redis,0 触发抓取。唯一会触发抓取的是 `POST /refresh` - **关闭源立即停抓**:admin 改 `enabled=false` 后调度器立即移除该 cron 任务 ## 部署 详见 [`docs/deploy/README.md`](docs/deploy/README.md)。三种模式: - **本地模式**(默认):无鉴权、CORS 全开、限速关闭 - **公网模式**:JWT + CORS 白名单 + 限速 + 登录页 - **Docker 模式**:`docker compose up -d` 一键起整套 公网模式生成密码哈希: ```bash go run ./cmd/hashpw "your-strong-password" # 把输出的 $2a$10$... 写入 .env 的 ADMIN_PASSWORD_HASH ``` ## 给 pixGallery 接入 pixGallery 当前的 `src/service/news_service.py` 调 RSSHub。改接 pixpulse: 1. pixGallery `.env` 设 `PIXPULSE_API_BASE_URL=http://localhost:8686/api/v1` 2. 重写 `NewsService.fetch_feed()` 调 `GET /api/v1/source/:slug/items` 3. seed 文件 `rsshub_route` 改成 pixpulse 的 `slug` 字段映射详见 [`docs/API.md`](docs/API.md) §5。 ## 开发 ```bash make dev # 本地开发(PG/Redis docker 起来 + air 热重载) make build # 编译单二进制 make test # 单测 make lint # go vet ``` 加新源(无需改框架代码): ```go // internal/adapter/your_source.go package adapter import "context" func init() { RegisterList(&yourSourceAdapter{}) } type yourSourceAdapter struct{} func (a *yourSourceAdapter) Meta() SourceMeta { return SourceMeta{ Slug: "your-source", Name: "源名称", Category: CategoryTech, AdapterType: TypeList, FetchInterval: 1800, SortOrder: 50, SiteURL: "https://example.com", IconURL: "https://example.com/favicon.ico", } } func (a *yourSourceAdapter) Fetch(ctx context.Context, cfg map[string]any) ([]Item, error) { // 实现抓取逻辑 return []Item{{Rank: 1, GUID: "...", Title: "...", URL: "..."}}, nil } ``` 启动时 seed 会自动把它加到 `source` 表(默认 `enabled=false`,调试面板里勾选启用)。 ## License 私有项目,未开源。