合并自建歌曲源支线(selfhost-source)+ 版本号按约定修正为 1.6.0
版本号:
- 1.5.11 越界(规则 3 规定 patch ≤ 10)→ 修正为 1.6.0(进位到 minor、patch 归 0)
- versionCode 43 不变:43 从未对外发布,本次修正只是把命名拉回约定
合并支线(原在工作区根目录、App 仓库之外,DESIGN.md 自称"支线"):
- selfhost-source/server/ 自建歌曲源服务器(纯 Python 标准库、零 pip 依赖)
- selfhost-source/deploy/、DESIGN.md、LIBRARY.md、build_inventory.py
- selfhost-source/inventory/ 小清单(playlists.csv、song-stats.md 等)
- ⚠️ inventory 生成物(songs-*.csv / singers-top.csv,共 84MB)不入库,
已写入 .gitignore;需要时用 build_inventory.py 依据 muse.db 重新生成
同时入库的 App 侧支线改动(此前为工作树未提交状态):
- Whoami.kt(whoami 设备心跳)、DeviceIdentity.kt(设备身份伪装)
- PushDownload.kt / PushDownloadClient.kt(点歌推送)
- AdVideoFilter 带 query/fragment 的地址闸门;KTV_BRIDGE_API 11 → 13
- 修 ktv_api.js 的 global.KtvBridgeApiVersion(12 → 13,与注释及 Kotlin 两处校验一致)
- 对应单测:WhoamiTest / DeviceIdentityTest / PushDownloadTest / AdVideoFilterTest(共 39 例)
文档:
- DESIGN.md 的"在 App 仓库之外"约定改为"已并入仓库统一版本化"
- AGENTS.md 版本号行更新为 1.6.0/43,并新增支线并入说明
验证:assembleRelease + testReleaseUnitTest 全过(39 例)
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
麦动KTV 自建歌曲源 —— IIS **媒体站**配置(站点 `md.kasugano.cn`,HTTPS 端口 **4433**)
|
||||
把这个文件放到该站点的根目录,文件名必须是 `web.config`。
|
||||
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 本目录一共有三份配置,**这一份只管文件下载**: │
|
||||
│ * `media-site/web.config` ← 你正在看的:md.kasugano.cn(HTTPS **4433**) │
|
||||
│ * `api-site/web.config` mdmuse.kasugano.cn(HTTPS 443)只提供 API │
|
||||
│ * `web.config`(上级目录) 只是"该看哪两份"的索引,本身不含任何规则 │
|
||||
│ 完整步骤见 `../README.md`(第 5 节「建两个站点」/ 第 5.3 节「4433 端口怎么绑」)。│
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
本站点**只有一条反代规则**:`media/<编号>.ts` → 内网服务的同名路径,其余路径一律 404。
|
||||
目的:让这个域名(端口)**只能下文件**,不能调接口;反过来,API 域名也不能批量拖文件
|
||||
(后端还会按 X-Forwarded-Host 做一次宿主隔离,见 `../README.md` 第 10 节)。
|
||||
|
||||
⚠️ 必须替换的占位值:`http://192.168.100.232:6677` → 你内网 Linux 服务器的真实 IP:端口;
|
||||
域名 `md.kasugano.cn` 与端口 `4433` → 你实际的媒体域名/端口(IIS 站点绑定里也要一致)。
|
||||
|
||||
⚠️ 端口 4433 怎么来的:IIS 站点 → Bindings → Add → Type `https` → Port 填 **4433** →
|
||||
SSL certificate 选你的证书(一张证书带 SAN 同时签 `md.kasugano.cn` 与
|
||||
`mdmuse.kasugano.cn` 最省事)→ OK。之后访问就是 `https://md.kasugano.cn:4433/...`。
|
||||
非 443 端口下 IIS 的 `{HTTP_HOST}` 会带端口(`md.kasugano.cn:4433`)——
|
||||
后端判定宿主时对端口容错,配 `media_hosts=["md.kasugano.cn"]` 也能命中。
|
||||
|
||||
⚠️ **Range/206 必须原样透传**(App 的 OkDownload 靠它断点续传/边下边播):
|
||||
* 本站点关掉压缩(见下面 urlCompression):压缩会破坏 Content-Length/Range 语义;
|
||||
* 不要在 media/* 上加任何缓存/出站改写规则;
|
||||
* ARR 侧不要开响应缓冲(Server Proxy Settings → Response buffer threshold 设为 0 更稳);
|
||||
* ARR 超时给足(媒体是大文件,默认 120 秒不够,见下面注释里的 600 秒)。
|
||||
|
||||
前置条件与 API 站完全相同:URL Rewrite 2.1 + ARR 3.0 已装、已启用代理、
|
||||
已放行四个服务器变量(HTTP_X_FORWARDED_FOR / HTTP_X_FORWARDED_PROTO /
|
||||
HTTP_X_REAL_IP / HTTP_X_FORWARDED_HOST)—— 不放行就是 500.19,不会给你 404。
|
||||
-->
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
|
||||
<!-- ══════════════ 反向代理规则(URL Rewrite + ARR)══════════════
|
||||
pattern `^(media/.*)$` 的 {R:0} = 整段匹配(`media/<编号>.ts`),
|
||||
所以目标是 `http://192.168.100.232:6677/media/{R:0}`,
|
||||
例如 `/media/7300123.ts` → `http://192.168.100.232:6677/media/7300123.ts`。
|
||||
⚠️ 别写成 `url="…/media/{R:0}"`(那会变成 /media/media/…,必 404)。 -->
|
||||
<rewrite>
|
||||
<rules>
|
||||
|
||||
<!-- ① 唯一的一条:GET/HEAD /media/<编号>.ts(支持 Range/206) -->
|
||||
<rule name="ktv-media-only" stopProcessing="true">
|
||||
<match url="^(media/.*)$" />
|
||||
<serverVariables>
|
||||
<set name="HTTP_X_FORWARDED_FOR" value="{REMOTE_ADDR}" />
|
||||
<set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
|
||||
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
|
||||
<!-- 原始 Host 交给后端:既是后端拼绝对地址的依据,也是它**宿主隔离**判定的依据
|
||||
(非 443 端口时这里会带 `:4433`,后端对端口做了容错) -->
|
||||
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
|
||||
</serverVariables>
|
||||
<action type="Rewrite" url="http://192.168.100.232:6677/{R:0}" appendQueryString="true" />
|
||||
</rule>
|
||||
|
||||
<!-- ② 其余路径一律 404:本站点**不提供任何接口**(接口在 API 站)。
|
||||
想临时放开别的路径?别放 —— 需要接口就用 API 域名。 -->
|
||||
<rule name="ktv-media-block-everything-else" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<action type="CustomResponse" statusCode="404" statusReason="Not Found"
|
||||
statusDescription="404 Not Found" />
|
||||
</rule>
|
||||
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
||||
<!-- 媒体是 TS 流(video/MP2T),**压缩它没有任何意义**,反而会把 206 分块/长度搞乱、
|
||||
还可能撑爆 CPU。整站关掉静态/动态压缩,让字节原样透传。 -->
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" />
|
||||
|
||||
<!-- ══════════════ ARR 侧的三项(保留 Host / 超时 / 缓冲)══════════════
|
||||
⚠️ `system.webServer/proxy` 这一节在 IIS 里**默认是锁定的**(overrideModeDefault="Deny"),
|
||||
直接写进站点 web.config 会让站点报 500.19。所以默认走**服务器级**:
|
||||
`../applicationHost.config.snippet.xml` 的
|
||||
<proxy enabled="true" preserveHostHeader="true"
|
||||
reverseRewriteHostInResponseHeaders="false"
|
||||
proxyTimeout="600" connectTimeout="600" sendTimeout="600" />
|
||||
或者在 IIS 管理器里:服务器节点 → Application Request Routing Cache →
|
||||
Server Proxy Settings → Enable proxy + Time-out 600 + Response buffer threshold 0。
|
||||
|
||||
若你的 IIS 明确放开了这一节(applicationHost.config 里把 proxy 的
|
||||
overrideModeDefault 改成 Allow),也可以就地取消下面这段注释,效果一样:
|
||||
<proxy preserveHostHeader="true" proxyTimeout="600" connectTimeout="600" sendTimeout="600" />
|
||||
-->
|
||||
|
||||
<!-- 站点若装了 WebDAV,它会在 URL Rewrite 之前拦下 PUT/DELETE 并回 405。
|
||||
本站点只用 GET/HEAD(媒体下载),一般无需处理;遇到 405 就取消下面的注释。
|
||||
<modules>
|
||||
<remove name="WebDAVModule" />
|
||||
</modules>
|
||||
<handlers>
|
||||
<remove name="WebDAV" />
|
||||
</handlers>
|
||||
-->
|
||||
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
||||
<!--
|
||||
══════════════ 验证 Range/206(部署完必做)══════════════
|
||||
下面这些命令在任意能访问 IIS 的机器上跑(把域名/编号换成你的):
|
||||
|
||||
# ① 只有 /media/* 通:其余必须 404(拿 API 域名上的任意接口路径来试都行)
|
||||
curl -s -o /dev/null -w '%{http_code}\n' 'https://md.kasugano.cn:4433/healthz' # → 404
|
||||
curl -s -o /dev/null -w '%{http_code}\n' 'https://md.kasugano.cn:4433/token' # → 404
|
||||
|
||||
# ② 媒体 HEAD:必须 200 + Content-Length + Accept-Ranges: bytes
|
||||
curl -sI 'https://md.kasugano.cn:4433/media/<编号>.ts' | grep -Ei 'HTTP/|content-length|accept-ranges'
|
||||
|
||||
# ③ Range:必须 206 + Content-Range(这一步不过 = App 断点续传/边下边播会出问题)
|
||||
curl -s -D - -o /dev/null -r 0-1023 'https://md.kasugano.cn:4433/media/<编号>.ts' \
|
||||
| grep -Ei 'HTTP/|content-range|content-length|accept-ranges'
|
||||
# → HTTP/1.1 206 Partial Content
|
||||
# Content-Range: bytes 0-1023/<总长>
|
||||
# Content-Length: 1024
|
||||
# Accept-Ranges: bytes
|
||||
|
||||
# ④ 反查宿主隔离是否生效(后端侧,可选):临时放通 API 站的 /api/client_ip,
|
||||
# 看 host=md.kasugano.cn:4433、media_host_match=true、api_host_match=false。
|
||||
|
||||
⚠️ 常见坑:③ 返回 200 且整文件 = Range 被吃掉了。检查顺序:
|
||||
压缩是否真的关了 → ARR 响应缓冲是否开着 → 是否还有别的出站规则改写了响应。
|
||||
-->
|
||||
Reference in New Issue
Block a user