mf转lx需要修改的地方和lx模板
发表于 : 2026年 6月 28日 15:31 星期天
需要修改:(现在已不用修改,代码通用了)
1. axios_1.default 改成 httpFetch
2.如果是通过歌名搜索的要将${title}改成${encodeURIComponent(title)}
不再需要进软件测试,已有js测试文档
下载电脑版测试api时,需要调试时:(设置为true,就可以看到运行日志)
//const DEV_ENABLE = true //代码已开启
1. axios_1.default 改成 httpFetch
2.如果是通过歌名搜索的要将${title}改成${encodeURIComponent(title)}
不再需要进软件测试,已有js测试文档
代码: 全选
const request = require('request');
/**
--复制中间的代码出来使用就行--
const musicItem = {'id':'193290598','title':'如愿','artist':'王菲'}; //kw
const musicItem = {'id':'ec1a18bbd6b61cb203e656b91f5cf2d1','title':'如愿','artist':'王菲'}; //kg
const musicItem = {'id':'1888381008','title':'如愿','artist':'王菲'}; //wy
const musicItem = {'songmid':'001ufyHx10iWpg','title':'如愿','artist':'王菲'}; //qq
const quality = '128k';
const quality = '320k';
const quality = 'flac';
const title = musicItem.title
${encodeURIComponent(title)}
console.log("res : ",res);
*/
const musicItem = {'id':'193290598','title':'如愿','artist':'王菲'}; //kw
const quality = '320k';
const kw_apis = [test_api];
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//api 代码部分
async function test_api(musicItem, quality) {
const qlist = {'128k':'standard', '320k':'exhigh', 'flac':'lossless', 'def':'exhigh',}
const q = qlist[quality] ?? qlist.def
const res = (await httpFetch(`https://musicapi.haitangw.net/music1/kw.php?type=mp3&id=${musicItem.id}&level=${q}`));
return res.request?.res?.responseUrl || res.headers?.location || '';
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
/////其他
/** 统一日志 **/
function logApi(apiName, msg, err = null) {
if (err) {
console.error(`[${apiName}] ${msg}`, err.message || err);
} else {
console.log(`[${apiName}] ${msg}`);
}
}
/** httpFetch - 自用修改的 **/
//如果lx源res.headers?.location得不到地址,试试res.request?.href
//return res.request?.res?.responseUrl || res.headers?.location || res.request?.href || '';
async function httpFetch(config = {}, options = {}) {
// ✔ 支持 httpFetch(url, options)
if (typeof config === "string") {config = { url: config, ...options };}
const {url, method = "GET", headers = {}, data, timeout = 10000, followRedirect = false,} = config;//因res.headers?.location需要:followRedirect = false关闭了跳转,需要时:打开true
return new Promise((resolve, reject) => {
request(url,{method, headers, timeout, followRedirect, body: method === "POST" && typeof data === "object" ? JSON.stringify(data) : data,},
(err, resp, body) => {
if (err) return reject(err);
let parsed = body;
try {if (typeof body === "string") parsed = JSON.parse(body);} catch {parsed = body}
resolve({data: parsed,body: parsed,status: resp.statusCode,headers: resp.headers || {},request: resp.request,});//body: parsed,兼容LX,data:parsed 方便不用修改代码
}
);
});
}
/** 通用执行器 **/
async function getMediaSource(musicItem, quality) {
console.log("========== 开始获取音源 ==========");
//自动选择自己定义的apis不用一个一个修改了
let apiList = typeof wy_apis !== "undefined" ? wy_apis : typeof kw_apis !== "undefined" ? kw_apis : typeof kg_apis !== "undefined" ? kg_apis : typeof qq_apis !== "undefined" ? qq_apis : [];
if (typeof qq_apis !== "undefined" && apiList === qq_apis) musicItem = { ...musicItem, id: musicItem.songmid };
const apiName = api.name;
try {
logApi(apiName, "开始:");
// ⏱️ 记录开始时间
const startTime = Date.now();
const musicUrl = await api(musicItem, quality);
// ⏱️ 结束时间 + 耗时
const costTime = Date.now() - startTime;
logApi(apiName, `耗时: ${costTime}ms`);
if (musicUrl && musicUrl !== "None") {
logApi(apiName, `成功: ${musicUrl}`);
//自己测试所有api的话,注释掉下面这行
//return {url: musicUrl,source: apiName,};
} else {
logApi(apiName, `获取失败!`);
}
} catch (err) {
logApi(apiName, `执行异常:`, err);
}
}
console.log("========== 所有API获取完成 ==========");
return {url: "",source: "",};
}
// 示例调用
(async () => {
const redirectUrl = await getMediaSource(musicItem, quality);
console.log("最终的重定向 URL:", redirectUrl);
})();
//const DEV_ENABLE = true //代码已开启
代码: 全选
/*!
* @name rx 20260707
*/
const rx_version = '20260707';
const kw_apis = [test_api];
const wy_apis = [test_api];
const qq_apis = [test_api];
const kg_apis = [test_api];
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------
async function test_api(musicItem, quality) {
const qlist = {'128k':'6', '320k':'8', 'flac':'10', 'def':'8',}
const q = qlist[quality] ?? qlist.def
const res = (await httpFetch(`https://api.vkeys.cn/v2/music/tencent?mid=${musicItem.id}&quality=${q}`));
return res?.data?.data?.url || "";
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------
//====复制上面部分使用
//====
//====
//====
//====
//====
//下面是固定代码,复制时复制上面部分
/** 统一日志 **/
function logApi(apiName, msg, err = null) {
if (err) {
console.error(`[${apiName}] ${msg}`, err.message || err);
} else {
console.log(`[${apiName}] ${msg}`);
}
}
/**
* 通用执行器
* @param {string} source tx | kw | kg | wy
* @param {object} musicItem
* @param {string} quality
* @returns {string} musicUrl
*/
async function getMediaSource(source, musicItem, quality) {
console.log("========== 开始获取音源 ==========");
// 根据 source 选择 API 列表
const apiMap = {tx: qq_apis,kw: kw_apis,kg: kg_apis,wy: wy_apis,};
const apis = apiMap[source];
// source 不合法
if (!apis) {console.log(`未知音源类型: ${source}`); return "";}
//apis开始执行
for (const api of apis) {
const apiName = api.name;
try {
logApi(apiName, "开始:");
const musicUrl = await api(musicItem, quality);
if (musicUrl && musicUrl !== "None") {
logApi(apiName, `成功: ${musicUrl}`);
// 获取成功立即返回
//return musicUrl;
} else {
logApi(apiName, "获取失败!");
}
} catch (err) {
logApi(apiName, "执行异常", err);
}
}
}
/**
* 洛雪调用接口 - handleGetMusicUrl
* 自己在里面改变了调用,自己使用
*/
const handleGetMusicUrl = async (source, musicInfo, quality) => {
//console.log('musicInfo:',musicInfo);//显示传入值,方便查看信息
const songId = musicInfo.hash ?? musicInfo.songmid;//kg使用的hash,其他都是songmid
//const musicItem = {[source === 'tx' ? 'songmid' : 'id']: songId,'title':musicInfo.name,'artist':musicInfo.singer ?? musicInfo.artist};//因musicfree代码格式,改变传入值,方便代码拿来直接使用,不用改原代码
const musicItem = {'id': songId,'title':musicInfo.name,'artist':musicInfo.singer ?? musicInfo.artist};//因musicfree代码格式,改变传入值,方便代码拿来直接使用,不用改原代码
const musicUrl = await getMediaSource(source, musicItem, quality)
if (!musicUrl) {
throw new Error('rx get musicUrl failed')
}
return musicUrl
}
/** httpFetch - 自用修改的 **/
//如果lx源res.headers?.location得不到地址,试试res.request?.href
//return res.request?.res?.responseUrl || res.headers?.location || res.request?.href || '';
async function httpFetch(config = {}, options = {}) {
// ✔ 支持 httpFetch(url, options)
if (typeof config === "string") {config = { url: config, ...options };}
const {url, method = "GET", headers = {}, data, timeout = 10000, followRedirect = false,} = config;//因res.headers?.location需要:followRedirect = false关闭了跳转,需要时:打开true
return new Promise((resolve, reject) => {
request(url,{method, headers, timeout, followRedirect, body: method === "POST" && typeof data === "object" ? JSON.stringify(data) : data,},
(err, resp, body) => {
if (err) return reject(err);
let parsed = body;
try {if (typeof body === "string") parsed = JSON.parse(body);} catch {parsed = body}
resolve({data: parsed,body: parsed,status: resp.statusCode,headers: resp.headers || {},request: resp.request,});//body: parsed,兼容LX,data:parsed 方便不用修改代码
}
);
});
}
//自用修改的httpFetch
//如果上面那个版本不能使用,试试这个老版,适应老接口
//需要放到代码最上面
/*
const httpFetch = (config = {}) =>
new Promise((resolve, reject) => {
if (typeof config === 'string') config = { url: config }
const { url, method = 'GET', headers = {}, data, timeout = 10000, maxRedirects } = config
request( url, {method, headers, timeout, maxRedirects, body: method === 'POST' && typeof data === 'object' ? JSON.stringify(data) : data,},
(err, resp, body) => {
if (err) return reject(err)
let d = body
try { if (typeof body === 'string') d = JSON.parse(body) } catch { d = body }
resolve({status: resp.statusCode, headers: resp.headers, data: d, body: d, request: resp.request,})//body: d兼容LX,data:d方便不用修改代码
}
)
})
*/
//上面是自己编写代码
//下面是原代码
const DEV_ENABLE = true
//const DEV_ENABLE = false
const MUSIC_QUALITY = {
kw: ["128k", "320k", "flac", "flac24bit"],
kg: ["128k", "320k", "flac", "flac24bit"],
tx: ["128k", "320k", "flac", "flac24bit"],
wy: ["128k", "320k", "flac", "flac24bit"],
mg: ["128k", "320k", "flac", "flac24bit"],
}
const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY)
const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx
const musicSources = {}
MUSIC_SOURCE.forEach(item => {
musicSources[item] = {
name: item,
type: 'music',
actions: ['musicUrl'],
qualitys: MUSIC_QUALITY[item],
}
})
on(EVENT_NAMES.request, ({ action, source, info }) => {
switch (action) {
case 'musicUrl':
if (env != 'mobile') {
console.group(`Handle Action(musicUrl)`)
console.log('source', source)
console.log('quality', info.type)
console.log('musicInfo', info.musicInfo)
console.groupEnd()
} else {
console.log(`Handle Action(musicUrl)`)
console.log('source', source)
console.log('quality', info.type)
console.log('musicInfo', info.musicInfo)
}
return handleGetMusicUrl(source, info.musicInfo, info.type)
.then(data => Promise.resolve(data))
.catch(err => Promise.reject(err))
default:
console.error(`action(${action}) not support`)
return Promise.reject('action not support')
}
})
// ========== 检查更新功能 ==========
// LX Music 官方规范:脚本需要处理 checkUpdate 事件来响应更新检查
const checkUpdate = async () => {
try {
console.log("rx checkUpdate begin: ")
const res = await httpFetch(`https://rxsub.eu.org/music/lx/rx.js?t=${Date.now()}`);
const js = typeof res.body === "string" ? res.body : "";
const match = js.match(/const\s+rx_version\s*=\s*['"]([^'"]+)['"]/);
if (!match) throw new Error("未找到版本号");
const latestVersion = match[1];
if (latestVersion !== rx_version) {
send(EVENT_NAMES.updateAlert, {
log: `${latestVersion}`,
updateUrl: "https://rxsub.eu.org/music/lx/rx.js"
});
}
} catch (err) {
console.error("[更新检查失败]", err);
return {
version: rx_version,
haveUpdate: false,
};
}
}
if (true) checkUpdate()
send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources })