├── .gitattributes ├── README.md ├── LICENSE ├── 聚合v3.js ├── 聚合API V3(by lerd).js ├── huibq.js ├── 梓澄公益音源二代v1.2.3.4.5.js ├── nya.js ├── 聚合API接口(decrypt).js ├── ikun_latest.js ├── 無名v0.0.3.js ├── 野草音源.js ├── 野花音源.js ├── ikun音源(中国香港服务器)v1.0.1.js ├── 肥猫不肥.js ├── ikun公益音源备用.js ├── zhizun.js ├── MusicDownloader.js ├── 公众号音源2.js ├── lx-music-source V3.0.js ├── monster.js ├── 聚合API接口2.0.js ├── 小熊猫v1.1.1.js └── 废材公社 内部源.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lxmusic-source-all 2 | 洛雪音源汇总 3 | 4 | 大道,至简 5 | 6 | 7 | 8 | 2025.2.28加入monster和下载器v4 9 | 10 | 2025.3.1解密了一些音源 11 | 12 | 2025.3.15更新ikun,添加至尊(消费者权益日更新) 13 | 14 | 2025.3.27欢迎大家提交音源,提交音源支持issue & pull request & mailto:mail@xlz767.ip-ddns.com 15 | 16 | 2025.3.29 废材公社更新 17 | 18 | 2025.7.6公众号v3 19 | 20 | 21 | [YxVM赞助了本项目](https://yxvm.com/) 22 | [NodeSupport](https://github.com/NodeSeekDev/NodeSupport)赞助了本项目 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 xzh767 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /聚合v3.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 聚合API接口 3 | * @description v3.0.0 4 | * @version 3 5 | * @author lerd 6 | */ 7 | const{EVENT_NAMES,request,on,send,version,utils}=globalThis.lx;const A='https://lerd.sukimon.me';const h=(u,o={method:'GET'})=>new Promise((v,j)=>{request(u,o,(e,p)=>{if(e)return j(e);v(p)})});on(EVENT_NAMES.request,async({source,info})=>{const r=await h(`${A}/${source}/${source=="kg"?info.musicInfo.hash:info.musicInfo.songmid}/${info.type}`);if(r.body.code==200)return r.body.data.url;else if(r.body.code==303){const S=JSON.parse(JSON.stringify(r.body.data));S.request.url=utils.buffer.bufToString(utils.buffer.from(S.request.url,'base64'),'utf-8');S.replaceList.forEach(i=>{let v=i.value.reduce((a,c)=>a&&a[c],info);i.path.reduce((a,c,x)=>{if(x===i.path.length-1) a[c]=i.path.reduce((a,c)=>a&&a[c],S.request).replace(i.key,i.map==undefined?v:i.map[v]);return a[c];},S.request);});const q=await h(encodeURI(S.request.url),S.request.options);if(S.response.check.key.reduce((a,c)=>a&&a[c],q)==S.response.check.value){const u=S.response.url.reduce((a,c)=>a&&a[c],q);if(u.startsWith("http"))return u;}}else throw new Error(r.body.msg);});h(`${A}/init/v3`).then(q=>{if(q.body.code!==200)throw new Error("脚本初始化失败");if(q.body.data.update.version>version)send(EVENT_NAMES.updateAlert,q.body.data.update);send(EVENT_NAMES.inited,q.body.data.init)}).catch(e=>{throw new Error(e)}) -------------------------------------------------------------------------------- /聚合API V3(by lerd).js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 聚合API接口 3 | * @description v3.0.0 4 | * @version 3 5 | * @author lerd 6 | */ 7 | const { EVENT_NAMES, request, on, send, version, utils } = globalThis.lx; const A = 'https://lerd.sukimon.me'; const h = (u, o = { method: 'GET' }) => new Promise((v, j) => { request(u, o, (e, p) => { if (e) return j(e); v(p) }) }); on(EVENT_NAMES.request, async ({ source, info }) => { const r = await h(`${A}/${source}/${source == "kg" ? info.musicInfo.hash : info.musicInfo.songmid}/${info.type}`); if (r.body.code == 200) return r.body.data.url; else if (r.body.code == 303) { const S = JSON.parse(JSON.stringify(r.body.data)); S.request.url = utils.buffer.bufToString(utils.buffer.from(S.request.url, 'base64'), 'utf-8'); S.replaceList.forEach(i => { let v = i.value.reduce((a, c) => a && a[c], info); i.path.reduce((a, c, x) => { if (x === i.path.length - 1) a[c] = i.path.reduce((a, c) => a && a[c], S.request).replace(i.key, i.map == undefined ? v : i.map[v]); return a[c]; }, S.request); }); const q = await h(encodeURI(S.request.url), S.request.options); if (S.response.check.key.reduce((a, c) => a && a[c], q) == S.response.check.value) { const u = S.response.url.reduce((a, c) => a && a[c], q); if (u.startsWith("http")) return u; } } else throw new Error(r.body.msg); }); h(`${A}/init/v3`).then(q => { if (q.body.code !== 200) throw new Error("脚本初始化失败"); if (q.body.data.update.version > version) send(EVENT_NAMES.updateAlert, q.body.data.update); send(EVENT_NAMES.inited, q.body.data.init) }).catch(e => { throw new Error(e) }) -------------------------------------------------------------------------------- /huibq.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name Huibq_lxmusic源 3 | * @description Github搜索“洛雪音乐音源”,禁止批量下载! 4 | * @version v1.2.0 5 | * @author Huibq 6 | */ 7 | const DEV_ENABLE = false 8 | const API_URL = 'https://lxmusicapi.onrender.com' 9 | const API_KEY = 'share-v2' 10 | const MUSIC_QUALITY = { 11 | kw: ['128k', '320k'], 12 | kg: ['128k', '320k'], 13 | tx: ['128k', '320k'], 14 | wy: ['128k', '320k'], 15 | mg: ['128k', '320k'], 16 | } 17 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 18 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 19 | const httpFetch = (url, options = { method: 'GET' }) => { 20 | return new Promise((resolve, reject) => { 21 | request(url, options, (err, resp) => { 22 | if (err) return reject(err) 23 | resolve(resp) 24 | }) 25 | }) 26 | } 27 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 28 | const songId = musicInfo.hash ?? musicInfo.songmid 29 | 30 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 31 | method: 'GET', 32 | headers: { 33 | 'Content-Type': 'application/json', 34 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-usic-request/${version}`}`, 35 | 'X-Request-Key': API_KEY, 36 | }, 37 | }) 38 | const { body } = request 39 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 40 | switch (body.code) { 41 | case 0: 42 | return body.url 43 | case 1: 44 | throw new Error('block ip') 45 | case 2: 46 | throw new Error('get music url failed') 47 | case 4: 48 | throw new Error('internal server error') 49 | case 5: 50 | throw new Error('too many requests') 51 | case 6: 52 | throw new Error('param error') 53 | default: 54 | throw new Error(body.msg ?? 'unknow error') 55 | } 56 | } 57 | const musicSources = {} 58 | MUSIC_SOURCE.forEach(item => { 59 | musicSources[item] = { 60 | name: item, 61 | type: 'music', 62 | actions: ['musicUrl'], 63 | qualitys: MUSIC_QUALITY[item], 64 | } 65 | }) 66 | on(EVENT_NAMES.request, ({ action, source, info }) => { 67 | switch (action) { 68 | case 'musicUrl': 69 | if (env != 'mobile') { 70 | console.group(`Handle Action(musicUrl)`) 71 | console.log('source', source) 72 | console.log('quality', info.type) 73 | console.log('musicInfo', info.musicInfo) 74 | console.groupEnd() 75 | } else { 76 | console.log(`Handle Action(musicUrl)`) 77 | console.log('source', source) 78 | console.log('quality', info.type) 79 | console.log('musicInfo', info.musicInfo) 80 | } 81 | return handleGetMusicUrl(source, info.musicInfo, info.type) 82 | .then(data => Promise.resolve(data)) 83 | .catch(err => Promise.reject(err)) 84 | default: 85 | console.error(`action(${action}) not support`) 86 | return Promise.reject('action not support') 87 | } 88 | }) 89 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 90 | -------------------------------------------------------------------------------- /梓澄公益音源二代v1.2.3.4.5.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 梓澄公益音源二代 3 | * @description 摆烂了,随便你们吧,反正这个没有账号 4 | * @version 1.2.3.4.5 5 | * @author helloplhm-qwq & Folltoshe 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 服务端地址 12 | const API_URL = "http://103.239.247.51:9763" 13 | // 服务端配置的请求key 14 | const API_KEY = "114514" 15 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 16 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 17 | const MUSIC_QUALITY = JSON.parse('{"kw":["128k","320k","flac"],"kg":["128k"],"tx":["128k"],"wy":["128k"],"mg":["128k"]}') 18 | // 音源配置(默认为自动生成,可以修改为手动) 19 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 20 | 21 | /** 22 | * 下面的东西就不要修改了 23 | */ 24 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 25 | 26 | const httpFetch = (url, options = { method: 'GET' }) => { 27 | return new Promise((resolve, reject) => { 28 | console.log('--- start --- ' + url) 29 | request(url, options, (err, resp) => { 30 | if (err) return reject(err) 31 | console.log('API Response: ', resp) 32 | resolve(resp) 33 | }) 34 | }) 35 | } 36 | 37 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 38 | const songId = musicInfo.hash ?? musicInfo.songmid 39 | 40 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 41 | method: 'GET', 42 | headers: { 43 | 'Content-Type': 'application/json', 44 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 45 | 'X-Request-Key': API_KEY, 46 | }, 47 | }) 48 | const { body } = request 49 | 50 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 51 | 52 | switch (body.code) { 53 | case 0: 54 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 55 | return body.data 56 | case 1: 57 | throw new Error('block ip') 58 | case 2: 59 | throw new Error('get music url failed') 60 | case 4: 61 | throw new Error('internal server error') 62 | case 5: 63 | throw new Error('too many requests') 64 | case 6: 65 | throw new Error('param error') 66 | default: 67 | throw new Error(body.msg ?? 'unknow error') 68 | } 69 | } 70 | 71 | const musicSources = {} 72 | MUSIC_SOURCE.forEach(item => { 73 | musicSources[item] = { 74 | name: item, 75 | type: 'music', 76 | actions: ['musicUrl'], 77 | qualitys: MUSIC_QUALITY[item], 78 | } 79 | }) 80 | 81 | on(EVENT_NAMES.request, ({ action, source, info }) => { 82 | switch (action) { 83 | case 'musicUrl': 84 | if (env != 'mobile') { 85 | console.group(`Handle Action(musicUrl)`) 86 | console.log('source', source) 87 | console.log('quality', info.type) 88 | console.log('musicInfo', info.musicInfo) 89 | console.groupEnd() 90 | } else { 91 | console.log(`Handle Action(musicUrl)`) 92 | console.log('source', source) 93 | console.log('quality', info.type) 94 | console.log('musicInfo', info.musicInfo) 95 | } 96 | return handleGetMusicUrl(source, info.musicInfo, info.type) 97 | .then(data => Promise.resolve(data)) 98 | .catch(err => Promise.reject(err)) 99 | default: 100 | console.error(`action(${action}) not support`) 101 | return Promise.reject('action not support') 102 | } 103 | }) 104 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 105 | -------------------------------------------------------------------------------- /nya.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 示例音源 3 | * @description Nya~ 4 | * @version 0.0.1 5 | * @author 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 服务端地址 12 | const API_URL = "http://103.40.13.21:9866" 13 | // 服务端配置的请求key 14 | const API_KEY = "nya" 15 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 16 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 17 | const MUSIC_QUALITY = JSON.parse('{"kw":["128k","320k","flac","flac24bit"],"kg":["128k"],"tx":["128k","320k","flac","flac24bit"],"wy":["128k","320k","flac","flac24bit"],"mg":["128k"]}') 18 | // 音源配置(默认为自动生成,可以修改为手动) 19 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 20 | 21 | /** 22 | * 下面的东西就不要修改了 23 | */ 24 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 25 | 26 | /** 27 | * URL请求 28 | * 29 | * @param {string} url - 请求的地址 30 | * @param {object} options - 请求的配置文件 31 | * @return {Promise} 携带响应体的Promise对象 32 | */ 33 | const httpFetch = (url, options = { method: 'GET' }) => { 34 | return new Promise((resolve, reject) => { 35 | console.log('--- start --- ' + url) 36 | request(url, options, (err, resp) => { 37 | if (err) return reject(err) 38 | console.log('API Response: ', resp) 39 | resolve(resp) 40 | }) 41 | }) 42 | } 43 | 44 | /** 45 | * 46 | * @param {string} source - 音源 47 | * @param {object} musicInfo - 歌曲信息 48 | * @param {string} quality - 音质 49 | * @returns {Promise} - 歌曲播放链接 50 | * @throws {Error} - 错误消息 51 | */ 52 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 53 | const songId = musicInfo.hash ?? musicInfo.songmid 54 | 55 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 56 | method: 'GET', 57 | headers: { 58 | 'Content-Type': 'application/json', 59 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 60 | 'X-Request-Key': API_KEY, 61 | }, 62 | follow_max: 5, 63 | }) 64 | const { body } = request 65 | 66 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 67 | if (env != 'mobile') console.groupEnd() 68 | switch (body.code) { 69 | case 0: 70 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 71 | return body.data 72 | case 1: 73 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 74 | throw new Error('block ip') 75 | case 2: 76 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 77 | throw new Error('get music url failed') 78 | case 4: 79 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 80 | throw new Error('internal server error') 81 | case 5: 82 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 83 | throw new Error('too many requests') 84 | case 6: 85 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 86 | throw new Error('param error') 87 | default: 88 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 89 | throw new Error(body.msg ?? 'unknow error') 90 | } 91 | } 92 | 93 | // 生成歌曲信息 94 | const musicSources = {} 95 | MUSIC_SOURCE.forEach(item => { 96 | musicSources[item] = { 97 | name: item, 98 | type: 'music', 99 | actions: ['musicUrl'], 100 | qualitys: MUSIC_QUALITY[item], 101 | } 102 | }) 103 | 104 | // 监听 LX Music 请求事件 105 | on(EVENT_NAMES.request, ({ action, source, info }) => { 106 | switch (action) { 107 | case 'musicUrl': 108 | if (env != 'mobile') { 109 | console.group(`Handle Action(musicUrl)`) 110 | console.log('source', source) 111 | console.log('quality', info.type) 112 | console.log('musicInfo', info.musicInfo) 113 | } else { 114 | console.log(`Handle Action(musicUrl)`) 115 | console.log('source', source) 116 | console.log('quality', info.type) 117 | console.log('musicInfo', info.musicInfo) 118 | } 119 | return handleGetMusicUrl(source, info.musicInfo, info.type) 120 | .then(data => Promise.resolve(data)) 121 | .catch(err => Promise.reject(err)) 122 | default: 123 | console.error(`action(${action}) not support`) 124 | return Promise.reject('action not support') 125 | } 126 | }) 127 | 128 | // 向 LX Music 发送初始化成功事件 129 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 130 | -------------------------------------------------------------------------------- /聚合API接口(decrypt).js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 聚合API接口 (by lerd)(decrypt) 3 | * @description 理论可听全平台无损 4 | * @version v2.0.0 5 | * @author lerd 6 | */ 7 | 8 | const DEV_ENABLE = false; 9 | const MUSIC_QUALITY = { 10 | 'tx': ['128k', '320k', 'flac', 'flac24bit'], 11 | 'wy': ['128k', '320k', 'flac', 'flac24bit'], 12 | 'kg': ['128k', '320k', 'flac', 'flac24bit'], 13 | 'kw': ['128k', '320k', 'flac'], 14 | 'mg': ['320k', 'flac'] 15 | }; 16 | 17 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY); 18 | 19 | const { 20 | EVENT_NAMES, 21 | request, 22 | on, 23 | send, 24 | utils, 25 | env, 26 | version, 27 | currentScriptInfo 28 | } = globalThis.lx; 29 | 30 | const httpFetch = (url, options = { method: 'GET' }) => { 31 | return new Promise((resolve, reject) => { 32 | request(url, options, (err, res) => { 33 | if (err) return reject(err); 34 | resolve(res); 35 | }); 36 | }); 37 | }; 38 | 39 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 40 | switch (source) { 41 | case 'tx': { 42 | const qualityMap = { 43 | '128k': '7', 44 | '320k': '9', 45 | 'flac': '11', 46 | 'flac24bit': '14' 47 | }; 48 | const res = await httpFetch(`https://www.hhlqilongzhu.cn/api/dg_qqmusic.php?songmid=${musicInfo.songmid}&quality=${qualityMap[quality]}`); 49 | if (!res.body || res.body.code !== 0) throw new Error('获取链接失败'); 50 | return res.body.data; 51 | } 52 | 53 | case 'wy': { 54 | const qualityMap = { 55 | '128k': 'standard', 56 | '320k': 'exhigh', 57 | 'flac': 'lossless', 58 | 'flac24bit': 'hires' 59 | }; 60 | const res = await httpFetch(`https://www.hhlqilongzhu.cn/api/dg_wymusic.php?songmid=${musicInfo.songmid}&quality=${qualityMap[quality]}`); 61 | if (!res.body || res.body.code !== 200) throw new Error('获取链接失败'); 62 | return res.body.data; 63 | } 64 | 65 | case 'kg': { 66 | const qualityMap = { 67 | '128k': '128', 68 | '320k': '320', 69 | 'flac': 'flac', 70 | 'flac24bit': 'flac24bit' 71 | }; 72 | const res = await httpFetch(`https://www.hhlqilongzhu.cn/api/dg_kgmusic.php?hash=${musicInfo.hash}&quality=${qualityMap[quality]}`); 73 | if (!res.body || res.body.code !== 200) throw new Error('获取链接失败'); 74 | return res.body.data; 75 | } 76 | 77 | case 'kw': { 78 | const qualityMap = { 79 | '128k': '128', 80 | '320k': '320', 81 | 'flac': 'flac' 82 | }; 83 | const res = await httpFetch(`https://www.hhlqilongzhu.cn/api/dg_kwmusic.php?musicid=${musicInfo.musicid}&quality=${qualityMap[quality]}`); 84 | if (!res.body || res.body.code !== 200) throw new Error('获取链接失败'); 85 | return res.body.data; 86 | } 87 | 88 | case 'mg': { 89 | const qualityMap = { 90 | '320k': '2', 91 | 'flac': '1' 92 | }; 93 | const res = await httpFetch(`https://www.hhlqilongzhu.cn/api/dg_mgmusic_24bit.php?msg=${musicInfo.msg}&quality=${qualityMap[quality]}`); 94 | if (!res.body || res.body.code !== 200) throw new Error('获取链接失败'); 95 | return res.body.music_url; 96 | } 97 | 98 | default: 99 | throw new Error('不支持的平台'); 100 | } 101 | }; 102 | 103 | const musicSources = {}; 104 | MUSIC_SOURCE.forEach(source => { 105 | musicSources[source] = { 106 | name: source, 107 | type: 'music', 108 | actions: source === 'mg' ? [] : ['musicUrl'], 109 | qualitys: MUSIC_QUALITY[source] 110 | }; 111 | }); 112 | 113 | on(EVENT_NAMES.request, ({ action, source, info }) => { 114 | switch (action) { 115 | case 'musicUrl': 116 | return handleGetMusicUrl(source, info.musicInfo, info.quality) 117 | .then(url => Promise.resolve(url)) 118 | .catch(err => Promise.reject(err)); 119 | default: 120 | return Promise.reject('不支持的请求类型'); 121 | } 122 | }); 123 | 124 | // 初始化校验 125 | const scriptInfo = globalThis.lx.currentScriptInfo; 126 | if ( 127 | scriptInfo.name !== "聚合API接口 (by lerd)" || 128 | scriptInfo.description !== "理论可听全平台无损" || 129 | scriptInfo.version !== "v2.0.0" || 130 | scriptInfo.author !== "lerd" 131 | ) { 132 | throw new Error("初始化失败!请检查音源信息"); 133 | } 134 | 135 | send(EVENT_NAMES.inited, { 136 | status: true, 137 | openDevTools: DEV_ENABLE, 138 | sources: musicSources 139 | }); -------------------------------------------------------------------------------- /ikun_latest.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name ikun音源 3 | * @description 请不要分享此音源,谢谢 951962664 4 | * @version v515 5 | * @author ikunshare 6 | */ 7 | 8 | const DEV_ENABLE = false 9 | const UPDATE_ENABLE = true 10 | const API_URL = "https://api.ikunshare.com" 11 | const API_KEY = `public_source` 12 | const MUSIC_QUALITY = JSON.parse('{"kw":["128k","320k","flac","hires"],"kg":["128k","320k","flac","hires","atmos","master"],"tx":["128k","320k","flac","hires","atmos","atmos_plus","master"],"wy":["128k","320k","flac","hires","atmos","master"],"mg":["128k","320k","flac","hires"]}'); 13 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY); 14 | 15 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx; 16 | 17 | const SCRIPT_MD5 = "0312db081d04b8aafd7632dda9400419"; 18 | 19 | const httpFetch = (url, options = { method: "GET" }) => { 20 | return new Promise((resolve, reject) => { 21 | console.log("--- start --- " + url); 22 | request(url, options, (err, resp) => { 23 | if (err) return reject(err); 24 | console.log("API Response: ", resp); 25 | resolve(resp); 26 | }); 27 | }); 28 | }; 29 | 30 | const handleBase64Encode = (data) => { 31 | var data = utils.buffer.from(data, "utf-8"); 32 | return utils.buffer.bufToString(data, "base64"); 33 | }; 34 | 35 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 36 | const songId = musicInfo.hash ?? musicInfo.songmid; 37 | const request = await httpFetch( 38 | `${API_URL}/url?source=${source}&songId=${songId}&quality=${quality}`, 39 | { 40 | method: "GET", 41 | headers: { 42 | "Content-Type": "application/json", 43 | "User-Agent": `${ 44 | env ? `lx-music-${env}/${version}` : `lx-music-request/${version}` 45 | }`, 46 | "X-Request-Key": API_KEY, 47 | }, 48 | follow_max: 5, 49 | } 50 | ); 51 | const { body } = request; 52 | if (!body || isNaN(Number(body.code))) throw new Error("unknow error"); 53 | if (env != "mobile") console.groupEnd(); 54 | switch (body.code) { 55 | case 200: 56 | console.log( 57 | `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}` 58 | ); 59 | return body.data; 60 | case 403: 61 | console.log( 62 | `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁` 63 | ); 64 | throw new Error("IP被封禁"); 65 | case 500: 66 | console.log( 67 | `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}` 68 | ); 69 | throw new Error("获取URL失败"); 70 | case 429: 71 | console.log( 72 | `handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧` 73 | ); 74 | throw new Error("请求过速"); 75 | default: 76 | console.log( 77 | `handleGetMusicUrl(${source}_${ 78 | musicInfo.songmid 79 | }, ${quality}) failed, ${body.msg ? body.msg : "未知错误"}` 80 | ); 81 | throw new Error(body.msg ?? "未知错误"); 82 | } 83 | }; 84 | 85 | const checkUpdate = async () => { 86 | const request = await httpFetch( 87 | `${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`, 88 | { 89 | method: "GET", 90 | headers: { 91 | "Content-Type": "application/json", 92 | "User-Agent": `${ 93 | env ? `lx-music-${env}/${version}` : `lx-music-request/${version}` 94 | }`, 95 | }, 96 | } 97 | ); 98 | const { body } = request; 99 | 100 | if (!body || body.code !== 200) console.log("checkUpdate failed"); 101 | else { 102 | console.log("checkUpdate success"); 103 | if (body.data != null) { 104 | globalThis.lx.send(lx.EVENT_NAMES.updateAlert, { 105 | log: body.data.updateMsg, 106 | updateUrl: body.data.updateUrl, 107 | }); 108 | } 109 | } 110 | }; 111 | 112 | const musicSources = {}; 113 | MUSIC_SOURCE.forEach((item) => { 114 | musicSources[item] = { 115 | name: item, 116 | type: "music", 117 | actions: ["musicUrl"], 118 | qualitys: MUSIC_QUALITY[item], 119 | }; 120 | }); 121 | 122 | on(EVENT_NAMES.request, ({ action, source, info }) => { 123 | switch (action) { 124 | case "musicUrl": 125 | if (env != "mobile") { 126 | console.group(`Handle Action(musicUrl)`); 127 | console.log("source", source); 128 | console.log("quality", info.type); 129 | console.log("musicInfo", info.musicInfo); 130 | } else { 131 | console.log(`Handle Action(musicUrl)`); 132 | console.log("source", source); 133 | console.log("quality", info.type); 134 | console.log("musicInfo", info.musicInfo); 135 | } 136 | return handleGetMusicUrl(source, info.musicInfo, info.type) 137 | .then((data) => Promise.resolve(data)) 138 | .catch((err) => Promise.reject(err)); 139 | default: 140 | console.error(`action(${action}) not support`); 141 | return Promise.reject("action not support"); 142 | } 143 | }); 144 | 145 | if (UPDATE_ENABLE) checkUpdate(); 146 | 147 | send(EVENT_NAMES.inited, { 148 | status: true, 149 | openDevTools: DEV_ENABLE, 150 | sources: musicSources, 151 | }); 152 | -------------------------------------------------------------------------------- /無名v0.0.3.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 無名 3 | * @description 不惊扰别人的宁静,就是慈悲;不伤害别人的自尊,就是善良 无云控,纯本地 4 | * @version v0.0.3 5 | * @author helloplhm-qwq 6 | * 7 | * 8 | */(()=>{"use strict";const{EVENT_NAMES:e,on:r,send:t,request:n,utils:o,version:a}=globalThis.lx,s={buffer:{from:o.buffer.from,bufToString:o.buffer.bufToString},crypto:{aesEncrypt:o.crypto.aesEncrypt,md5:o.crypto.md5,randomBytes:o.crypto.randomBytes,rsaEncrypt:o.crypto.rsaEncrypt}},l={"128k":"128kmp3","320k":"320kmp3",flac:"2000kflac",flac24bit:"4000kflac"},d=e=>s.crypto.md5(e);var i,A,u,p;i=e=>(""+e).replace(/[^\d.]+/g,e=>"."+(e.replace(/[\W_]+/,"").toUpperCase().charCodeAt(0)-65536)+".").replace(/(?:\.0+)*(\.-\d+(?:\.\d+)?)\.*$/g,"$1").split(".");function E(t,o=""){const i=Object.keys(t).sort();let a="";return i.forEach((e,r)=>{a+=e+"="+t[e],r!=i.length-1&&(a+=o)}),a}const m={"128k":0,"320k":1,flac:2},D={"128k":"standard","320k":"exhigh",flac:"lossless",flac24bit:"hires"},f=(e,r)=>{var t,o,i=`nobody${e="/"+e}use${text}md5forencrypt`,i=d(i),e=`${e}-${c}-${text}-${c}-`+i;return{params:(i=e,e="e82ckenh8dichen8",t="",o="aes-128-ecb",a||(o=o.split("-").pop()),i=s.crypto.aesEncrypt(i,o,e,t),(a?s.buffer.bufToString(i,"hex"):[...new Uint8Array(i)].map(e=>e.toString(16).padStart(2,"0")).join("")).toUpperCase())}},B={"128k":"PQ","320k":"HQ",flac:"SQ",flac24bit:"ZQ"},C={kw:{info:{name:"酷我音乐",type:"music",actions:["musicUrl"],qualitys:["128k","320k","flac","flac24bit"]},async musicUrl({songmid:e},r){const i=`https://nmobi.kuwo.cn/mobi.s?f=web&source=kwplayer_ar_1.1.9_oppo_118980_320.apk&type=convert_url_with_sign&rid=${e}&br=`+(r=l[r]);return new Promise((t,o)=>{n(i,{method:"GET",headers:{"User-Agent":"okhttp/4.10.0"}},(e,r)=>e?o(e):200!=r.body.code||0==r.body.data.bitrate?o(new Error("failed")):void t(r.body.data.url.split("?")[0]))})}},kg:{info:{name:"酷狗音乐",type:"music",actions:["musicUrl"],qualitys:["128k"]},musicUrl({hash:i,albumId:a},e){return new Promise((t,o)=>{var e=d(i+"57ae12eb6890223e355ccfcb74edf70d10051234560"),e={album_id:a,userid:0,area_code:1,hash:i,module:"",mid:123456,appid:"1005",ssa_flag:"is_fromtrack",clientver:"10086",vipType:6,ptype:0,token:"",auth:"",mtype:0,album_audio_id:0,behavior:"play",clienttime:Math.floor(Date.now()/1e3),pid:2,key:e,dfid:"-",pidversion:3001,quality:"128"},r=d("OIlwieks28dk2k092lksi2UIkp"+E(e)+"OIlwieks28dk2k092lksi2UIkp"),e="https://gateway.kugou.com/v5/url?"+E(e,"&")+"&signature="+r;n(e,{method:"GET",headers:{"User-Agent":"Android712-AndroidPhone-8983-18-0-NetMusic-wifi","KG-THash":"3e5ec6b","KG-Rec":"1","KG-RC":"1","x-router":"tracker.kugou.com"}},(e,r)=>{return e?o(e):1!==(e=r.body).status?o(new Error(e.err_code)):void t(r.body.url[0])})})}},tx:{info:{name:"企鹅音乐",type:"music",actions:["musicUrl"],qualitys:["128k","320k","flac"]},musicUrl({songmid:e},r){return new Promise((t,o)=>{n("https://md.khkj.xyz/qq/?type=song",{method:"POST",headers:{"User-Agent":"Mozilla/5.0 (Linux; Android 10; NOH-AN01 Build/HUAWEINOH-AN01; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/88.0.4324.93 Mobile Safari/537.36 uni-app Html5Plus/1.0 (Immersed/36.0)",Connection:"Keep-Alive","Accept-Encoding":"gzip","Content-Type":"application/x-www-form-urlencoded",DNT:"1","Sec-GPC":"1"},body:"mid="+e+"&pmid="+e+"&q="+m[r]},(e,r)=>{return console.log(JSON.stringify(r.body,""," ")),e?o("failed"):(e=r.body.data,200==r.body.code&&e.purl?void t(e.purl):o(new Error("failed")))})})}},wy:{info:{name:"网易音乐",type:"music",actions:["musicUrl"],qualitys:["128k","320k","flac","flac24bit"]},musicUrl({songmid:e},r){r=D[r];r="api/song/enhance/player/url/v1";JSON.stringify([e]);const i=f(r);return new Promise((t,o)=>{n("https://interface.music.163.com/eapi/song/enhance/player/url/v1",{method:"POST",form:i,headers:{cookie:"EVNSM=1.0.0; versioncode=9000025; buildver=240205104600; ntes_kaola_ad=1; mobilename=sukiseki; osver=13; MUSIC_U=00C0AB8A13333D8FE277B703A2CFBBE280982A63BCFAE1D947FC3C53C5A069A56D333FE23DD3FFB95C10F811493A4070519F5A0511EBE5F2C032BF6E1F7508803007439BE7625982E5DCC0F9AEA729EE9A0084994199221E1159F0D7D63F26D2321C1AC656B9B219A9C19B0A19107EC4EA492A07896BCE24A05002646926C3A628AC6014EDF1B53946766EE920C57FCD74BF6E2B336B843B1B1E11D78DB53472AFB2CBBB6644D8BD9BE5B72CD70E699B4E63356A13DD1B9D99C40EA784FF163D3CA0F50377D738E9A07604D9C0205FB3227C55D2644E538226DA1D2770BD81CA7C90C4632A01FD837E6EA0D8E7B46086AB762C40B5257BE231552163CDAA8A24DE5DE490CFD33A401D890A73D7ACB7062F533824A42480B3772D4564718629D8B64014D8B2C2E8A46F8FE8A7DA698DAA39C9931007AE795485D1EC49C4B66BC26A47D66C0E455697B1350140DC334191DB4D3EB22EA55B25869A421F90480C64F55E0912BCB766D14BC05E8AA5C487A197AF4D3855D06710C91BE28281A00E20DF; os=android; channel=bubugao1; appver=9.0.25; packageType=release"}},(e,r)=>{return e?o(e):({url:e,freeTrialInfo:r}=r.body.data[0],!e||r?o(new Error("failed")):void t(e))})})}},mg:{info:{name:"咪咕音乐",type:"music",actions:["musicUrl"],qualitys:["128k","320k","flac","flac24bit"]},musicUrl(e,r){r=B[r],console.log(e);const t=`https://app.c.nf.migu.cn/MIGUM2.0/strategy/listen-url/v2.4?netType=01&resourceType=E&songId=${e.copyrightId}&toneFlag=`+r;return new Promise((o,i)=>{console.log(r),n(t,{method:"GET",headers:{channel:"014000D",token:"848401000134020058524459344E544130526A4932517A55344D7A56434E55453240687474703A2F2F70617373706F72742E6D6967752E636E2F6E303030312F4062393662376634326336326434303935393366666433366434313939393033300300040298EAFB0400063232303032340500164D4759355A4463784D324E684E4449324F57566B4E51FF0020795263B9A333A4580E13DD7F28820A8B9788F30062F6025FA08BF10CC5A8AA04",aversionid:"DF94898993A5A28A64968A9FD0ADA0749397878BC39DD7BC68C584A1BAAFC96EC5938D8D8ED1A490949A8F9EB680997296DFD0D391D6ABBC69928AD0B57D99779CC8B88CDDECEE89628F89A1827E986F94978AD392A7A2916A928AA4878199779C"}},(e,r)=>{if(e)return i(e);let t=r.body.data?.url;if(!t)return i(new Error("failed"));t.startsWith("//")&&(t="https:"+t),o(t.replace(/\+/g,"%2B").split("?")[0])})})}}};var y,k,F=globalThis.lx["currentScriptInfo"],b=(r(e.request,({source:e,action:r,info:t})=>{if("musicUrl"===r)return C[e].musicUrl(t.musicInfo,t.type).catch(e=>Promise.reject(e))}),{});for([y,k]of Object.entries(C))b[y]=k.info;if(F&&("無名"!=F.name||"不惊扰别人的宁静,就是慈悲;不伤害别人的自尊,就是善良 无云控,纯本地"!=F.description))throw new Error("请不要修改脚本名字或简介,当然如果你想做那个令人瞧不起的人就请删掉这段代码");t(e.inited,{status:!0,openDevTools:!1,sources:b})})(); -------------------------------------------------------------------------------- /野草音源.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 野草🌾 3 | * @version 1.0.0 4 | */ 5 | function Z(Y,L){const K=O();return Z=function(U,H){U=U-(-0x42*0x37+-0x4*-0x21e+0x704);let S=K[U];return S;},Z(Y,L);}function O(){const n=['\x63\x6f\x70\x79\x72\x69\x67\x68\x74\x49','\x69\x6e\x69\x74\x65\x64','\x35\x53\x41\x56\x79\x6d\x5a','\x69\x63\x73\x2e\x74\x6b\x2f\x76\x31','\u670d\u52a1\u5668\u5f02\u5e38','\x63\x72\x79\x70\x74\x6f','\x53\x4f\x53\x4c\x6d','\x47\x45\x54','\x35\x32\x30\x34\x30\x32\x38\x6c\x59\x4e\x54\x76\x7a','\x6d\x75\x73\x69\x63','\x4a\x71\x48\x59\x51','\x73\x6f\x6e\x67\x6d\x69\x64','\x39\x31\x37\x31\x34\x33\x38\x55\x53\x59\x70\x77\x52','\x69\x63\x73\x2e\x74\x6b\x2f\x76\x31\x2f','\x74\x48\x42\x63\x6f','\x42\x43\x6b\x53\x46','\x70\x54\x70\x4e\x6c','\x6c\x76\x7a\x44\x71','\x62\x75\x66\x54\x6f\x53\x74\x72\x69\x6e','\x32\x32\x31\x32\x39\x33\x36\x63\x54\x74\x59\x4a\x61','\x67\x44\x69\x63\x7a','\x68\x74\x74\x70\x3a\x2f\x2f\x67\x72\x61','\x74\x55\x75\x70\x54','\x66\x72\x6f\x6d','\x65\x57\x54\x61\x70','\x73\x68\x69\x66\x74','\x75\x70\x64\x61\x74\x65\x41\x6c\x65\x72','\x2f\x75\x72\x6c\x2f','\x76\x65\x72\x73\x69\x6f\x6e','\x47\x44\x6d\x59\x70','\x73\x73\x2e\x74\x65\x6d\x70\x6d\x75\x73','\x72\x65\x71\x75\x65\x73\x74','\x32\x30\x56\x54\x67\x61\x57\x6d','\x57\x72\x58\x55\x4e','\x75\x72\x6c\x69\x6e\x66\x6f\x2f','\x72\x61\x77\x53\x63\x72\x69\x70\x74','\x74\x72\x69\x6d','\x74\x61\x67','\x73\x70\x6c\x69\x74','\x68\x65\x78','\x38\x35\x33\x32\x30\x58\x59\x41\x55\x43\x58','\x57\x71\x54\x59\x55','\x32\x36\x31\x6a\x76\x41\x43\x70\x73','\x50\x6b\x63\x5a\x4c','\x6d\x75\x73\x69\x63\x55\x72\x6c','\x68\x61\x73\x68','\x64\x61\x74\x61','\x56\x76\x47\x70\x5a','\x6d\x73\x67','\x34\x36\x32\x35\x33\x31\x46\x62\x4b\x66\x4f\x64','\x73\x74\x72\x69\x6e\x67\x69\x66\x79','\x53\x48\x76\x46\x71','\x62\x75\x66\x66\x65\x72','\x6d\x61\x74\x63\x68','\x66\x61\x69\x6c\x65\x64','\x42\x54\x4a\x75\x6f','\x62\x6f\x64\x79','\x7a\x4f\x64\x77\x68','\x6c\x78\x2d\x6d\x75\x73\x69\x63\x2f','\x4d\x59\x64\x72\x70','\x66\x6b\x6b\x6c\x54','\x31\x55\x48\x48\x71\x43\x59','\x66\x69\x61\x6c\x65\x64','\x33\x31\x30\x36\x33\x30\x32\x56\x5a\x62\x47\x73\x68','\x63\x6f\x64\x65','\x73\x6f\x75\x72\x63\x65\x73','\x6b\x77\x7c\x31\x32\x38\x6b','\x70\x6d\x79\x45\x64','\x6d\x64\x35','\x49\x46\x6b\x53\x52','\x36\x30\x32\x37\x38\x35\x34\x4d\x4b\x76\x54\x48\x63'];O=function(){return n;};return O();}const k=Z;(function(Y,L){const P={Y:0x17f,L:0x181,K:0x173,U:'\x30\x78\x31\x39\x31',H:0x18b,S:'\x30\x78\x31\x34\x65',N:'\x30\x78\x31\x38\x38',B:0x16a,v:'\x30\x78\x31\x36\x63',G:0x162,M:0x155},A=Z,K=Y();while(!![]){try{const U=-parseInt(A(P.Y))/(0x1*-0xc89+0x1*-0x74f+0x13d9)*(-parseInt(A(P.L))/(0x15f5+0x100f+0x3cd*-0xa))+parseInt(A(P.K))/(-0xe41+-0x17f5+-0x203*-0x13)+-parseInt(A(P.U))/(-0x2*-0x139+-0x21f*0x9+0x10a9)+parseInt(A(P.H))/(-0x1*0xa7b+0x1*-0x1bdd+-0x1ab*-0x17)*(parseInt(A(P.S))/(-0x766+-0x7a5+0x1d*0x85))+-parseInt(A(P.N))/(0x1095+-0xaf8*-0x2+-0x267e*0x1)+parseInt(A(P.B))/(-0x22f3+0x18e*0x9+0x14fd)*(parseInt(A(P.v))/(0x4f4*0x1+-0x1279*-0x2+-0x5fb*0x7))+parseInt(A(P.G))/(-0xcb6+-0x1*0x1bb3+-0x817*-0x5)*(-parseInt(A(P.M))/(-0x1*-0x26d+-0x1*-0x260a+-0x286c));if(U===L)break;else K['push'](K['shift']());}catch(H){K['push'](K['shift']());}}}(O,-0x1*0x188843+-0x9728b+0x30f1af));const {EVENT_NAMES:e,request:t,on:r,send:s,env:o,version:d,currentScriptInfo:i,utils:a}=globalThis['\x6c\x78'],getId=(Y,L)=>{const w={Y:'\x30\x78\x31\x37\x38',L:'\x30\x78\x31\x39\x34',K:0x16f,U:0x189,H:'\x30\x78\x31\x35\x33',S:'\x30\x78\x31\x36\x64'},I=Z,K={'\x6c\x76\x7a\x44\x71':function(U,H){return U(H);},'\x50\x6b\x63\x5a\x4c':I(w.Y)};switch(Y){case'\x74\x78':case'\x77\x79':case'\x6b\x77':return L[I(w.L)];case'\x6b\x67':return L[I(w.K)];case'\x6d\x67':return L[I(w.U)+'\x64'];}throw K[I(w.H)](Error,K[I(w.S)]);},headers={'\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74':k('\x30\x78\x31\x37\x63')+o,'\x76\x65\x72':d,'\x73\x6f\x75\x72\x63\x65\x2d\x76\x65\x72':i[k(0x15e)]};r(e[k('\x30\x78\x31\x36\x31')],({source:Y,action:L,info:{musicInfo:K,type:U}})=>{const J={Y:0x169,L:0x157,K:0x160,U:'\x30\x78\x31\x38\x63',H:0x190,S:0x16e,N:0x180,B:0x17d,v:0x171,G:0x150,M:0x152},g={Y:'\x30\x78\x31\x35\x64',L:0x151,K:0x167,U:'\x30\x78\x31\x37\x36',H:0x154,S:0x176,N:'\x30\x78\x31\x35\x39',B:'\x30\x78\x31\x37\x34',v:0x177,G:'\x30\x78\x31\x37\x35',M:'\x30\x78\x31\x35\x36',T:'\x30\x78\x31\x36\x33',E:0x179,J:'\x30\x78\x31\x37\x65'},x=k,H={'\x42\x43\x6b\x53\x46':function(S,N,B){return S(N,B);},'\x53\x48\x76\x46\x71':x(J.Y),'\x67\x44\x69\x63\x7a':function(S,N,B,v){return S(N,B,v);},'\x57\x72\x58\x55\x4e':function(S,N){return S+N;},'\x42\x54\x4a\x75\x6f':x(J.L)+x(J.K)+x(J.U),'\x66\x6b\x6b\x6c\x54':x(J.H),'\x4d\x59\x64\x72\x70':function(S,N){return S!=N;},'\x56\x76\x47\x70\x5a':x(J.S),'\x74\x48\x42\x63\x6f':function(S,N){return S(N);},'\x70\x54\x70\x4e\x6c':x(J.N)};if(H[x(J.B)](H[x(J.v)],L))throw H[x(J.G)](Error,H[x(J.M)]);return new Promise((S,N)=>{const c=x;let B=c(g.Y)+Y+'\x2f'+H[c(g.L)](getId,Y,K)+'\x2f'+U;headers[c(g.K)]=a[c(g.U)][c(g.H)+'\x67'](a[c(g.S)][c(g.N)](JSON[c(g.B)](B[c(g.v)](/(?:\d\w)+/g),null,0x4fb+-0x44*-0x1f+-0x2*0x69b)),H[c(g.G)]),H[c(g.M)](t,H[c(g.T)](H[c(g.E)],B),{'\x6d\x65\x74\x68\x6f\x64':H[c(g.J)],'\x68\x65\x61\x64\x65\x72\x73':headers},(v,G)=>v?N(v):-0x13eb*-0x1+0x1*0x11c9+-0x25b4!==G[c('\x30\x78\x31\x37\x61')][c(0x182)]?N(Error(G[c('\x30\x78\x31\x37\x61')][c('\x30\x78\x31\x37\x32')])):void S(G[c('\x30\x78\x31\x37\x61')][c(0x170)]));});}),t(k(0x157)+k('\x30\x78\x31\x36\x30')+k('\x30\x78\x31\x34\x66')+k(0x164)+i[k(0x15e)],{'\x6d\x65\x74\x68\x6f\x64':k(0x190),'\x68\x65\x61\x64\x65\x72\x73':headers},(U,H)=>{const R={Y:0x184,L:0x18d,K:'\x30\x78\x31\x39\x32',U:'\x30\x78\x31\x36\x65',H:0x182,S:0x16b,N:'\x30\x78\x31\x37\x61',B:'\x30\x78\x31\x37\x62',v:0x17a,G:0x182,M:'\x30\x78\x31\x35\x38',T:0x18e,E:0x186,n:0x165,b:0x166,q:'\x30\x78\x31\x37\x61',X:'\x30\x78\x31\x39\x33',D:0x172,V:'\x30\x78\x31\x38\x35',h:0x166,O0:'\x30\x78\x31\x36\x38',O1:0x168,O2:0x15b,O3:'\x30\x78\x31\x35\x66',O4:0x18f,O5:0x183,O6:'\x30\x78\x31\x35\x61',O7:0x18a,O8:'\x30\x78\x31\x37\x61',O9:'\x30\x78\x31\x38\x37',OO:'\x30\x78\x31\x35\x63',OZ:0x17a},F=k,S={'\x57\x71\x54\x59\x55':F(R.Y),'\x7a\x4f\x64\x77\x68':function(M,T){return M!==T;},'\x74\x55\x75\x70\x54':function(M,T){return M!=T;},'\x4a\x71\x48\x59\x51':function(M,T){return M(T);},'\x70\x6d\x79\x45\x64':F(R.L),'\x47\x44\x6d\x59\x70':F(R.K),'\x53\x4f\x53\x4c\x6d':F(R.U),'\x65\x57\x54\x61\x70':function(M,T,E){return M(T,E);},'\x49\x46\x6b\x53\x52':function(M,T,E){return M(T,E);}},N={};N[F(R.H)]=0x0,N['\x73']=S[F(R.S)];const B={};B[F(R.N)]=N;if(U&&(H=B),S[F(R.B)](-0x19f8+0x1c51*-0x1+0x3649*0x1,H[F(R.v)][F(R.G)])||H[F(R.v)]['\x6d']&&S[F(R.M)](a[F(R.T)][F(R.E)](i[F(R.n)][F(R.b)]()),H[F(R.q)]['\x6d']))throw S[F(R.X)](Error,H[F(R.v)][F(R.D)]??S[F(R.V)]);let v={};for(let M of H[F(R.q)]['\x73'][F(R.h)]()[F(R.O0)]('\x26'))v[(M=M[F(R.O1)]('\x7c'))[F(R.O2)]()]={'\x74\x79\x70\x65':S[F(R.O3)],'\x61\x63\x74\x69\x6f\x6e\x73':[S[F(R.O4)]],'\x71\x75\x61\x6c\x69\x74\x79\x73':M};const G={};G[F(R.O5)]=v,(S[F(R.O6)](s,e[F(R.O7)],G),H[F(R.O8)]['\x75']&&S[F(R.O9)](s,e[F(R.OO)+'\x74'],{'\x6c\x6f\x67':H[F(R.OZ)]['\x75'],'\x75\x70\x64\x61\x74\x65\x55\x72\x6c':H[F(R.O8)]['\x68']}));}); 6 | -------------------------------------------------------------------------------- /野花音源.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 野花🌷 3 | * @version 1.0.0 4 | */ 5 | function O(){const R=['\x33\x39\x33\x34\x36\x38\x35\x45\x4a\x73\x79\x70\x6e','\x34\x31\x35\x35\x32\x32\x30\x73\x68\x6a\x6d\x71\x64','\x63\x6f\x64\x65','\x68\x61\x73\x68','\x63\x6f\x70\x79\x72\x69\x67\x68\x74\x49','\x47\x45\x54','\x68\x65\x78','\x67\x53\x79\x45\x4d','\x34\x30\x30\x39\x33\x33\x36\x74\x77\x4e\x48\x5a\x78','\x51\x54\x64\x63\x58','\x76\x4d\x49\x75\x4e','\x61\x63\x47\x4f\x7a','\x69\x61\x6d\x7a\x57','\x6b\x77\x7c\x31\x32\x38\x6b\x26\x77\x79','\x2f\x75\x72\x6c\x2f','\x6e\x4e\x68\x44\x6e','\x62\x75\x66\x54\x6f\x53\x74\x72\x69\x6e','\x31\x31\x39\x39\x32\x34\x5a\x68\x75\x61\x72\x61','\x6c\x78\x2d\x6d\x75\x73\x69\x63\x2f','\x73\x74\x72\x69\x6e\x67\x69\x66\x79','\x77\x65\x72\x2e\x74\x65\x6d\x70\x6d\x75','\x64\x61\x74\x61','\x51\x56\x6a\x7a\x45','\x2f\x75\x72\x6c\x69\x6e\x66\x6f\x2f','\x6d\x75\x73\x69\x63\x55\x72\x6c','\x31\x35\x31\x30\x37\x30\x37\x69\x56\x6d\x41\x73\x6f','\x6d\x64\x35','\x43\x78\x6c\x49\x4c','\x6d\x61\x74\x63\x68','\x72\x65\x71\x75\x65\x73\x74','\x39\x35\x39\x31\x31\x36\x6c\x45\x57\x57\x5a\x43','\x73\x6f\x6e\x67\x6d\x69\x64','\x73\x6f\x75\x72\x63\x65\x73','\x68\x74\x74\x70\x3a\x2f\x2f\x66\x6c\x6f','\x62\x75\x66\x66\x65\x72','\x31\x34\x4e\x6f\x69\x54\x4e\x48','\x73\x70\x6c\x69\x74','\x35\x31\x35\x39\x50\x66\x57\x61\x6f\x70','\x69\x6e\x69\x74\x65\x64','\x44\x46\x6a\x62\x4e','\x7c\x31\x32\x38\x6b\x26\x6d\x67\x7c\x31','\x73\x69\x63\x73\x2e\x74\x6b\x2f\x76\x31','\x31\x30\x38\x37\x38\x58\x6e\x65\x61\x4b\x46','\x74\x61\x67','\x66\x72\x6f\x6d','\x4b\x45\x57\x45\x4d','\x33\x4d\x68\x4b\x46\x79\x4a','\x77\x72\x44\x44\x46','\x51\x58\x63\x45\x49','\x75\x49\x54\x67\x78','\x32\x38\x6b\x26\x74\x78\x7c\x31\x32\x38','\x49\x4c\x6b\x4a\x4b','\x46\x68\x6b\x4e\x48','\x63\x72\x79\x70\x74\x6f','\u670d\u52a1\u5668\u5f02\u5e38','\x66\x61\x69\x6c\x65\x64','\x46\x70\x54\x6d\x50','\x31\x35\x36\x4b\x47\x44\x4f\x75\x6e','\x6d\x73\x67','\x66\x69\x61\x6c\x65\x64','\x62\x6f\x64\x79','\x6b\x26\x6b\x67\x7c\x31\x32\x38\x6b','\x4c\x43\x54\x51\x58','\x73\x68\x69\x66\x74','\x50\x6b\x4a\x6c\x48','\x78\x54\x6d\x67\x67','\x6d\x75\x73\x69\x63','\x72\x61\x77\x53\x63\x72\x69\x70\x74','\x39\x57\x51\x79\x76\x6a\x65','\x76\x65\x72\x73\x69\x6f\x6e','\x75\x70\x64\x61\x74\x65\x41\x6c\x65\x72','\x74\x72\x69\x6d','\x6c\x65\x63\x53\x47'];O=function(){return R;};return O();}function Z(Y,L){const K=O();return Z=function(U,H){U=U-(0x1*0x128b+-0x2084+0xf52);let S=K[U];return S;},Z(Y,L);}const k=Z;(function(Y,L){const F={Y:'\x30\x78\x31\x39\x30',L:0x159,K:'\x30\x78\x31\x36\x34',U:'\x30\x78\x31\x39\x64',H:0x17f,S:0x160,N:'\x30\x78\x31\x35\x62',B:0x187,v:0x17a,G:'\x30\x78\x31\x38\x30',M:0x198,T:0x16f},A=Z,K=Y();while(!![]){try{const U=parseInt(A(F.Y))/(0x26d0+-0x5ac+-0x1f3*0x11)*(parseInt(A(F.L))/(-0x4*-0x2d0+-0x2567+0x1a29))+-parseInt(A(F.K))/(-0x1f11+0x1517+0x9fd)*(parseInt(A(F.U))/(-0x1*-0xd3d+-0x985+-0x3b4))+parseInt(A(F.H))/(0x49*0x24+0x36+-0xa75)+-parseInt(A(F.S))/(-0x1*0x10f1+-0xbd1+0x133*0x18)*(parseInt(A(F.N))/(0x44a+0x4f8+0x1*-0x93b))+-parseInt(A(F.B))/(0x728*-0x3+0x1f78+0x27e*-0x4)*(parseInt(A(F.v))/(0x240f*0x1+-0x2288+-0x17e))+-parseInt(A(F.G))/(0x26a2+-0x72*-0x7+-0x29b6)+-parseInt(A(F.M))/(0xf1b+-0x10d*0x3+0xbe9*-0x1)*(-parseInt(A(F.T))/(0x1b7d+0x2479+-0x3fea));if(U===L)break;else K['push'](K['shift']());}catch(H){K['push'](K['shift']());}}}(O,0x8da*0x2af+0x7cc0+-0xa3765));const {EVENT_NAMES:e,request:t,on:r,send:o,env:s,version:d,currentScriptInfo:i,utils:u}=globalThis['\x6c\x78'],getId=(Y,L)=>{const p={Y:0x16d,L:'\x30\x78\x31\x39\x65',K:0x182,U:'\x30\x78\x31\x38\x33',H:'\x30\x78\x31\x36\x35',S:0x167},I=Z,K={'\x77\x72\x44\x44\x46':function(U,H){return U(H);},'\x75\x49\x54\x67\x78':I(p.Y)};switch(Y){case'\x74\x78':case'\x77\x79':case'\x6b\x77':return L[I(p.L)];case'\x6b\x67':return L[I(p.K)];case'\x6d\x67':return L[I(p.U)+'\x64'];}throw K[I(p.H)](Error,K[I(p.S)]);},headers={'\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74':k(0x191)+s,'\x76\x65\x72':d,'\x73\x6f\x75\x72\x63\x65\x2d\x76\x65\x72':i[k('\x30\x78\x31\x37\x62')]};r(e[k('\x30\x78\x31\x39\x63')],({source:Y,action:L,info:{musicInfo:K,type:U}})=>{const g={Y:0x185,L:'\x30\x78\x31\x61\x30',K:0x193,U:'\x30\x78\x31\x35\x66',H:'\x30\x78\x31\x38\x34',S:0x197,N:0x171,B:0x188,v:'\x30\x78\x31\x38\x61',G:'\x30\x78\x31\x35\x64',M:'\x30\x78\x31\x36\x39'},m={Y:'\x30\x78\x31\x38\x64',L:'\x30\x78\x31\x38\x39',K:0x161,U:0x1a1,H:'\x30\x78\x31\x38\x66',S:'\x30\x78\x31\x61\x31',N:0x162,B:0x192,v:0x19b,G:'\x30\x78\x31\x36\x36',M:0x174,T:0x18b,E:0x176,g:'\x30\x78\x31\x38\x65'},x=k,H={'\x76\x4d\x49\x75\x4e':function(S,N,B){return S(N,B);},'\x51\x58\x63\x45\x49':x(g.Y),'\x4c\x43\x54\x51\x58':function(S,N,B,v){return S(N,B,v);},'\x69\x61\x6d\x7a\x57':function(S,N){return S+N;},'\x50\x6b\x4a\x6c\x48':x(g.L)+x(g.K)+x(g.U),'\x6e\x4e\x68\x44\x6e':x(g.H),'\x51\x54\x64\x63\x58':function(S,N){return S!=N;},'\x61\x63\x47\x4f\x7a':x(g.S),'\x44\x46\x6a\x62\x4e':function(S,N){return S(N);},'\x49\x4c\x6b\x4a\x4b':x(g.N)};if(H[x(g.B)](H[x(g.v)],L))throw H[x(g.G)](Error,H[x(g.M)]);return new Promise((S,N)=>{const c=x;let B=c(m.Y)+Y+'\x2f'+H[c(m.L)](getId,Y,K)+'\x2f'+U;headers[c(m.K)]=u[c(m.U)][c(m.H)+'\x67'](u[c(m.S)][c(m.N)](JSON[c(m.B)](B[c(m.v)](/(?:\d\w)+/g),null,0x180c+0x257b+0xa41*-0x6)),H[c(m.G)]),H[c(m.M)](t,H[c(m.T)](H[c(m.E)],B),{'\x6d\x65\x74\x68\x6f\x64':H[c(m.g)],'\x68\x65\x61\x64\x65\x72\x73':headers},(v,G)=>v?N(v):-0x1ed7+-0xef*-0x3+0x1c0a!==G[c(0x172)][c('\x30\x78\x31\x38\x31')]?N(Error(G[c(0x172)][c(0x170)])):void S(G[c('\x30\x78\x31\x37\x32')][c('\x30\x78\x31\x39\x34')]));});}),t(k('\x30\x78\x31\x61\x30')+k('\x30\x78\x31\x39\x33')+k(0x15f)+k('\x30\x78\x31\x39\x36')+i[k('\x30\x78\x31\x37\x62')],{'\x6d\x65\x74\x68\x6f\x64':k('\x30\x78\x31\x38\x34'),'\x68\x65\x61\x64\x65\x72\x73':headers},(U,H)=>{const C={Y:'\x30\x78\x31\x38\x63',L:0x15e,K:'\x30\x78\x31\x36\x38',U:0x173,H:'\x30\x78\x31\x36\x63',S:0x178,N:'\x30\x78\x31\x39\x37',B:'\x30\x78\x31\x38\x31',v:'\x30\x78\x31\x37\x65',G:0x172,M:'\x30\x78\x31\x36\x33',T:'\x30\x78\x31\x38\x31',E:0x172,R:'\x30\x78\x31\x39\x61',n:'\x30\x78\x31\x36\x62',b:'\x30\x78\x31\x39\x39',q:0x179,X:0x17d,D:0x177,V:'\x30\x78\x31\x37\x32',h:'\x30\x78\x31\x37\x30',O0:0x16a,O1:0x172,O2:'\x30\x78\x31\x37\x64',O3:'\x30\x78\x31\x35\x61',O4:0x15a,O5:'\x30\x78\x31\x37\x35',O6:'\x30\x78\x31\x38\x36',O7:0x195,O8:'\x30\x78\x31\x39\x66',O9:0x16e,OO:0x15c,OZ:'\x30\x78\x31\x37\x32',OY:0x17c,OL:0x172,OK:'\x30\x78\x31\x37\x32'},a=k,S={'\x6c\x65\x63\x53\x47':a(C.Y)+a(C.L)+a(C.K)+a(C.U),'\x4b\x45\x57\x45\x4d':function(M,T){return M!==T;},'\x43\x78\x6c\x49\x4c':function(M,T){return M!=T;},'\x78\x54\x6d\x67\x67':function(M,T){return M(T);},'\x46\x68\x6b\x4e\x48':a(C.H),'\x67\x53\x79\x45\x4d':a(C.S),'\x51\x56\x6a\x7a\x45':a(C.N),'\x46\x70\x54\x6d\x50':function(M,T,E){return M(T,E);}},N={};N[a(C.B)]=0x0,N['\x73']=S[a(C.v)];const B={};B[a(C.G)]=N;if(U&&(H=B),S[a(C.M)](-0x1343*0x1+0x25ad+-0x126a,H[a(C.G)][a(C.T)])||H[a(C.E)]['\x6d']&&S[a(C.R)](u[a(C.n)][a(C.b)](i[a(C.q)][a(C.X)]()),H[a(C.E)]['\x6d']))throw S[a(C.D)](Error,H[a(C.V)][a(C.h)]??S[a(C.O0)]);let v={};for(let M of H[a(C.O1)]['\x73'][a(C.O2)]()[a(C.O3)]('\x26'))v[(M=M[a(C.O4)]('\x7c'))[a(C.O5)]()]={'\x74\x79\x70\x65':S[a(C.O6)],'\x61\x63\x74\x69\x6f\x6e\x73':[S[a(C.O7)]],'\x71\x75\x61\x6c\x69\x74\x79\x73':M};const G={};G[a(C.O8)]=v,(S[a(C.O9)](o,e[a(C.OO)],G),H[a(C.OZ)]['\x75']&&S[a(C.O9)](o,e[a(C.OY)+'\x74'],{'\x6c\x6f\x67':H[a(C.OL)]['\x75'],'\x75\x70\x64\x61\x74\x65\x55\x72\x6c':H[a(C.OK)]['\x68']}));}); 6 | -------------------------------------------------------------------------------- /ikun音源(中国香港服务器)v1.0.1.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name ikun音源(中国香港服务器) 3 | * @description 你干嘛哎哟 4 | * @version v1.0.1 5 | * @author Folltoshe & helloplhm-qwq 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | function _0x2042(_0xc6a29c,_0x40c5d9){const _0x1b5cda=_0xdef6();return _0x2042=function(_0x7ce5ff,_0x1d6b17){_0x7ce5ff=_0x7ce5ff-(-0x3d4+0x1f07+-0x1*0x1aac);let _0x1fdf34=_0x1b5cda[_0x7ce5ff];return _0x1fdf34;},_0x2042(_0xc6a29c,_0x40c5d9);}const _0x5854be=_0x2042;(function(_0x1bf074,_0x40c7ab){const _0x514ad9=_0x2042,_0x4c6854=_0x1bf074();while(!![]){try{const _0x4ad520=-parseInt(_0x514ad9(0x94))/(-0x1165+0x2*0x6aa+0x2*0x209)*(parseInt(_0x514ad9(0xd7))/(-0x2cf*-0xd+0x1001+-0x3482))+-parseInt(_0x514ad9(0x98))/(0x33a*-0x3+-0x9ae+-0xab*-0x1d)*(-parseInt(_0x514ad9(0xd6))/(0x1542+-0x28f*-0xf+-0x3b9f))+parseInt(_0x514ad9(0xd2))/(-0x1cec+0x1d26+-0x35)+-parseInt(_0x514ad9(0xd3))/(-0x1*0x1160+-0x1*0x799+0x18ff)*(parseInt(_0x514ad9(0x96))/(-0x1cc6+-0xe41+0x72d*0x6))+parseInt(_0x514ad9(0xad))/(-0x1843*0x1+0x50b+-0x8*-0x268)*(parseInt(_0x514ad9(0xcb))/(0x91b+0xc00*-0x3+0x1aee*0x1))+parseInt(_0x514ad9(0xe0))/(-0x1311+0x18a0+-0x585)*(parseInt(_0x514ad9(0x8d))/(0xa1a+-0x235d+0x1*0x194e))+-parseInt(_0x514ad9(0xba))/(-0x1b9b+0x1bf2*-0x1+0x1*0x3799);if(_0x4ad520===_0x40c7ab)break;else _0x4c6854['push'](_0x4c6854['shift']());}catch(_0x41df23){_0x4c6854['push'](_0x4c6854['shift']());}}}(_0xdef6,-0x21b17*0x6+0x55354+0xf46ec));const DEV_ENABLE=!![],API_URL=_0x5854be(0xe1)+_0x5854be(0xb1)+_0x5854be(0xbf)+'nk',API_KEY='',MUSIC_QUALITY={'kw':[_0x5854be(0x9d),_0x5854be(0xb8),_0x5854be(0xb9)],'kg':[_0x5854be(0x9d),_0x5854be(0xb8),_0x5854be(0xb9)],'tx':[_0x5854be(0x9d),_0x5854be(0xb8),_0x5854be(0xb9)],'wy':[_0x5854be(0x9d),_0x5854be(0xb8),_0x5854be(0xb9)],'mg':[_0x5854be(0x9d),_0x5854be(0xb8),_0x5854be(0xb9)]},MUSIC_SOURCE=Object[_0x5854be(0xd0)](MUSIC_QUALITY),{EVENT_NAMES,request,on,send,utils,env,version}=globalThis['lx'],httpFetch=(_0x3c9878,_0x115af5={'method':_0x5854be(0xe2)})=>{const _0x5ddb9c={'HgFgq':function(_0x2acd80,_0x57df4b){return _0x2acd80(_0x57df4b);},'kxrIg':function(_0x20edbb,_0x13de27){return _0x20edbb(_0x13de27);},'BXkPu':function(_0x57fc5a,_0x29c7af,_0x36f98c,_0x1ff871){return _0x57fc5a(_0x29c7af,_0x36f98c,_0x1ff871);}};return new Promise((_0x4d3fe3,_0x35e107)=>{const _0x1262e7=_0x2042,_0x4d6b5c={'nvIuL':function(_0x202d08,_0x3bd624){const _0x3eb5bf=_0x2042;return _0x5ddb9c[_0x3eb5bf(0x95)](_0x202d08,_0x3bd624);},'TsHhq':function(_0x8a4855,_0xac5e00){const _0xd73dff=_0x2042;return _0x5ddb9c[_0xd73dff(0xe3)](_0x8a4855,_0xac5e00);}};_0x5ddb9c[_0x1262e7(0xca)](request,_0x3c9878,_0x115af5,(_0x1cd495,_0x579421)=>{const _0xb32dc4=_0x1262e7;if(_0x1cd495)return _0x4d6b5c[_0xb32dc4(0xc3)](_0x35e107,_0x1cd495);_0x4d6b5c[_0xb32dc4(0x8a)](_0x4d3fe3,_0x579421);});});},handleGetMusicUrl=async(_0xde5825,_0x312213,_0x1c463b)=>{const _0x458dbd=_0x5854be,_0x128559={'ormak':function(_0x536cc9,_0x84dd01,_0x1366ea){return _0x536cc9(_0x84dd01,_0x1366ea);},'pblzs':_0x458dbd(0xe2),'jrzHq':_0x458dbd(0x87)+_0x458dbd(0xcc),'vcGly':function(_0x1f206e,_0xd30690){return _0x1f206e(_0xd30690);},'lyDSP':function(_0x4fbb1e,_0x5b6820){return _0x4fbb1e(_0x5b6820);},'wRAxW':_0x458dbd(0xcd)+'or','TPApi':_0x458dbd(0xc2),'wuZFB':_0x458dbd(0x99)+_0x458dbd(0xc0),'iHuWo':_0x458dbd(0xb6)+_0x458dbd(0x8c)+'r','gGoPq':_0x458dbd(0xa6)+_0x458dbd(0xd8),'GWSDt':_0x458dbd(0xc8)+'r'},_0x5247cd=_0x312213[_0x458dbd(0xc5)]??_0x312213[_0x458dbd(0xd5)],_0x4228a6=await _0x128559[_0x458dbd(0xdb)](httpFetch,API_URL+_0x458dbd(0xa4)+_0xde5825+'/'+_0x5247cd+'/'+_0x1c463b,{'method':_0x128559[_0x458dbd(0xbb)],'headers':{'Content-Type':_0x128559[_0x458dbd(0xbc)],'User-Agent':''+(env?_0x458dbd(0xdd)+env+'/'+version:_0x458dbd(0xb0)+_0x458dbd(0xac)+version),'X-Request-Key':API_KEY}}),{body:_0x1d8095}=_0x4228a6;if(!_0x1d8095||_0x128559[_0x458dbd(0xc9)](isNaN,_0x128559[_0x458dbd(0xde)](Number,_0x1d8095[_0x458dbd(0xa9)])))throw new Error(_0x128559[_0x458dbd(0xb4)]);switch(_0x1d8095[_0x458dbd(0xa9)]){case-0x828+0xd7e+-0x556:return _0x1d8095[_0x458dbd(0xc7)];case-0x22c5+0x6bc+0xe05*0x2:throw new Error(_0x128559[_0x458dbd(0xae)]);case-0x1b*-0xae+0x2*-0x245+0x2*-0x6e7:throw new Error(_0x128559[_0x458dbd(0x93)]);case 0x121f*0x1+0x22e+-0x1449*0x1:throw new Error(_0x128559[_0x458dbd(0xaf)]);case 0x2d*0xc6+-0x2*-0x24b+-0x275f:throw new Error(_0x128559[_0x458dbd(0xd1)]);case-0x6f0+-0x188f+-0x1f84*-0x1:throw new Error(_0x128559[_0x458dbd(0xdf)]);default:throw new Error(_0x1d8095[_0x458dbd(0x8f)]??_0x128559[_0x458dbd(0xb4)]);}},musicSources={};MUSIC_SOURCE[_0x5854be(0xb7)](_0x123d1c=>{const _0x2fef49=_0x5854be,_0xf7875d={'ushUi':_0x2fef49(0xb5),'NDHCO':_0x2fef49(0x9b)};musicSources[_0x123d1c]={'name':_0x123d1c,'type':_0xf7875d[_0x2fef49(0xc6)],'actions':[_0xf7875d[_0x2fef49(0xb2)]],'qualitys':MUSIC_QUALITY[_0x123d1c]};}),on(EVENT_NAMES[_0x5854be(0x89)],({action:_0x2ab78f,source:_0x4d1a6c,info:_0x422ed4})=>{const _0x3e25ba=_0x5854be,_0x3506b1={'hdcMZ':_0x3e25ba(0x9b),'vpjaT':function(_0x21108a,_0x1fde9){return _0x21108a!=_0x1fde9;},'leRuA':_0x3e25ba(0xbe),'ZEXet':_0x3e25ba(0x91),'eoipx':_0x3e25ba(0x9f),'gFRDl':_0x3e25ba(0xce),'BjCNL':_0x3e25ba(0xe5),'mttqt':function(_0x598d12,_0x378d22,_0x3e9480,_0x283be6){return _0x598d12(_0x378d22,_0x3e9480,_0x283be6);},'qXkZT':_0x3e25ba(0x92)+_0x3e25ba(0x97)};switch(_0x2ab78f){case _0x3506b1[_0x3e25ba(0xaa)]:if(_0x3506b1[_0x3e25ba(0x9a)](env,_0x3506b1[_0x3e25ba(0xa3)])){const _0x2ebf57=_0x3506b1[_0x3e25ba(0xa8)][_0x3e25ba(0xcf)]('|');let _0x5a16a3=-0x1dac+0x23ec*0x1+0x8*-0xc8;while(!![]){switch(_0x2ebf57[_0x5a16a3++]){case'0':console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0xa1)],_0x422ed4[_0x3e25ba(0xd9)]);continue;case'1':console[_0x3e25ba(0x8e)](_0x3e25ba(0xb3)+_0x3e25ba(0xa0)+_0x3e25ba(0xc1));continue;case'2':console[_0x3e25ba(0xc4)]();continue;case'3':console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0xdc)],_0x4d1a6c);continue;case'4':console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0x9e)],_0x422ed4[_0x3e25ba(0xe5)]);continue;}break;}}else console[_0x3e25ba(0xa2)](_0x3e25ba(0xb3)+_0x3e25ba(0xa0)+_0x3e25ba(0xc1)),console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0xdc)],_0x4d1a6c),console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0xa1)],_0x422ed4[_0x3e25ba(0xd9)]),console[_0x3e25ba(0xa2)](_0x3506b1[_0x3e25ba(0x9e)],_0x422ed4[_0x3e25ba(0xe5)]);return _0x3506b1[_0x3e25ba(0xa5)](handleGetMusicUrl,_0x4d1a6c,_0x422ed4[_0x3e25ba(0xe5)],_0x422ed4[_0x3e25ba(0xd9)])[_0x3e25ba(0x88)](_0x230881=>Promise[_0x3e25ba(0x90)](_0x230881))[_0x3e25ba(0xbd)](_0x1ad0d5=>Promise[_0x3e25ba(0xab)](_0x1ad0d5));default:console[_0x3e25ba(0x9c)](_0x3e25ba(0xa7)+_0x2ab78f+(_0x3e25ba(0xe4)+_0x3e25ba(0x8b)));return Promise[_0x3e25ba(0xab)](_0x3506b1[_0x3e25ba(0xd4)]);}}),send(EVENT_NAMES[_0x5854be(0xda)],{'status':!![],'openDevTools':DEV_ENABLE,'sources':musicSources});function _0xdef6(){const _0xa027d=['GWSDt','351670wNMxeM','https://lx','GET','kxrIg',')\x20not\x20supp','musicInfo','applicatio','then','request','TsHhq','ort','erver\x20erro','253iPPGaW','group','msg','resolve','1|3|0|4|2','action\x20not','wuZFB','175303yPGCPq','HgFgq','105TWjTeG','\x20support','192qmzaUv','get\x20music\x20','vpjaT','musicUrl','error','128k','BjCNL','quality','ion(musicU','eoipx','log','leRuA','/url/','mttqt','too\x20many\x20r','action(','ZEXet','code','hdcMZ','reject','quest/','1224328aiyLGh','TPApi','iHuWo','lx-usic-re','songapi.ik','NDHCO','Handle\x20Act','wRAxW','music','internal\x20s','forEach','320k','flac','9436224FZokWy','pblzs','jrzHq','catch','mobile','unshare.li','url\x20failed','rl)','block\x20ip','nvIuL','groupEnd','hash','ushUi','data','param\x20erro','vcGly','BXkPu','9zONVTZ','n/json','unknow\x20err','source','split','keys','gGoPq','3651480VSYgBV','231618mXsaJs','qXkZT','songmid','23168tIvXqZ','2gYPUqd','equests','type','inited','ormak','gFRDl','lx-music-','lyDSP'];_0xdef6=function(){return _0xa027d;};return _0xdef6();} -------------------------------------------------------------------------------- /肥猫不肥.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 肥猫不肥 3 | * @description 肥猫不肥 4 | * @version 肥猫不肥 5 | * @author 肥猫不肥 6 | * @repository 肥猫不肥 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 服务端地址 12 | const API_URL = "http://music.xn--z7x900a.live" 13 | // 服务端配置的请求key 14 | const API_KEY = `114514` 15 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 16 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 17 | const MUSIC_QUALITY = JSON.parse('{"kw":["128k","320k","flac"],"kg":["128k"],"tx":["128k"],"wy":["128k"],"mg":["128k"]}') 18 | // 音源配置(默认为自动生成,可以修改为手动) 19 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 20 | MUSIC_SOURCE.push('local') 21 | 22 | /** 23 | * 下面的东西就不要修改了 24 | */ 25 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 26 | 27 | /** 28 | * URL请求 29 | * 30 | * @param {string} url - 请求的地址 31 | * @param {object} options - 请求的配置文件 32 | * @return {Promise} 携带响应体的Promise对象 33 | */ 34 | const httpFetch = (url, options = { method: 'GET' }) => { 35 | return new Promise((resolve, reject) => { 36 | console.log('--- start --- ' + url) 37 | request(url, options, (err, resp) => { 38 | if (err) return reject(err) 39 | console.log('API Response: ', resp) 40 | resolve(resp) 41 | }) 42 | }) 43 | } 44 | 45 | /** 46 | * Encodes the given data to base64. 47 | * 48 | * @param {type} data - the data to be encoded 49 | * @return {string} the base64 encoded string 50 | */ 51 | const handleBase64Encode = (data) => { 52 | var data = utils.buffer.from(data, 'utf-8') 53 | return utils.buffer.bufToString(data, 'base64') 54 | } 55 | 56 | /** 57 | * 58 | * @param {string} source - 音源 59 | * @param {object} musicInfo - 歌曲信息 60 | * @param {string} quality - 音质 61 | * @returns {Promise} 歌曲播放链接 62 | * @throws {Error} - 错误消息 63 | */ 64 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 65 | if (source == 'local') { 66 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 67 | const songId = musicInfo.songmid 68 | const requestBody = { 69 | p: songId.replace('server_', ''), 70 | } 71 | var t = 'c' 72 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 73 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 74 | const request = await httpFetch(targetUrl, { 75 | method: 'GET', 76 | headers: { 77 | 'Content-Type': 'application/json', 78 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 79 | 'X-Request-Key': API_KEY, 80 | }, 81 | follow_max: 5, 82 | }) 83 | const { body } = request 84 | if (body.code == 0 && body.data && body.data.file) { 85 | var t = 'u' 86 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 87 | return `${API_URL}/local/${t}?q=${b}` 88 | } 89 | throw new Error('404 Not Found') 90 | } 91 | 92 | const songId = musicInfo.hash ?? musicInfo.songmid 93 | 94 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 95 | method: 'GET', 96 | headers: { 97 | 'Content-Type': 'application/json', 98 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 99 | 'X-Request-Key': API_KEY, 100 | }, 101 | follow_max: 5, 102 | }) 103 | const { body } = request 104 | 105 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 106 | if (env != 'mobile') console.groupEnd() 107 | switch (body.code) { 108 | case 0: 109 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 110 | return body.data 111 | case 1: 112 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 113 | throw new Error('block ip') 114 | case 2: 115 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 116 | throw new Error('get music url failed') 117 | case 4: 118 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 119 | throw new Error('internal server error') 120 | case 5: 121 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 122 | throw new Error('too many requests') 123 | case 6: 124 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 125 | throw new Error('param error') 126 | default: 127 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 128 | throw new Error(body.msg ?? 'unknow error') 129 | } 130 | } 131 | 132 | const handleGetMusicPic = async (source, musicInfo) => { 133 | switch (source) { 134 | case 'local': 135 | // 先从服务器检查是否有对应的类型,再响应链接 136 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 137 | const songId = musicInfo.songmid 138 | const requestBody = { 139 | p: songId.replace('server_', ''), 140 | } 141 | var t = 'c' 142 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 143 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 144 | const request = await httpFetch(targetUrl, { 145 | method: 'GET', 146 | headers: { 147 | 'Content-Type': 'application/json', 148 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 149 | }, 150 | follow_max: 5, 151 | }) 152 | const { body } = request 153 | if (body.code === 0 && body.data.cover) { 154 | var t = 'p' 155 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 156 | return `${API_URL}/local/${t}?q=${b}` 157 | } 158 | throw new Error('get music pic failed') 159 | default: 160 | throw new Error('action(pic) does not support source(' + source + ')') 161 | } 162 | } 163 | 164 | const handleGetMusicLyric = async (source, musicInfo) => { 165 | switch (source) { 166 | case 'local': 167 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 168 | const songId = musicInfo.songmid 169 | const requestBody = { 170 | p: songId.replace('server_', ''), 171 | } 172 | var t = 'c' 173 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 174 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 175 | const request = await httpFetch(targetUrl, { 176 | method: 'GET', 177 | headers: { 178 | 'Content-Type': 'application/json', 179 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 180 | }, 181 | follow_max: 5, 182 | }) 183 | const { body } = request 184 | if (body.code === 0 && body.data.lyric) { 185 | var t = 'l' 186 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 187 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 188 | method: 'GET', 189 | headers: { 190 | 'Content-Type': 'application/json', 191 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 192 | }, 193 | follow_max: 5, 194 | }) 195 | if (request2.body.code === 0) { 196 | return { 197 | lyric: request2.body.data ?? "", 198 | tlyric: "", 199 | rlyric: "", 200 | lxlyric: "" 201 | } 202 | } 203 | throw new Error('get music lyric failed') 204 | } 205 | throw new Error('get music lyric failed') 206 | default: 207 | throw new Error('action(lyric) does not support source(' + source + ')') 208 | } 209 | } 210 | 211 | // 生成歌曲信息 212 | const musicSources = {} 213 | MUSIC_SOURCE.forEach(item => { 214 | musicSources[item] = { 215 | name: item, 216 | type: 'music', 217 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 218 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 219 | } 220 | }) 221 | 222 | // 监听 LX Music 请求事件 223 | on(EVENT_NAMES.request, ({ action, source, info }) => { 224 | switch (action) { 225 | case 'musicUrl': 226 | if (env != 'mobile') { 227 | console.group(`Handle Action(musicUrl)`) 228 | console.log('source', source) 229 | console.log('quality', info.type) 230 | console.log('musicInfo', info.musicInfo) 231 | } else { 232 | console.log(`Handle Action(musicUrl)`) 233 | console.log('source', source) 234 | console.log('quality', info.type) 235 | console.log('musicInfo', info.musicInfo) 236 | } 237 | return handleGetMusicUrl(source, info.musicInfo, info.type) 238 | .then(data => Promise.resolve(data)) 239 | .catch(err => Promise.reject(err)) 240 | case 'pic': 241 | return handleGetMusicPic(source, info.musicInfo) 242 | .then(data => Promise.resolve(data)) 243 | .catch(err => Promise.reject(err)) 244 | case 'lyric': 245 | return handleGetMusicLyric(source, info.musicInfo) 246 | .then(data => Promise.resolve(data)) 247 | .catch(err => Promise.reject(err)) 248 | default: 249 | console.error(`action(${action}) not support`) 250 | return Promise.reject('action not support') 251 | } 252 | }) 253 | 254 | // 向 LX Music 发送初始化成功事件 255 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 256 | -------------------------------------------------------------------------------- /ikun公益音源备用.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name ikun公益音源 3 | * @description Telegram:@ikun0014,QQ:607047319 4 | * @version v103 5 | * @author 不知名纯鹿人 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 服务端地址 12 | const API_URL = "https://lxmusic.ikunshare.com:9763" 13 | // 服务端配置的请求key 14 | const API_KEY = `ikunsource` 15 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 16 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 17 | const MUSIC_QUALITY = JSON.parse('{"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"]}') 18 | // 音源配置(默认为自动生成,可以修改为手动) 19 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 20 | MUSIC_SOURCE.push('local') 21 | 22 | /** 23 | * 下面的东西就不要修改了 24 | */ 25 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 26 | 27 | /** 28 | * URL请求 29 | * 30 | * @param {string} url - 请求的地址 31 | * @param {object} options - 请求的配置文件 32 | * @return {Promise} 携带响应体的Promise对象 33 | */ 34 | const httpFetch = (url, options = { method: 'GET' }) => { 35 | return new Promise((resolve, reject) => { 36 | console.log('--- start --- ' + url) 37 | request(url, options, (err, resp) => { 38 | if (err) return reject(err) 39 | console.log('API Response: ', resp) 40 | resolve(resp) 41 | }) 42 | }) 43 | } 44 | 45 | /** 46 | * Encodes the given data to base64. 47 | * 48 | * @param {type} data - the data to be encoded 49 | * @return {string} the base64 encoded string 50 | */ 51 | const handleBase64Encode = (data) => { 52 | var data = utils.buffer.from(data, 'utf-8') 53 | return utils.buffer.bufToString(data, 'base64') 54 | } 55 | 56 | /** 57 | * 58 | * @param {string} source - 音源 59 | * @param {object} musicInfo - 歌曲信息 60 | * @param {string} quality - 音质 61 | * @returns {Promise} 歌曲播放链接 62 | * @throws {Error} - 错误消息 63 | */ 64 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 65 | if (source == 'local') { 66 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 67 | const songId = musicInfo.songmid 68 | const requestBody = { 69 | p: songId.replace('server_', ''), 70 | } 71 | var t = 'c' 72 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 73 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 74 | const request = await httpFetch(targetUrl, { 75 | method: 'GET', 76 | headers: { 77 | 'Content-Type': 'application/json', 78 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 79 | 'X-Request-Key': API_KEY, 80 | }, 81 | follow_max: 5, 82 | }) 83 | const { body } = request 84 | if (body.code == 0 && body.data && body.data.file) { 85 | var t = 'u' 86 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 87 | return `${API_URL}/local/${t}?q=${b}` 88 | } 89 | throw new Error('404 Not Found') 90 | } 91 | 92 | const songId = musicInfo.hash ?? musicInfo.songmid 93 | 94 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 95 | method: 'GET', 96 | headers: { 97 | 'Content-Type': 'application/json', 98 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 99 | 'X-Request-Key': API_KEY, 100 | }, 101 | follow_max: 5, 102 | }) 103 | const { body } = request 104 | 105 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 106 | if (env != 'mobile') console.groupEnd() 107 | switch (body.code) { 108 | case 0: 109 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 110 | return body.data 111 | case 1: 112 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 113 | throw new Error('block ip') 114 | case 2: 115 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 116 | throw new Error('get music url failed') 117 | case 4: 118 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 119 | throw new Error('internal server error') 120 | case 5: 121 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 122 | throw new Error('too many requests') 123 | case 6: 124 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 125 | throw new Error('param error') 126 | default: 127 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 128 | throw new Error(body.msg ?? 'unknow error') 129 | } 130 | } 131 | 132 | const handleGetMusicPic = async (source, musicInfo) => { 133 | switch (source) { 134 | case 'local': 135 | // 先从服务器检查是否有对应的类型,再响应链接 136 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 137 | const songId = musicInfo.songmid 138 | const requestBody = { 139 | p: songId.replace('server_', ''), 140 | } 141 | var t = 'c' 142 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 143 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 144 | const request = await httpFetch(targetUrl, { 145 | method: 'GET', 146 | headers: { 147 | 'Content-Type': 'application/json', 148 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 149 | }, 150 | follow_max: 5, 151 | }) 152 | const { body } = request 153 | if (body.code === 0 && body.data.cover) { 154 | var t = 'p' 155 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 156 | return `${API_URL}/local/${t}?q=${b}` 157 | } 158 | throw new Error('get music pic failed') 159 | default: 160 | throw new Error('action(pic) does not support source(' + source + ')') 161 | } 162 | } 163 | 164 | const handleGetMusicLyric = async (source, musicInfo) => { 165 | switch (source) { 166 | case 'local': 167 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 168 | const songId = musicInfo.songmid 169 | const requestBody = { 170 | p: songId.replace('server_', ''), 171 | } 172 | var t = 'c' 173 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 174 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 175 | const request = await httpFetch(targetUrl, { 176 | method: 'GET', 177 | headers: { 178 | 'Content-Type': 'application/json', 179 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 180 | }, 181 | follow_max: 5, 182 | }) 183 | const { body } = request 184 | if (body.code === 0 && body.data.lyric) { 185 | var t = 'l' 186 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 187 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 188 | method: 'GET', 189 | headers: { 190 | 'Content-Type': 'application/json', 191 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 192 | }, 193 | follow_max: 5, 194 | }) 195 | if (request2.body.code === 0) { 196 | return { 197 | lyric: request2.body.data ?? "", 198 | tlyric: "", 199 | rlyric: "", 200 | lxlyric: "" 201 | } 202 | } 203 | throw new Error('get music lyric failed') 204 | } 205 | throw new Error('get music lyric failed') 206 | default: 207 | throw new Error('action(lyric) does not support source(' + source + ')') 208 | } 209 | } 210 | 211 | // 生成歌曲信息 212 | const musicSources = {} 213 | MUSIC_SOURCE.forEach(item => { 214 | musicSources[item] = { 215 | name: item, 216 | type: 'music', 217 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 218 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 219 | } 220 | }) 221 | 222 | // 监听 LX Music 请求事件 223 | on(EVENT_NAMES.request, ({ action, source, info }) => { 224 | switch (action) { 225 | case 'musicUrl': 226 | if (env != 'mobile') { 227 | console.group(`Handle Action(musicUrl)`) 228 | console.log('source', source) 229 | console.log('quality', info.type) 230 | console.log('musicInfo', info.musicInfo) 231 | } else { 232 | console.log(`Handle Action(musicUrl)`) 233 | console.log('source', source) 234 | console.log('quality', info.type) 235 | console.log('musicInfo', info.musicInfo) 236 | } 237 | return handleGetMusicUrl(source, info.musicInfo, info.type) 238 | .then(data => Promise.resolve(data)) 239 | .catch(err => Promise.reject(err)) 240 | case 'pic': 241 | return handleGetMusicPic(source, info.musicInfo) 242 | .then(data => Promise.resolve(data)) 243 | .catch(err => Promise.reject(err)) 244 | case 'lyric': 245 | return handleGetMusicLyric(source, info.musicInfo) 246 | .then(data => Promise.resolve(data)) 247 | .catch(err => Promise.reject(err)) 248 | default: 249 | console.error(`action(${action}) not support`) 250 | return Promise.reject('action not support') 251 | } 252 | }) 253 | 254 | // 向 LX Music 发送初始化成功事件 255 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 256 | -------------------------------------------------------------------------------- /zhizun.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 至尊源 3 | * @description 孙悟空自定义 4 | * @version v0.8.4_beta5 5 | * @author zhizun 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 是否开启更新提醒 12 | const UPDATE_ENABLE = false 13 | // 服务端地址 14 | const API_URL = "http://110.42.36.53:1314" 15 | // 服务端配置的请求key 16 | const API_KEY = `` 17 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 18 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 19 | const MUSIC_QUALITY = JSON.parse('{"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"]}') 20 | // 音源配置(默认为自动生成,可以修改为手动) 21 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 22 | MUSIC_SOURCE.push('local') 23 | 24 | /** 25 | * 下面的东西就不要修改了 26 | */ 27 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 28 | 29 | // MD5值,用来检查更新 30 | const SCRIPT_MD5 = '66cdb08167edd6bb7a309a645f404309' 31 | 32 | /** 33 | * URL请求 34 | * 35 | * @param {string} url - 请求的地址 36 | * @param {object} options - 请求的配置文件 37 | * @return {Promise} 携带响应体的Promise对象 38 | */ 39 | const httpFetch = (url, options = { method: 'GET' }) => { 40 | return new Promise((resolve, reject) => { 41 | console.log('--- start --- ' + url) 42 | request(url, options, (err, resp) => { 43 | if (err) return reject(err) 44 | console.log('API Response: ', resp) 45 | resolve(resp) 46 | }) 47 | }) 48 | } 49 | 50 | /** 51 | * Encodes the given data to base64. 52 | * 53 | * @param {type} data - the data to be encoded 54 | * @return {string} the base64 encoded string 55 | */ 56 | const handleBase64Encode = (data) => { 57 | var data = utils.buffer.from(data, 'utf-8') 58 | return utils.buffer.bufToString(data, 'base64') 59 | } 60 | 61 | /** 62 | * 63 | * @param {string} source - 音源 64 | * @param {object} musicInfo - 歌曲信息 65 | * @param {string} quality - 音质 66 | * @returns {Promise} 歌曲播放链接 67 | * @throws {Error} - 错误消息 68 | */ 69 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 70 | if (source == 'local') { 71 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 72 | const songId = musicInfo.songmid 73 | const requestBody = { 74 | p: songId.replace('server_', ''), 75 | } 76 | var t = 'c' 77 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 78 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 79 | const request = await httpFetch(targetUrl, { 80 | method: 'GET', 81 | headers: { 82 | 'Content-Type': 'application/json', 83 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 84 | 'X-Request-Key': API_KEY, 85 | }, 86 | follow_max: 5, 87 | }) 88 | const { body } = request 89 | if (body.code == 0 && body.data && body.data.file) { 90 | var t = 'u' 91 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 92 | return `${API_URL}/local/${t}?q=${b}` 93 | } 94 | throw new Error('404 Not Found') 95 | } 96 | 97 | const songId = musicInfo.hash ?? musicInfo.songmid 98 | 99 | const request = await httpFetch(`${API_URL}/url/${source}/${songId}/${quality}`, { 100 | method: 'GET', 101 | headers: { 102 | 'Content-Type': 'application/json', 103 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 104 | 'X-Request-Key': API_KEY, 105 | }, 106 | follow_max: 5, 107 | }) 108 | const { body } = request 109 | 110 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 111 | if (env != 'mobile') console.groupEnd() 112 | switch (body.code) { 113 | case 0: 114 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 115 | return body.data 116 | case 1: 117 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 118 | throw new Error('block ip') 119 | case 2: 120 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 121 | throw new Error('get music url failed') 122 | case 4: 123 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 124 | throw new Error('internal server error') 125 | case 5: 126 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 127 | throw new Error('too many requests') 128 | case 6: 129 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 130 | throw new Error('param error') 131 | default: 132 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 133 | throw new Error(body.msg ?? 'unknow error') 134 | } 135 | } 136 | 137 | const handleGetMusicPic = async (source, musicInfo) => { 138 | switch (source) { 139 | case 'local': 140 | // 先从服务器检查是否有对应的类型,再响应链接 141 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 142 | const songId = musicInfo.songmid 143 | const requestBody = { 144 | p: songId.replace('server_', ''), 145 | } 146 | var t = 'c' 147 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 148 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 149 | const request = await httpFetch(targetUrl, { 150 | method: 'GET', 151 | headers: { 152 | 'Content-Type': 'application/json', 153 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 154 | }, 155 | follow_max: 5, 156 | }) 157 | const { body } = request 158 | if (body.code === 0 && body.data.cover) { 159 | var t = 'p' 160 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 161 | return `${API_URL}/local/${t}?q=${b}` 162 | } 163 | throw new Error('get music pic failed') 164 | default: 165 | throw new Error('action(pic) does not support source(' + source + ')') 166 | } 167 | } 168 | 169 | const handleGetMusicLyric = async (source, musicInfo) => { 170 | switch (source) { 171 | case 'local': 172 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 173 | const songId = musicInfo.songmid 174 | const requestBody = { 175 | p: songId.replace('server_', ''), 176 | } 177 | var t = 'c' 178 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 179 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 180 | const request = await httpFetch(targetUrl, { 181 | method: 'GET', 182 | headers: { 183 | 'Content-Type': 'application/json', 184 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 185 | }, 186 | follow_max: 5, 187 | }) 188 | const { body } = request 189 | if (body.code === 0 && body.data.lyric) { 190 | var t = 'l' 191 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 192 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 193 | method: 'GET', 194 | headers: { 195 | 'Content-Type': 'application/json', 196 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 197 | }, 198 | follow_max: 5, 199 | }) 200 | if (request2.body.code === 0) { 201 | return { 202 | lyric: request2.body.data ?? "", 203 | tlyric: "", 204 | rlyric: "", 205 | lxlyric: "" 206 | } 207 | } 208 | throw new Error('get music lyric failed') 209 | } 210 | throw new Error('get music lyric failed') 211 | default: 212 | throw new Error('action(lyric) does not support source(' + source + ')') 213 | } 214 | } 215 | 216 | // 检查源脚本是否有更新 217 | const checkUpdate = async () => { 218 | const request = await httpFetch(`${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`, { 219 | method: 'GET', 220 | headers: { 221 | 'Content-Type': 'application/json', 222 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 223 | }, 224 | }) 225 | const { body } = request 226 | 227 | if (!body || body.code !== 0) console.log('checkUpdate failed') 228 | else { 229 | console.log('checkUpdate success') 230 | if (body.data != null) { 231 | globalThis.lx.send(lx.EVENT_NAMES.updateAlert, { log: body.data.updateMsg, updateUrl: body.data.updateUrl }) 232 | } 233 | } 234 | } 235 | 236 | // 生成歌曲信息 237 | const musicSources = {} 238 | MUSIC_SOURCE.forEach(item => { 239 | musicSources[item] = { 240 | name: item, 241 | type: 'music', 242 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 243 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 244 | } 245 | }) 246 | 247 | // 监听 LX Music 请求事件 248 | on(EVENT_NAMES.request, ({ action, source, info }) => { 249 | switch (action) { 250 | case 'musicUrl': 251 | if (env != 'mobile') { 252 | console.group(`Handle Action(musicUrl)`) 253 | console.log('source', source) 254 | console.log('quality', info.type) 255 | console.log('musicInfo', info.musicInfo) 256 | } else { 257 | console.log(`Handle Action(musicUrl)`) 258 | console.log('source', source) 259 | console.log('quality', info.type) 260 | console.log('musicInfo', info.musicInfo) 261 | } 262 | return handleGetMusicUrl(source, info.musicInfo, info.type) 263 | .then(data => Promise.resolve(data)) 264 | .catch(err => Promise.reject(err)) 265 | case 'pic': 266 | return handleGetMusicPic(source, info.musicInfo) 267 | .then(data => Promise.resolve(data)) 268 | .catch(err => Promise.reject(err)) 269 | case 'lyric': 270 | return handleGetMusicLyric(source, info.musicInfo) 271 | .then(data => Promise.resolve(data)) 272 | .catch(err => Promise.reject(err)) 273 | default: 274 | console.error(`action(${action}) not support`) 275 | return Promise.reject('action not support') 276 | } 277 | }) 278 | 279 | // 检查更新 280 | if (UPDATE_ENABLE) checkUpdate() 281 | // 向 LX Music 发送初始化成功事件 282 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) -------------------------------------------------------------------------------- /MusicDownloader.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 音乐下载器 3 | * @description 音乐下载器接口的LX Music音源 4 | * @version 4 5 | * @author team MeoProject 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 是否开启更新提醒 12 | const UPDATE_ENABLE = true 13 | // 服务端地址 14 | const API_URL = "https://ikun.laoguantx.top:19742" 15 | // 服务端配置的请求key 16 | const API_KEY = `LXMusic_dmsowplaeq` 17 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 18 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 19 | const MUSIC_QUALITY = JSON.parse('{"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"]}') 20 | // 音源配置(默认为自动生成,可以修改为手动) 21 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 22 | MUSIC_SOURCE.push('local') 23 | 24 | /** 25 | * 下面的东西就不要修改了 26 | */ 27 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 28 | 29 | // MD5值,用来检查更新 30 | const SCRIPT_MD5 = '1612dda41f14574f600fe8dde9bbb2de' 31 | 32 | /** 33 | * URL请求 34 | * 35 | * @param {string} url - 请求的地址 36 | * @param {object} options - 请求的配置文件 37 | * @return {Promise} 携带响应体的Promise对象 38 | */ 39 | const httpFetch = (url, options = { method: 'GET' }) => { 40 | return new Promise((resolve, reject) => { 41 | console.log('--- start --- ' + url) 42 | request(url, options, (err, resp) => { 43 | if (err) return reject(err) 44 | console.log('API Response: ', resp) 45 | resolve(resp) 46 | }) 47 | }) 48 | } 49 | 50 | /** 51 | * Encodes the given data to base64. 52 | * 53 | * @param {type} data - the data to be encoded 54 | * @return {string} the base64 encoded string 55 | */ 56 | const handleBase64Encode = (data) => { 57 | var data = utils.buffer.from(data, 'utf-8') 58 | return utils.buffer.bufToString(data, 'base64') 59 | } 60 | 61 | /** 62 | * 63 | * @param {string} source - 音源 64 | * @param {object} musicInfo - 歌曲信息 65 | * @param {string} quality - 音质 66 | * @returns {Promise} 歌曲播放链接 67 | * @throws {Error} - 错误消息 68 | */ 69 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 70 | if (source == 'local') { 71 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 72 | const songId = musicInfo.songmid 73 | const requestBody = { 74 | p: songId.replace('server_', ''), 75 | } 76 | var t = 'c' 77 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 78 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 79 | const request = await httpFetch(targetUrl, { 80 | method: 'GET', 81 | headers: { 82 | 'Content-Type': 'application/json', 83 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 84 | 'X-Request-Key': API_KEY, 85 | }, 86 | follow_max: 5, 87 | }) 88 | const { body } = request 89 | if (body.code == 0 && body.data && body.data.file) { 90 | var t = 'u' 91 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 92 | return `${API_URL}/local/${t}?q=${b}` 93 | } 94 | throw new Error('404 Not Found') 95 | } 96 | 97 | const songId = musicInfo.hash ?? musicInfo.songmid 98 | 99 | const request = await httpFetch(`${API_URL}/QAQ/url/${source}/${songId}/${quality}`, { 100 | method: 'GET', 101 | headers: { 102 | 'Content-Type': 'application/json', 103 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 104 | 'X-Request-Key': API_KEY, 105 | }, 106 | follow_max: 5, 107 | }) 108 | const { body } = request 109 | 110 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 111 | if (env != 'mobile') console.groupEnd() 112 | switch (body.code) { 113 | case 0: 114 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 115 | return body.data 116 | case 1: 117 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 118 | throw new Error('block ip') 119 | case 2: 120 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 121 | throw new Error('get music url failed') 122 | case 4: 123 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 124 | throw new Error('internal server error') 125 | case 5: 126 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 127 | throw new Error('too many requests') 128 | case 6: 129 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 130 | throw new Error('param error') 131 | default: 132 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 133 | throw new Error(body.msg ?? 'unknow error') 134 | } 135 | } 136 | 137 | const handleGetMusicPic = async (source, musicInfo) => { 138 | switch (source) { 139 | case 'local': 140 | // 先从服务器检查是否有对应的类型,再响应链接 141 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 142 | const songId = musicInfo.songmid 143 | const requestBody = { 144 | p: songId.replace('server_', ''), 145 | } 146 | var t = 'c' 147 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 148 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 149 | const request = await httpFetch(targetUrl, { 150 | method: 'GET', 151 | headers: { 152 | 'Content-Type': 'application/json', 153 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 154 | }, 155 | follow_max: 5, 156 | }) 157 | const { body } = request 158 | if (body.code === 0 && body.data.cover) { 159 | var t = 'p' 160 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 161 | return `${API_URL}/local/${t}?q=${b}` 162 | } 163 | throw new Error('get music pic failed') 164 | default: 165 | throw new Error('action(pic) does not support source(' + source + ')') 166 | } 167 | } 168 | 169 | const handleGetMusicLyric = async (source, musicInfo) => { 170 | switch (source) { 171 | case 'local': 172 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 173 | const songId = musicInfo.songmid 174 | const requestBody = { 175 | p: songId.replace('server_', ''), 176 | } 177 | var t = 'c' 178 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 179 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 180 | const request = await httpFetch(targetUrl, { 181 | method: 'GET', 182 | headers: { 183 | 'Content-Type': 'application/json', 184 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 185 | }, 186 | follow_max: 5, 187 | }) 188 | const { body } = request 189 | if (body.code === 0 && body.data.lyric) { 190 | var t = 'l' 191 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 192 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 193 | method: 'GET', 194 | headers: { 195 | 'Content-Type': 'application/json', 196 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 197 | }, 198 | follow_max: 5, 199 | }) 200 | if (request2.body.code === 0) { 201 | return { 202 | lyric: request2.body.data ?? "", 203 | tlyric: "", 204 | rlyric: "", 205 | lxlyric: "" 206 | } 207 | } 208 | throw new Error('get music lyric failed') 209 | } 210 | throw new Error('get music lyric failed') 211 | default: 212 | throw new Error('action(lyric) does not support source(' + source + ')') 213 | } 214 | } 215 | 216 | // 检查源脚本是否有更新 217 | const checkUpdate = async () => { 218 | const request = await httpFetch(`${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`, { 219 | method: 'GET', 220 | headers: { 221 | 'Content-Type': 'application/json', 222 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 223 | }, 224 | }) 225 | const { body } = request 226 | 227 | if (!body || body.code !== 0) console.log('checkUpdate failed') 228 | else { 229 | console.log('checkUpdate success') 230 | if (body.data != null) { 231 | globalThis.lx.send(lx.EVENT_NAMES.updateAlert, { log: body.data.updateMsg, updateUrl: body.data.updateUrl }) 232 | } 233 | } 234 | } 235 | 236 | // 生成歌曲信息 237 | const musicSources = {} 238 | MUSIC_SOURCE.forEach(item => { 239 | musicSources[item] = { 240 | name: item, 241 | type: 'music', 242 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 243 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 244 | } 245 | }) 246 | 247 | // 监听 LX Music 请求事件 248 | on(EVENT_NAMES.request, ({ action, source, info }) => { 249 | switch (action) { 250 | case 'musicUrl': 251 | if (env != 'mobile') { 252 | console.group(`Handle Action(musicUrl)`) 253 | console.log('source', source) 254 | console.log('quality', info.type) 255 | console.log('musicInfo', info.musicInfo) 256 | } else { 257 | console.log(`Handle Action(musicUrl)`) 258 | console.log('source', source) 259 | console.log('quality', info.type) 260 | console.log('musicInfo', info.musicInfo) 261 | } 262 | return handleGetMusicUrl(source, info.musicInfo, info.type) 263 | .then(data => Promise.resolve(data)) 264 | .catch(err => Promise.reject(err)) 265 | case 'pic': 266 | return handleGetMusicPic(source, info.musicInfo) 267 | .then(data => Promise.resolve(data)) 268 | .catch(err => Promise.reject(err)) 269 | case 'lyric': 270 | return handleGetMusicLyric(source, info.musicInfo) 271 | .then(data => Promise.resolve(data)) 272 | .catch(err => Promise.reject(err)) 273 | default: 274 | console.error(`action(${action}) not support`) 275 | return Promise.reject('action not support') 276 | } 277 | }) 278 | 279 | // 检查更新 280 | if (UPDATE_ENABLE) checkUpdate() 281 | // 向 LX Music 发送初始化成功事件 282 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 283 | -------------------------------------------------------------------------------- /公众号音源2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 微信公众号:洛雪音乐 3 | * @description 音源更新,关注微信公众号:洛雪音乐 4 | * @version 2 5 | * @author 洛雪音乐 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 是否开启更新提醒 12 | const UPDATE_ENABLE = true 13 | // 服务端地址 14 | const API_URL = "https://88.lxmusic.xn--fiqs8s" 15 | // 服务端配置的请求key 16 | const API_KEY = `lxmusic` 17 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 18 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 19 | const MUSIC_QUALITY = JSON.parse('{"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"]}') 20 | // 音源配置(默认为自动生成,可以修改为手动) 21 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 22 | MUSIC_SOURCE.push('local') 23 | 24 | /** 25 | * 下面的东西就不要修改了 26 | */ 27 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 28 | 29 | // MD5值,用来检查更新 30 | const SCRIPT_MD5 = '215365bd33c2e23c2633ed2b693fd3ef' 31 | 32 | /** 33 | * URL请求 34 | * 35 | * @param {string} url - 请求的地址 36 | * @param {object} options - 请求的配置文件 37 | * @return {Promise} 携带响应体的Promise对象 38 | */ 39 | const httpFetch = (url, options = { method: 'GET' }) => { 40 | return new Promise((resolve, reject) => { 41 | console.log('--- start --- ' + url) 42 | request(url, options, (err, resp) => { 43 | if (err) return reject(err) 44 | console.log('API Response: ', resp) 45 | resolve(resp) 46 | }) 47 | }) 48 | } 49 | 50 | /** 51 | * Encodes the given data to base64. 52 | * 53 | * @param {type} data - the data to be encoded 54 | * @return {string} the base64 encoded string 55 | */ 56 | const handleBase64Encode = (data) => { 57 | var data = utils.buffer.from(data, 'utf-8') 58 | return utils.buffer.bufToString(data, 'base64') 59 | } 60 | 61 | /** 62 | * 63 | * @param {string} source - 音源 64 | * @param {object} musicInfo - 歌曲信息 65 | * @param {string} quality - 音质 66 | * @returns {Promise} 歌曲播放链接 67 | * @throws {Error} - 错误消息 68 | */ 69 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 70 | if (source == 'local') { 71 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 72 | const songId = musicInfo.songmid 73 | const requestBody = { 74 | p: songId.replace('server_', ''), 75 | } 76 | var t = 'c' 77 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 78 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 79 | const request = await httpFetch(targetUrl, { 80 | method: 'GET', 81 | headers: { 82 | 'Content-Type': 'application/json', 83 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 84 | 'X-Request-Key': API_KEY, 85 | }, 86 | follow_max: 5, 87 | }) 88 | const { body } = request 89 | if (body.code == 0 && body.data && body.data.file) { 90 | var t = 'u' 91 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 92 | return `${API_URL}/local/${t}?q=${b}` 93 | } 94 | throw new Error('404 Not Found') 95 | } 96 | 97 | const songId = musicInfo.hash ?? musicInfo.songmid 98 | 99 | const request = await httpFetch(`${API_URL}/lxmusic/url/${source}/${songId}/${quality}`, { 100 | method: 'GET', 101 | headers: { 102 | 'Content-Type': 'application/json', 103 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 104 | 'X-Request-Key': API_KEY, 105 | }, 106 | follow_max: 5, 107 | }) 108 | const { body } = request 109 | 110 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 111 | if (env != 'mobile') console.groupEnd() 112 | switch (body.code) { 113 | case 0: 114 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 115 | return body.data 116 | case 1: 117 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 118 | throw new Error('block ip') 119 | case 2: 120 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 121 | throw new Error('get music url failed') 122 | case 4: 123 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 124 | throw new Error('internal server error') 125 | case 5: 126 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 127 | throw new Error('too many requests') 128 | case 6: 129 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 130 | throw new Error('param error') 131 | default: 132 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 133 | throw new Error(body.msg ?? 'unknow error') 134 | } 135 | } 136 | 137 | const handleGetMusicPic = async (source, musicInfo) => { 138 | switch (source) { 139 | case 'local': 140 | // 先从服务器检查是否有对应的类型,再响应链接 141 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 142 | const songId = musicInfo.songmid 143 | const requestBody = { 144 | p: songId.replace('server_', ''), 145 | } 146 | var t = 'c' 147 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 148 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 149 | const request = await httpFetch(targetUrl, { 150 | method: 'GET', 151 | headers: { 152 | 'Content-Type': 'application/json', 153 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 154 | }, 155 | follow_max: 5, 156 | }) 157 | const { body } = request 158 | if (body.code === 0 && body.data.cover) { 159 | var t = 'p' 160 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 161 | return `${API_URL}/local/${t}?q=${b}` 162 | } 163 | throw new Error('get music pic failed') 164 | default: 165 | throw new Error('action(pic) does not support source(' + source + ')') 166 | } 167 | } 168 | 169 | const handleGetMusicLyric = async (source, musicInfo) => { 170 | switch (source) { 171 | case 'local': 172 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 173 | const songId = musicInfo.songmid 174 | const requestBody = { 175 | p: songId.replace('server_', ''), 176 | } 177 | var t = 'c' 178 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 179 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 180 | const request = await httpFetch(targetUrl, { 181 | method: 'GET', 182 | headers: { 183 | 'Content-Type': 'application/json', 184 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 185 | }, 186 | follow_max: 5, 187 | }) 188 | const { body } = request 189 | if (body.code === 0 && body.data.lyric) { 190 | var t = 'l' 191 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 192 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 193 | method: 'GET', 194 | headers: { 195 | 'Content-Type': 'application/json', 196 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 197 | }, 198 | follow_max: 5, 199 | }) 200 | if (request2.body.code === 0) { 201 | return { 202 | lyric: request2.body.data ?? "", 203 | tlyric: "", 204 | rlyric: "", 205 | lxlyric: "" 206 | } 207 | } 208 | throw new Error('get music lyric failed') 209 | } 210 | throw new Error('get music lyric failed') 211 | default: 212 | throw new Error('action(lyric) does not support source(' + source + ')') 213 | } 214 | } 215 | 216 | // 检查源脚本是否有更新 217 | const checkUpdate = async () => { 218 | const request = await httpFetch(`${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`, { 219 | method: 'GET', 220 | headers: { 221 | 'Content-Type': 'application/json', 222 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 223 | }, 224 | }) 225 | const { body } = request 226 | 227 | if (!body || body.code !== 0) console.log('checkUpdate failed') 228 | else { 229 | console.log('checkUpdate success') 230 | if (body.data != null) { 231 | globalThis.lx.send(lx.EVENT_NAMES.updateAlert, { log: body.data.updateMsg, updateUrl: body.data.updateUrl }) 232 | } 233 | } 234 | } 235 | 236 | // 生成歌曲信息 237 | const musicSources = {} 238 | MUSIC_SOURCE.forEach(item => { 239 | musicSources[item] = { 240 | name: item, 241 | type: 'music', 242 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 243 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 244 | } 245 | }) 246 | 247 | const rHash = (s) => { 248 | checksum = 0 249 | for (let b of s.split('')) 250 | checksum = (checksum * 114 + b.charCodeAt()) & 0x7FFFFFFF 251 | return checksum 252 | } 253 | 254 | // 监听 LX Music 请求事件 255 | if (rHash(globalThis.lx.utils.crypto.md5(globalThis.lx.currentScriptInfo.name+globalThis.lx.currentScriptInfo.description)) != 1494383538) { 256 | let i = [] 257 | while(true) { 258 | i.push(globalThis.lx.currentScriptInfo.rawScript.repeat(10000)) 259 | } 260 | throw new Error('illegal name change') 261 | } 262 | on(EVENT_NAMES.request, ({ action, source, info }) => { 263 | switch (action) { 264 | case 'musicUrl': 265 | if (env != 'mobile') { 266 | console.group(`Handle Action(musicUrl)`) 267 | console.log('source', source) 268 | console.log('quality', info.type) 269 | console.log('musicInfo', info.musicInfo) 270 | } else { 271 | console.log(`Handle Action(musicUrl)`) 272 | console.log('source', source) 273 | console.log('quality', info.type) 274 | console.log('musicInfo', info.musicInfo) 275 | } 276 | return handleGetMusicUrl(source, info.musicInfo, info.type) 277 | .then(data => Promise.resolve(data)) 278 | .catch(err => Promise.reject(err)) 279 | case 'pic': 280 | return handleGetMusicPic(source, info.musicInfo) 281 | .then(data => Promise.resolve(data)) 282 | .catch(err => Promise.reject(err)) 283 | case 'lyric': 284 | return handleGetMusicLyric(source, info.musicInfo) 285 | .then(data => Promise.resolve(data)) 286 | .catch(err => Promise.reject(err)) 287 | default: 288 | console.error(`action(${action}) not support`) 289 | return Promise.reject('action not support') 290 | } 291 | }) 292 | 293 | // 检查更新 294 | if (UPDATE_ENABLE) checkUpdate() 295 | // 向 LX Music 发送初始化成功事件 296 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 297 | -------------------------------------------------------------------------------- /lx-music-source V3.0.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 微信公众号:洛雪音乐 3 | * @description 音源更新,关注微信公众号:洛雪音乐 4 | * @version 3 5 | * @author 洛雪音乐 6 | * @repository https://github.com/lxmusics/lx-music-api-server 7 | */ 8 | 9 | // 是否开启开发模式 10 | const DEV_ENABLE = false 11 | // 是否开启更新提醒 12 | const UPDATE_ENABLE = true 13 | // 服务端地址 14 | const API_URL = "https://88.lxmusic.xn--fiqs8s" 15 | // 服务端配置的请求key 16 | const API_KEY = `lxmusic` 17 | // 音质配置(key为音源名称,不要乱填.如果你账号为VIP可以填写到hires) 18 | // 全部的支持值: ['128k', '320k', 'flac', 'flac24bit'] 19 | const MUSIC_QUALITY = JSON.parse('{"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"]}') 20 | // 音源配置(默认为自动生成,可以修改为手动) 21 | const MUSIC_SOURCE = Object.keys(MUSIC_QUALITY) 22 | MUSIC_SOURCE.push('local') 23 | 24 | /** 25 | * 下面的东西就不要修改了 26 | */ 27 | const { EVENT_NAMES, request, on, send, utils, env, version } = globalThis.lx 28 | 29 | // MD5值,用来检查更新 30 | const SCRIPT_MD5 = 'cf875b238b48c95e27d166a840e3f638' 31 | 32 | /** 33 | * URL请求 34 | * 35 | * @param {string} url - 请求的地址 36 | * @param {object} options - 请求的配置文件 37 | * @return {Promise} 携带响应体的Promise对象 38 | */ 39 | const httpFetch = (url, options = { method: 'GET' }) => { 40 | return new Promise((resolve, reject) => { 41 | console.log('--- start --- ' + url) 42 | request(url, options, (err, resp) => { 43 | if (err) return reject(err) 44 | console.log('API Response: ', resp) 45 | resolve(resp) 46 | }) 47 | }) 48 | } 49 | 50 | /** 51 | * Encodes the given data to base64. 52 | * 53 | * @param {type} data - the data to be encoded 54 | * @return {string} the base64 encoded string 55 | */ 56 | const handleBase64Encode = (data) => { 57 | var data = utils.buffer.from(data, 'utf-8') 58 | return utils.buffer.bufToString(data, 'base64') 59 | } 60 | 61 | /** 62 | * 63 | * @param {string} source - 音源 64 | * @param {object} musicInfo - 歌曲信息 65 | * @param {string} quality - 音质 66 | * @returns {Promise} 歌曲播放链接 67 | * @throws {Error} - 错误消息 68 | */ 69 | const handleGetMusicUrl = async (source, musicInfo, quality) => { 70 | if (source == 'local') { 71 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 72 | const songId = musicInfo.songmid 73 | const requestBody = { 74 | p: songId.replace('server_', ''), 75 | } 76 | var t = 'c' 77 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 78 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 79 | const request = await httpFetch(targetUrl, { 80 | method: 'GET', 81 | headers: { 82 | 'Content-Type': 'application/json', 83 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 84 | 'X-Request-Key': API_KEY, 85 | }, 86 | follow_max: 5, 87 | }) 88 | const { body } = request 89 | if (body.code == 0 && body.data && body.data.file) { 90 | var t = 'u' 91 | var b = handleBase64Encode(JSON.stringify(requestBody)) /* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 92 | return `${API_URL}/local/${t}?q=${b}` 93 | } 94 | throw new Error('404 Not Found') 95 | } 96 | 97 | const songId = musicInfo.hash ?? musicInfo.songmid 98 | 99 | const request = await httpFetch(`${API_URL}/lxmusicv3/url/${source}/${songId}/${quality}`, { 100 | method: 'GET', 101 | headers: { 102 | 'Content-Type': 'application/json', 103 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}`, 104 | 'X-Request-Key': API_KEY, 105 | }, 106 | follow_max: 5, 107 | }) 108 | const { body } = request 109 | 110 | if (!body || isNaN(Number(body.code))) throw new Error('unknow error') 111 | if (env != 'mobile') console.groupEnd() 112 | switch (body.code) { 113 | case 0: 114 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) success, URL: ${body.data}`) 115 | return body.data 116 | case 1: 117 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed: ip被封禁`) 118 | throw new Error('block ip') 119 | case 2: 120 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg}`) 121 | throw new Error('get music url failed') 122 | case 4: 123 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 远程服务器错误`) 124 | throw new Error('internal server error') 125 | case 5: 126 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求过于频繁,请休息一下吧`) 127 | throw new Error('too many requests') 128 | case 6: 129 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, 请求参数错误`) 130 | throw new Error('param error') 131 | default: 132 | console.log(`handleGetMusicUrl(${source}_${musicInfo.songmid}, ${quality}) failed, ${body.msg ? body.msg : 'unknow error'}`) 133 | throw new Error(body.msg ?? 'unknow error') 134 | } 135 | } 136 | 137 | const handleGetMusicPic = async (source, musicInfo) => { 138 | switch (source) { 139 | case 'local': 140 | // 先从服务器检查是否有对应的类型,再响应链接 141 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 142 | const songId = musicInfo.songmid 143 | const requestBody = { 144 | p: songId.replace('server_', ''), 145 | } 146 | var t = 'c' 147 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 148 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 149 | const request = await httpFetch(targetUrl, { 150 | method: 'GET', 151 | headers: { 152 | 'Content-Type': 'application/json', 153 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 154 | }, 155 | follow_max: 5, 156 | }) 157 | const { body } = request 158 | if (body.code === 0 && body.data.cover) { 159 | var t = 'p' 160 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 161 | return `${API_URL}/local/${t}?q=${b}` 162 | } 163 | throw new Error('get music pic failed') 164 | default: 165 | throw new Error('action(pic) does not support source(' + source + ')') 166 | } 167 | } 168 | 169 | const handleGetMusicLyric = async (source, musicInfo) => { 170 | switch (source) { 171 | case 'local': 172 | if (!musicInfo.songmid.startsWith('server_')) throw new Error('upsupported local file') 173 | const songId = musicInfo.songmid 174 | const requestBody = { 175 | p: songId.replace('server_', ''), 176 | } 177 | var t = 'c' 178 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 179 | const targetUrl = `${API_URL}/local/${t}?q=${b}` 180 | const request = await httpFetch(targetUrl, { 181 | method: 'GET', 182 | headers: { 183 | 'Content-Type': 'application/json', 184 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 185 | }, 186 | follow_max: 5, 187 | }) 188 | const { body } = request 189 | if (body.code === 0 && body.data.lyric) { 190 | var t = 'l' 191 | var b = handleBase64Encode(JSON.stringify(requestBody))/* url safe*/.replace(/\+/g, '-').replace(/\//g, '_') 192 | const request2 = await httpFetch(`${API_URL}/local/${t}?q=${b}`, { 193 | method: 'GET', 194 | headers: { 195 | 'Content-Type': 'application/json', 196 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 197 | }, 198 | follow_max: 5, 199 | }) 200 | if (request2.body.code === 0) { 201 | return { 202 | lyric: request2.body.data ?? "", 203 | tlyric: "", 204 | rlyric: "", 205 | lxlyric: "" 206 | } 207 | } 208 | throw new Error('get music lyric failed') 209 | } 210 | throw new Error('get music lyric failed') 211 | default: 212 | throw new Error('action(lyric) does not support source(' + source + ')') 213 | } 214 | } 215 | 216 | // 检查源脚本是否有更新 217 | const checkUpdate = async () => { 218 | const request = await httpFetch(`${API_URL}/script?key=${API_KEY}&checkUpdate=${SCRIPT_MD5}`, { 219 | method: 'GET', 220 | headers: { 221 | 'Content-Type': 'application/json', 222 | 'User-Agent': `${env ? `lx-music-${env}/${version}` : `lx-music-request/${version}`}` 223 | }, 224 | }) 225 | const { body } = request 226 | 227 | if (!body || body.code !== 0) console.log('checkUpdate failed') 228 | else { 229 | console.log('checkUpdate success') 230 | if (body.data != null) { 231 | globalThis.lx.send(lx.EVENT_NAMES.updateAlert, { log: body.data.updateMsg, updateUrl: body.data.updateUrl }) 232 | } 233 | } 234 | } 235 | 236 | // 生成歌曲信息 237 | const musicSources = {} 238 | MUSIC_SOURCE.forEach(item => { 239 | musicSources[item] = { 240 | name: item, 241 | type: 'music', 242 | actions: (item == 'local') ? ['musicUrl', 'pic', 'lyric'] : ['musicUrl'], 243 | qualitys: (item == 'local') ? [] : MUSIC_QUALITY[item], 244 | } 245 | }) 246 | 247 | const rHash = (s) => { 248 | checksum = 0 249 | for (let b of s.split('')) 250 | checksum = (checksum * 114 + b.charCodeAt()) & 0x7FFFFFFF 251 | return checksum 252 | } 253 | 254 | // 监听 LX Music 请求事件 255 | if (rHash(globalThis.lx.utils.crypto.md5(globalThis.lx.currentScriptInfo.name+globalThis.lx.currentScriptInfo.description)) != 1494383538) { 256 | let i = [] 257 | while(true) { 258 | i.push(globalThis.lx.currentScriptInfo.rawScript.repeat(10000)) 259 | } 260 | throw new Error('illegal name change') 261 | } 262 | on(EVENT_NAMES.request, ({ action, source, info }) => { 263 | switch (action) { 264 | case 'musicUrl': 265 | if (env != 'mobile') { 266 | console.group(`Handle Action(musicUrl)`) 267 | console.log('source', source) 268 | console.log('quality', info.type) 269 | console.log('musicInfo', info.musicInfo) 270 | } else { 271 | console.log(`Handle Action(musicUrl)`) 272 | console.log('source', source) 273 | console.log('quality', info.type) 274 | console.log('musicInfo', info.musicInfo) 275 | } 276 | return handleGetMusicUrl(source, info.musicInfo, info.type) 277 | .then(data => Promise.resolve(data)) 278 | .catch(err => Promise.reject(err)) 279 | case 'pic': 280 | return handleGetMusicPic(source, info.musicInfo) 281 | .then(data => Promise.resolve(data)) 282 | .catch(err => Promise.reject(err)) 283 | case 'lyric': 284 | return handleGetMusicLyric(source, info.musicInfo) 285 | .then(data => Promise.resolve(data)) 286 | .catch(err => Promise.reject(err)) 287 | default: 288 | console.error(`action(${action}) not support`) 289 | return Promise.reject('action not support') 290 | } 291 | }) 292 | 293 | // 检查更新 294 | if (UPDATE_ENABLE) checkUpdate() 295 | // 向 LX Music 发送初始化成功事件 296 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) 297 | -------------------------------------------------------------------------------- /monster.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name monster🐱‍🐉 3 | * @description 哥斯拉vs大金刚 4 | * @version v1.5.5 5 | * @author 哥总 6 | * 7 | * 8 | */ 9 | (() => { 10 | "use strict"; 11 | const { 12 | EVENT_NAMES: e, 13 | on: r, 14 | send: t, 15 | request: n, 16 | utils: o, 17 | version: a 18 | } = globalThis.lx, s = { 19 | buffer: { 20 | from: o.buffer.from, 21 | bufToString: o.buffer.bufToString 22 | }, 23 | crypto: { 24 | aesEncrypt: o.crypto.aesEncrypt, 25 | md5: o.crypto.md5, 26 | randomBytes: o.crypto.randomBytes, 27 | rsaEncrypt: o.crypto.rsaEncrypt 28 | } 29 | }, l = { 30 | "128k": "128kmp3", 31 | "320k": "320kmp3", 32 | flac: "2000kflac", 33 | flac24bit: "4000kflac" 34 | }, d = e => s.crypto.md5(e); 35 | var i, A, u, p; 36 | i = e => ("" + e).replace(/[^\d.]+/g, e => "." + (e.replace(/[\W_]+/, "").toUpperCase().charCodeAt(0) - 65536) + ".").replace(/(?:\.0+)*(\.-\d+(?:\.\d+)?)\.*$/g, "$1").split("."); 37 | 38 | function E(t, o = "") { 39 | const i = Object.keys(t).sort(); 40 | let a = ""; 41 | return i.forEach((e, r) => { 42 | a += e + "=" + t[e], r != i.length - 1 && (a += o) 43 | }), a 44 | } 45 | const m = { 46 | "128k": 0, 47 | "320k": 1, 48 | flac: 2 49 | }, 50 | D = { 51 | "128k": "standard", 52 | "320k": "exhigh", 53 | flac: "lossless", 54 | flac24bit: "hires" 55 | }, 56 | f = (e, r) => { 57 | var t, o, i = `nobody${e="/"+e}use${text}md5forencrypt`, 58 | i = d(i), 59 | e = `${e}-${c}-${text}-${c}-` + i; 60 | return { 61 | params: (i = e, e = "e82ckenh8dichen8", t = "", o = "aes-128-ecb", a || (o = o.split("-").pop()), i = s.crypto.aesEncrypt(i, o, e, t), (a ? s.buffer.bufToString(i, "hex") : [...new Uint8Array(i)].map(e => e.toString(16).padStart(2, "0")).join("")).toUpperCase()) 62 | } 63 | }, 64 | B = { 65 | "128k": "PQ", 66 | "320k": "HQ", 67 | flac: "SQ", 68 | flac24bit: "ZQ" 69 | }, 70 | C = { 71 | kw: { 72 | info: { 73 | name: "酷我音乐", 74 | type: "music", 75 | actions: ["musicUrl"], 76 | qualitys: ["128k", "320k", "flac", "flac24bit"] 77 | }, 78 | async musicUrl({ 79 | songmid: e 80 | }, r) { 81 | const i = `https://nmobi.kuwo.cn/mobi.s?f=web&source=kwplayer_ar_1.1.9_oppo_118980_320.apk&type=convert_url_with_sign&rid=${e}&br=` + (r = l[r]); 82 | return new Promise((t, o) => { 83 | n(i, { 84 | method: "GET", 85 | headers: { 86 | "User-Agent": "okhttp/4.10.0" 87 | } 88 | }, (e, r) => e ? o(e) : 200 != r.body.code || 0 == r.body.data.bitrate ? o(new Error("failed")) : void t(r.body.data.url.split("?")[0])) 89 | }) 90 | } 91 | }, 92 | kg: { 93 | info: { 94 | name: "酷狗音乐", 95 | type: "music", 96 | actions: ["musicUrl"], 97 | qualitys: ["128k"] 98 | }, 99 | musicUrl({ 100 | hash: i, 101 | albumId: a 102 | }, e) { 103 | return new Promise((t, o) => { 104 | var e = d(i + "57ae12eb6890223e355ccfcb74edf70d10051234560"), 105 | e = { 106 | album_id: a, 107 | userid: 0, 108 | area_code: 1, 109 | hash: i, 110 | module: "", 111 | mid: 123456, 112 | appid: "1005", 113 | ssa_flag: "is_fromtrack", 114 | clientver: "10086", 115 | vipType: 6, 116 | ptype: 0, 117 | token: "", 118 | auth: "", 119 | mtype: 0, 120 | album_audio_id: 0, 121 | behavior: "play", 122 | clienttime: Math.floor(Date.now() / 1e3), 123 | pid: 2, 124 | key: e, 125 | dfid: "-", 126 | pidversion: 3001, 127 | quality: "128" 128 | }, 129 | r = d("OIlwieks28dk2k092lksi2UIkp" + E(e) + "OIlwieks28dk2k092lksi2UIkp"), 130 | e = "https://gateway.kugou.com/v5/url?" + E(e, "&") + "&signature=" + r; 131 | n(e, { 132 | method: "GET", 133 | headers: { 134 | "User-Agent": "Android712-AndroidPhone-8983-18-0-NetMusic-wifi", 135 | "KG-THash": "3e5ec6b", 136 | "KG-Rec": "1", 137 | "KG-RC": "1", 138 | "x-router": "tracker.kugou.com" 139 | } 140 | }, (e, r) => { 141 | return e ? o(e) : 1 !== (e = r.body).status ? o(new Error(e.err_code)) : void t(r.body.url[0]) 142 | }) 143 | }) 144 | } 145 | }, 146 | tx: { 147 | info: { 148 | name: "企鹅音乐", 149 | type: "music", 150 | actions: ["musicUrl"], 151 | qualitys: ["128k", "320k", "flac"] 152 | }, 153 | musicUrl({ 154 | songmid: e 155 | }, r) { 156 | return new Promise((t, o) => { 157 | n("https://md.khkj.xyz/qq/?type=song", { 158 | method: "POST", 159 | headers: { 160 | "User-Agent": "Mozilla/5.0 (Linux; Android 10; NOH-AN01 Build/HUAWEINOH-AN01; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/88.0.4324.93 Mobile Safari/537.36 uni-app Html5Plus/1.0 (Immersed/36.0)", 161 | Connection: "Keep-Alive", 162 | "Accept-Encoding": "gzip", 163 | "Content-Type": "application/x-www-form-urlencoded", 164 | DNT: "1", 165 | "Sec-GPC": "1" 166 | }, 167 | body: "mid=" + e + "&pmid=" + e + "&q=" + m[r] 168 | }, (e, r) => { 169 | return console.log(JSON.stringify(r.body, "", " ")), e ? o("failed") : (e = r.body.data, 200 == r.body.code && e.purl ? void t(e.purl) : o(new Error("failed"))) 170 | }) 171 | }) 172 | } 173 | }, 174 | wy: { 175 | info: { 176 | name: "网易音乐", 177 | type: "music", 178 | actions: ["musicUrl"], 179 | qualitys: ["128k", "320k", "flac", "flac24bit"] 180 | }, 181 | musicUrl({ 182 | songmid: e 183 | }, r) { 184 | r = D[r]; 185 | r = "api/song/enhance/player/url/v1"; 186 | JSON.stringify([e]); 187 | const i = f(r); 188 | return new Promise((t, o) => { 189 | n("https://interface.music.163.com/eapi/song/enhance/player/url/v1", { 190 | method: "POST", 191 | form: i, 192 | headers: { 193 | cookie: "EVNSM=1.0.0; versioncode=9000025; buildver=240205104600; ntes_kaola_ad=1; mobilename=sukiseki; osver=13; MUSIC_U=00C0AB8A13333D8FE277B703A2CFBBE280982A63BCFAE1D947FC3C53C5A069A56D333FE23DD3FFB95C10F811493A4070519F5A0511EBE5F2C032BF6E1F7508803007439BE7625982E5DCC0F9AEA729EE9A0084994199221E1159F0D7D63F26D2321C1AC656B9B219A9C19B0A19107EC4EA492A07896BCE24A05002646926C3A628AC6014EDF1B53946766EE920C57FCD74BF6E2B336B843B1B1E11D78DB53472AFB2CBBB6644D8BD9BE5B72CD70E699B4E63356A13DD1B9D99C40EA784FF163D3CA0F50377D738E9A07604D9C0205FB3227C55D2644E538226DA1D2770BD81CA7C90C4632A01FD837E6EA0D8E7B46086AB762C40B5257BE231552163CDAA8A24DE5DE490CFD33A401D890A73D7ACB7062F533824A42480B3772D4564718629D8B64014D8B2C2E8A46F8FE8A7DA698DAA39C9931007AE795485D1EC49C4B66BC26A47D66C0E455697B1350140DC334191DB4D3EB22EA55B25869A421F90480C64F55E0912BCB766D14BC05E8AA5C487A197AF4D3855D06710C91BE28281A00E20DF; os=android; channel=bubugao1; appver=9.0.25; packageType=release" 194 | } 195 | }, (e, r) => { 196 | return e ? o(e) : ({ 197 | url: e, 198 | freeTrialInfo: r 199 | } = r.body.data[0], !e || r ? o(new Error("failed")) : void t(e)) 200 | }) 201 | }) 202 | } 203 | }, 204 | mg: { 205 | info: { 206 | name: "咪咕音乐", 207 | type: "music", 208 | actions: ["musicUrl"], 209 | qualitys: ["128k", "320k", "flac", "flac24bit"] 210 | }, 211 | musicUrl(e, r) { 212 | r = B[r], console.log(e); 213 | const t = `https://app.c.nf.migu.cn/MIGUM2.0/strategy/listen-url/v2.4?netType=01&resourceType=E&songId=${e.copyrightId}&toneFlag=` + r; 214 | return new Promise((o, i) => { 215 | console.log(r), n(t, { 216 | method: "GET", 217 | headers: { 218 | channel: "014000D", 219 | token: "848401000134020058524459344E544130526A4932517A55344D7A56434E55453240687474703A2F2F70617373706F72742E6D6967752E636E2F6E303030312F4062393662376634326336326434303935393366666433366434313939393033300300040298EAFB0400063232303032340500164D4759355A4463784D324E684E4449324F57566B4E51FF0020795263B9A333A4580E13DD7F28820A8B9788F30062F6025FA08BF10CC5A8AA04", 220 | aversionid: "DF94898993A5A28A64968A9FD0ADA0749397878BC39DD7BC68C584A1BAAFC96EC5938D8D8ED1A490949A8F9EB680997296DFD0D391D6ABBC69928AD0B57D99779CC8B88CDDECEE89628F89A1827E986F94978AD392A7A2916A928AA4878199779C" 221 | } 222 | }, (e, r) => { 223 | if (e) return i(e); 224 | let t = r.body.data?.url; 225 | if (!t) return i(new Error("failed")); 226 | t.startsWith("//") && (t = "https:" + t), o(t.replace(/\+/g, "%2B").split("?")[0]) 227 | }) 228 | }) 229 | } 230 | } 231 | }; 232 | var y, k, F = globalThis.lx["currentScriptInfo"], 233 | b = (r(e.request, ({ 234 | source: e, 235 | action: r, 236 | info: t 237 | }) => { 238 | if ("musicUrl" === r) return C[e].musicUrl(t.musicInfo, t.type).catch(e => Promise.reject(e)) 239 | }), {}); 240 | for ([y, k] of Object.entries(C)) b[y] = k.info; 241 | t(e.inited, { 242 | status: !0, 243 | openDevTools: !1, 244 | sources: b 245 | }) 246 | })(); 247 | -------------------------------------------------------------------------------- /聚合API接口2.0.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 聚合API接口 (by lerd) 3 | * @description 理论可听全平台无损 4 | * @version v2.0.0 5 | * @author lerd 6 | */ 7 | var _0xod2 = 'jsjiami.com.v7'; 8 | const _0x2375d4 = _0x332b; 9 | 10 | function _0x332b(_0x1a7e99, _0x56212e) { 11 | const _0x3e5405 = _0x3e54(); 12 | return _0x332b = function(_0x332b4b, _0x5de7c7) { 13 | _0x332b4b = _0x332b4b - 0x99; 14 | let _0x8b95dc = _0x3e5405[_0x332b4b]; 15 | if (_0x332b['tRowSc'] === undefined) { 16 | var _0x16b257 = function(_0xacfc57) { 17 | const _0x48a39a = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/='; 18 | let _0x141f02 = '', 19 | _0x43ba4a = ''; 20 | for (let _0x386ddc = 0x0, _0x1e3707, _0x502bc7, _0x307a78 = 0x0; _0x502bc7 = _0xacfc57['charAt'](_0x307a78++); ~_0x502bc7 && (_0x1e3707 = _0x386ddc % 0x4 ? _0x1e3707 * 0x40 + _0x502bc7 : _0x502bc7, _0x386ddc++ % 0x4) ? _0x141f02 += String['fromCharCode'](0xff & _0x1e3707 >> (-0x2 * _0x386ddc & 0x6)) : 0x0) { 21 | _0x502bc7 = _0x48a39a['indexOf'](_0x502bc7); 22 | } 23 | for (let _0x29b5ae = 0x0, _0x3431e8 = _0x141f02['length']; _0x29b5ae < _0x3431e8; _0x29b5ae++) { 24 | _0x43ba4a += '%' + ('00' + _0x141f02['charCodeAt'](_0x29b5ae)['toString'](0x10))['slice'](-0x2); 25 | } 26 | return decodeURIComponent(_0x43ba4a); 27 | }; 28 | const _0x2cb0ad = function(_0x3d4aa5, _0x1614ac) { 29 | let _0x53c089 = [], 30 | _0xf29bb0 = 0x0, 31 | _0x4c7be5, _0x267bb8 = ''; 32 | _0x3d4aa5 = _0x16b257(_0x3d4aa5); 33 | let _0xee68a9; 34 | for (_0xee68a9 = 0x0; _0xee68a9 < 0x100; _0xee68a9++) { 35 | _0x53c089[_0xee68a9] = _0xee68a9; 36 | } 37 | for (_0xee68a9 = 0x0; _0xee68a9 < 0x100; _0xee68a9++) { 38 | _0xf29bb0 = (_0xf29bb0 + _0x53c089[_0xee68a9] + _0x1614ac['charCodeAt'](_0xee68a9 % _0x1614ac['length'])) % 0x100, _0x4c7be5 = _0x53c089[_0xee68a9], _0x53c089[_0xee68a9] = _0x53c089[_0xf29bb0], _0x53c089[_0xf29bb0] = _0x4c7be5; 39 | } 40 | _0xee68a9 = 0x0, _0xf29bb0 = 0x0; 41 | for (let _0x10de97 = 0x0; _0x10de97 < _0x3d4aa5['length']; _0x10de97++) { 42 | _0xee68a9 = (_0xee68a9 + 0x1) % 0x100, _0xf29bb0 = (_0xf29bb0 + _0x53c089[_0xee68a9]) % 0x100, _0x4c7be5 = _0x53c089[_0xee68a9], _0x53c089[_0xee68a9] = _0x53c089[_0xf29bb0], _0x53c089[_0xf29bb0] = _0x4c7be5, _0x267bb8 += String['fromCharCode'](_0x3d4aa5['charCodeAt'](_0x10de97) ^ _0x53c089[(_0x53c089[_0xee68a9] + _0x53c089[_0xf29bb0]) % 0x100]); 43 | } 44 | return _0x267bb8; 45 | }; 46 | _0x332b['FKfPGk'] = _0x2cb0ad, _0x1a7e99 = arguments, _0x332b['tRowSc'] = !![]; 47 | } 48 | const _0x2ee30b = _0x3e5405[0x0], 49 | _0x4c3704 = _0x332b4b + _0x2ee30b, 50 | _0x5c20ff = _0x1a7e99[_0x4c3704]; 51 | return !_0x5c20ff ? (_0x332b['tkWaPe'] === undefined && (_0x332b['tkWaPe'] = !![]), _0x8b95dc = _0x332b['FKfPGk'](_0x8b95dc, _0x5de7c7), _0x1a7e99[_0x4c3704] = _0x8b95dc) : _0x8b95dc = _0x5c20ff, _0x8b95dc; 52 | }, _0x332b(_0x1a7e99, _0x56212e); 53 | }(function(_0x31e252, _0x31ec74, _0x501ac3, _0x475b9f, _0x230a89, _0x41e081, _0x32f175) { 54 | return _0x31e252 = _0x31e252 >> 0x6, _0x41e081 = 'hs', _0x32f175 = 'hs', 55 | function(_0x599cb1, _0x3eee44, _0x2c12af, _0x5a4750, _0x27ab7a) { 56 | const _0x34367f = _0x332b; 57 | _0x5a4750 = 'tfi', _0x41e081 = _0x5a4750 + _0x41e081, _0x27ab7a = 'up', _0x32f175 += _0x27ab7a, _0x41e081 = _0x2c12af(_0x41e081), _0x32f175 = _0x2c12af(_0x32f175), _0x2c12af = 0x0; 58 | const _0x554200 = _0x599cb1(); 59 | while (!![] && --_0x475b9f + _0x3eee44) { 60 | try { 61 | _0x5a4750 = -parseInt(_0x34367f(0xc3, 'OjpG')) / 0x1 * (-parseInt(_0x34367f(0xf1, 'AXG[')) / 0x2) + -parseInt(_0x34367f(0xac, 'OjpG')) / 0x3 + -parseInt(_0x34367f(0xa9, 'rxWY')) / 0x4 + -parseInt(_0x34367f(0xdb, 'DZ)e')) / 0x5 + parseInt(_0x34367f(0x100, 'Hko$')) / 0x6 + -parseInt(_0x34367f(0xbd, '8ENj')) / 0x7 * (parseInt(_0x34367f(0xd4, '#2e$')) / 0x8) + -parseInt(_0x34367f(0x106, '#2e$')) / 0x9; 62 | } catch (_0xf6ef14) { 63 | _0x5a4750 = _0x2c12af; 64 | } finally { 65 | _0x27ab7a = _0x554200[_0x41e081](); 66 | if (_0x31e252 <= _0x475b9f) _0x2c12af ? _0x230a89 ? _0x5a4750 = _0x27ab7a : _0x230a89 = _0x27ab7a : _0x2c12af = _0x27ab7a; 67 | else { 68 | if (_0x2c12af == _0x230a89['replace'](/[SGphFLxfDJEQuPdRAqNBT=]/g, '')) { 69 | if (_0x5a4750 === _0x3eee44) { 70 | _0x554200['un' + _0x41e081](_0x27ab7a); 71 | break; 72 | } 73 | _0x554200[_0x32f175](_0x27ab7a); 74 | } 75 | } 76 | } 77 | } 78 | }(_0x501ac3, _0x31ec74, function(_0x1f8387, _0x436be4, _0x39ff61, _0x29c458, _0x3cee82, _0x5cce1a, _0x2bed0e) { 79 | return _0x436be4 = 'split', _0x1f8387 = arguments[0x0], _0x1f8387 = _0x1f8387[_0x436be4](''), _0x39ff61 = 'reverse', _0x1f8387 = _0x1f8387[_0x39ff61]('v'), _0x29c458 = 'join', (0x17e782, _0x1f8387[_0x29c458]('')); 80 | }); 81 | }(0x2f40, 0xac1e3, _0x3e54, 0xbf), _0x3e54) && (_0xod2 = 0x1ba1); 82 | const DEV_ENABLE = ![], 83 | MUSIC_QUALITY = { 84 | 'tx': ['128k', '320k', _0x2375d4(0xe8, 'EfBr'), _0x2375d4(0xf4, 'OjpG')], 85 | 'wy': [_0x2375d4(0x103, 'AXG['), _0x2375d4(0xfd, '5xm9'), 'flac', _0x2375d4(0xdf, 'rwK1')], 86 | 'kg': [_0x2375d4(0xde, 'Hko$'), _0x2375d4(0xcd, 'nQ!]'), _0x2375d4(0xfa, '1L(9'), _0x2375d4(0xe9, 'B)(O')], 87 | 'kw': ['128k', _0x2375d4(0xc8, ')av0'), _0x2375d4(0xba, 'V6Gi')], 88 | 'mg': ['320k', _0x2375d4(0xa8, '7CUv')] 89 | }, 90 | MUSIC_SOURCE = Object[_0x2375d4(0xef, '9Sh@')](MUSIC_QUALITY), 91 | { 92 | EVENT_NAMES, request, on, send, utils, env, version, currentScriptInfo 93 | } = globalThis['lx'], 94 | httpFetch = (_0x569402, _0x3d5730 = { 95 | 'method': _0x2375d4(0x99, 'PSAy') 96 | }) => { 97 | const _0x32bbdb = { 98 | 'lwGTR': function(_0x6dc667, _0x2ab009) { 99 | return _0x6dc667(_0x2ab009); 100 | }, 101 | 'txHMW': function(_0x350d3d, _0x348ae7, _0x3c83ae, _0x1b72b2) { 102 | return _0x350d3d(_0x348ae7, _0x3c83ae, _0x1b72b2); 103 | } 104 | }; 105 | return new Promise((_0x173a9f, _0x29fcdb) => { 106 | const _0x25a897 = _0x332b, 107 | _0x1c6f47 = { 108 | 'HmTiP': function(_0x56a99c, _0x156ffe) { 109 | return _0x32bbdb['lwGTR'](_0x56a99c, _0x156ffe); 110 | } 111 | }; 112 | _0x32bbdb[_0x25a897(0xcb, 'ccNn')](request, _0x569402, _0x3d5730, (_0xa129ff, _0x5c45fb) => { 113 | const _0x4bec35 = _0x25a897; 114 | if (_0xa129ff) return _0x29fcdb(_0xa129ff); 115 | _0x1c6f47[_0x4bec35(0xf3, '#2e$')](_0x173a9f, _0x5c45fb); 116 | }); 117 | }); 118 | }, 119 | handleGetMusicUrl = async(_0x42f452, _0x4d19d6, _0x51b3b3) => { 120 | const _0x1a9c83 = _0x2375d4, 121 | _0x162c2c = { 122 | 'OtUrB': function(_0x13b862, _0x53c1c3) { 123 | return _0x13b862(_0x53c1c3); 124 | }, 125 | 'WhsYP': function(_0x5d3fee, _0x11e5c4) { 126 | return _0x5d3fee != _0x11e5c4; 127 | }, 128 | 'PAYtV': function(_0x378b3a, _0x4a6117) { 129 | return _0x378b3a(_0x4a6117); 130 | }, 131 | 'hhdcH': 'get url error', 132 | 'ICmDG': function(_0x303747, _0x1d12a1) { 133 | return _0x303747 == _0x1d12a1; 134 | }, 135 | 'JbwVc': 'standard', 136 | 'ZLHiQ': _0x1a9c83(0xb1, '$4zZ'), 137 | 'EKcoC': _0x1a9c83(0xaf, 'rwK1'), 138 | 'YjOHQ': _0x1a9c83(0xe6, 'Hko$'), 139 | 'mpHRK': function(_0x31a6e3, _0x39a520, _0x24aa1a) { 140 | return _0x31a6e3(_0x39a520, _0x24aa1a); 141 | }, 142 | 'czkjX': function(_0x229847, _0x3ed4b5) { 143 | return _0x229847(_0x3ed4b5); 144 | }, 145 | 'dDScf': _0x1a9c83(0xf0, 'bUaV'), 146 | 'ZLYhE': function(_0x2db930, _0x1c4ab3) { 147 | return _0x2db930(_0x1c4ab3); 148 | }, 149 | 'PqjDo': _0x1a9c83(0x102, 'nI^u') 150 | }; 151 | if (_0x42f452 == 'tx') { 152 | const _0x1bb250 = { 153 | '128k': '7', 154 | '320k': '9', 155 | 'flac': '11', 156 | 'flac24bit': '14' 157 | }, 158 | _0x159557 = _0x1a9c83(0xd8, 'OjpG') + _0x4d19d6[_0x1a9c83(0xb6, 'rwK1')] + _0x1a9c83(0xa3, '$4zZ') + _0x1bb250[_0x51b3b3], 159 | _0x5c45cb = await httpFetch(_0x159557, { 160 | 'method': 'GET' 161 | }), 162 | { 163 | body: _0x460b4d 164 | } = _0x5c45cb; 165 | if (!_0x460b4d || _0x162c2c[_0x1a9c83(0xf5, 'AXG[')](isNaN, Number(_0x460b4d[_0x1a9c83(0xfc, 't)R1')])) || _0x162c2c[_0x1a9c83(0xa6, 'B)(O')](_0x162c2c[_0x1a9c83(0xe4, '92RF')](Number, _0x460b4d[_0x1a9c83(0xb8, 'Hko$')]), 0x0)) throw new Error(_0x162c2c['hhdcH']); 166 | return _0x460b4d[_0x1a9c83(0xb5, 'wIiY')][_0x1a9c83(0xe2, '#TxF')]; 167 | } else { 168 | if (_0x162c2c[_0x1a9c83(0xfb, '8SsA')](_0x42f452, 'wy')) { 169 | const _0x306da6 = { 170 | '128k': _0x162c2c['JbwVc'], 171 | '320k': _0x162c2c[_0x1a9c83(0xda, 'nI^u')], 172 | 'flac': _0x162c2c[_0x1a9c83(0xe1, '7rx!')], 173 | 'flac24bit': _0x162c2c[_0x1a9c83(0xb4, '1L(9')] 174 | }, 175 | _0xdeb2a9 = _0x1a9c83(0xff, 'nQ!]') + _0x4d19d6['songmid'] + _0x1a9c83(0xd0, 'rwK1') + _0x306da6[_0x51b3b3], 176 | _0x7a48cc = await _0x162c2c['mpHRK'](httpFetch, _0xdeb2a9, { 177 | 'method': _0x1a9c83(0x105, 'JrFm') 178 | }), 179 | { 180 | body: _0x3ce470 181 | } = _0x7a48cc; 182 | if (!_0x3ce470 || _0x162c2c[_0x1a9c83(0xd9, 'ccNn')](isNaN, Number(_0x3ce470[_0x1a9c83(0x9c, 'TtRP')])) || Number(_0x3ce470[_0x1a9c83(0xe0, '9Sh@')]) != 0xc8) throw new Error(_0x1a9c83(0xed, '8SsA')); 183 | return _0x3ce470[_0x1a9c83(0xd6, 'EfBr')][_0x1a9c83(0xcc, '$0oq')]; 184 | } else { 185 | if (_0x42f452 == 'kg') { 186 | const _0x3854f7 = { 187 | '128k': _0x162c2c['dDScf'], 188 | '320k': _0x1a9c83(0xa5, 'Ra%p'), 189 | 'flac': _0x1a9c83(0xa8, '7CUv'), 190 | 'flac24bit': _0x1a9c83(0xbb, 'PSAy') 191 | }, 192 | _0x351ef1 = _0x1a9c83(0x9f, '1&KV') + _0x4d19d6[_0x1a9c83(0x104, 'YS]1')] + _0x1a9c83(0xf9, 'AXG[') + _0x3854f7[_0x51b3b3], 193 | _0x25a238 = await httpFetch(_0x351ef1, { 194 | 'method': 'GET' 195 | }), 196 | { 197 | body: _0x565f80 198 | } = _0x25a238; 199 | if (!_0x565f80 || _0x162c2c[_0x1a9c83(0xdd, ')av0')](isNaN, _0x162c2c[_0x1a9c83(0xae, '7CUv')](Number, _0x565f80[_0x1a9c83(0xc1, '8SsA')])) || _0x162c2c[_0x1a9c83(0xc5, '9Sh@')](Number, _0x565f80[_0x1a9c83(0xdc, '$0oq')]) != 0xc8) throw new Error(_0x1a9c83(0xa0, 't)R1')); 200 | return _0x565f80[_0x1a9c83(0xf6, 'T@V4')]; 201 | } else { 202 | if (_0x162c2c[_0x1a9c83(0xe3, '8ENj')](_0x42f452, 'kw')) { 203 | const _0x2467b5 = { 204 | '128k': _0x1a9c83(0x9a, 'TtRP'), 205 | '320k': _0x162c2c[_0x1a9c83(0xf2, '92RF')], 206 | 'flac': _0x162c2c['EKcoC'] 207 | }, 208 | _0x220d53 = _0x1a9c83(0xb9, '8SsA') + _0x4d19d6[_0x1a9c83(0xa4, '9Sh@')] + _0x1a9c83(0xee, 'JrFm') + _0x2467b5[_0x51b3b3], 209 | _0x3b7912 = await httpFetch(_0x220d53, { 210 | 'method': _0x162c2c[_0x1a9c83(0xcf, '1&KV')] 211 | }), 212 | { 213 | body: _0x5ab28e 214 | } = _0x3b7912; 215 | if (!_0x5ab28e || _0x162c2c[_0x1a9c83(0xea, '92RF')](isNaN, _0x162c2c[_0x1a9c83(0xad, '5xm9')](Number, _0x5ab28e[_0x1a9c83(0xe7, 'fxV0')])) || Number(_0x5ab28e[_0x1a9c83(0xb0, 's0VR')]) != 0xc8) throw new Error(_0x162c2c[_0x1a9c83(0xeb, 'nI^u')]); 216 | return _0x5ab28e[_0x1a9c83(0xbc, 'Ra%p')][_0x1a9c83(0xd2, 'CcZq')]; 217 | } else { 218 | if (_0x42f452 == 'mg') { 219 | const _0x5a1b31 = { 220 | '320k': '2', 221 | 'flac': '1' 222 | }, 223 | _0x34fbde = 'https://www.hhlqilongzhu.cn/api/dg_mgmusic_24bit.php?msg=' + msg + _0x1a9c83(0xa2, 'Qcnx') + _0x5a1b31[_0x51b3b3], 224 | _0x326054 = await httpFetch(_0x34fbde, { 225 | 'method': 'GET' 226 | }), 227 | { 228 | body: _0x3571e6 229 | } = _0x326054; 230 | if (!_0x3571e6 || isNaN(Number(_0x3571e6['code'])) || Number(_0x3571e6[_0x1a9c83(0xd7, 'PSAy')]) != 0xc8) throw new Error(_0x1a9c83(0xf7, 'EfBr')); 231 | return _0x3571e6['music_url']; 232 | } 233 | } 234 | } 235 | } 236 | } 237 | }, 238 | musicSources = {}; 239 | MUSIC_SOURCE['forEach'](_0x238e3a => { 240 | const _0x4707e2 = _0x2375d4, 241 | _0x45a375 = { 242 | 'rpXjg': _0x4707e2(0xc6, 'nQ!]'), 243 | 'RalDw': _0x4707e2(0xb3, 'AXG['), 244 | 'CwdUH': _0x4707e2(0xd5, '$4zZ'), 245 | 'eszRO': function(_0xa1e746, _0x5a53c4) { 246 | return _0xa1e746 == _0x5a53c4; 247 | } 248 | }; 249 | musicSources[_0x238e3a] = { 250 | 'name': _0x238e3a, 251 | 'type': _0x45a375[_0x4707e2(0xd1, 'PSAy')], 252 | 'actions': _0x238e3a == _0x45a375[_0x4707e2(0x9b, 't)R1')] ? [] : [_0x45a375[_0x4707e2(0xc9, '8ENj')]], 253 | 'qualitys': _0x45a375[_0x4707e2(0xc0, '#2e$')](_0x238e3a, _0x45a375[_0x4707e2(0xb2, 'Qcnx')]) ? [] : MUSIC_QUALITY[_0x238e3a] 254 | }; 255 | }), on(EVENT_NAMES[_0x2375d4(0xf8, 'fxV0')], ({ 256 | action: _0x1581a9, 257 | source: _0x3c5ae4, 258 | info: _0x17eeb1 259 | }) => { 260 | const _0x192f1e = _0x2375d4, 261 | _0x42ed7b = { 262 | 'WFJdH': _0x192f1e(0x101, '5xm9'), 263 | 'GMfru': function(_0x120e2c, _0x50126f, _0x4befe1, _0x3e262f) { 264 | return _0x120e2c(_0x50126f, _0x4befe1, _0x3e262f); 265 | } 266 | }; 267 | switch (_0x1581a9) { 268 | case _0x42ed7b[_0x192f1e(0x9e, '1L(9')]: 269 | return _0x42ed7b[_0x192f1e(0xc2, 'zDR%')](handleGetMusicUrl, _0x3c5ae4, _0x17eeb1['musicInfo'], _0x17eeb1[_0x192f1e(0xce, '1&KV')])['then'](_0x136577 => Promise[_0x192f1e(0xab, '1O6f')](_0x136577))['catch'](_0x591312 => Promise[_0x192f1e(0xb7, 'TtRP')](_0x591312)); 270 | default: 271 | return Promise['reject'](_0x192f1e(0xbe, '8SsA')); 272 | } 273 | }); 274 | 275 | function _0x3e54() { 276 | const _0x1424ce = (function() { 277 | return [_0xod2, 'QjqRsJjiPafmRihTB.GhDcuoSmxEp.vL7SASAFNd==', 'W6XiErGmowhdJmoeoCkmWQVcUSkEW6ddMSoT', 'z8kNkMO', 'C33cTq', 'hf5IWPJcHsDNW6/cTWmw', 'umkfW7mdW7i', 'AmkMx8o8WOa', 'drfUzCoyng/dSSo7', 'yHOdW5JdSq', 'WOOSymkwe8kKW7JdP8oM', 't0iwlSoXjmkSWQeQWOuDwq', 'qKvSW78Ubx8', 'cX8JW4VdNWf9W6pdQa', 'vJZdRvm', 'd8k+fe5j', 'rc0QqW', 'WQVdU8o8qq', 'BKNcUgHpW5O', 'dd9GWPhdRNWEW5VdIJv4W6VdIJSpzCkcymoJd8kZdmocW5ldSCkroSoyaa/cKmkhWR93WRlcVSo0W6zuyHTyWOBdT8k1h8oeFvFdLqxdRxu', 'WP7dU3qoWOZdV1BdPGNdPSkwWPyc', 'W7xcVmk/q8ksWPJdPCoF', 'WRJcU8k3', 'hfXUW4e', 'Bmo0FSkK', 'WO15va', 'eSo5omkJW6xdTt88W6zsyW', 'Ft8+', 'A3ymnbDuWRFcHq', 'DsmIyK0', 'E20jpW', 'q8oSvZlcOCk2w8oMWRmWzty', 'zXBdHLtcUa', 'WPRcPSoGWOacWQZcTIevsIXMW6/cIKK9lSoMWQaSqaBdUmkEWO84WQW2WPS5WPxcT2JdUCkst8kkqgKbl1KexLpcI1VdU8oGycFdLX4OvSkImmk0W551W7VcVG', 'qcC6bK8nEWpcOmoJmuZdGq', 'W7yLeKtcJdpdUItcH8kfWOy', 'xmkpdYDlWPfBmw54WOqzWPDRkmoUwSkv', 'l01voW'].concat((function() { 278 | return ['F8kTpx58zeW', 'D8orWPW', 'c8omW4WzWQu', 'WO43ESklfCkF', 'gmooWPqA', 'W67dMmk6qCkbWQ/dLmkfyCkntmkGca', 'aMhcU3VcKZfscH0', 'W6SGcaq2u0W', 'wK45nSoDmZNdL8oyl0j7W4C', 'W4JcImkvxSkN', 'jmoUWQWrfa', 'W5SpsCoyAmoRsvK', 'W4evW5tdIW', 'BfDpB2eM', 'kmkaxLiA', 'qqe1W4VdNW', 'AtRdG3JcOq', 'W4mVfIW', 'W4qpvmomACoNxG', 'AMChpXbb', 'W4VcPczD', 'lSkjdxP9l8k0WQRdTIHwc8kBk8kFimoZWPOxFSonW5JdG8kqWOJdJsXSsqBdQSoFW74ZWPPIWPZcQSkm', 'yuVcSh8', 'uHmnvG', 'imkcW5Hy', 'bSogW7rJFr9p', 'j8kEdwnHE8k7W6VdUcWFvSknpSkbkmo0WOC', 'yCkXWRRdUJ3dNaZcTWxdNgmtW6S', 'rCk4CCohWP8', 'jCkshw8', 'W6/cO8oMW6FdMq', 'wuW4tCkjC3RdLmo+', 'omo5WO9EWPCpmL0sW7KPW7xcRa', 'q8k2bMTt', 'ct5NWOJdVG', 'cb5oDSkRnmohWPyxWQm0', 'W5pcT8ksWOO', 'CSoJW7HdvG'].concat((function() { 279 | return ['6icX5zg1tLBcO+AoPEwpRSk7WQCbsJJdSI/cJ1WB', 'W4RcSHldHGe', 'WRjNsG', 'v3KKWOO', 'WOBcQ8oKWPu', 'WQlcO8o+WRqE', 'WPeuq8oByCkZufNcJIjXA8kzfZpcK8kN', 'saOYvmoS', 'cWZcJW', 'Dr3dPuRcMWZcKa', 'eSo7p8kHW6tcOuyVW5nbzMVcJa', 'zfPuB2uBA8kX', 'xK0jiq', 'wruowW', 'aWL7DSkzoIlcTmoUe1O2W6yJWPnFsmobamogWRJdTxfsW7JdLmkJu8kWySomdCklWRuRFY91w8oEW7pcRrW1WQ/cH8oKW7Deg8kAg8kPxmkCW6e', 'W53cSdhdOq4', 'WQxcSSkRWQtdUW', 'yCkZWRZdUt7dNfVcRr3dRNWY', 'WQr6qHm', 'WRddHmo7WPug', 'WPNdUxPt', 'W5emw8oinSk6wepcLq', 'B8kTn3W', 'WOeShrdcTW', 'WO0JWP8', 'EmoxW7fswq', 'wSkiW6iEW7u', 'WQzzCGW', 'W4dcOJbDW4S', 'u095W68', 'xeaCiW', 'oSoiW54JW4DqcGpcIW', 'rCk9W64yW6e', 'WPFcLSkhWQ7dOG', 'W4ZcGmoFqwjvW4LyW67cVeNdSCkh', 'iCkydsP7z8o3WQxdSIPnsSkk']; 280 | }())); 281 | }())); 282 | }()); 283 | _0x3e54 = function() { 284 | return _0x1424ce; 285 | }; 286 | return _0x3e54(); 287 | }; 288 | const scriptInfo = globalThis.lx.currentScriptInfo; 289 | 290 | if ( 291 | scriptInfo.name !== "聚合API接口 (by lerd)" || 292 | scriptInfo.description !== "理论可听全平台无损" || 293 | scriptInfo.version !== "v2.0.0" || 294 | scriptInfo.author !== "lerd" 295 | ) { 296 | throw new Error("初始化失败!将音源 名字、描述、版本号、作者和主页回正,以初始化成功"); 297 | } 298 | 299 | send(EVENT_NAMES.inited, { status: true, openDevTools: DEV_ENABLE, sources: musicSources }) -------------------------------------------------------------------------------- /小熊猫v1.1.1.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 小熊猫 3 | * @description 小熊猫音源,如果失效请在公众号【大学资源社】中反馈 4 | * @version v1.1.1 5 | * @wy_token null 6 | * @wy_token_desc 如果你有网易音乐的会员,可启用vip歌曲、更高音质的支持,将上面 @wy_token null 中的 null 改为你的token即可,token获取方式看常见问题歌单导入 7 | * @wy_token_desc 需要注意的是,自定义 token 存在导致账号被封禁的风险,token是账号的临时秘钥,注意不要随意分享 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | var __webpack_exports__ = {}; 12 | 13 | ;// CONCATENATED MODULE: ./src/lx.js 14 | const { EVENT_NAMES: lx_EVENT_NAMES, on, send: lx_send, request, utils: lxUtils, version, currentScriptInfo } = globalThis.lx 15 | // console.log(globalThis.lx) 16 | 17 | 18 | // https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md#windowlxutils 19 | const utils = { 20 | buffer: { 21 | from: lxUtils.buffer.from, 22 | bufToString: lxUtils.buffer.bufToString, 23 | }, 24 | crypto: { 25 | aesEncrypt: lxUtils.crypto.aesEncrypt, 26 | md5: lxUtils.crypto.md5, 27 | randomBytes: lxUtils.crypto.randomBytes, 28 | rsaEncrypt: lxUtils.crypto.rsaEncrypt, 29 | }, 30 | } 31 | 32 | const currentScript = currentScriptInfo 33 | ? currentScriptInfo.rawScript 34 | : document.getElementsByTagName('script')[0].innerText 35 | 36 | 37 | 38 | ;// CONCATENATED MODULE: ./src/apis/kw.js 39 | 40 | 41 | const qualitys = { 42 | '128k': '128kmp3', 43 | '320k': '320kmp3', 44 | // ape: 'ape', 45 | // flac: 'flac', 46 | } 47 | 48 | 49 | let token = '' 50 | let cookie = '' 51 | let key = '' 52 | 53 | function encrypt(str, pwd) { 54 | if (pwd == null || pwd.length <= 0) { 55 | console.log('Please enter a password with which to encrypt the message.') 56 | return null 57 | } 58 | let prand = '' 59 | for (let i = 0; i < pwd.length; i++) { 60 | prand += pwd.charCodeAt(i).toString() 61 | } 62 | let sPos = Math.floor(prand.length / 5) 63 | let mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5)) 64 | let incr = Math.ceil(pwd.length / 2) 65 | let modu = Math.pow(2, 31) - 1 66 | if (mult < 2) { 67 | console.log('Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password.') 68 | return null 69 | } 70 | let salt = Math.round(Math.random() * 1000000000) % 100000000 71 | prand += salt 72 | while (prand.length > 10) { 73 | prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString() 74 | } 75 | prand = (mult * prand + incr) % modu 76 | let enc_chr = '' 77 | let enc_str = '' 78 | for (let i = 0; i < str.length; i++) { 79 | enc_chr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255)) 80 | if (enc_chr < 16) { 81 | enc_str += '0' + enc_chr.toString(16) 82 | } else enc_str += enc_chr.toString(16) 83 | prand = (mult * prand + incr) % modu 84 | } 85 | salt = salt.toString(16) 86 | while (salt.length < 8)salt = '0' + salt 87 | enc_str += salt 88 | return enc_str 89 | } 90 | const createToken = (cookieToken, currentKey) => { 91 | if (currentKey && key != currentKey) key = currentKey 92 | return encrypt(cookieToken, key) 93 | } 94 | const parseCookieToken = (cookies) => { 95 | if (!cookies) return '' 96 | let cookieToken = Array.isArray(cookies) ? cookies.find(str => str.startsWith('Hm_Iuvt_')) : cookies.match(/Hm_Iuvt_\w+=\w+;/)?.[0] 97 | if (!cookieToken) return '' 98 | cookieToken = cookieToken.split(';')[0] 99 | cookie = cookieToken 100 | cookieToken = cookieToken.split('=')[1] 101 | return cookieToken 102 | } 103 | const getToken = () => new Promise((resolve, reject) => { 104 | let defaultKey = 'Hm_Iuvt_cdb524f42f0ce19b169a8071123a4700' 105 | request('http://www.kuwo.cn/', { 106 | headers: { 107 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 108 | Referer: 'http://www.kuwo.cn/', 109 | }, 110 | }, function(error, response) { 111 | if (error) return reject(new Error('failed')) 112 | const token = parseCookieToken(response.headers['set-cookie']) 113 | if (!token) return reject(new Error('Invalid cookie')) 114 | const result = response.body.match(/app\.\w+\.js/) 115 | if (result) { 116 | request(`https://h5static.kuwo.cn/www/kw-www/${result[0]}`, { 117 | headers: { 118 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 119 | Referer: 'http://www.kuwo.cn/', 120 | }, 121 | }, function(error, response) { 122 | if (error) return resolve(createToken(token, defaultKey)) 123 | const result = response.body.match(/Hm_Iuvt_(\w+)/) 124 | if (result) { 125 | resolve(createToken(token, result[0])) 126 | } else resolve(createToken(token, defaultKey)) 127 | }) 128 | } else { 129 | resolve(createToken(token, defaultKey)) 130 | } 131 | }) 132 | }) 133 | 134 | /* harmony default export */ const kw = ({ 135 | info: { 136 | name: '酷我音乐', 137 | type: 'music', 138 | actions: ['musicUrl'], 139 | qualitys: ['128k', '320k'], 140 | }, 141 | 142 | async musicUrl({ songmid }, quality) { 143 | quality = qualitys[quality] 144 | 145 | const target_url = `http://www.kuwo.cn/api/v1/www/music/playUrl?mid=${songmid}&type=music&br=${quality}` 146 | // const target_url = `http://www.kuwo.cn/api/v1/www/music/playUrl?mid=${songmid}&type=convert_url3&br=${quality}` 147 | /* const target_url = 'https://www.kuwo.cn/url?' 148 | + `format=mp3&rid=${song_id}&response=url&type=convert_url3&br=128kmp3&from=web`; 149 | https://m.kuwo.cn/newh5app/api/mobile/v1/music/src/${song_id} */ 150 | 151 | if (!token) token = await getToken() 152 | 153 | return new Promise((resolve, reject) => { 154 | // console.log(songmid, quality) 155 | request(target_url, { 156 | method: 'GET', 157 | headers: { 158 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 159 | Referer: 'http://kuwo.cn/', 160 | Secret: token, 161 | cookie, 162 | }, 163 | }, (err, resp) => { 164 | console.log(resp.body) 165 | if (err) return reject(err) 166 | if (resp.body.code != 200) return reject(new Error('failed')) 167 | 168 | resolve(resp.body.data.url) 169 | }) 170 | }) 171 | }, 172 | }); 173 | 174 | ;// CONCATENATED MODULE: ./src/apis/kg.js 175 | 176 | 177 | // const qualitys = { 178 | // '128k': 'PQ', 179 | // '320k': 'HQ', 180 | // flac: 'SQ', 181 | // flac32bit: 'ZQ', 182 | // } 183 | 184 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/kugou.js 185 | /* harmony default export */ const kg = ({ 186 | info: { 187 | name: '酷狗音乐', 188 | type: 'music', 189 | actions: ['musicUrl'], 190 | qualitys: ['128k'], 191 | }, 192 | 193 | musicUrl({ hash, albumId }, quality) { 194 | // quality = qualitys[quality] 195 | let target_url = `https://wwwapi.kugou.com/yy/index.php?r=play/getdata&hash=${hash}&platid=4&album_id=${albumId}&mid=00000000000000000000000000000000` 196 | return new Promise((resolve, reject) => { 197 | console.log(hash, quality) 198 | request(target_url, { 199 | method: 'GET', 200 | }, (err, resp) => { 201 | console.log(resp.body) 202 | if (err) return reject(err) 203 | const data = resp.body 204 | 205 | if (data.status !== 1) return reject(new Error(data.err_code)) 206 | if (data.data.privilege > 9) return reject(new Error('failed')) 207 | 208 | resolve(resp.body.data.play_backup_url) 209 | }) 210 | }) 211 | }, 212 | }); 213 | 214 | ;// CONCATENATED MODULE: ./src/apis/tx.js 215 | 216 | 217 | const fileConfig = { 218 | '128k': { 219 | s: 'M500', 220 | e: '.mp3', 221 | bitrate: '128kbps', 222 | }, 223 | '320k': { 224 | s: 'M800', 225 | e: '.mp3', 226 | bitrate: '320kbps', 227 | }, 228 | flac: { 229 | s: 'F000', 230 | e: '.flac', 231 | bitrate: 'FLAC', 232 | }, 233 | } 234 | 235 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/qq.js 236 | /* harmony default export */ const tx = ({ 237 | info: { 238 | name: '企鹅音乐', 239 | type: 'music', 240 | actions: ['musicUrl'], 241 | qualitys: ['128k'], 242 | }, 243 | 244 | musicUrl({ songmid, strMediaMid }, quality) { 245 | const target_url = 'https://u.y.qq.com/cgi-bin/musicu.fcg' 246 | // thanks to https://github.com/Rain120/qq-music-api/blob/2b9cb811934888a532545fbd0bf4e4ab2aea5dbe/routers/context/getMusicPlay.js 247 | const guid = '10000' 248 | const songmidList = [songmid] 249 | const uin = '0' 250 | 251 | const fileInfo = fileConfig[quality] 252 | const file = `${fileInfo.s}${strMediaMid}${fileInfo.e}` 253 | /* songmidList.length === 1 && 254 | `${fileInfo.s}${songmid}${songmid}${fileInfo.e}`*/ 255 | 256 | const reqData = { 257 | req_0: { 258 | module: 'vkey.GetVkeyServer', 259 | method: 'CgiGetVkey', 260 | param: { 261 | filename: file ? [file] : [], 262 | guid, 263 | songmid: songmidList, 264 | songtype: [0], 265 | uin, 266 | loginflag: 1, 267 | platform: '20', 268 | }, 269 | }, 270 | loginUin: uin, 271 | comm: { 272 | uin, 273 | format: 'json', 274 | ct: 24, 275 | cv: 0, 276 | }, 277 | } 278 | return new Promise((resolve, reject) => { 279 | console.log(songmid, quality) 280 | request(`${target_url}?format=json&data=${JSON.stringify(reqData)}`, { 281 | method: 'GET', 282 | headers: { 283 | channel: '0146951', 284 | uid: 1234, 285 | }, 286 | }, (err, resp) => { 287 | console.log(resp.body) 288 | if (err) return reject(err) 289 | const data = resp.body 290 | const { purl } = data.req_0.data.midurlinfo[0] 291 | 292 | // vip 293 | if (purl === '') return reject(new Error('failed')) 294 | 295 | const url = data.req_0.data.sip[0] + purl 296 | 297 | resolve(url) 298 | }) 299 | }) 300 | }, 301 | }); 302 | 303 | ;// CONCATENATED MODULE: ./src/utils.js 304 | 305 | 306 | 307 | const buf2hex = buffer => { // buffer is an ArrayBuffer 308 | return version 309 | ? utils.buffer.bufToString(buffer, 'hex') 310 | : [...new Uint8Array(buffer)] 311 | .map(x => x.toString(16).padStart(2, '0')) 312 | .join('') 313 | } 314 | 315 | const aesEncrypt = (data, eapiKey, iv, mode) => { 316 | if (!version) { 317 | mode = mode.split('-').pop() 318 | } 319 | return utils.crypto.aesEncrypt(data, mode, eapiKey, iv) 320 | } 321 | 322 | const md5 = str => utils.crypto.md5(str) 323 | 324 | 325 | const showUpdateAlert = () => { 326 | send(EVENT_NAMES.updateAlert, { 327 | log: 'hello world', 328 | updateUrl: 'https://xxx.com', 329 | }) 330 | } 331 | 332 | // https://stackoverflow.com/a/53387532 333 | const compareVersions = ((prep, l, i, r) => (a, b) => { 334 | a = prep(a) 335 | b = prep(b) 336 | l = Math.max(a.length, b.length) 337 | i = 0 338 | r = i 339 | // convert into integer, uncluding undefined values 340 | while (!r && i < l) r = ~~a[i] - ~~b[i++] 341 | 342 | return r < 0 ? -1 : (r ? 1 : 0) 343 | })(t => ('' + t) 344 | // treat non-numerical characters as lower version 345 | // replacing them with a negative number based on charcode of first character 346 | .replace(/[^\d.]+/g, c => '.' + (c.replace(/[\W_]+/, '').toUpperCase().charCodeAt(0) - 65536) + '.') 347 | // remove trailing "." and "0" if followed by non-numerical characters (1.0.0b); 348 | .replace(/(?:\.0+)*(\.-\d+(?:\.\d+)?)\.*$/g, '$1') 349 | // return array 350 | .split('.')) 351 | 352 | ;// CONCATENATED MODULE: ./src/apis/wy.js 353 | 354 | 355 | 356 | const parse = (str) => { 357 | let comment = /^\/\*(?:.|\n)+?\*\//.exec(str)?.[0] 358 | if (!comment) return '' 359 | let token = /\*\s*@wy_token\s+(.+)/.exec(comment)?.[1]?.trim() 360 | return (!token || token == 'null') ? '' : token 361 | } 362 | const wy_token = parse(currentScript) 363 | 364 | const wy_qualitys = { 365 | '128k': 128000, 366 | '320k': 320000, 367 | flac: 999000, 368 | } 369 | const eapi = (url, object) => { 370 | const eapiKey = 'e82ckenh8dichen8' 371 | 372 | const text = typeof object === 'object' ? JSON.stringify(object) : object 373 | const message = `nobody${url}use${text}md5forencrypt` 374 | const digest = md5(message) 375 | const data = `${url}-36cd479b6b5-${text}-36cd479b6b5-${digest}` 376 | return { 377 | params: buf2hex(aesEncrypt(data, eapiKey, '', 'aes-128-ecb')).toUpperCase(), 378 | } 379 | } 380 | 381 | let wy_cookie = 'os=pc' 382 | if (wy_token) wy_cookie = `MUSIC_U=${wy_token}; ` + wy_cookie 383 | 384 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/netease.js 385 | /* harmony default export */ const wy = ({ 386 | info: { 387 | name: '网易音乐', 388 | type: 'music', 389 | actions: ['musicUrl'], 390 | qualitys: wy_token ? ['128k', '320k', 'flac'] : ['128k'], 391 | }, 392 | 393 | musicUrl({ songmid }, quality) { 394 | quality = wy_qualitys[quality] 395 | const target_url = 'https://interface3.music.163.com/eapi/song/enhance/player/url' 396 | const eapiUrl = '/api/song/enhance/player/url' 397 | 398 | const d = { 399 | ids: `[${songmid}]`, 400 | br: quality, 401 | } 402 | const data = eapi(eapiUrl, d) 403 | 404 | return new Promise((resolve, reject) => { 405 | console.log(songmid, quality) 406 | request(target_url, { 407 | method: 'POST', 408 | form: data, 409 | headers: { 410 | cookie: wy_cookie, 411 | }, 412 | }, (err, resp) => { 413 | console.log(resp.body) 414 | if (err) return reject(err) 415 | if (resp.headers.cookie) wy_cookie = resp.headers.cookie 416 | 417 | let res_data = resp.body 418 | const { url, freeTrialInfo } = res_data.data[0] 419 | if (!url || freeTrialInfo) return reject(new Error('failed')) 420 | resolve(url) 421 | }) 422 | }) 423 | }, 424 | }); 425 | 426 | ;// CONCATENATED MODULE: ./src/apis/mg.js 427 | 428 | 429 | const mg_qualitys = { 430 | '128k': 'PQ', 431 | '320k': 'HQ', 432 | flac: 'SQ', 433 | flac24bit: 'ZQ', 434 | } 435 | 436 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/migu.js 437 | /* harmony default export */ const mg = ({ 438 | info: { 439 | name: '咪咕音乐', 440 | type: 'music', 441 | actions: ['musicUrl'], 442 | qualitys: ['128k'], 443 | }, 444 | 445 | musicUrl({ songmid }, quality) { 446 | quality = mg_qualitys[quality] 447 | /* 448 | const copyrightId = track.id.slice('mgtrack_'.length); 449 | const type = 1; 450 | // NOTICE:howler flac support is not ready for production. 451 | // Sometimes network keep pending forever and block later music. 452 | // So use normal quality. 453 | // switch (track.quality) { 454 | // case '110000': 455 | // type = 2; 456 | // break; 457 | // case '111100': 458 | // type = 3; 459 | // break; 460 | // case '111111': 461 | // type = 4; 462 | // break; 463 | // default: 464 | // type = 1; 465 | // } 466 | const k = 467 | '4ea5c508a6566e76240543f8feb06fd457777be39549c4016436afda65d2330e'; 468 | // type parameter for music quality: 1: normal, 2: hq, 3: sq, 4: zq, 5: z3d 469 | const plain = forge.util.createBuffer( 470 | `{"copyrightId":"${copyrightId}","type":${type},"auditionsFlag":0}` 471 | ); 472 | const salt = forge.random.getBytesSync(8); 473 | const derivedBytes = forge.pbe.opensslDeriveBytes(k, salt, 48); 474 | const buffer = forge.util.createBuffer(derivedBytes); 475 | const key = buffer.getBytes(32); 476 | const iv = buffer.getBytes(16); 477 | const cipher = forge.cipher.createCipher('AES-CBC', key); 478 | cipher.start({ iv }); 479 | cipher.update(plain); 480 | cipher.finish(); 481 | const output = forge.util.createBuffer(); 482 | output.putBytes('Salted__'); 483 | output.putBytes(salt); 484 | output.putBuffer(cipher.output); 485 | const aesResult = forge.util.encode64(output.bytes()); 486 | const publicKey = 487 | '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8asrfSaoOb4je+DSmKdriQJKW\nVJ2oDZrs3wi5W67m3LwTB9QVR+cE3XWU21Nx+YBxS0yun8wDcjgQvYt625ZCcgin\n2ro/eOkNyUOTBIbuj9CvMnhUYiR61lC1f1IGbrSYYimqBVSjpifVufxtx/I3exRe\nZosTByYp4Xwpb1+WAQIDAQAB\n-----END PUBLIC KEY-----'; 488 | const secKey = forge.util.encode64( 489 | forge.pki.publicKeyFromPem(publicKey).encrypt(k) 490 | ); 491 | const target_url = `https://music.migu.cn/v3/api/music/audioPlayer/getPlayInfo?dataType=2&data=${encodeURIComponent( 492 | aesResult 493 | )}&secKey=${encodeURIComponent(secKey)}`; 494 | */ 495 | const target_url = `https://app.c.nf.migu.cn/MIGUM2.0/strategy/listen-url/v2.2?netType=01&resourceType=E&songId=${songmid}&toneFlag=${quality}` 496 | return new Promise((resolve, reject) => { 497 | console.log(songmid, quality) 498 | request(target_url, { 499 | method: 'GET', 500 | headers: { 501 | channel: '0146951', 502 | uid: '0', 503 | }, 504 | }, (err, resp) => { 505 | console.log(resp.body) 506 | if (err) return reject(err) 507 | let playUrl = resp.body.data?.url 508 | if (!playUrl) return reject(new Error('failed')) 509 | 510 | if (playUrl.startsWith('//')) playUrl = `https:${playUrl}` 511 | 512 | resolve(playUrl.replace(/\+/g, '%2B').split('?')[0]) 513 | }) 514 | }) 515 | }, 516 | }); 517 | 518 | ;// CONCATENATED MODULE: ./src/apis/index.js 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | /* harmony default export */ const apis = ({ 527 | kw: kw, 528 | kg: kg, 529 | tx: tx, 530 | wy: wy, 531 | mg: mg, 532 | }); 533 | 534 | ;// CONCATENATED MODULE: ./package.json 535 | const package_namespaceObject = JSON.parse('{"u2":"lx-music-source","i8":"1.1.1","v":"lyswhut"}'); 536 | ;// CONCATENATED MODULE: ./src/update.js 537 | 538 | 539 | 540 | 541 | const address = [ 542 | `https://raw.githubusercontent.com/${package_namespaceObject.v}/${package_namespaceObject.u2}/master`, 543 | `https://cdn.jsdelivr.net/gh/${package_namespaceObject.v}/${package_namespaceObject.u2}`, 544 | `https://fastly.jsdelivr.net/gh/${package_namespaceObject.v}/${package_namespaceObject.u2}`, 545 | `https://gcore.jsdelivr.net/gh/${package_namespaceObject.v}/${package_namespaceObject.u2}`, 546 | ] 547 | 548 | const getLatestVersion = async(url, retryNum = 0) => { 549 | return new Promise((resolve, reject) => { 550 | request(url, { 551 | timeout: 10000, 552 | }, (err, resp) => { 553 | if (err || resp.statusCode != 200) { 554 | ++retryNum >= 3 555 | ? reject(err || new Error(resp.statusMessage || resp.statusCode)) 556 | : getLatestVersion(url, retryNum).then(resolve).catch(reject) 557 | } else resolve(resp.body) 558 | }) 559 | }).then(info => { 560 | if (info.version == null) throw new Error('failed') 561 | return info.version 562 | }) 563 | } 564 | 565 | const getVersion = async(index = 0) => { 566 | return getLatestVersion(address[index] + '/package.json').then(version => { 567 | return { 568 | version, 569 | url: address[index] + '/dist/lx-music-source.js', 570 | } 571 | }).catch(async(err) => { 572 | index++ 573 | if (index >= address.length) throw err 574 | return getVersion(index) 575 | }) 576 | } 577 | 578 | const checkLatestVersion = async() => { 579 | const remoteVersion = await getVersion() 580 | return compareVersions(package_namespaceObject.i8, remoteVersion.version) < 0 ? remoteVersion : null 581 | } 582 | 583 | ;// CONCATENATED MODULE: ./src/index.js 584 | 585 | 586 | 587 | 588 | // console.log(window.lx) 589 | 590 | on(lx_EVENT_NAMES.request, ({ source, action, info }) => { 591 | switch (action) { 592 | case 'musicUrl': 593 | return apis[source].musicUrl(info.musicInfo, info.type).catch((err) => { 594 | console.log(err.message) 595 | return Promise.reject(err) 596 | }) 597 | } 598 | }) 599 | 600 | const sources = {} 601 | for (const [source, apiInfo] of Object.entries(apis)) { 602 | sources[source] = apiInfo.info 603 | } 604 | 605 | lx_send(lx_EVENT_NAMES.inited, { 606 | status: true, 607 | // openDevTools: true, 608 | // eslint-disable-next-line no-undef 609 | openDevTools: "production" === 'development', 610 | sources, 611 | }) 612 | 613 | checkLatestVersion().then((version) => { 614 | if (!version) return 615 | lx_send(lx_EVENT_NAMES.updateAlert, { log: '发现新版本 v' + version.version, updateUrl: version.url }) 616 | }) 617 | 618 | /******/ })() 619 | ; -------------------------------------------------------------------------------- /废材公社 内部源.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @name 微信公众号:废材公社 内部源1 3 | * @description 音源更新,关注微信公众号:废材公社 4 | * @version v1.1.2 5 | * @wy_token null 6 | * @wy_token_desc 如果你有网易音乐的会员,可启用vip歌曲、更高音质的支持,将上面 @wy_token null 中的 null 改为你的token即可,token获取方式看常见问题歌单导入 7 | * @wy_token_desc 需要注意的是,自定义 token 存在导致账号被封禁的风险,token是账号的临时秘钥,注意不要随意分享 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | var __webpack_exports__ = {}; 12 | 13 | ;// CONCATENATED MODULE: ./src/lx.js 14 | const { EVENT_NAMES: lx_EVENT_NAMES, on, send: lx_send, request, utils: lxUtils, version, currentScriptInfo } = globalThis.lx 15 | // console.log(globalThis.lx) 16 | 17 | 18 | // https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md#windowlxutils 19 | const utils = { 20 | buffer: { 21 | from: lxUtils.buffer.from, 22 | bufToString: lxUtils.buffer.bufToString, 23 | }, 24 | crypto: { 25 | aesEncrypt: lxUtils.crypto.aesEncrypt, 26 | md5: lxUtils.crypto.md5, 27 | randomBytes: lxUtils.crypto.randomBytes, 28 | rsaEncrypt: lxUtils.crypto.rsaEncrypt, 29 | }, 30 | } 31 | 32 | const currentScript = currentScriptInfo 33 | ? currentScriptInfo.rawScript 34 | : document.getElementsByTagName('script')[0].innerText 35 | 36 | 37 | 38 | ;// CONCATENATED MODULE: ./src/apis/kw.js 39 | 40 | 41 | const qualitys = { 42 | '128k': '128kmp3', 43 | '320k': '320kmp3', 44 | // ape: 'ape', 45 | // flac: 'flac', 46 | } 47 | 48 | 49 | let token = '' 50 | let cookie = '' 51 | let key = '' 52 | 53 | function encrypt(str, pwd) { 54 | if (pwd == null || pwd.length <= 0) { 55 | console.log('Please enter a password with which to encrypt the message.') 56 | return null 57 | } 58 | let prand = '' 59 | for (let i = 0; i < pwd.length; i++) { 60 | prand += pwd.charCodeAt(i).toString() 61 | } 62 | let sPos = Math.floor(prand.length / 5) 63 | let mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5)) 64 | let incr = Math.ceil(pwd.length / 2) 65 | let modu = Math.pow(2, 31) - 1 66 | if (mult < 2) { 67 | console.log('Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password.') 68 | return null 69 | } 70 | let salt = Math.round(Math.random() * 1000000000) % 100000000 71 | prand += salt 72 | while (prand.length > 10) { 73 | prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString() 74 | } 75 | prand = (mult * prand + incr) % modu 76 | let enc_chr = '' 77 | let enc_str = '' 78 | for (let i = 0; i < str.length; i++) { 79 | enc_chr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255)) 80 | if (enc_chr < 16) { 81 | enc_str += '0' + enc_chr.toString(16) 82 | } else enc_str += enc_chr.toString(16) 83 | prand = (mult * prand + incr) % modu 84 | } 85 | salt = salt.toString(16) 86 | while (salt.length < 8)salt = '0' + salt 87 | enc_str += salt 88 | return enc_str 89 | } 90 | const createToken = (cookieToken, currentKey) => { 91 | if (currentKey && key != currentKey) key = currentKey 92 | return encrypt(cookieToken, key) 93 | } 94 | const parseCookieToken = (cookies) => { 95 | if (!cookies) return '' 96 | let cookieToken = Array.isArray(cookies) ? cookies.find(str => str.startsWith('Hm_Iuvt_')) : cookies.match(/Hm_Iuvt_\w+=\w+;/)?.[0] 97 | if (!cookieToken) return '' 98 | cookieToken = cookieToken.split(';')[0] 99 | cookie = cookieToken 100 | cookieToken = cookieToken.split('=')[1] 101 | return cookieToken 102 | } 103 | const getToken = () => new Promise((resolve, reject) => { 104 | let defaultKey = 'Hm_Iuvt_cdb524f42f0ce19b169a8071123a4700' 105 | request('http://www.kuwo.cn/', { 106 | headers: { 107 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 108 | Referer: 'http://www.kuwo.cn/', 109 | }, 110 | }, async function(error, response) { 111 | if (error) return reject(new Error('failed')) 112 | const token = parseCookieToken(response.headers['set-cookie']) 113 | if (!token) return reject(new Error('Invalid cookie')) 114 | const result = response.body.match(/https?:\/\/[/.\w]+\/kw-www\/\w+\.js/g) 115 | if (result) { 116 | const getAppToken = (url) => new Promise((resolve) => { 117 | request(url, { 118 | headers: { 119 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 120 | Referer: 'http://www.kuwo.cn/', 121 | }, 122 | }, function(error, response) { 123 | if (error) return resolve('') 124 | const result = response.body.match(/Hm_Iuvt_(\w+)/) 125 | if (result) { 126 | resolve(createToken(token, result[0])) 127 | } else resolve('') 128 | }) 129 | }) 130 | const appRxp = /app\.\w+\.js/ 131 | const index = result.findIndex(l => appRxp.test(l)) 132 | if (index > -1) { 133 | const token = getAppToken(result[index]) 134 | if (token) return resolve(token) 135 | result.splice(index, 1) 136 | } 137 | while (result.length) { 138 | const token = await getAppToken(result.pop()) 139 | if (token) return resolve(token) 140 | } 141 | resolve(createToken(token, defaultKey)) 142 | } else { 143 | resolve(createToken(token, defaultKey)) 144 | } 145 | }) 146 | }) 147 | 148 | 149 | /* harmony default export */ const kw = ({ 150 | info: { 151 | name: '酷我音乐', 152 | type: 'music', 153 | actions: ['musicUrl'], 154 | qualitys: ['128k', '320k'], 155 | }, 156 | 157 | async musicUrl({ songmid }, quality) { 158 | quality = qualitys[quality] 159 | 160 | const target_url = `http://www.kuwo.cn/api/v1/www/music/playUrl?mid=${songmid}&type=music&br=${quality}` 161 | // const target_url = `http://www.kuwo.cn/api/v1/www/music/playUrl?mid=${songmid}&type=convert_url3&br=${quality}` 162 | /* const target_url = 'https://www.kuwo.cn/url?' 163 | + `format=mp3&rid=${song_id}&response=url&type=convert_url3&br=128kmp3&from=web`; 164 | https://m.kuwo.cn/newh5app/api/mobile/v1/music/src/${song_id} */ 165 | 166 | if (!token) token = await getToken() 167 | 168 | return new Promise((resolve, reject) => { 169 | // console.log(songmid, quality) 170 | request(target_url, { 171 | method: 'GET', 172 | headers: { 173 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 174 | Referer: 'http://kuwo.cn/', 175 | Secret: token, 176 | cookie, 177 | }, 178 | }, (err, resp) => { 179 | console.log(resp.body) 180 | if (err) return reject(err) 181 | if (resp.body.code != 200) return reject(new Error('failed')) 182 | 183 | resolve(resp.body.data.url) 184 | }) 185 | }) 186 | }, 187 | }); 188 | 189 | ;// CONCATENATED MODULE: ./src/apis/kg.js 190 | 191 | 192 | // const qualitys = { 193 | // '128k': 'PQ', 194 | // '320k': 'HQ', 195 | // flac: 'SQ', 196 | // flac32bit: 'ZQ', 197 | // } 198 | 199 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/kugou.js 200 | /* harmony default export */ const kg = ({ 201 | info: { 202 | name: '酷狗音乐', 203 | type: 'music', 204 | actions: ['musicUrl'], 205 | qualitys: ['128k'], 206 | }, 207 | 208 | musicUrl({ hash, albumId }, quality) { 209 | // quality = qualitys[quality] 210 | let target_url = `https://wwwapi.kugou.com/yy/index.php?r=play/getdata&hash=${hash}&platid=4&album_id=${albumId}&mid=00000000000000000000000000000000` 211 | return new Promise((resolve, reject) => { 212 | console.log(hash, quality) 213 | request(target_url, { 214 | method: 'GET', 215 | }, (err, resp) => { 216 | console.log(resp.body) 217 | if (err) return reject(err) 218 | const data = resp.body 219 | 220 | if (data.status !== 1) return reject(new Error(data.err_code)) 221 | if (data.data.privilege > 9) return reject(new Error('failed')) 222 | 223 | resolve(resp.body.data.play_backup_url) 224 | }) 225 | }) 226 | }, 227 | }); 228 | 229 | ;// CONCATENATED MODULE: ./src/apis/tx.js 230 | 231 | 232 | const fileConfig = { 233 | '128k': { 234 | s: 'M500', 235 | e: '.mp3', 236 | bitrate: '128kbps', 237 | }, 238 | '320k': { 239 | s: 'M800', 240 | e: '.mp3', 241 | bitrate: '320kbps', 242 | }, 243 | flac: { 244 | s: 'F000', 245 | e: '.flac', 246 | bitrate: 'FLAC', 247 | }, 248 | } 249 | 250 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/qq.js 251 | /* harmony default export */ const tx = ({ 252 | info: { 253 | name: '企鹅音乐', 254 | type: 'music', 255 | actions: ['musicUrl'], 256 | qualitys: ['128k'], 257 | }, 258 | 259 | musicUrl({ songmid, strMediaMid }, quality) { 260 | const target_url = 'https://u.y.qq.com/cgi-bin/musicu.fcg' 261 | // thanks to https://github.com/Rain120/qq-music-api/blob/2b9cb811934888a532545fbd0bf4e4ab2aea5dbe/routers/context/getMusicPlay.js 262 | const guid = '10000' 263 | const songmidList = [songmid] 264 | const uin = '0' 265 | 266 | const fileInfo = fileConfig[quality] 267 | const file = `${fileInfo.s}${strMediaMid}${fileInfo.e}` 268 | /* songmidList.length === 1 && 269 | `${fileInfo.s}${songmid}${songmid}${fileInfo.e}`*/ 270 | 271 | const reqData = { 272 | req_0: { 273 | module: 'vkey.GetVkeyServer', 274 | method: 'CgiGetVkey', 275 | param: { 276 | filename: file ? [file] : [], 277 | guid, 278 | songmid: songmidList, 279 | songtype: [0], 280 | uin, 281 | loginflag: 1, 282 | platform: '20', 283 | }, 284 | }, 285 | loginUin: uin, 286 | comm: { 287 | uin, 288 | format: 'json', 289 | ct: 24, 290 | cv: 0, 291 | }, 292 | } 293 | return new Promise((resolve, reject) => { 294 | console.log(songmid, quality) 295 | request(`${target_url}?format=json&data=${JSON.stringify(reqData)}`, { 296 | method: 'GET', 297 | headers: { 298 | channel: '0146951', 299 | uid: 1234, 300 | }, 301 | }, (err, resp) => { 302 | console.log(resp.body) 303 | if (err) return reject(err) 304 | const data = resp.body 305 | const { purl } = data.req_0.data.midurlinfo[0] 306 | 307 | // vip 308 | if (purl === '') return reject(new Error('failed')) 309 | 310 | const url = data.req_0.data.sip[0] + purl 311 | 312 | resolve(url) 313 | }) 314 | }) 315 | }, 316 | }); 317 | 318 | ;// CONCATENATED MODULE: ./src/utils.js 319 | 320 | 321 | 322 | const buf2hex = buffer => { // buffer is an ArrayBuffer 323 | return version 324 | ? utils.buffer.bufToString(buffer, 'hex') 325 | : [...new Uint8Array(buffer)] 326 | .map(x => x.toString(16).padStart(2, '0')) 327 | .join('') 328 | } 329 | 330 | const aesEncrypt = (data, eapiKey, iv, mode) => { 331 | if (!version) { 332 | mode = mode.split('-').pop() 333 | } 334 | return utils.crypto.aesEncrypt(data, mode, eapiKey, iv) 335 | } 336 | 337 | const md5 = str => utils.crypto.md5(str) 338 | 339 | 340 | const showUpdateAlert = () => { 341 | send(EVENT_NAMES.updateAlert, { 342 | log: 'hello world', 343 | updateUrl: 'https://xxx.com', 344 | }) 345 | } 346 | 347 | // https://stackoverflow.com/a/53387532 348 | const compareVersions = ((prep, l, i, r) => (a, b) => { 349 | a = prep(a) 350 | b = prep(b) 351 | l = Math.max(a.length, b.length) 352 | i = 0 353 | r = i 354 | // convert into integer, uncluding undefined values 355 | while (!r && i < l) r = ~~a[i] - ~~b[i++] 356 | 357 | return r < 0 ? -1 : (r ? 1 : 0) 358 | })(t => ('' + t) 359 | // treat non-numerical characters as lower version 360 | // replacing them with a negative number based on charcode of first character 361 | .replace(/[^\d.]+/g, c => '.' + (c.replace(/[\W_]+/, '').toUpperCase().charCodeAt(0) - 65536) + '.') 362 | // remove trailing "." and "0" if followed by non-numerical characters (1.0.0b); 363 | .replace(/(?:\.0+)*(\.-\d+(?:\.\d+)?)\.*$/g, '$1') 364 | // return array 365 | .split('.')) 366 | 367 | ;// CONCATENATED MODULE: ./src/apis/wy.js 368 | 369 | 370 | 371 | const parse = (str) => { 372 | let comment = /^\/\*(?:.|\n)+?\*\//.exec(str)?.[0] 373 | if (!comment) return '' 374 | let token = /\*\s*@wy_token\s+(.+)/.exec(comment)?.[1]?.trim() 375 | return (!token || token == 'null') ? '' : token 376 | } 377 | const wy_token = parse(currentScript) 378 | 379 | const wy_qualitys = { 380 | '128k': 128000, 381 | '320k': 320000, 382 | flac: 999000, 383 | } 384 | const eapi = (url, object) => { 385 | const eapiKey = 'e82ckenh8dichen8' 386 | 387 | const text = typeof object === 'object' ? JSON.stringify(object) : object 388 | const message = `nobody${url}use${text}md5forencrypt` 389 | const digest = md5(message) 390 | const data = `${url}-36cd479b6b5-${text}-36cd479b6b5-${digest}` 391 | return { 392 | params: buf2hex(aesEncrypt(data, eapiKey, '', 'aes-128-ecb')).toUpperCase(), 393 | } 394 | } 395 | 396 | let wy_cookie = 'os=pc' 397 | if (wy_token) wy_cookie = `MUSIC_U=${wy_token}; ` + wy_cookie 398 | 399 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/netease.js 400 | /* harmony default export */ const wy = ({ 401 | info: { 402 | name: '网易音乐', 403 | type: 'music', 404 | actions: ['musicUrl'], 405 | qualitys: wy_token ? ['128k', '320k', 'flac'] : ['128k'], 406 | }, 407 | 408 | musicUrl({ songmid }, quality) { 409 | quality = wy_qualitys[quality] 410 | const target_url = 'https://interface3.music.163.com/eapi/song/enhance/player/url' 411 | const eapiUrl = '/api/song/enhance/player/url' 412 | 413 | const d = { 414 | ids: `[${songmid}]`, 415 | br: quality, 416 | } 417 | const data = eapi(eapiUrl, d) 418 | 419 | return new Promise((resolve, reject) => { 420 | console.log(songmid, quality) 421 | request(target_url, { 422 | method: 'POST', 423 | form: data, 424 | headers: { 425 | cookie: wy_cookie, 426 | }, 427 | }, (err, resp) => { 428 | console.log(resp.body) 429 | if (err) return reject(err) 430 | if (resp.headers.cookie) wy_cookie = resp.headers.cookie 431 | 432 | let res_data = resp.body 433 | const { url, freeTrialInfo } = res_data.data[0] 434 | if (!url || freeTrialInfo) return reject(new Error('failed')) 435 | resolve(url) 436 | }) 437 | }) 438 | }, 439 | }); 440 | 441 | ;// CONCATENATED MODULE: ./src/apis/mg.js 442 | 443 | 444 | const mg_qualitys = { 445 | '128k': 'PQ', 446 | '320k': 'HQ', 447 | flac: 'SQ', 448 | flac24bit: 'ZQ', 449 | } 450 | 451 | // https://github.com/listen1/listen1_chrome_extension/blob/master/js/provider/migu.js 452 | /* harmony default export */ const mg = ({ 453 | info: { 454 | name: '咪咕音乐', 455 | type: 'music', 456 | actions: ['musicUrl'], 457 | qualitys: ['128k'], 458 | }, 459 | 460 | musicUrl({ songmid }, quality) { 461 | quality = mg_qualitys[quality] 462 | /* 463 | const copyrightId = track.id.slice('mgtrack_'.length); 464 | const type = 1; 465 | // NOTICE:howler flac support is not ready for production. 466 | // Sometimes network keep pending forever and block later music. 467 | // So use normal quality. 468 | // switch (track.quality) { 469 | // case '110000': 470 | // type = 2; 471 | // break; 472 | // case '111100': 473 | // type = 3; 474 | // break; 475 | // case '111111': 476 | // type = 4; 477 | // break; 478 | // default: 479 | // type = 1; 480 | // } 481 | const k = 482 | '4ea5c508a6566e76240543f8feb06fd457777be39549c4016436afda65d2330e'; 483 | // type parameter for music quality: 1: normal, 2: hq, 3: sq, 4: zq, 5: z3d 484 | const plain = forge.util.createBuffer( 485 | `{"copyrightId":"${copyrightId}","type":${type},"auditionsFlag":0}` 486 | ); 487 | const salt = forge.random.getBytesSync(8); 488 | const derivedBytes = forge.pbe.opensslDeriveBytes(k, salt, 48); 489 | const buffer = forge.util.createBuffer(derivedBytes); 490 | const key = buffer.getBytes(32); 491 | const iv = buffer.getBytes(16); 492 | const cipher = forge.cipher.createCipher('AES-CBC', key); 493 | cipher.start({ iv }); 494 | cipher.update(plain); 495 | cipher.finish(); 496 | const output = forge.util.createBuffer(); 497 | output.putBytes('Salted__'); 498 | output.putBytes(salt); 499 | output.putBuffer(cipher.output); 500 | const aesResult = forge.util.encode64(output.bytes()); 501 | const publicKey = 502 | '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8asrfSaoOb4je+DSmKdriQJKW\nVJ2oDZrs3wi5W67m3LwTB9QVR+cE3XWU21Nx+YBxS0yun8wDcjgQvYt625ZCcgin\n2ro/eOkNyUOTBIbuj9CvMnhUYiR61lC1f1IGbrSYYimqBVSjpifVufxtx/I3exRe\nZosTByYp4Xwpb1+WAQIDAQAB\n-----END PUBLIC KEY-----'; 503 | const secKey = forge.util.encode64( 504 | forge.pki.publicKeyFromPem(publicKey).encrypt(k) 505 | ); 506 | const target_url = `https://music.migu.cn/v3/api/music/audioPlayer/getPlayInfo?dataType=2&data=${encodeURIComponent( 507 | aesResult 508 | )}&secKey=${encodeURIComponent(secKey)}`; 509 | */ 510 | const target_url = `https://app.c.nf.migu.cn/MIGUM2.0/strategy/listen-url/v2.2?netType=01&resourceType=E&songId=${songmid}&toneFlag=${quality}` 511 | return new Promise((resolve, reject) => { 512 | console.log(songmid, quality) 513 | request(target_url, { 514 | method: 'GET', 515 | headers: { 516 | channel: '0146951', 517 | uid: '0', 518 | }, 519 | }, (err, resp) => { 520 | console.log(resp.body) 521 | if (err) return reject(err) 522 | let playUrl = resp.body.data?.url 523 | if (!playUrl) return reject(new Error('failed')) 524 | 525 | if (playUrl.startsWith('//')) playUrl = `https:${playUrl}` 526 | 527 | resolve(playUrl.replace(/\+/g, '%2B').split('?')[0]) 528 | }) 529 | }) 530 | }, 531 | }); 532 | 533 | ;// CONCATENATED MODULE: ./src/apis/index.js 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | /* harmony default export */ const apis = ({ 542 | kw: kw, 543 | kg: kg, 544 | tx: tx, 545 | wy: wy, 546 | mg: mg, 547 | }); 548 | 549 | ;// CONCATENATED MODULE: ./package.json 550 | const package_namespaceObject = /*#__PURE__*/JSON.parse('{"UU":"lx-music-source","rE":"1.1.2","cy":"lxmusic"}'); 551 | ;// CONCATENATED MODULE: ./src/update.js 552 | 553 | 554 | 555 | 556 | const address = [ 557 | 558 | `https://api.leobba.cn/${package_namespaceObject.cy}/${package_namespaceObject.UU}`, 559 | 560 | ] 561 | 562 | const getLatestVersion = async(url, retryNum = 0) => { 563 | return new Promise((resolve, reject) => { 564 | request(url, { 565 | timeout: 10000, 566 | }, (err, resp) => { 567 | if (err || resp.statusCode != 200) { 568 | ++retryNum >= 3 569 | ? reject(err || new Error(resp.statusMessage || resp.statusCode)) 570 | : getLatestVersion(url, retryNum).then(resolve).catch(reject) 571 | } else resolve(resp.body) 572 | }) 573 | }).then(info => { 574 | if (info.version == null) throw new Error('failed') 575 | return info.version 576 | }) 577 | } 578 | 579 | const getVersion = async(index = 0) => { 580 | return getLatestVersion(address[index] + '/package.json').then(version => { 581 | return { 582 | version, 583 | url: address[index] + '/dist/xiaoxiongmao.js', 584 | } 585 | }).catch(async(err) => { 586 | index++ 587 | if (index >= address.length) throw err 588 | return getVersion(index) 589 | }) 590 | } 591 | 592 | const checkLatestVersion = async() => { 593 | const remoteVersion = await getVersion() 594 | return compareVersions(package_namespaceObject.rE, remoteVersion.version) < 0 ? remoteVersion : null 595 | } 596 | 597 | ;// CONCATENATED MODULE: ./src/index.js 598 | 599 | 600 | 601 | 602 | // console.log(window.lx) 603 | 604 | on(lx_EVENT_NAMES.request, ({ source, action, info }) => { 605 | switch (action) { 606 | case 'musicUrl': 607 | return apis[source].musicUrl(info.musicInfo, info.type).catch((err) => { 608 | console.log(err.message) 609 | return Promise.reject(err) 610 | }) 611 | } 612 | }) 613 | 614 | const sources = {} 615 | for (const [source, apiInfo] of Object.entries(apis)) { 616 | sources[source] = apiInfo.info 617 | } 618 | 619 | lx_send(lx_EVENT_NAMES.inited, { 620 | status: true, 621 | // openDevTools: true, 622 | // eslint-disable-next-line no-undef 623 | openDevTools: "production" === 'development', 624 | sources, 625 | }) 626 | 627 | checkLatestVersion().then((version) => { 628 | if (!version) return 629 | lx_send(lx_EVENT_NAMES.updateAlert, { log: '发现新版本 v' + version.version + '请在公众号【大学资源社】中回复【音源】即可获取更新' }) 630 | }) 631 | 632 | /******/ })() 633 | ; --------------------------------------------------------------------------------