Files
2026-06-22 18:53:26 +08:00

322 lines
9.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Write Server
Hugo 博客的管理后台,基于 Next.js 16 + Tailwind CSS 4,Docker 容器化部署。
域名:`https://post.usj.cc`
## 功能模块
| 模块 | 路径 | 权限 | 说明 |
|------|------|------|------|
| 文章管理 | `/` | admin/user | 列表、搜索、编辑、删除、预览(user 只看自己的文章) |
| 撰写文章 | `/edit` | admin/user | Markdown 编辑器,图片/视频上传,作者自动填充 |
| 评论管理 | `/comments` | admin/user | Artalk 评论回复、删除 |
| 图片管理 | `/images` | admin/user | 图片上传管理 |
| 回收站 | `/recycle` | admin/user | 已删文章恢复(30 天) |
| 订阅源 | `/feeds` | admin | RSS 订阅源管理 |
| 友链管理 | `/links` | admin | 友链增删改查 |
| 公众号 | `/wechat` | admin | 微信公众号发布(自包含,直连微信 API) |
| Bot 管理 | `/bot` | admin | Telegram Bot / Hugo 预览状态 |
| 用户管理 | `/users` | admin | 添加/删除用户、修改密码 |
## 技术栈
- **框架**: Next.js 16 (Turbopack, standalone 输出)
- **样式**: Tailwind CSS 4, SEN 暖色系
- **数据**: 直接读写 Hugo Markdown 文件,无数据库
- **认证**: Service Worker + SHA-256 密码哈希,3 小时自动过期
- **评论**: Artalk API v2 + 新评论 Telegram 实时推送
- **Bot**: Telegram Bot(长轮询,语音转文字,GIF/视频处理)
- **公众号**: 微信 API 直连(access_token 自动管理)
- **视频**: ffmpeg GIF 转换 + Amigo 风格自定义播放器
- **反向代理**: Nginx + HTTPS
- **Hugo 预览**: 独立端口 1313,HTTPS 访问
## Telegram Bot 功能
| 命令 | 说明 |
|------|------|
| `/new` | 新建文章 |
| `/edit` | 编辑文章 |
| `/delete` | 删除文章 |
| `/list` | 文章列表 |
| `/publish` | 保存发布 |
| `/draft` | 保存草稿 |
| `/deploy` | 推送到线上 |
| `/links` | 友链管理 |
| `/feeds` | 订阅管理 |
| `/stats` | 网站数据 |
| 语音消息 | 自动转文字写入文章(需配置 DeepSeek/OpenAI API) |
| 图片 | 自动保存到文章目录 |
| GIF 动画 | ffmpeg 自动转换为 GIF 格式,透明背景 |
| 视频 | 保存为视频文件,自定义播放器 |
| 文档 | 根据类型自动处理 |
Bot 支持多用户,通过 `TG_ALLOWED_CHAT_IDS` 配置授权。
## 视频与 GIF 支持
### Telegram Bot 自动处理
| 发送类型 | 处理方式 | 结果 |
|---------|---------|------|
| GIF 动画 | ffmpeg 转换为 `.gif` | `<img>` 标签,自动循环播放 |
| 视频 | 直接保存 `.mp4` | 自定义播放器(播放/暂停/进度条/静音/全屏) |
| 图片 | 直接保存 | Markdown 图片语法 |
### Hugo Shortcode
```markdown
{{< video src="xxx.mp4" >}} ← 普通视频
{{< video src="xxx.mp4" caption="视频说明" >}} ← 带说明的视频
{{< video src="xxx.gif" loop="true" muted="true" >}} ← GIF 模式
{{< bilibili BV1xx411c7mD >}} ← B站视频
{{< youtube dQw4w9WgXcQ >}} ← YouTube 视频
```
### 播放器特性
- **Amigo 风格**自定义播放器
- 播放/暂停按钮(中央大按钮 + 底部控制栏)
- 进度条拖拽
- 时间显示
- 静音切换
- 全屏播放
- 悬停显示控制栏
- 暗黑模式适配
## 用户系统
用户配置文件:`users.json`(明文写入,容器启动时自动哈希)
```json
{
"users": [
{ "username": "admin", "password": "密码", "name": "昵称", "role": "admin" },
{ "username": "user1", "password": "密码", "name": "昵称", "role": "user" }
]
}
```
- **admin**: 看所有文章,管理所有模块,可添加/删除用户
- **user**: 只看自己写的文章,只能用文章/撰写/评论/图片/回收站
修改密码:
- 网页端:侧边栏「用户管理」页面
- 命令行:编辑 `users.json` → 重启容器
## 目录结构
```
write-server/
├── src/
│ ├── app/ # Next.js 页面和 API
│ │ ├── api/auth/login/ # 登录认证
│ │ ├── api/posts/ # 文章 CRUD(按用户过滤)
│ │ ├── api/users/ # 用户管理
│ │ ├── api/rss/wechat/ # 微信公众号发布
│ │ ├── api/recycle/ # 回收站
│ │ ├── login/ # 登录页面
│ │ └── users/ # 用户管理页面
│ ├── components/ # React 组件
│ │ ├── AppShell.tsx # 布局(登录页/主界面切换)
│ │ ├── AuthGuard.tsx # 登录状态检查
│ │ ├── PostEditor.tsx # 文章编辑器
│ │ ├── ShortcutPanel.tsx # 快捷插入(视频/B站/YouTube)
│ │ └── Sidebar.tsx # 侧边栏(按角色显示菜单)
│ └── lib/
│ ├── auth.ts # 认证(SHA-256 哈希)
│ ├── posts.ts # 文章读写
│ ├── recycle.ts # 回收站
│ ├── wechat.ts # 微信 API 直连
│ ├── voice.ts # 语音转文字
│ ├── hugo.ts # Hugo Server 管理
│ └── bot/ # Telegram Bot
│ ├── poll.ts # 消息轮询 + GIF/视频处理
│ ├── handlers.ts # 命令处理
│ └── notify.ts # 新评论推送
├── nginx/
│ ├── conf.d/
│ │ ├── write-server.conf # 主站配置
│ │ └── hugo-preview.conf # Hugo 预览 HTTPS
│ ├── login.html # 登录页(备用)
│ └── sw.js # Service Worker(认证)
├── scripts/
│ ├── hash-users.js # 密码哈希脚本
│ └── ...
├── users.json # 用户配置
├── entrypoint.sh # Docker 入口(权限修复 + 密码哈希 + ffmpeg)
├── Dockerfile
└── docker-compose.yml
```
## 端口说明
| 端口 | 用途 | 协议 |
|------|------|------|
| 80 | HTTP → HTTPS 重定向 | HTTP |
| 443 | 写作后台(nginx → 8016) | HTTPS |
| 1313 | Hugo 预览(nginx 代理) | HTTPS |
## 环境变量 (.env)
```bash
# 评论系统
ARTALK_SERVER=https://artalk.usj.cc
ARTALK_SITE=优世界
# Telegram Bot
TG_BOT_TOKEN=your-bot-token
TG_ALLOWED_CHAT_IDS=7499586710,123456789
# 微信公众号(自包含)
WECHAT_APP_ID=your-app-id
WECHAT_APP_SECRET=your-app-secret
# RSS/友链 API
RSS_API_BASE=https://api.usj.cc
RSS_API_TOKEN=your-token
# AI / 语音转文字
DEEPSEEK_API_KEY=your-key
DEEPSEEK_BASE_URL=https://api.deepseek.com
# 其他
DEFAULT_AUTHOR=小赵
PREFER_IFACE=eth0
```
**注意:** `BLOG_ROOT` 不要写在 `.env` 里!Docker 部署通过 `docker-compose.yml` 的 volume 映射自动处理。
## 常用命令
```bash
# 启动
docker compose up -d
# 停止
docker compose down
# 重建(代码变更后)
docker compose down && docker compose build --no-cache && docker compose up -d
# 查看日志
docker logs write-server -f
docker logs write-nginx -f
# 重启单个服务
docker compose restart write-server
docker compose restart nginx
# 重启 Hugo 预览
curl -X DELETE http://127.0.0.1:8016/api/hugo
curl http://127.0.0.1:8016/api/hugo
# 清除 Hugo 缓存
rm -rf /path/to/blog/resources/_gen
docker compose restart write-server
```
---
## 迁移到新服务器
### 1. 安装 Docker
```bash
curl -fsSL https://get.docker.com | sh
systemctl enable docker && systemctl start docker
apt install -y docker-compose-plugin git certbot
```
### 2. 克隆项目
```bash
cd ~ && mkdir -p hugo && cd hugo
git clone <repo-url> blog
cd blog/write-server
```
### 3. 配置
```bash
# 环境变量
cp .env.example .env && nano .env
# 用户(明文密码,启动时自动哈希)
cat > users.json << 'EOF'
{
"users": [
{ "username": "admin", "password": "你的密码", "name": "小赵", "role": "admin" },
{ "username": "test", "password": "她的密码", "name": "辣辣", "role": "user" }
]
}
EOF
```
### 4. DNS + SSL
```bash
# DNS: post.usj.cc → 新服务器 IP
# SSL 证书
docker compose up -d nginx
docker compose stop nginx
certbot certonly --standalone -d post.usj.cc --agree-tos --email you@email.com
mkdir -p nginx/ssl
cp /etc/letsencrypt/live/post.usj.cc/fullchain.pem nginx/ssl/
cp /etc/letsencrypt/live/post.usj.cc/privkey.pem nginx/ssl/
```
### 5. 防火墙 + 启动
```bash
ufw allow 22,80,443,1313/tcp && ufw enable
git config --global --add safe.directory /root/hugo/blog
docker compose up -d
```
### 6. 自动续期 SSL
```bash
crontab -e
# 添加: 0 3 1 * * certbot renew --quiet && docker compose restart nginx
```
---
## 迁移清单
| 类型 | 内容 | 说明 |
|------|------|------|
| 必须 | 博客源码 | `git clone` |
| 必须 | `.env` | 手动填写 Token |
| 必须 | `users.json` | 手动创建,明文密码(启动时自动哈希) |
| 必须 | SSL 证书 | 新服务器重新申请 |
| 可选 | `recycle/` | 30 天过期,可不迁移 |
| 不需要 | Docker 镜像 | 重新构建 |
| 不需要 | `node_modules` | 自动安装 |
---
## Hugo 主题集成
write-server 依赖 Hugo 主题(Ying)的以下功能:
- **视频 shortcode** (`layouts/shortcodes/video.html`) - 支持本地视频、B站、YouTube
- **视频渲染钩子** (`layouts/_default/_markup/render-video.html`) - Markdown 视频标签
- **视频 CSS** (`assets/css/main.css`) - Amigo 风格播放器样式
- **暗黑模式** - 纯色背景,无背景图
## 已知限制
- Hugo 预览(1313 端口)导航链接独立,和主站不互通
- 博客目录 owner 会被 entrypoint 改为 uid 1001
- 语音转文字需要配置 `DEEPSEEK_API_KEY` 或 `WHISPER_API_KEY`
- 新评论推送每 60 秒检查一次
- GIF 转换需要 ffmpeg(Docker 镜像已内置)
## License
MIT