需求一:流程反转 + 上报绑定官方源成功 - 默认 sourceHosts 反转为 ["http://zk.ktv1.top:6677", "https://mdmuse.kasugano.cn"]; SourceHosts.DEFAULT / SongUrlResolver.DEFAULT_HOSTS(收敛为引用前者)/ ktv_api.js CONFIG.HOSTS+HOST 三处一致。 - 取址结果改为 SourcedSongUrl(url, sourceHost)(**显式来源标志**,不靠 URL 猜): 新增 SongSourceFlow(回落链 firstAvailable / 上报判定 shouldReportToSelfHost / 全失败信号);JS 侧新增 android.onSongSource(requestId, host) 回传命中的源。 - 汇合点 SongApiClient.getSongDownloadUrl 只在"地址来自官方源"时才 POST /push_download; 自建源自己给的地址与 DB 回落都不上报。 - 推送默认目标改为"从歌曲源列表里找第一个自建源"(自建源不再排第一,旧写法会直接关掉推送)。 - 1.6.1 落盘的旧默认顺序(自建源优先)在 KtvStore.load() 里一次性迁移;自定义列表不动。 - 业务码 404(自建源没有这首歌)仍只当"该源没地址",不置 sawForbidden、不进冷却、不污染受限统计。 需求二:6 条隐患 1) 设置页改源对 JS 立即生效:KtvJsBridge.applySourceSettingsNow 重新注入 KtvApiConfig.* 并把已构造实例的 window.api.sourceOrder 重置为新列表;SongApiClient.applySourceSettings 接线。 2) JS 路径识别业务码 403:新增 KtvJsBridge.riskForbidden(status, body)(纯函数,手写判定 避免 org.json 在单测里是空壳),HTTP 403 与 HTTP 200+{"code":403} 都算风控,与原生 sawForbidden 同口径。 3) isTrustedDownloadUrl 移除广告域名 ac16.vip 白名单,并改为黑名单优先(不再依赖调用顺序)。 4) MainActivity.download(song)(第五条地址消费点)补 AdVideoFilter.isTrustedSongUrl 闸门, 不可信按"源失效"处理(Eac19WindowGuard.noteAllSourcesFailed),不再静默下载。 5) SongApiClient.fetchFromDb 不再静默吞异常:曲库打不开/查询异常各记一条 MiliLog.localWarn(含编号与异常)。 6) 删除死代码 streamDownloadAndPlay(全仓 grep 无调用点,且内部取址不过最终闸门)。 需求三:死代码/漂移清理(均先全仓搜索确认无引用) - AdVideoFilter.replacementUrl 无任何写入点(恒为 null)→ 删除,resolve() 只保留"屏蔽"语义。 - ktv_api.js CONFIG.VER/VN 由"从不生效的死值"改为实际使用值 2.0 / 4.1.3.03281430。 - CONFIG.HOST 改为被 getToken 真正读取(不再"注入但从未被读")。 - KTV_BRIDGE_API 14 → 15(JS 两处 + KtvJsBridge 两处校验);AGENTS.md / README.md / README.en.md 的陈旧标记统一到 15。 - do.php 的 limit 与 i.php 的 retry/ordertype/end_date/heart_time 确认无消费方 → 不新增解析(保持现状)。 需求四:测试与打包 - 新增 SourceOrderConsistencyTest / SongSourceFlowTest / JsBridgeGateTest / DownloadEntryGateTest, 更新 SourceHostsTest / AdVideoFilterTest;app/build.gradle 打开 unitTests.returnDefaultValues。 - testReleaseUnitTest --rerun-tasks --offline:12 个测试类 / 87 例全过。 - assembleRelease --offline 通过(lintVital NewApi 0 条);版本 1.6.1/44 → 1.6.2/45。 不发布:未推 Gitea/Gitee、未动 Release/tag。
7.5 KiB
麦动 KTV
面向 Android TV 与横屏点歌设备的本地 KTV 应用
遥控器操作 · 歌曲检索 · 点播队列 · 下载管理 · 稳定播放
📌 项目说明
本仓库:https://gitea.kasugano.cn/zijunchiang/maidong-ktv
内容框架来源:https://gitee.com/yangyachao-X/maidong-ktv
本仓库基于上游「麦动 KTV」的界面与功能框架进行改造,并使用 DSH(DeepSeek Harness) 重写内核与数据源:重新实现曲库同步、歌曲源接入、设备认证、风控应对、远程日志与广告屏蔽等底层逻辑。上游框架的版权归原作者所有,本项目仅作学习与技术交流。
⚠️ 严正声明
本软件是完全免费且公开源码的个人学习与技术交流项目。
- 【禁止任何形式的营利性使用】:本软件(包括源码和编译后的 APK)严禁任何商家或个人进行打包售卖、硬件预装、收费技术支持或商业运营。
- 【侵权必究】:如果您是付费购买的本软件,说明您已被骗,请立即向平台举报商家并退款。
- 完整授权条款请参见项目根目录下的 LICENSE 文件。
核心功能
- TV 遥控器全局导航,支持方向键、确认键、返回键和长按操作。
- 统一焦点反馈,按钮、列表、卡片、开关和弹窗均提供清晰的选中状态。
- 首页提供排行榜、歌名、歌星、常唱、收藏、分类和本地歌曲入口。
- 支持全网与本地歌曲检索、语种筛选、分页浏览和首字母键盘输入。
- 歌星页面支持头像标签分类和歌手歌曲浏览。
- 支持歌曲点播、批量点歌、置顶、收藏、取消收藏和文件管理。
- 已点、已唱和下载列表实时同步歌曲状态。
- 已下载歌曲直接加入队列;未下载歌曲完成下载后自动加入,不打断当前播放。
- 已点列表存在歌曲时自动开始播放,并在切歌后同步队列与播放状态。
- 手机扫码点歌(局域网 HTTP 服务 + 二维码)。
播放功能
- 使用 IJK 播放器处理本地与下载歌曲(双 ABI:arm64-v8a / armeabi-v7a)。
- 支持小窗播放与全屏播放,切换页面和执行点歌操作时保持视频连续播放。
- 支持播放、暂停、切歌、重唱、进度显示和拖动。
- 支持原唱与伴唱切换,并保持当前播放或暂停状态。
- 支持歌曲片头信息、播放提示和暂停常驻提示。
- 支持视频比例、自动全屏和音画同步设置。
内核与数据源(DSH 重写部分)
- 曲库:统一走官方 Muse 同步(
mconn.cherryonline.cnmls-api/v1/sqlite/sync,RSA 登录 + 增量文件校验),不再依赖代码托管仓库承载数据库。 - 歌曲源:接入
w.w345.my(i.php取 token →do.php解析播放地址),固定设备标识并复刻签名算法;广告/错号资源(如返回wb66.cn/.../719.ts或文件名与 musicno 不一致)会被拦截并重试。 - 风控应对:源对陌生出口 IP 存在试用窗口(约 10 分钟,403"检测到异常行为"),App 检测到 403 后弹窗提示更换公网 IP;同 token 退避重试,不放大请求量。
- JS 热更新:歌曲接口逻辑在
app/src/main/assets/mobile/ktv_api.js,安装后从本仓库自动拉取兼容版本(须保留KTV_BRIDGE_API: 15标记)。 - 应用更新:以 Gitea Release 标签作为版本号(如
1.3.0),Release 需附带一个.apk附件;仅当标签高于当前BuildConfig.VERSION_NAME时提示下载。
🔧 编译教程
1. 环境要求
| 项目 | 要求 |
|---|---|
| JDK | OpenJDK 17 |
| Android SDK | compileSdk 35、minSdk 21、targetSdk 25 |
| Gradle | 使用仓库自带 wrapper(8.13),无需单独安装 |
| 构建系统 | Linux / macOS / Windows(命令行) |
2. 准备 Android SDK
安装 platforms;android-35、build-tools(≥ 34)与平台工具,并接受许可:
export ANDROID_HOME=/path/to/android-sdk
export ANDROID_SDK_ROOT=$ANDROID_HOME
yes | sdkmanager --licenses > /dev/null
sdkmanager "platforms;android-35" "build-tools;35.0.0" "platform-tools"
3. 配置签名密钥
app/build.gradle 的 release 签名默认读取仓库外相对路径的密钥:
storeFile file("../../ktv_keystore.jks")
storePassword "123456"
keyAlias "ktv"
keyPassword "123456"
即密钥位于仓库根目录的上一级(<项目根>/../ktv_keystore.jks)。若没有该密钥,可用 keytool 生成并放到对应位置(或直接改 app/build.gradle 中的路径与口令):
keytool -genkeypair -v \
-keystore ../ktv_keystore.jks \
-alias ktv -keyalg RSA -keysize 2048 -validity 10000 \
-storepass 123456 -keypass 123456 \
-dname "CN=Maidong KTV, OU=Dev, O=Maidong, L=Beijing, ST=Beijing, C=CN"
若只想快速跑通、不关心签名,可把
app/build.gradle的signingConfigs.release临时替换为signingConfigs.debug。
4. 执行编译
# 仓库根目录
cd maidong-ktv
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 # 按本机实际 JDK 路径调整
export ANDROID_HOME=/path/to/android-sdk
export ANDROID_SDK_ROOT=$ANDROID_HOME
./gradlew assembleRelease
首次运行会自动下载 Gradle 8.13 与依赖,耗时取决于网络。构建成功后在:
app/build/outputs/apk/release/app-release.apk
产物为已签名的 release APK,包含 armeabi-v7a 与 arm64-v8a 双 ABI。
5. 安装到设备
adb install -r app/build/outputs/apk/release/app-release.apk
首次启动会自动初始化曲库(官方 Muse 同步,需联网);播放歌曲时由 ktv_api.js 实时解析 w.w345.my 播放地址并下载到本地。
6. 常见问题
- 曲库初始化失败:检查设备网络能否访问
mconn.cherryonline.cn;已在设置页提供「重置数据库」。 - 点歌报 403 / 无播放地址:多为歌曲源对当前公网 IP 的试用窗口到期,重启光猫/路由器更换公网 IP 后恢复。
- 热更新脚本不生效:确认远端
ktv_api.js保留KTV_BRIDGE_API: 15标记,否则内置版本优先。 - 想改签名/ABI:编辑
app/build.gradle的signingConfigs与ndk.abiFilters后重新编译。
项目结构
maidong-ktv/
├── app/
│ ├── src/main/java/com/local/ktv/ # Kotlin 源码
│ │ ├── MainActivity.kt # 主界面 / 播放 / 下载编排
│ │ ├── MuseDbSync.kt # 官方曲库同步
│ │ ├── MuseDatabase.kt # 曲库访问
│ │ ├── KtvJsBridge.kt # JS 桥(HTTP/RSA/热更新)
│ │ ├── MiliLog.kt # 远程日志上报(GlogCenter)
│ │ └── SongOkDownloadManager.kt # 下载管理
│ ├── src/main/assets/mobile/ktv_api.js # 歌曲源逻辑(热更新)
│ └── src/main/res/ # 资源 / 证书
├── tools/ # 辅助脚本
├── build.gradle / settings.gradle
└── gradlew
免责声明
本项目仅用于个人学习与技术交流。请遵守所在地区法律法规,尊重上游作者版权与歌曲版权;请勿将本软件用于任何商业或侵权用途。
