feat(音乐平台): 增加歌曲可播放性检查功能

使用 check_music API 批量检查歌曲是否可播放,优化了歌曲锁定状态的判断逻辑。当 API 检查失败时回退到基于 privileges 字段的判断,并添加了请求批处理和延迟以避免过快请求。
This commit is contained in:
史悦
2026-01-08 17:54:12 +08:00
parent f368e1790e
commit 4ae9081914

View File

@@ -2,7 +2,7 @@ const logger = require('consola');
const {
cloud, cloudsearch, cloud_match, song_detail,
user_playlist, playlist_detail, user_account, playlist_track_all,
login_qr_check, login_qr_create, login_qr_key,
login_qr_check, login_qr_create, login_qr_key, check_music,
} = require('NeteaseCloudMusicApi');
const fs = require('fs');
const path = require('path');
@@ -201,12 +201,61 @@ async function getSongsFromPlaylist(uid, source, playlistId) {
songsMap[song.id] = song;
});
const isBlockedSong = (song, songInfo) => {
// 使用 check_music API 检查歌曲是否可播放
// 注意:由于需要批量检查,这里优化为分批处理
const checkSongsPlayable = async (songIds) => {
const batchSize = 50; // 每批检查50首
const results = {};
for (let i = 0; i < songIds.length; i += batchSize) {
const batch = songIds.slice(i, i + batchSize);
const batchPromises = batch.map(async (songId) => {
try {
const response = await safeRequest(uid, check_music, { id: songId, br: 999000 }, false);
if (response && response.success === true) {
return { id: songId, playable: true };
} else {
return { id: songId, playable: false };
}
} catch (error) {
logger.warn(`check music failed for ${songId}: ${error.message}`);
// 如果检查失败,回退到基于 privileges 字段的判断
return { id: songId, playable: null }; // null 表示未知,需要回退判断
}
});
const batchResults = await Promise.all(batchPromises);
batchResults.forEach(result => {
results[result.id] = result.playable;
});
// 添加延迟,避免请求过快
if (i + batchSize < songIds.length) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
return results;
};
// 检查所有歌曲的可播放性
const songIds = songsResponse.songs.map(song => song.id);
logger.info(`[getSongsFromPlaylist] Checking playable status for ${songIds.length} songs...`);
const playableResults = await checkSongsPlayable(songIds);
logger.info(`[getSongsFromPlaylist] Checked ${Object.keys(playableResults).length} songs`);
const isBlockedSong = (song, songInfo, playable) => {
// the song has been added to cloud if the pc field is present
if (songInfo.pc) {
return false;
}
// 优先使用 check_music API 的结果
if (playable !== null) {
return !playable; // playable === true 表示不锁定
}
// 回退到基于 privileges 字段的判断
// 收费歌曲
if (song.fee === 1) {
if (song.realPayed === 1 || song.payed === 1) {
@@ -229,7 +278,8 @@ async function getSongsFromPlaylist(uid, source, playlistId) {
return;
}
const isBlocked = isBlockedSong(song, songInfo);
const playable = playableResults[song.id] ?? null;
const isBlocked = isBlockedSong(song, songInfo, playable);
const isCloud = !!songInfo.pc;
info.songs.push({
songId: songInfo.id,