提出需求
之前利用自建播客成功的在Moon FM中播放私人音频,后来发现Moon FM还可以听电台,但是国内电台并不全。
所以我们可以稍微改造一下让他支持我们自定义电台。
原理
Moon FM中关于电台的收听除了发现页面最下面少的可怜的推荐位以外就是搜索了。
因为Moon FM官方地址被墙,所以我们需要利用Quantumult X来进行抓包。
我们找一个基本没有电台会用的关键词custom
进行搜索,作为基础json文件。
搜索api 的地址为:
1
| https://backend.moon.fm/api/search?search_k=custom&search_type=radio&page=1
|
返回json文件为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "search_type" : "radio", "data" : { "last_page_url" : "https://backend.moon.fm/api/search?page=1", "prev_page_url" : null, "from" : null, "total" : 0, "path" : "https://backend.moon.fm/api/search", "first_page_url" : "https://backend.moon.fm/api/search?page=1", "last_page" : 1, "next_page_url" : null, "data" : [], "current_page" : 1, "per_page" : 20, "to" : null } }
|
同理我们搜索一个有返回结果的电台,例如音乐之声:
返回json文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| { "search_type" : "radio", "data" : { "last_page_url" : "https://backend.moon.fm/api/search?page=1", "prev_page_url" : null, "from" : 1, "total" : 1, "path" : "https://backend.moon.fm/api/search", "first_page_url" : "https://backend.moon.fm/api/search?page=1", "last_page" : 1, "next_page_url" : null, "data" : [ { "id" : 413131, "countryName" : "China", "image_url" : "https://moon.fm/images/radio_logo/29c8456d-0f0b-44bc-c275-c062e5d259ca.jpg", "name" : "CNR 音乐之声 Music Radio", "streamURL" : "http://ngcdn003.cnr.cn/live/yyzs/index.m3u8", "hidden" : 0 } ], "current_page" : 1, "per_page" : 20, "to" : 1 } }
|
返回结果经过分析发现
- 主要将搜索结果保存在data中
- 返回列表——data
- 搜索结果总数——total
- 每页数量——per_page
- 电台指向的就是一个m3u8地址
因此,如果我们自定义电台的数量少于20个,那么就无需考虑翻页以及next_page_url等问题。
篡改请求体
1.拦截请求
拦截请求体我们需要先利用正则命中请求链接。
利用在线正则表达式工具,我们可以得到命中的正则表达式。
1 2 3 4
| ^https\:\/\/backend\.moon\.fm\/api\/search\?search\_k\=custom\&search\_type\=radio
// 原文本:https://backend.moon.fm/api/search?search_k=custom&search_type=radio&page=1 // 命中:https://backend.moon.fm/api/search?search_k=custom&search_type=radio
|
那么我们需要在QuantumultX的conf文件中进行本地重写
1 2
| [rewrite_local] ^https\:\/\/backend\.moon\.fm\/api\/search\?search\_k\=custom\&search\_type\=radio url script-response-body test.js
|
2.篡改请求体
准备工作:
- 打开Quantumult X的iCloud开关
- 在Mac的
iCloud云盘/Quantumult X/Scripts
文件夹中创建test.js
这样利用Mac中的VSCode编辑test.js后保存即可同步至手机进行调试。
脚本编写:
首先我们需要先读取拦截的response请求,然后将修改后的请求返还给App。
首先,先把所有数据修改后进行返还。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| let obj = JSON.parse($response.body || '{}');
c_body = { "data": { "current_page": 1, "data": [{ "id": 446945, "streamURL": "http://satellitepull.cnr.cn/live/wxzjjtgb/playlist.m3u8", "name": "浙江交通之声", "image_url": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/%E6%B5%99%E6%B1%9F%E4%BA%A4%E9%80%9A%E4%B9%8B%E5%A3%B0.png", "hidden": 0, "countryName": "China" },{ "id": 446945, "streamURL": "http://satellitepull.cnr.cn/live/wxzjzs/playlist.m3u8", "name": "浙江之声", "image_url": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/%E6%B5%99%E6%B1%9F%E4%B9%8B%E5%A3%B0.png", "hidden": 0, "countryName": "China" }], "first_page_url": "https://backend.moon.fm/api/search?page=1", "from": 1, "last_page": 1, "last_page_url": "https://backend.moon.fm/api/search?page=1", "next_page_url": null, "path": "https://backend.moon.fm/api/search", "per_page": 20, "prev_page_url": null, "to": 15, "total": 15 }, "search_type": "radio" }
$done({ body: JSON.stringify(c_body) });
|
在Moon FM中搜索custom
,可以看到我们添加的两个电台,测试通过。
但是代码写成上面这样并不优雅,我们可以在线托管需要的电台json,然后让篡改脚本请求并返还,这样不管是电台管理还是可读性上面都比较舒服了。
3.优化代码
首先建立远程json文件,相关电台m3u8地址网上自行搜索或者去抓取喜马拉雅等App的地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| { "list": [ { "name": "浙江之声", "url": "http://satellitepull.cnr.cn/live/wxzjzs/playlist.m3u8", "image": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/浙江之声.png" }, { "name": "浙江交通之声", "url": "http://satellitepull.cnr.cn/live/wxzjjtgb/playlist.m3u8", "image": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/浙江交通之声.png" }, { "name": "浙江音乐调频·动听968", "url": "http://satellitepull.cnr.cn/live/wxzj968/playlist.m3u8", "image": "https://gitee.com/radioer/transparentlogo/raw/master/musicradio/动听968.png" }, { "name": "浙江旅游之声", "url": "http://satellitepull.cnr.cn/live/wxzj1045/playlist.m3u8", "image": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/浙江旅游之声.png" }, { "name": "浙江民生资讯广播", "url": "http://satellitepull.cnr.cn/live/wxzjmsgb/playlist.m3u8", "image": "https://gitee.com/radioer/transparentlogo/raw/master/generalradio/浙江民生广播.png" }, { "name": "杭州交通经济广播", "url": "http://livewsa.ximalaya.com/radio-first-page-app/live/632/64.m3u8", "image": "http://imagev2.xmcdn.com/group74/M05/9D/83/wKgO0l6C9I6iJSG0AACQznxf1WY094.png" }, { "name": "杭州西湖之声", "url": "http://livewsa.ximalaya.com/radio-first-page-app/live/635/64.m3u8", "image": "http://imagev2.xmcdn.com/group78/M02/8F/11/wKgO4F6C9LaDB0RYAAB_O87sIKU487.png" } ] }
|
然后改造篡改脚本,通过请求远程json后添加至response-body即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
const obj = JSON.parse($response.body || '{}'); const myRequest = { url: `https://raw.githubusercontent.com/ZiGmaX809/PrivateRules/master/QuantumultX/Scripts/CustomRadio/RadioList.json`, method: `GET`, };
$task.fetch(myRequest).then(response => { let new_data = [] let data = JSON.parse(response.body).list; let id = 0;
data.forEach(item => { new_data.push({ "id": id, "streamURL": item.url, "name": item.name, "image_url": item.image, "hidden": 0, "countryName": "China" }) id++; }); obj.data.data = new_data; $done({body :JSON.stringify(obj)}); }, reason => { console.log(reason.error); $done(); });
|
4.将脚本修改为资源列表(重写),以便自由开关该功能
1 2 3 4 5
|
hostname = backend.moon.fm
^https\:\/\/backend\.moon\.fm\/api\/search\?search\_k\=custom\&search\_type\=radio url script-response-body https:
|
并且修改Quantumult X的conf文件
1 2 3 4 5 6
| [rewrite_remote] https:
[rewrite_local] ^https\:\/\/backend\.moon\.fm\/api\/search\?search\_k\=custom\&search\_type\=radio url script-response-body test.js
|