臭鱼烂虾分享小站 v2.1 完工小结
技术栈
后端:PHP 8.3 + SQLite(零外部依赖,单文件部署)
视频:ffmpeg 转 480p HLS,每片~100KB,配合 FRP 小带宽也丝滑
部署:1Panel + Nginx,独立域名
new.nlook.top,跟主站吐槽博客物理隔离
核心功能
视频:批量添加、二级分类、分类内选集、循环播放开关、隐藏 / 显示
用户:名字登录、管理员 / 普通用户、分类级屏蔽(谁能看哪个分类)、公告可见性开关
体验:按账号续播(刷新 / 换设备接着看)、评论 + 管理员回复、多图轮播附件
公告:登录弹窗 + 个人中心可重看,支持 Markdown(分割线、有序列表、图片居中)
后台:全部右侧抽屉操作,列表分页 15 条,按更新时间倒序,CSRF 校验
为什么爽
一个切片 100KB,所有人打开都秒播,不用等缓冲
SQLite 单文件,备份就是拷一个 .db
前后端都是我自己撸的,没有任何框架包袱
主站写心情,副站放视频,域名分开互不暴露
从 ffmpeg 切 HLS 开始,一路写到用户权限细分、公告系统、续播记忆,两天迭代了 9 轮代码评审。小而美的东西,最让人上头。
建设踩坑实录(v2.1)
项目:基于 PHP 8.3 + SQLite + HLS 的个人视频分享站 周期:2 天,9 轮迭代 部署:1Panel + Nginx,独立域名 nlook.top
一、视频处理与传输
1. HLS 切片大小怎么定
问题:直接传 MP4,小带宽用户加载卡顿明显。 方案:用 ffmpeg 压到 480p 后切 HLS,每片控制在~100KB。 关键命令思路:
-c:v libx264 -preset veryfast -crf 28 压体积
-hls_time 2 每片约 2 秒
-hls_list_size 0 生成完整 m3u8
效果:客户端要哪片拉哪片,首屏秒开,FRP 内网穿透也不卡。
2. Web 静态资源也可以学 HLS 的思路
问题:一个网页 2MB+(CSS/JS/ 图片一堆),首屏加载慢。 结论:Nginx 本身就是 "要哪个文件回哪个文件",关键是:
资源要小、要分文件、要能并行缓存
别把所有 JS 打成一个大 bundle
图片走懒加载、WebP、响应式尺寸
二、部署与域名
3. 证书域名不匹配(ERR_CERT_COMMON_NAME_INVALID)
现象:新域名 new.nlook.top 打开报证书错误。 原因:1Panel 站点配置里 ssl_certificate 路径指到了老主站 CrossTime 目录下的证书,跟新域名对不上。 解决:在 1Panel 面板里给新站点重新申请 / 绑定证书,路径切到 /www/sites/<新站点>/ssl/。 教训:换域名先看 nginx 配置里的证书路径是不是跟着站点走,别复制老配置。
4. 主站和副站要物理隔离
背景:主站是吐槽内容,副站放视频。 方案:分开域名、分开站点目录、分开证书。不要共用一个域名路径,否则主站被墙 / 被查会连坐副站。
三、后台编辑器集成(Vditor 翻车实录)
5. Vditor 静态资源 404 连环坑
问题:嵌入 Vditor 4.0 后控制台一堆 404。 根因:Vditor 的 cdn 配置指向包根目录,它自己会拼 /dist/...,文件目录结构必须严格匹配:
解决:直接下完整 tgz 解压,别一个个文件抠。
6. 上传图片路径相对路径 bug
现象:后台编辑器里插图后,图片裂了,控制台请求 /admin/uploads/xxx.gif 404。 原因:上传接口返回 uploads/xxx.gif(相对路径),在 admin 页面浏览器会拼成 /admin/uploads/...。 解决:接口返回 /uploads/xxx.gif(前导斜杠,从网站根开始)。数据库里仍存 uploads/xxx.gif(服务端文件操作用相对路径)。
7. 最终放弃 Vditor
原因:小屏幕上分屏编辑体验太差,工具栏挤成一团。 决策:回退到原生 textarea + 自带 mdToHtml(支持标题 粗斜体 列表 链接 图片 行内代码 分割线 / 有序列表)。 教训:富文本编辑器是给桌面端用的,移动端后台别硬上。简单 textarea + 预览按钮反而好用。
四、Windows 环境踩坑
8. PowerShell here-string 吞正则捕获组
现象:用 PowerShell 写前端 JS 正则替换,2 全变成空字符串。 原因:PowerShell 双引号字符串会把 $1 当变量解析。 解决:
用单引号 here-string @'...'@(不解析变量)
或者把 JS 块写到临时文件,再用 PowerShell 按行号拼接
不要在 PowerShell 里硬写带 $ 的正则
9. Edit 工具频繁报 "File has not been read yet"
现象:刚 Read 过的文件,Edit 还是报错。 解决:改用 PowerShell 按行号切片替换,或者先完整 Read 整个文件再 Edit。
五、安全与数据
10. 代码评审修的 9 项
| 问题 | 修复 |
| 隐藏视频对非管理员可见 | 查询加 visible=1 过滤 |
| 评论内容 XSS | 输出统一 esc() 转义 |
| 每请求写调试日志 | 删掉 _debug_session.txt |
| 初始密码明文散落 | 写入 data/initial_credentials.txt |
| 删视频残留封面 评论 续播记录 | 级联清理 |
| 每次请求都跑迁移 SQL | 用 schema_version 缓存跳过 |
| 续播上报太频繁 | 位置变化 ≥10 秒才 POST |
| 后台 POST 无 CSRF 校验 | 所有 POST 加 token |
11. 续播记录从 localStorage 升级到数据库
问题:localStorage 换设备 / 换浏览器就丢。 方案:按账号存 watch_progress 表(user_id + video_id + position)。 节流:前端每 10 秒位置变化才上报一次,别拖慢视频。
六、权限设计
12. 用户权限分层
一级:能不能登录(名字在白名单里就行)
二级:分类级屏蔽(这个用户不能看哪个分类)
三级:公告可见性(默认能看,可单独关闭)
管理员:不受以上限制
13. Markdown 渲染补全
--- *** ___ → 分割线
1. xxx 1) xxx 1、xxx → 有序列表
所有图片自动居中(display:block; margin:auto)
七、经验总结
小带宽场景下,HLS 切片思路可以推广到所有静态资源:小文件、分块、按需加载。
第三方编辑器 / 库先在小屏幕测一遍再决定要不要集成。
文件路径要么全相对、要么全绝对,别混用,尤其在子目录页面里。
Windows + PowerShell 写代码时,涉及 ****$** 的字符串一律走临时文件拼接**。
SQLite 单文件够用就别上 MySQL,备份就是拷一个文件。
权限设计要分层:登录、分类、公告,三层独立开关,别揉一起。