{{ crumb.t }} {{ crumb.s }}
{{ h.kind }}
{{ h.title }}{{ h.sub }}
没有匹配「{{ gq }}」的内容
{{ disk ? fmtSize(disk.free) : '…' }}空闲 {{ hasFfmpeg ? 'ffmpeg' : '无ffmpeg' }} {{ appVer ? 'v'+appVer.versionName : '未发布' }}
{{ a.t }}{{ a.s }} {{ a.label }}
线路配置
{{ lines.length }}条
使用中 {{ onLines.length }} · 已停用 {{ lines.length - onLines.length }} · 检测异常 {{ badChecks.length }}
爬虫代码
{{ codes.length }}个
未被线路引用 {{ unusedCodes.length }} · 所属线路已停用 {{ disabledCodes.length }}
本地视频
{{ videos.length }}个
剧集 {{ epGroups.length }} 部 · 共 {{ totalVidSize }} · 未分类 {{ uncatVids.length }}
磁盘可用
{{ fmtSize(disk.free) }}
—
{{ disk ? '共 '+fmtSize(disk.total)+' · 已用 '+diskUse+'% · '+(hasFfmpeg?'ffmpeg 就绪':'未装 ffmpeg') : '读取中…' }}
线上 App 版本
v{{ appVer.versionName }}
未发布
{{ appVer ? appVer.filename + ' · ' + fmtSize(appVer.size) : 'App 端检测不到更新' }}
线路健康管理全部线路 →
还没有线路文件
{{ f.name }}
{{ f.note || '无备注' }} · {{ checks[f.name] ? checks[f.name].msg : '未检测' }}
{{ f.enabled ? '使用中' : '已停用' }} {{ hostOf(f.url) }}
最近上传进入视频库 →
还没有上传过视频
▶
{{ v.name }}
{{ fmtSize(v.size) }} · {{ fmtTime(v.mtime) }}
播放
本地媒体线路
{{ info.line || '—' }}
TVBox 系 / 桌面版 / 闭原版通用 · 上传视频自动更新 · 当前收录 {{ info.count || 0 }} 个视频
红果取址刷新
代理模块(手机)
{{ relay ? (relay.agent_alive ? '在线 · 心跳 ' + relay.agent_age + ' 秒前' : '离线 · 超过 15 秒无心跳') : '读取中…' }}
签名机 APK
{{ relay ? (relay.signer_alive ? '在线 · ' + relay.signer_age + ' 秒前活跃' : '离线') : '读取中…' }}
今日取址成功 {{ relay.ok_count }} 次 · 失败 {{ relay.fail_count }} · agent 配额 {{ relay.quota_used }}/{{ relay.quota_cap }}
快捷操作
线路
上传视频
新建文件
重建线路
下载备份
回收站
{{ hasFfmpeg ? "ffmpeg 已就绪: 支持自动截帧封面 / 720p 压缩" : "未检测到 ffmpeg: 截帧封面与 720p 压缩不可用" }}
全部 {{ lines.length }} 使用中 {{ onLines.length }} 已停用 {{ lines.length - onLines.length }} 检测异常 {{ badChecks.length }}
{{ showLines.length }} / {{ lines.length }} 条
线路 / 备注 类型 启用 连通检测 大小 / 修改 操作
{{ f.name }}
{{ f.url }}
{{ f.note || '+ 添加备注' }}
{{ f.auto ? '系统' : ext(f.name) }} {{ f.enabled ? '使用中' : '已停用' }} {{ checks[f.name].msg }}
{{ fmtSize(f.size) }}
{{ fmtTime(f.mtime) }}
生成二维码 复制配置地址 在新窗口查看 编辑备注 系统生成线路,不可重命名/删除
没有符合当前筛选条件的线路
还没有线路文件,点击右上角「+ 新建线路」创建
已选 {{ selLines.length }} 条 取消选择 ×
● 未保存 ● 已保存, 待重启生效 {{ cur }} · Ctrl+S 保存{{ srcMode ? ' (需口令, 重启才生效)' : '' }}
{{ srcPending.length }} 个文件已存盘但未生效{{ srcPending.join('、') }} —— 进程里还是旧代码,点右上「重启服务生效」才会换过来
保存 = 语法检查(编译不执行) + 备份到 backups/src/(每个模块留最近 20 份),都要再输一次登录口令。 语法错会被拦下,运行时的错拦不住 —— 重启前先在本地把这条模块跑通。
模块 作用 大小 修改时间 操作
{{ f.name }} {{ f.desc }} 已保存未生效 这台机器没有 在跑 {{ f.exists ? fmtSize(f.size) : '—' }} {{ f.exists ? fmtTime(f.mtime) : '—' }}
正在读取模块清单…
上一个包没装上{{ pkg.bad }} 知道了
这台机器没有 uvpy 线路包装依赖改走系统 python 的 venv + pip,一样能装、只是慢一些;装上 uv 会快很多。js 线路包不受影响
py 包没隔离{{ pkg.sandbox.why }} —— 这台机器上的包能互相读代码,也能读到瓶子的口令;要收别人上传的包,先按提示把隔离开起来
{{ pkgName ? pkgName : '把线路包拖到这里,或点一下选文件' }}
{{ fmtSize(pkgSize) }} · 移除
.zip · 最大 {{ fmtSize(pkg.cap) }} · 装好立刻生效,不用重启服务
给别人开放上传
{{ apiKeys.length ? (apiKeys.length + ' 把 API Key 已生成') : '还没生成 API Key' }}
系统只有你一个管理员,装包直接拖进来即可。要把上传权限发给别人,去「OpenAPI」生成 API Key,他拿 Key 调开放接口就能上传线路包,动不了别的管理功能。
线路包 / 填进 App 的地址 类型 版本 启用 进聚合线路 运行状态 操作
{{ p.name }}
{{ pkgAddr(p) }}
挂载 {{ p.mount.join(' ') }}
{{ p.desc }}
{{ p.kind.toUpperCase() }} {{ p.version }} {{ p.enabled ? '使用中' : '已停用' }} {{ !p.enabled ? '未生效' : (p.in_line ? '已进' : '未进') }} {{ pkgRun(p).text }}
{{ pkgRun(p).msg }}
手机扫码添加 重试启动 编辑代码 复制包 id {{ p.in_line ? '从聚合线路移出' : '加进聚合线路' }} 删除包
包结构: plugin.json(清单: id / kind=js|py / name / line / 版本) + 线路配置 + 爬虫。 一个包只能带自己的爬虫: 站点 api 指向别人的服务器、带 jar、混第二条线路,装的时候一律拒绝。
js 包整份下发到 App 里跑 —— 谁拿到线路都能把代码抄走,想防抄就用 py 包(爬虫留在服务器上,App 只拿到壳)。
包默认只发给拿到这个地址的人。想让用这台机器的所有人都拿到它,再单独勾「进聚合线路」;不勾就谁传上来的包都不会变成你分发的线路。
全部 {{ codes.length }} 被引用 {{ usedCodes.length }} 未引用 {{ unusedCodes.length }} 线路已停用 {{ disabledCodes.length }}
{{ showCodes.length }} / {{ codes.length }} 个
代码文件 被这些线路引用 大小 修改时间 操作
{{ c.name }} {{ u }} 未被线路引用 所属线路已停用 {{ fmtSize(c.size) }} {{ fmtTime(c.mtime) }}
复制文件名 复制文件地址 删除代码
没有符合当前筛选条件的代码文件
暂无代码文件,点击右上角「+ 新建代码」创建
{{ links.length }} 个直链 全部 {{ c.name }} ({{ c.n }}) × + 新建分类
官方线路地址(TVBox 系 / 桌面版 通用,点击复制)
{{ linksLine }}
并入的线路 json 站点 操作
{{ j.name }} {{ j.sites.length }} 个 · {{ jJar(j) }} 个 jar 源(电脑端跑不了)
名称 视频链接 所属剧集 分类 操作
{{ x.name }} {{ x.url }} {{ x.group || '—' }}{{ x.ep ? ' · 第' + x.ep + '集' : '' }} {{ x.cat || '—' }}
复制链接 删除
没有符合筛选条件的链接
官方线路还是空的 — 点右上角「+ 添加链接」粘贴视频直链, 或粘贴一条别人的线路 json, App 里点开即播
瓶子只做分发, 直链要播放器自己能连上; 需要代理请自带 js 源
{{ notices.length }} 封 · 下发中 {{ notices.filter(n => n.enabled).length }} 封
公告下发地址(客户端免登录 GET,?end=android / pc / tv;不带 end 回全部)
{{ noticeFeed }}
标题 / 正文 发到哪些端 启用 更新 操作
{{ n.title }}
{{ n.body }}
{{ noticeEndName(e) }} {{ n.enabled ? '下发中' : '已停用' }} {{ fmtTime(n.updated) }}
手机扫码看 删除
还没有公告 — 点右上角「+ 发布公告」写一封,勾选要发给哪几个端,手机端/PC端/TV版 启动后各弹一次
同一封弹过就不再弹;改了正文或停用过再启用,「更新时刻」变、客户端才会当成新的一次再弹
分类 全部 ({{ videos.length }}) {{ c.name }} ({{ c.n }}) × + 新建分类
网格 列表
松开鼠标, 上传视频文件
将打开上传设置弹窗
正在上传 {{ upName }} — {{ upPct }}%
本地媒体线路地址(TVBox 系 / 桌面版 / 闭原版 通用,点击复制)
{{ info.line }}
当前条件命中 {{ filtVideos.length }} 个视频
封面片名 / 文件名分类 所属剧集大小修改时间操作
▶ {{ v.name }}{{ v.file }} {{ v.cat || '未分类' }} {{ v.group || '—' }} {{ fmtSize(v.size) }} {{ fmtTime(v.mtime) }} 播放 编辑 ⋯ 手机扫码播放 复制播放地址 自动截帧当封面 压缩为 720p 删除视频
没有符合当前条件的视频
视频库为空,点击右上角「上传视频」添加第一个视频
也可以直接把视频文件拖到这里
支持 mp4 / mkv / webm / mov / avi / ts
已选 {{ selSet.length }} / {{ filtVideos.length }} 退出批量 ×
更新说明 线上 v{{ appVer.versionName }} · {{ appVer.filename }}
正在上传 {{ apkName }} — {{ apkPct }}%
当前线上版本(App 启动后自动检测, 无需任何配置)
尚未发布版本,App 端检测不到更新
PC 桌面版(桌面端启动后自动检测, 设置里可手动检查)
这条版本线还没发包,桌面版检测不到更新
正在上传 {{ pcName }} — {{ pcPct }}%
命名规则: 文件名需含版本号, 如 MyApp_v2.1.44.apk、MyApp_v2.0.1.exe(版本号从文件名自动解析, 上传即覆盖旧版本)。
App 端零配置: 启动后自动比对线路源版本号, 有新版本弹窗提示下载安装; 「我的 → 检查更新」可手动检测。
PC 端: 上传 Inno Setup 安装包 (.exe), 桌面版启动后自动检测, 有新版本在设置页提示下载并静默安装。
还没有 API Key右边生成一把, 发给要上传线路包的人; 他拿 Key 调开放接口就能传包, 动不了别的管理功能。
给别人开放上传
系统只有你一个管理员, 自己装包去「线路包」页拖进来就行, 用不着任何口令。
要让别人也能传包: 生成一把 API Key 发给他, 他拿 Key 调 POST /openapi/pkgUpload 传 .zip 即可, 装好立刻生效 —— 除了传包什么都干不了, Key 随时可以吊销。
curl -X POST '{{ apiBase }}/openapi/pkgUpload' \
  -H 'X-API-Key: 你的Key' \
  -F 'file=@线路包.zip'
接口文档(免登录, 可直接发给别人看):{{ apiBase }}/openapi/docs
生成新的 API Key
完整 Key 只显示一次, 生成后立即复制
备注Key(掩码)创建时间最近使用操作
{{ k.name || '未命名' }} {{ k.key_mask }} {{ fmtTime(k.created) }} {{ k.last_used ? fmtTime(k.last_used) : '从未使用' }}
还没有密钥 —— 上面生成一把就有了
用户管理
在线客户端 注册账号
按客户端 IP(设备)统计 —— App 不登录时, 服务端能认的唯一身份就是 TCP 对端地址; 同一个 WiFi 下的多个人会算成一个用户。 同一台机器上并存的几个端(手机短剧接口 / 播放器 / PC)按 UA 分开计数, 不再被最后一条请求抹掉。
这一维是 App「我的」页里注册的账号: 看它登在几台设备、存了多少历史收藏, 能踢下线、停用、删号。 停用会让它手上没吊销的登录当场失效, 恢复后这些设备不用重新登录。
封禁名单({{ onlineBanned.length }})
封掉后对方请求线路直接 403(含线路包自己挂载的取址口), 后台管理端不受影响。
{{ b }} 还没有封任何人
停用中的账号({{ accBanned.length }})
停用不改密码也不删数据, 恢复后设备上的登录接着能用。
{{ a.nick || a.name }} 没有在停用的账号
客户端 当前线路 状态 几个端在用它 最近请求 最近活跃 请求数 操作
{{ u.ip }}
见于 {{ fmtTime(u.first_seen) }}
{{ u.line || u.top_line || '—' }} 已封禁 在线 离线 {{ tag }} ×{{ n }} — {{ u.last_path || '—' }}
{{ Object.entries(u.api).slice(0,3).map(kv => kv[0] + '×' + kv[1]).join(' · ') }}
{{ fmtIdle(u.idle) }} {{ u.reqs }}
{{ onlineAll ? '最近 24 小时没有客户端请求过线路' : '当前没有在线客户端 —— 5 分钟内有请求就会出现在这里(服务重启前记过的客户端也从磁盘读回来了)' }}
账号 状态 设备 最后活跃 注册于 存了什么 操作
{{ a.nick || a.name }}
uid {{ a.uid }}
已停用 正常 {{ a.devices }} 台 {{ a.active_at ? fmtIdle(nowSec() - a.active_at) : '没登录过' }} {{ fmtTime(a.created) }} {{ kindName(k) }} {{ n }}
{{ accQ ? '没有匹配「' + accQ + '」的账号' : '还没有人注册账号 —— App 里「我的」页注册了才会出现在这里' }}

{{ accDlg.nick || accDlg.name }} uid {{ accDlg.uid }}

注册于 {{ fmtTime(accDlg.created) }} · {{ accDlg.banned ? '已停用' : '正常' }}
签名: {{ accDlg.sign }}
登录着的设备({{ accDlg.devices.filter(d => !d.revoked).length }})
凭据号设备最近活动
{{ d.id }} {{ d.device || '未上报机型' }} · 已吊销 {{ fmtIdle(nowSec() - d.last_seen) }}
这台账号没有登录记录
数据分布
{{ kindName(k) }} {{ n }} {{ l.mode }} 线路备份 {{ l.n }} 条 还没在 App 里存过任何东西
最近在弄什么
{{ kindName(it.kind) }} {{ it.name || '—' }} {{ it.idx }}/{{ it.total }}{{ it.finished ? ' · 看完' : '' }} {{ fmtTime(fmtTs(it.ts)) }}
还没有上报过任何观看记录

{{ cliDlg.ip }} {{ cliDlg.seen.online ? '当前在线' : '已离线' }} · {{ cliDlg.seen.reqs }} 次请求

最后请求 {{ fmtIdle(cliDlg.seen.idle) }}前 · {{ fmtTime(cliDlg.seen.last) }} · 见于 {{ fmtTime(cliDlg.seen.first) }} · 此刻在用的线路 {{ cliDlg.seen.line || '—' }}
UA 原文: {{ cliDlg.seen.ua || '—' }}
E · 这个地址上登录着谁
账号设备最近活动
{{ a.nick || a.name }}
uid {{ a.uid }}{{ a.banned ? ' · 已停用' : '' }}
{{ a.device || '未上报机型' }} {{ fmtIdle(cliDlg.now - a.last_seen) }}前
没查到 —— 客户端只对 /u/* 同步和评论写侧带 token,普通线路请求光秃秃的(只有一个伪装 UA), 所以没登录、没发过评论的地址认不出是谁。
C · 他正在看哪一部
剧名进度哪个包答的 / id操作
{{ w.name }} 查不到名字
{{ fmtTime(w.last || w.at) }}
已看完
{{ Math.floor(w.seconds / 60) }} 分钟处
{{ w.pkg || '没人接管' }} · {{ w.id }}
{{ w.path }}
{{ w.why }}
不能自动查
这 {{ cliDlg.watchingHidden }} 条请求的地址尾巴上只有集 id / 流 id(播放器取流那一跳), 认不出是哪部剧, 就不列在这儿了
最近 20 条请求里没有点播类的 id
剧名默认只从这个账号自己上报过的历史/收藏里取(一次上游都不打);查不到时点「查剧名」才会现问一次线路包, 问到就缓存进 data/names.json,六小时内不再重复打。
D · 媒体流实际交了多少字节
这条地址上还没走过媒体流(只取过址 / 线路文件)
B · 请求流水
这个地址这次没留下流水(记账功能上线前的请求)
时刻方法请求状态耗时哪个包
{{ fmtHms(h.t, h.ms) }} {{ h.m }} {{ h.p }} {{ h.s }} {{ h.d.toFixed(2) }}s {{ h.k || '—' }}
耗时只量到响应头(和日志里 [计时] 同一个口径),媒体流的真实字节/速率看上面 D 段。
A · 累计计数
{{ k }} ×{{ n }} 线路 {{ k }} ×{{ n }} {{ k }} ×{{ n }}
最后一次请求: {{ cliDlg.seen.last_path }}

新建线路文件

重命名

编辑视频信息

点击选择封面图片
jpg / png / webp, 8MB 内

新建分类

创建后可先归入视频, App 内按此分类浏览; 空分类也可保留

新建分类

创建后添加/编辑链接时可选用; 空分类也会显示在 App 线路里

{{ linkEdId ? '编辑链接' : '添加链接' }}

视频直链 线路 json

{{ noticeEdId ? '编辑公告 #' + noticeEdId : '发布公告' }}

{{ noticeEndName(e) }}
{{ noticeOn ? '下发中' : '只存着不发' }}
客户端按「公告号 + 更新时刻」记已读: 同一封弹过就不再弹, 改了正文或重新启用时刻会变, 那边才会再弹一次。 {{ noticeEdId ? '现在改的是已发出去的第 ' + noticeEdId + ' 封。' : '' }}
▶

{{ curSeries.name }}

共{{ curSeries.eps.length }}集 {{ curSeries.cat }} 荐
{{ batchMode ? "勾选分集后关闭弹窗, 使用页面上的批量操作" : "点击分集右侧操作进行管理; 修改分集的「所属剧集」可调整归组" }}
{{ i + 1 }} {{ e.name }} {{ fmtSize(e.size) }} 播放 编辑 二维码 截帧 压缩 删除
该剧集暂无分集

上传视频

点击选择视频文件
或拖入到此处 · 支持 mp4 / mkv / webm / mov / avi / ts · 上传后自动纳入「本地媒体」线路

编辑备注

{{ ntName }}

{{ qrTitle }}

{{ qrUrl }}

查看代码 ● 未保存

{{ c.name }}
{{ fmtSize(c.size) }} · {{ fmtTime(c.mtime) }}
暂无代码文件, 点右上角「+ 新建代码」创建

编辑线路包代码 ● 未保存 {{ pkgCodeName }} · {{ curPkgFile }}

{{ f.name }}
{{ fmtSize(f.size) }} · {{ fmtTime(f.mtime) }}
这个包里没有可编辑的代码文件
保存前会先做语法检查并自动备份改前版本(服务器 backups/pkg/); py 包保存后立即重启 worker, 新代码当场生效。 改坏了 worker 会起不来, 面板上这条线的状态会变红, 把报错修回去或从备份拷回即可。

修改登录密码

{{ srcPassAct === 'save' ? '保存 ' + cur : '重启瓶子服务' }}

先做语法检查再写盘,写之前把当前版本备份一份;存盘不等于生效,要等重启。
重启会中断正在进行的下载与播放,并把待生效的 {{ srcPending.length ? srcPending.length + ' 个文件' : '0 个文件' }}换进进程。

API Key 已生成

这是完整 Key, 只显示这一次, 请立即复制保存。把它发给要上传线路包的人即可, 吊销后立刻失效。
{{ newApiKey }}

{{ pkgPassTitle }}

{{ pkgPassHint }}
{{ pkgPct < 100 ? '正在上传 ' + pkgName + ' — ' + pkgPct + '%' : '正在校验并安装…' }}
没装上{{ pkgErr }}

回收站 (保留 7 天, 过期自动清理)

回收站是空的
{{ it.kind === "video" ? "视频" : "线路" }}
{{ it.orig.split("\\").pop() }}
{{ fmtSize(it.size) }} · 删除于 {{ fmtTime(it.time) }}
{{ toastMsg }}