12 KiB
Koneko QZ Music v2 鎻掍欢寮€鍙戦伩鍧戞寚鍗?
鐗堟湰: 0.0.3 | 浣滆€? 浜戞眬(Miao-moe) | 鐩爣: 鏀寔鍒板埆鐨?AI 缁х画寮€鍙?
涓€銆侀」鐩儗鏅?
QZ Music v2 鏄竴娆?Android 闊充箰鎾斁鍣紝鏀寔閫氳繃鎷撳睍鎻掍欢鎺ュ叆澶氬钩鍙伴煶婧愩€傛彃浠剁郴缁熷熀浜?Node.js 杩愯鏃讹紙Javet/V8锛夛紝姣忎釜鎻掍欢鏄竴涓崟鐙殑 .js 鏂囦欢锛岄€氳繃 module.exports 瀵煎嚭鎺ュ彛銆?
1.1 鎻掍欢鍔犺浇鏈哄埗
- canary 12-4 鐗堟湰涔嬪墠锛氱洿鎺ュ姞杞?
.js鏂囦欢 - **canary 12-4 鍙婁箣鍚?*锛氶渶瑕?
鏂囦欢澶?+ plugin.json + index.js缁撴瀯锛堜絾鐢ㄦ埛瑕佹眰鍙敤.js锛屾墍浠ュ綋鍓嶇増鏈槸鍗曟枃浠讹級 - 杩愯鏃剁幆澧冨彉閲忛€氳繃
global.env璁块棶锛?涓嶆槸*process.env
1.2 鎻掍欢瀵煎嚭鏍煎紡
module.exports = {
musicSearch: { search: fn, tipSearch: fn, hotSearch: fn },
tipSearch: { getList: fn },
hotSearch: { getList: fn },
getUrl: fn,
pluginInfo: { info: {...}, env: [...], ext: [...], quality: [...], supportFunc: [] },
// 缃戞槗浜戠壒鏈? userPlaylist: fn,
dailyRecommend: fn,
personalFm: fn,
myLikedSongs: fn
}
浜屻€丣avet/V8 鍏煎鎬уぇ鍧戯紙鏈€閲嶈锛?
QZ Music 浣跨敤 Javet 浣滀负 JS 杩愯鏃讹紙鍩轰簬 V8锛夛紝涓嶆敮鎸佺幇浠?ES 璇硶锛屽繀椤荤敤淇濆畧鍐欐硶锛?
| 璇硶 | 鏄惁鏀寔 | 姝g‘鍐欐硶 |
|---|---|---|
let / const |
鉂? | var |
绠ご鍑芥暟 () => {} |
鉂? | function() {} |
async / await |
鉂? | Promise 閾惧紡璋冪敤 |
catch { }锛堟棤鍙傛暟锛墊 鉂? |
catch (e) { } |
|
Promise.allSettled |
鉂? | Promise.all + 鎵嬪姩鍖呰 |
Object.entries / Object.values |
鉂? | for...in 閬嶅巻 |
Array.prototype.includes |
鉂? | indexOf(...) !== -1 |
String.prototype.startsWith |
鉂? | indexOf(...) === 0 |
BigInt 瀛楅潰閲? |
鈿狅笍 鎱庣敤 | BigInt('0x' + hex) |
class |
鉂? | 瀵硅薄瀛楅潰閲? |
妯℃澘瀛楃涓?${} |
鉁? | 鍙敤 |
Buffer |
鉁? | Node.js 鍐呯疆 |
require |
鉁? | CommonJS |
2.1 Promise.allSettled 鏇夸唬鏂规
// 鉂?涓嶆敮鎸?Promise.allSettled(promises)
// 鉁?姝g‘鍐欐硶
Promise.all(promises.map(function(p) {
return p.then(function(v) {
return { status: 'fulfilled', value: v }
}).catch(function(e) {
return { status: 'rejected', reason: e }
})
})).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].status === 'fulfilled') {
return results[i].value
}
}
throw new Error('all failed')
})
涓夈€佹悳绱㈢粨鏋滄牸寮忓ぇ鍧?
App 鐨?MusicListResponse 鍙嶅簭鍒楀寲瑕佹眰蹇呴』鏈?list 瀛楁锛屼笉鏄?songs锛?
3.1 姝g‘鐨勬悳绱㈣繑鍥炴牸寮?
return {
list: [
{
id: '姝屾洸ID瀛楃涓?,
name: '姝屾洸鍚?,
artists: '姝屾墜1銆佹瓕鎵?',
albumName: '涓撹緫鍚?,
albumId: '涓撹緫ID',
source: 'tx', // tx/kg/kw/wy/mg/git
pic: '灏侀潰澶у浘URL',
mPic: '灏侀潰涓浘URL',
sPic: '灏侀潰灏忓浘URL',
interval: '3:45', // 鎾斁鏃堕暱 m:ss
qualities: {
standard: '3.21MB',
exhigh: '7.85MB',
lossless: '25.3MB',
hires: '48.2MB'
}
}
],
allPage: 5, // 鎬婚〉鏁? limit: 30, // 姣忛〉鏉℃暟
total: 150, // 鎬绘潯鏁? source: 'tx' // 骞冲彴鏍囪瘑
}
3.2 瀛楁鍚嶅鐓ц〃
| 鍚箟 | 姝g‘瀛楁鍚? | 閿欒瀛楁鍚? |
|---|---|---|
| 姝屾墜 | artists |
artist |
| 灏侀潰鍥? | pic / mPic / sPic |
picUrl |
| 鏃堕暱 | interval (瀛楃涓?m:ss) |
duration |
| 姝屾洸鍒楄〃 | list |
songs |
鍥涖€佸悇骞冲彴 API 韪╁潙璁板綍
4.1 QQ闊充箰 (tx)
鎼滅储绛惧悕锛歚zzcSign` = SHA1 + 鑷畾涔夌储寮曟彁鍙?+ XOR 娣锋穯 + base64
var PART_1_INDEXES = [23, 14, 6, 36, 16, 40, 7, 19]
var PART_2_INDEXES = [16, 1, 32, 12, 19, 27, 8, 5]
var SCRAMBLE_VALUES = [89, 39, 179, 150, 218, 82, 58, 252, 177, 52, 186, 123, 120, 64, 242, 133, 143, 161, 121, 179]
**灏侀潰鍥捐鍒?*锛?- 鏈変笓杈慖D锛歚https://y.gtimg.cn/music/photo_new/T002R500x500M000{albumId}.jpg`
- 鏃犱笓杈慖D锛堟瓕鎵嬪浘锛夛細
https://y.gtimg.cn/music/photo_new/T001R500x500M000{singerMid}.jpg
getUrl 闊宠川鍙傛暟锛欰PI 闇€瑕佸甫 k锛屽 320k锛屼笉鏄?320
4.2 閰风嫍闊充箰 (kg)
鎼滅储鎺ュ彛锛歚http://mobilecdn.kugou.com/api/v3/search/song`
閲嶈锛氳繑鍥炲瓧娈垫槸 errcode锛堜笉鏄?error_code锛夛紒
// 鉁?姝g‘
if (result.errcode !== 0) { ... }
// 鉂?閿欒
if (result.error_code !== 0) { ... }
**灏侀潰鍥?*锛氭悳绱㈢粨鏋滆嚜甯?imgurl 瀛楁锛屾浛鎹?{size} 涓?400
var picUrl = item.imgurl ? item.imgurl.replace('{size}', '400') : ''
getUrl 闊宠川鍙傛暟锛歚128k/320k/999k`
4.3 閰锋垜闊充箰 (kw)
鎼滅储鎺ュ彛锛歚http://search.kuwo.cn/r.s`
**灏侀潰鍥?*锛歚https://img2.kuwo.cn/star/albumcover/300/{ALBUMID}.jpg`
闊宠川淇℃伅锛氬湪 N_MINFO 瀛楁涓紝鏍煎紡涓?level:xxx,bitrate:xxx,format:xxx,size:xxx;...
var parts = info.N_MINFO.split(';')
for (var j = 0; j < parts.length; j++) {
var m = parts[j].match(/level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/)
if (m) {
if (m[2] === '20900') qualities.jymaster = m[4]
else if (m[2] === '4000') qualities.hires = m[4]
else if (m[2] === '2000') qualities.lossless = m[4]
else if (m[2] === '320') qualities.exhigh = m[4]
else if (m[2] === '128') qualities.standard = m[4]
}
}
getUrl 闊宠川鍙傛暟锛歚128k/320k/999k`
4.4 缃戞槗浜戦煶涔?(wy)
鎼滅储鎺ュ彛锛歚https://music.163.com/api/search/get/web锛堢畝鍗?GET锛屼笉闇€瑕?weapi 鍔犲瘑锛? **灏侀潰鍥?*锛歚picId 闇€瑕?Base64 缂栫爜鍚庢嫾鎺?
var picIdStr = String(s.album.picId)
var picIdB64 = Buffer.from(picIdStr).toString('base64').replace(/=/g, '')
var pic = 'https://p2.music.126.net/' + picIdB64 + '/' + picIdStr + '.jpg'
getUrl 闊宠川鍙傛暟锛氭暟瀛楁牸寮?128000 / 320000 / 999000锛堜笉鏄甫k鐨勶級
鍔犲瘑鎺ュ彛锛?- eapi锛欰ES-128-ECB锛宬ey = e82ckenh8dichen8
weapi锛欰ES-128-CBC + RSA锛堢敤浜庨渶瑕佺櫥褰曠殑鎺ュ彛锛? ext 鍔熻兘锛?-userPlaylist锛氶渶瑕?playlist_url鐜鍙橀噺锛堢綉鏄撲簯涓汉涓婚〉閾炬帴锛?-dailyRecommend锛氭瘡鏃ユ帹鑽?-personalFm锛氱浜篎MmyLikedSongs锛氭垜鍠滄鐨勯煶涔?
4.5 鍜挄闊充箰 (mg)
鎼滅储绛惧悕锛歁D5 鎷兼帴
var sign = crypto.createHash('md5').update(
str + signatureMd5 + 'yyapp2d16148780a1dcc7408e06336b98cfd50' + deviceId + time
).digest('hex')
**灏侀潰鍥?*锛氭悳绱㈢粨鏋滃彲鑳借繑鍥炵浉瀵硅矾寰勶紝闇€瑕佹嫾鎺ュ煙鍚?
var img = data.img3 || data.img2 || data.img1 || ''
if (img && img.indexOf('http') !== 0) img = 'https://d.musicapp.migu.cn' + img
getUrl 闊宠川鍙傛暟锛歚128k/320k/999k`
4.6 GIT闊虫簮 (git)
- 鏃犳悳绱㈠姛鑳斤紙杩斿洖绌哄垪琛級
- 绾煶婧愭彃浠讹紝鍙湁
getUrl - getUrl 闊宠川鍙傛暟锛歚128k
/320k/999k`
浜斻€乬etUrl 娴嬮€熷鐏鹃€昏緫
鎵€鏈夊钩鍙扮粺涓€浣跨敤**骞跺彂娴嬮€?*妯″紡锛氬悓鏃惰姹傚涓?API锛屽彇绗竴涓垚鍔熺殑缁撴灉銆?
function getUrl(songId, quality) {
var apis = buildApis(songId, quality)
var promises = []
for (var i = 0; i < apis.length; i++) {
(function(api) {
promises.push(
httpGet(api.url, api.headers, 8000).then(function(res) {
var url = api.extract(res)
if (url) return { name: api.name, url: url }
throw new Error('no url')
}).catch(function(err) {
throw err
})
)
})(apis[i])
}
return Promise.all(promises.map(function(p) {
return p.then(function(v) { return { status: 'fulfilled', value: v } })
.catch(function(e) { return { status: 'rejected', reason: e } })
})).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].status === 'fulfilled') return results[i].value.url
}
return ''
})
}
5.1 闊虫簮 API 鍒楄〃
| API | 鏀寔骞冲彴 | 鐗圭偣 |
|---|---|---|
| 鑱嗘緶 | 鍏ㄩ儴 | 闇€瑕?ceru_key锛屾渶绋冲畾 |
| HUIBQ (lxmusicapi) | 鍏ㄩ儴 | X-Request-Key: share-v3 |
| 鏄熸捣 | 鍏ㄩ儴 | 鑱氬悎鎺ュ彛 |
| 蹇靛績 | tx/kg/kw/mg | 涓汉缁存姢 |
| 闀块潚 | tx/kg/kw/mg | 涓汉缁存姢 |
| 鏄熸捣澶? | 鍏ㄩ儴 | 澶囩敤 |
| fish | 鍏ㄩ儴 | 涓汉缁存姢 |
| HYW | 鍏ㄩ儴 | 闇€瑕?X-Card-Key |
| 蹇嗛煶 | tx | 鐩存帴杩斿洖 URL |
| 鏀堕泦QQ | tx | 涓撶敤 |
| 鏀堕泦KW | kw | 涓撶敤 |
| bb | wy | 缃戞槗浜戜笓鐢? |
| ymc | wy | 缃戞槗浜戜笓鐢? |
| unms | wy | 缃戞槗浜戜笓鐢? |
| 瀹樻柟 | wy | 缃戞槗浜戝畼鏂?weapi |
鍏€佺増鏈彿绠$悊瑙勮寖
**鎵€鏈夊钩鍙扮粺涓€鐗堟湰鍙?*锛屾瘡娆′慨鏀瑰叏閮ㄥ崌绾э細
- 褰撳墠鐗堟湰锛歚0.0.3`
- 涓嬫淇敼锛歚0.0.1`
- 鍐嶄笅娆★細
0.0.5
鏂囦欢鍚嶆牸寮忥細Koneko_{骞冲彴鍚峿_v{鐗堟湰鍙穧.js
涓冦€佸父瑙佹姤閿欎笌瑙e喅
| 鎶ラ敊 | 鍘熷洜 | 瑙e喅 |
|---|---|---|
Cannot find module 'axios' |
鐢ㄤ簡 axios | 鏀圭敤 http/https 鍐呯疆妯″潡 |
String cannot be converted to JSONObject |
鎼滅储杩斿洖浜嗛潪瀵硅薄/瀛楃涓? | 鍔?.catch() 鍏滃簳杩斿洖姝g‘鏍煎紡 |
Field 'list' is required |
鎼滅储杩斿洖 songs 鑰岄潪 list |
鏀瑰瓧娈靛悕涓?list |
SyntaxError: Invalid or unexpected token |
鐢ㄤ簡 catch { } |
鏀逛负 catch (e) { } |
FileNotFoundException: plugin.json |
12-4鐗堟湰闇€瑕佹枃浠跺す缁撴瀯 | 鍒涘缓 plugin.json + index.js |
| 鎼滅储鏃犵粨鏋? | 瀛楁鍚嶄笉鍖归厤 | 妫€鏌?errcode vs error_code |
| 鎾斁澶辫触 | mapBr 杩斿洖鏍煎紡涓嶅 |
QQ/kg/kw/mg/git 鐢?320k锛寃y 鐢?320000 |
| 灏侀潰鍥句笉鏄剧ず | URL 鏍煎紡閿欒鎴栬法鍩? | 妫€鏌ュ悇骞冲彴灏侀潰鍥炬嫾鎺ヨ鍒? |
鍏€佺幆澧冨彉閲?
var env = global.env || {}
var CERU_KEY = env.ceru_key || '' // 鑱嗘緶API瀵嗛挜
var WY_COOKIE = env.cookie || '' // 缃戞槗浜慍ookie
var PLAYLIST_URL = env.playlist_url || '' // 缃戞槗浜戜釜浜轰富椤甸摼鎺?```
鍦?QZ Music 璁剧疆涓厤缃幆澧冨彉閲忥紝鎻掍欢閫氳繃 `global.env` 璇诲彇銆?
---
## 涔濄€佸畬鏁翠唬鐮佸弬鑰?
6涓钩鍙扮殑瀹屾暣浠g爜瑙佷骇鐗╃洰褰曪細
- `Koneko_QQ闊充箰_v0.0.3.js`
- `Koneko_閰风嫍闊充箰_v0.0.3.js`
- `Koneko_閰锋垜闊充箰_v0.0.3.js`
- `Koneko_缃戞槗浜戦煶涔恄v0.0.3.js`
- `Koneko_鍜挄闊充箰_v0.0.3.js`
- `Koneko_GIT闊虫簮_v0.0.3.js`
---
## 鍗併€佸悗缁紑鍙戝缓璁?
1. **姣忔淇敼鍏ㄩ儴骞冲彴缁熶竴鍗囩骇鐗堟湰鍙?*
2. **鍏堝湪娴忚鍣? curl 娴嬭瘯 API 鏄惁鍙敤**
3. **娉ㄦ剰 Javet 鍏煎鎬э紝閬垮厤鐜颁唬 JS 璇硶**
4. **鎼滅储杩斿洖鍔″繀鍖呭惈 `list` 瀛楁**
5. **getUrl 娉ㄦ剰鍚勫钩鍙伴煶璐ㄥ弬鏁版牸寮忓樊寮?*
6. **灏侀潰鍥?URL 纭繚鍙闂紙娉ㄦ剰璺ㄥ煙鍜岄槻鐩楅摼锛?*
7. **鎵€鏈夊紓姝ユ搷浣滃姞 `.catch()` 鍏滃簳**
8. **浼樺厛浣跨敤瀹樻柟鎼滅储鎺ュ彛锛岄煶婧愮敤绗笁鏂?API 瀹圭伨**