魏无羡影院 —— 从 Cloudflare Workers 迁到 Ubuntu 盒子(nginx + PHP)
https://wwbda.lanzouv.com/iIzkn4ff234j
目标:http://192.168.41.102:6001/ 直接打开视频主页,所有接口都在盒子上跑,新增影片走后台,不再改 img.txt、也不再往仓库里建空的 xxx.html。
一、改了什么
| 项目 | 原来(Cloudflare Workers) | 现在(盒子 192.168.41.102:6001) |
|---|---|---|
| 首页 | vqq.521156.xyz 静态页 |
/ → index.html(nginx 直接出) |
| 片单接口 | vqqadmin.521156.xyz:读 GitHub 仓库 2091k/vqq 的分类目录 + vqqimg.521156.xyz/img.txt 封面 |
/api/home、/api/list:读 data/videos.json |
| 搜索 / 详情 / 播放 | vqq2026.521156.xyz |
/api/search、/api/detail、/api/play,PHP 直接抓 qiyou04 |
| CORS 代理 | jasu.521156.xyz(跨域必须) |
不需要了,同源调用 |
| 加新片 | 改 img.txt + 在 电影/ 里建 xxx.html |
后台 /admin.html 填「名称 + 选分类 + 封面」 |
| 分类 | 写死 电影/电视剧/动漫 | 后台「分类管理」自己增删,首页标签跟着变 |
| 导入导出 | 手工改 img.txt |
后台「导入 / 导出」,导出备份、导入恢复(支持合并/覆盖) |
| 源站域名 | 写死在 vqq2026.js 的 BASE_URL,改要重新部署 Worker |
后台「站点配置」直接填,保存即生效,旧缓存自动清空 |
| 首页后台入口 | —— | 不放,后台地址自己记着(/admin.html) |
原来那 68 部片的片单和封面已经迁移进 data/videos.json,顺序沿用 img.txt 的顺序,一部没丢。
二、目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/var/www/vqq/
├── index.html 首页(已改成调 /api/*)
├── player.html 播放页(已改成调 /api/play)
├── admin.html 后台(登录后可增删改片单)
├── api/
│ ├── index.php 接口路由(所有 /api/* 都进这里)
│ ├── vqq.php 采集层:qiyou04 搜索/详情/播放地址
│ └── store.php 数据读写 + 后台登录鉴权
├── data/ ★ 只有 www-data 能写,nginx 里已禁对外访问
│ ├── videos.json 片单(后台改的就是它)
│ ├── config.json 后台密码 + 分类表 + 源站域名(首次访问自动生成)
│ ├── cache/ 抓取缓存(详情页缓存 6 小时)
│ └── img.txt.legacy 旧的 img.txt,留个底,不参与运行
├── deploy/
│ ├── vqq-nginx.conf nginx 站点配置(listen 6001)
│ ├── install.sh 一键安装
│ └── selftest.sh 装完自检
└── tools/ 迁移/改造脚本,只在电脑上跑,盒子用不到
三、上传
三种任选,最终要落到 /var/www/vqq:
方式 1:WinSCP / FileZilla
主机 192.168.41.102,端口 22,用户 root,把 vqq-ubuntu 整个文件夹拖到 /var/www/,然后把文件夹名改成 vqq。
方式 2:压缩包(推荐,一个文件传完)
1
2
3
4
# 先把 vqq.tar.gz 传到 /tmp,然后在盒子上执行
mkdir -p /var/www
tar xzf /tmp/vqq.tar.gz -C /var/www
ls /var/www/vqq # 应该能看到 index.html / api / data ...
方式 3:scp(在 Windows PowerShell 里)
1
scp -r D:\bt\x86\ai-agent\ai\vqq-ubuntu root@192.168.41.102:/var/www/vqq
传完先确认一句:
ls /var/www/vqq/api/index.php存在,再往下走。
四、安装(一条命令)
1
sudo bash /var/www/vqq/deploy/install.sh
脚本做的事(每步都有回显,出错会自己撤销):
chown -R www-data:www-data /var/www/vqq/data,建data/cache(漏了这步后台保存会报 500);- 把
deploy/vqq-nginx.conf装到/etc/nginx/sites-available/vqq(已有同名文件先备份); - 软链到
/etc/nginx/sites-enabled/vqq; nginx -t检查,不通过就撤销这次的软链,不影响你现在 80 端口上的站点;systemctl reload nginx,然后自己 curl 一次/api/home报状态码。
装完打开:
- 主页:
http://192.168.41.102:6001/ - 后台:
http://192.168.41.102:6001/admin.html(或/admin),默认密码vqq@2026,登录后第一件事改掉
五、装完自检
1
bash /var/www/vqq/deploy/selftest.sh
或者手动几条:
1
2
3
4
curl -s http://127.0.0.1:6001/api/home | head -c 200 # 片单
curl -s "http://127.0.0.1:6001/api/list?type=电影" | head -c 150
curl -s "http://127.0.0.1:6001/api/search?keyword=棋士" | head -c 250 # 抓源站,首次约 3-5 秒
curl -s "http://127.0.0.1:6001/api/detail?id=36010" | head -c 250
预期:/api/home 返回 {"types":[...],"data":{"电影":[...。
六、后台怎么用
打开 /admin.html,输密码登录。左边「功能列表」五块,点哪个右边就切到哪个:
① 影片管理
- 「添加影片」:填 影片名称、分类(下拉选,只能选已有分类)、图片链接(腾讯视频封面地址,留空就是占位图),右边实时预览封面;
- 保存后首页刷新即可看到,顺序就是添加顺序,列表里
↑ ↓可调同一分类内的位置; - 「编辑」改名称/分类/封面,「删除」直接移除;
- 上面可按名称筛选、按分类筛选;筛选条件一改就自动回第 1 页;
- 列表分页显示,每页 20 部(现在的 68 部就是 4 页),底部一排:
首页 / 上一页 / 第 X / Y 页 · 共 N 部 · 每页 20 部 / 下一页 / 末页,已经在首页或末页时对应按钮自动变灰; - 新加的片子排在所属分类的最前面(首页、
/list、后台列表用的都是这个顺序),不用再手动上移;保存后列表会自动切到该分类、回到第 1 页,第一行就是它;
② 分类管理
- 输入分类名(比如「综艺」「纪录片」)点「添加分类」,首页立刻多一个标签,影片管理的下拉里也能选到;
- 有影片的分类不能删(按钮是灰的),先把影片删掉或改到别的分类;
- 空分类可以删,删掉后首页对应标签消失。
③ 导入 / 导出
- 「导出片单 JSON」下载整份片单(
title / type / img),当备份; - 「导入」选 JSON 文件,两种方式:合并(已有的不动,只补新片,同名同分类自动跳过)、覆盖(先清空再照文件重建);
- 文件里的新分类会自动加到分类表;导入完会回显「新增 x 部、跳过 y 部、格式不对 z 条、现在共 n 部」;
- 文件格式:
{"videos":[{"title":"片名","type":"电影","img":"https://..."}]},img可以留空。
④ 站点配置
- 「源站地址」只填协议+域名(例如
http://www.qiyou04.com),带路径会被拒绝; - 保存后立即生效,并且自动清空详情缓存;「测试能不能打开」会拿当前域名搜一次「棋士」,能返回结果就说明源站活着;
- 这个源站哪天打不开了,换成结构相同的站即可(
/search.php、/view/{id}.html、/play/{id}-{源}-{集}.html); - 「清空详情缓存」用于强制重新抓一遍。
⑤ 修改密码
- 至少 6 位;改完
config.json里is_default变 false。
名称重复会被拒绝(同分类内不允许同名),因为播放页是拿名称去源站搜的。
七、几个技术点(避免以后踩坑)
- 为什么不用 PHP 的 curl:这台盒子的 PHP 7.4 没装
php7.4-curl。所以单页抓取用file_get_contents(allow_url_fopen已开),搜索结果这种「一次要抓十几页」的场景,用原生socket + stream_select并发抓,14 路并发,30 条结果约 3-5 秒。想更快可以apt install php7.4-curl(不装也能正常用)。 - 缓存:详情页按 ID 缓存 6 小时(
data/cache/view_<id>.json),重复搜索同一批片子基本秒回。想强制刷新就删data/cache/里的文件。 - 登录态:PHP 原生 session(cookie 名
vqqsid),12 小时过期;连续输错 8 次锁 5 分钟(data/.login.json)。 - 端口:6001 是独立 server 段,和你 80 端口的
default/nginx_any168/nginx_radio/nginx_webdav四个站点互不干扰,不用动它们。 - 必须是 http:源站搜索/详情页是 http,播放 iframe 现在给的是 https 的
meizi.yongfan99.com,两种都能过;站点用http://访问最稳,不要强行套 https 反代,否则容易撞混合内容。 - 数据目录不能公开:
videos.json、config.json在data/里,nginx 对/data/一律return 404,别把 data 挪出站点根目录乱放。
八、回滚 / 停用旧 Worker
回滚(站点立即消失,文件都还在):
1
2
rm /etc/nginx/sites-enabled/vqq
nginx -t && systemctl reload nginx
确认新站稳定后,Cloudflare 上这几个可以直接删掉/停用:vqqadmin、vqq2026、jasu、vqqimg(vqqadmin 还依赖 GitHub token,一起作废就行)。
九、出问题先看这里
| 现象 | 排查 |
|---|---|
| 主页 404 / 502 | tail -50 /var/log/nginx/vqq.error.log;systemctl status php7.4-fpm |
| 接口 502 | 一般是 php-fpm 没起,或 fastcgi_pass 的 socket 路径不对(本机是 /run/php/php7.4-fpm.sock) |
| 后台能登录但保存 500 | data/ 权限问题:chown -R www-data:www-data /var/www/vqq/data |
| 首页空白、弹「首页加载失败」 | F12 看 /api/home 是否 200;data/videos.json 格式被改坏就看 .bak |
| 搜索转圈很久 | 源站慢或被墙,先 curl -I http://www.qiyou04.com/ 看通不通 |
| 封面不显示 | 封面是腾讯外链,有些地址只有 http://,浏览器会按 onerror 显示占位 |
| 播放黑屏 | /api/play 返回的 url 为空,说明源站那集的 iframe 结构变了 |
十、这套代码已经实测过的(在盒子上跑的,不是纸上推测)
在盒子上把文件放到 /tmp 里,用 PHP 7.4.3 直接跑了一遍(PHP 内置服务器起真实 HTTP 请求,测完已清理,没动 /var/www 和 nginx):
| 测的东西 | 结果 |
|---|---|
php -l 三个 PHP 文件 |
全部 No syntax errors detected |
GET /api/home |
200,电影 51 / 电视剧 5 / 动漫 12,合计 68 部 |
GET /api/list?type=电影&page=1 |
200,51 条,封面地址正常 |
GET /api/detail?id=36010 |
200,棋士 / 电视剧 / 2025 / 大陆 / 王宝强…,2 个播放源、43 集 |
GET /api/play?id=36010&episodePath=/play/36010-0-0.html |
200,拿到真实 m3u8 地址(meizi.yongfan99.com/...&type=ffm3u8) |
GET /api/search?keyword=棋士 |
200,0.44 秒,1 条 |
GET /api/search?keyword=雪 |
200,4.3 秒,30 条(14 路并发,全都有名字) |
| 后台错误密码 | 401 密码错误 |
| 后台正确密码 | 200,下发 vqqsid session,/api/admin/me 正常 |
| 后台新增「综艺」分类影片 | 200,首页立刻多出「综艺(1)」标签 |
| 分类接口 | 新增 200 / 重名 409 / 有影片时删除 409 / 空分类删除 200 |
| 影片分类校验 | 填不存在的分类 → 400,提示先加分类 |
| 站点配置 | 存 http://www.qiyou04.com/ 自动去掉尾斜杠 200;带路径 400;不带协议 400;保存后搜索/详情/播放全部照常 |
| 导入(合并) | 2 条数据:新增 1、跳过重复 1;文件里的新分类「纪录片」自动加进分类表 |
| 导入(覆盖) | 用导出的 68 部文件覆盖,回到 68 部,数据完整 |
| 导出 | GET /api/admin/export 200,68 条整份 JSON |
| 清空缓存 | 200,返回删除文件数 |
| 同分类重名 | 409 拒绝 |
| 上移/下移、删除、改密码 | 全部 200;改完密码 is_default 变 false |
| 未登录调后台接口 | 401 |
| 浏览器实测首页 | 分类标签、封面墙正常,右上角已无「后台」入口,控制台无报错 |
| 浏览器实测播放页 | 自动请求 /api/play 并起播源站播放器 |
| 浏览器实测后台 | 功能列表五块可切换;分类下拉联动;UI 上加分类、上传 JSON 导入(新增 1 跳过 1)都正常 |
| 后台列表分页 | 68 部 → 第 1 / 4 页显示 20 行,首页/上一页置灰;点「下一页」→ 第 2 / 4 页 20 行;筛选「小黄人」自动回第 1 页只剩 1 行;删除后回到 68 部、第 4 页剩 8 行 |
| 新片置顶 | 加「置顶测试片」(电影)→ /api/home 里电影第一条就是它;再加「置顶测试剧」(电视剧)→ 电视剧第一条是它、电影那条仍在第一;后台列表同样排在该分类首位;后台保存后自动筛到该分类、第 1 页第一行即新片;删掉后恢复 68 部、计数回到 51/5/12 |
nginx -t(拿这套 server 段单独测) |
syntax is ok / test is successful |
顺带修掉的三个真 bug:① 播放源列表的正则拿
#当分隔符、模式里又出现href="#down1",PCRE 报 “Unknown modifier”;② 详情 URL 把缓存 keyview_36010直接拼成/view/view_36010.html,抓到 404 页所以标题变成“未知剧集”;③ 搜索顺手把不带播放源的记录写进详情缓存,会让详情接口拿不到集数。现在都改好了。
测试期间这台盒子自己重启过一次(655MB 内存、负载常年偏高),
/tmp被清空后重传重测,最终结果以上表为准。装好之后如果还频繁重启,建议别在它上面加别的常驻服务;详情缓存 6 小时能明显减少抓取压力。