diff --git a/聆澜/Koneko_聆澜_GIT音源_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_GIT音源_v0.1.3_QZv2.js similarity index 88% rename from 聆澜/Koneko_聆澜_GIT音源_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_GIT音源_v0.1.3_QZv2.js index 8c3467b..d097952 100644 --- a/聆澜/Koneko_聆澜_GIT音源_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_GIT音源_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var https = require('https'); var http = require('http'); var crypto = require('crypto'); @@ -166,10 +165,16 @@ function search(str, page, limit, retryNum) { // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); if (!songId) return Promise.resolve(''); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=git&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -227,11 +232,14 @@ var pluginInfo = { info: { id: 'koneko_ceru_git', name: 'GIT音源 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'git', description: 'GIT音源,基于 GitCode audio_database.json 本地搜索 + Ceru 播放接口' }, - ext: [], + ext: [ + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } + ], env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }], quality: [ { name: '标准音质', ui: '标', id: '128k' }, @@ -241,6 +249,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -254,5 +273,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo }; diff --git a/聆澜/Koneko_聆澜_QQ音乐_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_QQ音乐_v0.1.3_QZv2.js similarity index 89% rename from 聆澜/Koneko_聆澜_QQ音乐_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_QQ音乐_v0.1.3_QZv2.js index ae03749..f20df9a 100644 --- a/聆澜/Koneko_聆澜_QQ音乐_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_QQ音乐_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var https = require('https'); var http = require('http'); var crypto = require('crypto'); @@ -149,9 +148,9 @@ function handleSearchResult(rawList) { if (!item.file || !item.file.media_mid) continue; var qualities = {}; var file = item.file; - if (file.size_128mp3) qualities['128k'] = sizeFormate(file.size_128mp3); - if (file.size_320mp3) qualities['320k'] = sizeFormate(file.size_320mp3); - if (file.size_flac) qualities['flac'] = sizeFormate(file.size_flac); + if (file.size_128mp3 !== 0) qualities['128k'] = sizeFormate(file.size_128mp3); + if (file.size_320mp3 !== 0) qualities['320k'] = sizeFormate(file.size_320mp3); + if (file.size_flac !== 0) qualities['flac'] = sizeFormate(file.size_flac); var albumId = ''; var albumName = ''; if (item.album) { albumName = item.album.name; albumId = item.album.mid; } @@ -191,9 +190,15 @@ function search(str, page, limit, retryNum) { // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=tx&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -310,11 +315,14 @@ var pluginInfo = { info: { id: 'koneko_ceru_tx', name: 'QQ音乐 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'tx', description: 'QQ音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口' }, - ext: [], + ext: [ + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } + ], env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }], quality: [ { name: '标准音质', ui: '标', id: '128k' }, @@ -324,6 +332,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -337,5 +356,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo }; diff --git a/聆澜/Koneko_聆澜_咪咕音乐_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_咪咕音乐_v0.1.3_QZv2.js similarity index 87% rename from 聆澜/Koneko_聆澜_咪咕音乐_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_咪咕音乐_v0.1.3_QZv2.js index d45392d..c4125ab 100644 --- a/聆澜/Koneko_聆澜_咪咕音乐_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_咪咕音乐_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var https = require('https'); var http = require('http'); var crypto = require('crypto'); @@ -133,9 +132,15 @@ function search(str, page, limit, retryNum) { // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=mg&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -195,11 +200,14 @@ var pluginInfo = { info: { id: 'koneko_ceru_mg', name: '咪咕音乐 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'mg', description: '咪咕音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口' }, - ext: [], + ext: [ + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } + ], env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }], quality: [ { name: '标准音质', ui: '标', id: '128k' }, @@ -209,6 +217,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -222,5 +241,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo }; diff --git a/聆澜/Koneko_聆澜_网易云音乐_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_网易云音乐_v0.1.3_QZv2.js similarity index 95% rename from 聆澜/Koneko_聆澜_网易云音乐_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_网易云音乐_v0.1.3_QZv2.js index 737a53c..5b5eb23 100644 --- a/聆澜/Koneko_聆澜_网易云音乐_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_网易云音乐_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var WY_COOKIE = env.cookie || ''; var https = require('https'); var http = require('http'); @@ -213,9 +212,15 @@ function search(str, page, limit, retryNum) { // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=wy&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -624,13 +629,15 @@ var pluginInfo = { info: { id: 'koneko_ceru_wy', name: '网易云音乐 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'wy', description: '网易云音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口' }, ext: [ { type: 'homePage', url: 'https://music.163.com/', name: '网易云音乐主页', description: '网易云音乐主页', entry: '' }, - { type: 'share', url: 'https://music.163.com/song/media/outer/url?id={id}.mp3', name: '外链分享', description: '外链分享', entry: '' } + { type: 'share', url: 'https://music.163.com/song/media/outer/url?id={id}.mp3', name: '外链分享', description: '外链分享', entry: '' }, + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } ], env: [ { key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }, @@ -644,6 +651,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -657,5 +675,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo }; diff --git a/聆澜/Koneko_聆澜_酷我音乐_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_酷我音乐_v0.1.3_QZv2.js similarity index 64% rename from 聆澜/Koneko_聆澜_酷我音乐_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_酷我音乐_v0.1.3_QZv2.js index 583918d..5390efb 100644 --- a/聆澜/Koneko_聆澜_酷我音乐_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_酷我音乐_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var https = require('https'); var http = require('http'); var crypto = require('crypto'); @@ -74,10 +73,23 @@ function sizeFormate(bytes) { } // ===== 搜索实现 ===== +function stripEm(s) { + if (!s) return ''; + return String(s).replace(/<\/?em>/g, '').replace(/ /g, ' ').replace(/&/g, '&').replace(/\\\\u0026/g, '&').trim(); +} + function musicSearch(str, page, limit) { - var url = 'https://kuwo-api.vercel.app/api/search?key=' + encodeURIComponent(str) + '&page=' + page + '&limit=' + limit; - return requestUrl(url, 'GET', { 'User-Agent': 'Mozilla/5.0 (Linux; Android 10)' }).then(function(res) { - if (res.body && res.body.data && res.body.data.list) return res.body.data.list; + var pn = (page - 1) * limit; + var url = 'http://search.kuwo.cn/r.s?all=' + encodeURIComponent(str) + '&ft=music&itemset=1&rformat=json&encoding=utf8&pn=' + pn + '&rn=' + limit; + return requestUrl(url, 'GET', { + 'User-Agent': 'Mozilla/5.0 (Linux; Android 10)', + 'Referer': 'http://www.kuwo.cn/' + }).then(function(res) { + var body = res.body; + if (typeof body === 'string') { + try { body = JSON.parse(body.replace(/'/g, '"')); } catch (e) { body = null; } + } + if (body && body.abslist) return body; throw new Error('kw search failed'); }); } @@ -87,25 +99,33 @@ function handleSearchResult(rawList) { if (!rawList) return list; for (var i = 0; i < rawList.length; i++) { var item = rawList[i]; + var rid = ''; + if (item.MUSICRID) rid = String(item.MUSICRID).replace('MUSIC_', ''); + else if (item.DC_TARGETID) rid = String(item.DC_TARGETID); + else rid = String(item.rid || item.id || ''); var qualities = {}; - var size128 = item.filesize || item.mp3size || item.mp3Size || 0; - var size320 = item.sqfilesize || item.hqsize || item['320size'] || item['320filesize'] || 0; - var sizeFlac = item.flacfilesize || item.flacsize || item.flacSize || 0; - if (size128) qualities['128k'] = sizeFormate(size128); - if (size320) qualities['320k'] = sizeFormate(size320); - if (sizeFlac) qualities['flac'] = sizeFormate(sizeFlac); - var picUrl = item.pic || item.albumpic || ''; + var formats = String(item.FORMATS || ''); + var minfo = String(item.MINFO || ''); + if (formats.indexOf('MP3128') !== -1 || minfo.indexOf('bitrate:128') !== -1) qualities['128k'] = ''; + if (formats.indexOf('MP3H') !== -1 || minfo.indexOf('bitrate:320') !== -1) qualities['320k'] = ''; + if (formats.indexOf('ALFLAC') !== -1 || minfo.indexOf('format:flac') !== -1) qualities['flac'] = ''; + var name = stripEm(item.SONGNAME || item.NAME || ''); + var artist = stripEm(item.ARTIST || ''); + var albumName = stripEm(item.ALBUM || ''); + var picUrl = item.web_albumpic_short || item.albumpic || item.ALBUMPIC || ''; + if (picUrl && picUrl.indexOf('http') !== 0 && picUrl.length > 2) picUrl = 'http://img1.kuwo.cn/star/albumcover/' + picUrl; + var duration = parseInt(item.DURATION || '0', 10); list.push({ - id: String(item.rid || item.id || ''), - name: item.name || '', - artists: item.artist || '', + id: rid, + name: name, + artists: artist, source: 'kw', pic: picUrl, mPic: picUrl, sPic: picUrl, - albumName: item.album || '', - albumId: String(item.albumid || ''), - interval: String(formatPlayTime(item.duration) || '--/--'), + albumName: albumName, + albumId: String(item.ALBUMID || ''), + interval: String(formatPlayTime(duration) || '--/--'), qualities: qualities }); } @@ -116,17 +136,25 @@ function search(str, page, limit, retryNum) { if (retryNum === undefined) retryNum = 0; if (++retryNum > 3) return Promise.reject(new Error('try max num')); if (!limit) limit = 30; - return musicSearch(str, page, limit).then(function(rawList) { + return musicSearch(str, page, limit).then(function(data) { + var rawList = data.abslist || []; + var total = parseInt(data.TOTAL || '0', 10) || rawList.length * 10; var list = handleSearchResult(rawList); - return { list: list, allPage: page + 1, limit: limit, total: list.length * 10, source: 'kw' }; + return { list: list, allPage: Math.ceil(total / limit), limit: limit, total: total, source: 'kw' }; }); } // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=kw&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -185,11 +213,14 @@ var pluginInfo = { info: { id: 'koneko_ceru_kw', name: '酷我音乐 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'kw', description: '酷我音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口' }, - ext: [], + ext: [ + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } + ], env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }], quality: [ { name: '标准音质', ui: '标', id: '128k' }, @@ -199,6 +230,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -212,5 +254,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo }; diff --git a/聆澜/Koneko_聆澜_酷狗音乐_v0.1.2_QZv2.js b/聆澜/Koneko_聆澜_酷狗音乐_v0.1.3_QZv2.js similarity index 75% rename from 聆澜/Koneko_聆澜_酷狗音乐_v0.1.2_QZv2.js rename to 聆澜/Koneko_聆澜_酷狗音乐_v0.1.3_QZv2.js index 6596602..5cd4c56 100644 --- a/聆澜/Koneko_聆澜_酷狗音乐_v0.1.2_QZv2.js +++ b/聆澜/Koneko_聆澜_酷狗音乐_v0.1.3_QZv2.js @@ -1,6 +1,5 @@ var env = global.env || {}; -var CERU_KEY = env.ceru_key || ''; var https = require('https'); var http = require('http'); var crypto = require('crypto'); @@ -74,10 +73,15 @@ function sizeFormate(bytes) { } // ===== 搜索实现 ===== +function stripEm(s) { + if (!s) return ''; + return String(s).replace(/<\/?em>/g, '').replace(/ /g, ' ').replace(/&/g, '&').trim(); +} + function musicSearch(str, page, limit) { - var url = 'http://mobilecdn.kugou.com/api/v3/search/song?showtype=14&highlight=em&pagesize=' + limit + '&page=' + page + '&keyword=' + encodeURIComponent(str); + var url = 'https://songsearch.kugou.com/song_search_v2?keyword=' + encodeURIComponent(str) + '&page=' + page + '&pagesize=' + limit + '&showtype=10&utf8=1'; return requestUrl(url, 'GET', { 'User-Agent': 'Mozilla/5.0 (Linux; Android 10)' }).then(function(res) { - if (res.body && res.body.data && res.body.data.info) return res.body.data; + if (res.body && res.body.data && res.body.data.lists) return res.body.data; throw new Error('kg search failed'); }); } @@ -88,21 +92,24 @@ function handleSearchResult(rawList) { for (var i = 0; i < rawList.length; i++) { var item = rawList[i]; var qualities = {}; - if (item.filesize) qualities['128k'] = sizeFormate(item.filesize); - if (item.sqfilesize) qualities['320k'] = sizeFormate(item.sqfilesize); - if (item.flacfilesize) qualities['flac'] = sizeFormate(item.flacfilesize); - var picUrl = item.img || ''; + if (item.FileSize) qualities['128k'] = sizeFormate(item.FileSize); + if (item.HQFileSize) qualities['320k'] = sizeFormate(item.HQFileSize); + if (item.SQFileSize) qualities['flac'] = sizeFormate(item.SQFileSize); + var picUrl = item.AblumPic || ''; + if (picUrl && picUrl.indexOf('http') !== 0) picUrl = 'https://' + picUrl.replace(/^\/+/, ''); + var name = stripEm(item.FileName || item.SongName || ''); + var singerName = stripEm(item.SingerName || ''); list.push({ - id: String(item.hash || item.audio_id || ''), - name: item.songname || '', - artists: item.singername || '', + id: String(item.FileHash || item.HQFileHash || item.SQFileHash || ''), + name: name, + artists: singerName, source: 'kg', pic: picUrl, mPic: picUrl, sPic: picUrl, - albumName: item.album_name || '', - albumId: String(item.album_id || ''), - interval: String(formatPlayTime(item.duration) || '--/--'), + albumName: stripEm(item.AlbumName || ''), + albumId: String(item.AlbumID || ''), + interval: String(formatPlayTime(item.Duration) || '--/--'), qualities: qualities }); } @@ -114,7 +121,7 @@ function search(str, page, limit, retryNum) { if (++retryNum > 3) return Promise.reject(new Error('try max num')); if (!limit) limit = 30; return musicSearch(str, page, limit).then(function(data) { - var rawList = data.info || []; + var rawList = data.lists || []; var total = data.total || rawList.length * 10; var list = handleSearchResult(rawList); return { list: list, allPage: Math.ceil(total / limit), limit: limit, total: total, source: 'kg' }; @@ -123,9 +130,15 @@ function search(str, page, limit, retryNum) { // ===== 播放链接 ===== function getUrl(songId, quality) { + // Map QZ v2 quality names to Ceru API format + if (quality === 'standard') quality = '128k'; + else if (quality === 'exhigh') quality = '320k'; + else if (quality === 'lossless' || quality === 'hires' || quality === 'jymaster') quality = 'flac'; songId = String(songId || ''); quality = String(quality || '128k'); - var ceruKey = CERU_KEY || ''; + // Read env FRESH each call (dynamic refresh) + var envNow = global.env || {}; + var ceruKey = envNow.ceru_key || ''; var headers = { 'User-Agent': 'QZMusic/2.0' }; if (ceruKey) headers['X-API-Key'] = ceruKey; return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=kg&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(quality), 'GET', headers) @@ -195,11 +208,14 @@ var pluginInfo = { info: { id: 'koneko_ceru_kg', name: '酷狗音乐 - Koneko 聆澜', - version: '0.1.2', + version: '0.1.3', source: 'kg', description: '酷狗音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口' }, - ext: [], + ext: [ + { type: 'button', name: '激活付费', description: '点击激活付费模式(需先在环境变量填入 ceru_key)', entry: 'activatePremium' }, + { type: 'button', name: '公益模式', description: '切换到公益模式(不使用 API Key)', entry: 'activatePublic' } + ], env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }], quality: [ { name: '标准音质', ui: '标', id: '128k' }, @@ -209,6 +225,17 @@ var pluginInfo = { supportFunc: ['search_song', 'search_playlist', 'playlist', 'album', 'lyric'] } +// ===== 激活/切换模式 ===== +function activatePremium() { + var envNow = global.env || {}; + if (!envNow.ceru_key) return Promise.reject(new Error('请先在环境变量中填写 ceru_key')); + return Promise.resolve({ success: true, message: '付费模式已激活,下次播放将使用高音质' }); +} + +function activatePublic() { + return Promise.resolve({ success: true, message: '已切换到公益模式' }); +} + module.exports = { musicSearch: { search: search }, tipSearch: { search: tipSearch }, @@ -222,5 +249,7 @@ module.exports = { getUrl: getUrl, musicDetail: musicDetail, musicInfo: musicInfo, + activatePremium: activatePremium, + activatePublic: activatePublic, pluginInfo: pluginInfo };