mirror of
https://github.com/metowolf/Meting.git
synced 2026-09-03 07:27:07 +08:00
chore: bump version to v1.6.0 and remove Xiami Music support
BREAKING CHANGE: Xiami Music platform support has been removed as the service has been discontinued. Changes: - Remove Xiami Music provider implementation (src/providers/xiami.js) - Update supported platforms list from 6 to 5 (NetEase, Tencent, KuGou, Baidu, Kuwo) - Update all documentation (README.md, CLAUDE.md, ARCHITECTURE.md) - Update package.json version to 1.6.0 and remove Xiami references - Add CHANGELOG.md with detailed migration guide Migration: Users should switch to alternative platforms. The library will automatically fallback to 'netease' if 'xiami' is specified. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,6 @@ src/
|
||||
├── base.js # 基础 Provider 接口
|
||||
├── netease.js # 网易云音乐 Provider
|
||||
├── tencent.js # 腾讯音乐 Provider
|
||||
├── xiami.js # 虾米音乐 Provider
|
||||
├── kugou.js # 酷狗音乐 Provider
|
||||
├── baidu.js # 百度音乐 Provider
|
||||
└── kuwo.js # 酷我音乐 Provider
|
||||
|
||||
73
CHANGELOG.md
Normal file
73
CHANGELOG.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.6.0] - 2025-10-25
|
||||
|
||||
### Removed
|
||||
- **BREAKING CHANGE**: Removed Xiami Music platform support
|
||||
- Deleted `src/providers/xiami.js` provider implementation
|
||||
- Removed Xiami from all documentation and examples
|
||||
- Updated supported platforms list: NetEase, Tencent, KuGou, Baidu, Kuwo (5 platforms)
|
||||
- Reason: Xiami Music service has been discontinued
|
||||
|
||||
### Changed
|
||||
- Updated `package.json` description to reflect current supported platforms
|
||||
- Updated `README.md` to remove Xiami references from features list, platform codes, and support table
|
||||
- Updated `CLAUDE.md` project overview
|
||||
- Updated `ARCHITECTURE.md` structure documentation
|
||||
- Updated `test/example.js` comments
|
||||
- Cleaned up keywords in `package.json`
|
||||
|
||||
### Migration Guide
|
||||
If you were using Xiami platform (`'xiami'`), please switch to one of the supported platforms:
|
||||
- NetEase Cloud Music (`'netease'`)
|
||||
- Tencent Music (`'tencent'`)
|
||||
- KuGou Music (`'kugou'`)
|
||||
- Baidu Music (`'baidu'`)
|
||||
- Kuwo Music (`'kuwo'`)
|
||||
|
||||
```javascript
|
||||
// Before
|
||||
const meting = new Meting('xiami');
|
||||
|
||||
// After - choose an alternative platform
|
||||
const meting = new Meting('netease');
|
||||
```
|
||||
|
||||
Note: The library will automatically fallback to `'netease'` if an unsupported platform is specified.
|
||||
|
||||
## [1.5.14] - 2025-01-XX
|
||||
|
||||
### Fixed
|
||||
- Added HTML entity decoding for Tencent Music lyrics
|
||||
|
||||
### Changed
|
||||
- Improved npm authentication configuration in GitHub Actions
|
||||
- Simplified npm authentication using `~/.npmrc`
|
||||
|
||||
## [1.5.13] - Earlier
|
||||
|
||||
### Added
|
||||
- Initial stable release with 6 platform support
|
||||
- Provider pattern architecture
|
||||
- Zero-dependency implementation
|
||||
- Built-in encryption support
|
||||
- Promise-based async/await APIs
|
||||
- Unified data format across platforms
|
||||
- Version number injection at build time
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.6.0** - Removed Xiami Music support (breaking change)
|
||||
- **v1.5.14** - Bug fixes and CI improvements
|
||||
- **v1.5.13** - Stable release with complete platform support
|
||||
|
||||
[1.6.0]: https://github.com/metowolf/Meting/compare/v1.5.14...v1.6.0
|
||||
[1.5.14]: https://github.com/metowolf/Meting/compare/v1.5.13...v1.5.14
|
||||
[1.5.13]: https://github.com/metowolf/Meting/releases/tag/v1.5.13
|
||||
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## 项目概述
|
||||
|
||||
Meting Node.js 版本是一个强大的音乐 API 框架,用于加速音乐相关应用的开发。这是原版 PHP Meting 项目的 Node.js 移植版本,支持多个主流音乐平台的 API 调用,包括网易云音乐(netease)、腾讯音乐(tencent)、虾米音乐(xiami)、酷狗音乐(kugou)、百度音乐(baidu)和酷我音乐(kuwo)。
|
||||
Meting Node.js 版本是一个强大的音乐 API 框架,用于加速音乐相关应用的开发。这是原版 PHP Meting 项目的 Node.js 移植版本,支持多个主流音乐平台的 API 调用,包括网易云音乐(netease)、腾讯音乐(tencent)、酷狗音乐(kugou)、百度音乐(baidu)和酷我音乐(kuwo)。
|
||||
|
||||
## 开发相关命令
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Meting is a powerful music API framework designed to accelerate music-related de
|
||||
|
||||
### Features
|
||||
|
||||
- **🎵 Multi-Platform Support** - Supports NetEase Cloud Music, Tencent Music, Xiami, KuGou, Baidu Music, and Kuwo
|
||||
- **🎵 Multi-Platform Support** - Supports NetEase Cloud Music, Tencent Music, KuGou, Baidu Music, and Kuwo
|
||||
- **🚀 Lightweight & Fast** - Zero external dependencies, built with Node.js native modules only
|
||||
- **📱 Modern Async/Await** - Promise-based APIs with full async/await support
|
||||
- **🔄 Unified Interface** - Standardized data format across all music platforms
|
||||
@@ -44,7 +44,7 @@ yarn add @meting/core
|
||||
import Meting from '@meting/core';
|
||||
|
||||
// Initialize with a music platform
|
||||
const meting = new Meting('netease'); // 'netease', 'tencent', 'xiami', 'kugou', 'baidu', 'kuwo'
|
||||
const meting = new Meting('netease'); // 'netease', 'tencent', 'kugou', 'baidu', 'kuwo'
|
||||
|
||||
// Enable data formatting for consistent output
|
||||
meting.format(true);
|
||||
@@ -115,7 +115,7 @@ musicExample();
|
||||
const meting = new Meting(server);
|
||||
```
|
||||
|
||||
- `server` (string): Music platform ('netease', 'tencent', 'xiami', 'kugou', 'baidu', 'kuwo')
|
||||
- `server` (string): Music platform ('netease', 'tencent', 'kugou', 'baidu', 'kuwo')
|
||||
|
||||
### Core Methods
|
||||
|
||||
@@ -167,7 +167,6 @@ await meting.pic(id, size) // Get album artwork
|
||||
|----------|------|--------|------|-------|--------|----------|-----|-------|---------|
|
||||
| NetEase Cloud Music | `netease` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Tencent Music | `tencent` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Xiami Music | `xiami` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| KuGou Music | `kugou` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Baidu Music | `baidu` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Kuwo Music | `kuwo` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@meting/core",
|
||||
"version": "1.5.14",
|
||||
"description": "A powerful music API framework to accelerate development - Node.js port. Support Netease, Tencent, Xiami, Kugou, Baidu, Kuwo music platforms.",
|
||||
"version": "1.6.0",
|
||||
"description": "A powerful music API framework to accelerate development - Node.js port. Support Netease, Tencent, Kugou, Baidu, Kuwo music platforms.",
|
||||
"main": "./lib/meting.js",
|
||||
"module": "./lib/meting.esm.js",
|
||||
"type": "module",
|
||||
@@ -26,7 +26,6 @@
|
||||
"api",
|
||||
"netease",
|
||||
"tencent",
|
||||
"xiami",
|
||||
"kugou",
|
||||
"baidu",
|
||||
"kuwo",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import NeteaseProvider from './netease.js';
|
||||
import TencentProvider from './tencent.js';
|
||||
import XiamiProvider from './xiami.js';
|
||||
import KugouProvider from './kugou.js';
|
||||
import BaiduProvider from './baidu.js';
|
||||
import KuwoProvider from './kuwo.js';
|
||||
@@ -12,7 +11,6 @@ export default class ProviderFactory {
|
||||
static providers = {
|
||||
netease: NeteaseProvider,
|
||||
tencent: TencentProvider,
|
||||
xiami: XiamiProvider,
|
||||
kugou: KugouProvider,
|
||||
baidu: BaiduProvider,
|
||||
kuwo: KuwoProvider
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
import crypto from 'crypto';
|
||||
import BaseProvider from './base.js';
|
||||
|
||||
/**
|
||||
* 虾米音乐平台提供者
|
||||
*/
|
||||
export default class XiamiProvider extends BaseProvider {
|
||||
constructor(meting) {
|
||||
super(meting);
|
||||
this.name = 'xiami';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取虾米音乐的请求头配置
|
||||
*/
|
||||
getHeaders() {
|
||||
return {
|
||||
'Cookie': '_m_h5_tk=15d3402511a022796d88b249f83fb968_1511163656929; _m_h5_tk_enc=b6b3e64d81dae577fc314b5c5692df3c',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) XIAMI-MUSIC/3.1.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36',
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept-Language': 'zh-CN'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索歌曲
|
||||
*/
|
||||
search(keyword, option = {}) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.search.searchservice.searchsongs/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
key: keyword,
|
||||
pagingVO: {
|
||||
page: option.page || 1,
|
||||
pageSize: option.limit || 30
|
||||
}
|
||||
},
|
||||
r: 'mtop.alimusic.search.searchservice.searchsongs'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
format: 'data.data.songs'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取歌曲详情
|
||||
*/
|
||||
song(id) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongdetail/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
songId: id
|
||||
},
|
||||
r: 'mtop.alimusic.music.songservice.getsongdetail'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
format: 'data.data.songDetail'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取专辑信息
|
||||
*/
|
||||
album(id) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.albumservice.getalbumdetail/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
albumId: id
|
||||
},
|
||||
r: 'mtop.alimusic.music.albumservice.getalbumdetail'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
format: 'data.data.albumDetail.songs'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取艺术家作品
|
||||
*/
|
||||
artist(id, limit = 50) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getartistsongs/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
artistId: id,
|
||||
pagingVO: {
|
||||
page: 1,
|
||||
pageSize: limit
|
||||
}
|
||||
},
|
||||
r: 'mtop.alimusic.music.songservice.getartistsongs'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
format: 'data.data.songs'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取播放列表
|
||||
*/
|
||||
playlist(id) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.list.collectservice.getcollectdetail/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
listId: id,
|
||||
isFullTags: false,
|
||||
pagingVO: {
|
||||
page: 1,
|
||||
pageSize: 1000
|
||||
}
|
||||
},
|
||||
r: 'mtop.alimusic.music.list.collectservice.getcollectdetail'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
format: 'data.data.collectDetail.songs'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取音频播放链接
|
||||
*/
|
||||
url(id, br = 320) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongs/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
songIds: [id]
|
||||
},
|
||||
r: 'mtop.alimusic.music.songservice.getsongs'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
decode: 'xiami_url'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取歌词
|
||||
*/
|
||||
lyric(id) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: 'https://acs.m.xiami.com/h5/mtop.alimusic.music.lyricservice.getsonglyrics/1.0/',
|
||||
body: {
|
||||
data: {
|
||||
songId: id
|
||||
},
|
||||
r: 'mtop.alimusic.music.lyricservice.getsonglyrics'
|
||||
},
|
||||
encode: 'xiami_sign',
|
||||
decode: 'xiami_lyric'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取封面图片
|
||||
*/
|
||||
async pic(id, size = 300) {
|
||||
const format = this.meting.isFormat;
|
||||
const data = await this.meting.format(false).song(id);
|
||||
this.meting.isFormat = format;
|
||||
const songData = JSON.parse(data);
|
||||
let url = songData.data.data.songDetail.albumLogo;
|
||||
url = url.replace('http:', 'https:') + `@1e_1c_100Q_${size}h_${size}w`;
|
||||
return JSON.stringify({ url: url });
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化虾米音乐数据
|
||||
*/
|
||||
format(data) {
|
||||
const result = {
|
||||
id: data.songId,
|
||||
name: data.songName,
|
||||
artist: [],
|
||||
album: data.albumName,
|
||||
pic_id: data.songId,
|
||||
url_id: data.songId,
|
||||
lyric_id: data.songId,
|
||||
source: 'xiami'
|
||||
};
|
||||
|
||||
data.singerVOs.forEach(singer => {
|
||||
result.artist.push(singer.artistName);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理虾米音乐的编码/解码逻辑
|
||||
*/
|
||||
async handleEncode(api) {
|
||||
if (api.encode === 'xiami_sign') {
|
||||
return this.signEncrypt(api);
|
||||
}
|
||||
return api;
|
||||
}
|
||||
|
||||
async handleDecode(decodeType, data) {
|
||||
if (decodeType === 'xiami_url') {
|
||||
return this.urlDecode(data);
|
||||
} else if (decodeType === 'xiami_lyric') {
|
||||
return this.lyricDecode(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虾米音乐签名加密
|
||||
*/
|
||||
async signEncrypt(api) {
|
||||
// 获取 token
|
||||
const tokenUrl = 'https://acs.m.xiami.com/h5/mtop.alimusic.recommend.songservice.getdailysongs/1.0/?appKey=12574478&t=1560663823000&dataType=json&data=%7B%22requestStr%22%3A%22%7B%5C%22header%5C%22%3A%7B%5C%22platformId%5C%22%3A%5C%22mac%5C%22%7D%2C%5C%22model%5C%22%3A%5B%5D%7D%22%7D&api=mtop.alimusic.recommend.songservice.getdailysongs&v=1.0&type=originaljson&sign=22ad1377ee193f3e2772c17c6192b17c';
|
||||
|
||||
await this.meting._curl(tokenUrl, null, true);
|
||||
const cookieMatch = this.meting.raw.match(/_m_h5[^;]+/g);
|
||||
if (cookieMatch && cookieMatch.length >= 2) {
|
||||
this.meting.header['Cookie'] = cookieMatch[0] + '; ' + cookieMatch[1];
|
||||
}
|
||||
|
||||
const data = JSON.stringify({
|
||||
requestStr: JSON.stringify({
|
||||
header: {
|
||||
platformId: 'mac'
|
||||
},
|
||||
model: api.body.data
|
||||
})
|
||||
});
|
||||
|
||||
const appkey = '12574478';
|
||||
const cookie = this.meting.header['Cookie'];
|
||||
const tokenMatch = cookie.match(/_m_h5_tk=([^_]+)/);
|
||||
const token = tokenMatch ? tokenMatch[1] : '';
|
||||
const t = Date.now();
|
||||
|
||||
const signStr = `${token}&${t}&${appkey}&${data}`;
|
||||
const sign = crypto.createHash('md5').update(signStr).digest('hex');
|
||||
|
||||
api.body = {
|
||||
appKey: appkey,
|
||||
t: t,
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
api: api.body.r,
|
||||
v: '1.0',
|
||||
type: 'originaljson',
|
||||
sign: sign
|
||||
};
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虾米音乐 URL 解码
|
||||
*/
|
||||
urlDecode(result) {
|
||||
const data = JSON.parse(result);
|
||||
|
||||
const qualityMap = {
|
||||
's': 740,
|
||||
'h': 320,
|
||||
'l': 128,
|
||||
'f': 64,
|
||||
'e': 32
|
||||
};
|
||||
|
||||
let maxBr = 0;
|
||||
let url;
|
||||
|
||||
data.data.data.songs[0].listenFiles.forEach(file => {
|
||||
const br = qualityMap[file.quality];
|
||||
if (br <= this.meting.temp.br && br > maxBr) {
|
||||
maxBr = br;
|
||||
url = {
|
||||
url: file.listenFile,
|
||||
size: file.fileSize,
|
||||
br: br
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (!url) {
|
||||
url = {
|
||||
url: '',
|
||||
size: 0,
|
||||
br: -1
|
||||
};
|
||||
}
|
||||
|
||||
return JSON.stringify(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 虾米音乐歌词解码
|
||||
*/
|
||||
lyricDecode(result) {
|
||||
const data = JSON.parse(result);
|
||||
|
||||
let lyricData;
|
||||
if (data.data.data.lyrics.length > 0) {
|
||||
let content = data.data.data.lyrics[0].content;
|
||||
content = content.replace(/<[^>]+>/g, '');
|
||||
|
||||
const matches = content.match(/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/gi);
|
||||
if (matches) {
|
||||
const lyricLines = [];
|
||||
const tlyricLines = [];
|
||||
|
||||
matches.forEach(match => {
|
||||
const parts = match.match(/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/i);
|
||||
if (parts) {
|
||||
lyricLines.push(`[${parts[1]}]${parts[2]}`);
|
||||
tlyricLines.push(`[${parts[1]}]${parts[3]}`);
|
||||
}
|
||||
});
|
||||
|
||||
lyricData = {
|
||||
lyric: content.replace(/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/gi, (match, time, lyric) => `[${time}]${lyric}`),
|
||||
tlyric: content.replace(/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/gi, (match, time, lyric, trans) => `[${time}]${trans}`)
|
||||
};
|
||||
} else {
|
||||
lyricData = {
|
||||
lyric: content,
|
||||
tlyric: ''
|
||||
};
|
||||
}
|
||||
} else {
|
||||
lyricData = {
|
||||
lyric: '',
|
||||
tlyric: ''
|
||||
};
|
||||
}
|
||||
|
||||
return JSON.stringify(lyricData);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import Meting from '../lib/meting.esm.js';
|
||||
|
||||
async function main() {
|
||||
// 创建 Meting 实例
|
||||
const meting = new Meting('netease'); // 可选: 'netease', 'tencent', 'xiami', 'kugou', 'baidu', 'kuwo'
|
||||
const meting = new Meting('netease'); // 可选: 'netease', 'tencent', 'kugou', 'baidu', 'kuwo'
|
||||
|
||||
// 开启数据格式化
|
||||
meting.format(true);
|
||||
|
||||
Reference in New Issue
Block a user