feat(media_fetcher): 添加 TuneHub 作为主要音乐源并优化搜索逻辑
优先使用 TuneHub 进行音乐搜索,仅在失败时回退到 media-get 移除对 media-get 的强制依赖检查 添加更完善的错误处理逻辑
This commit is contained in:
@@ -5,8 +5,6 @@ const process = require('process');
|
|||||||
initDir();
|
initDir();
|
||||||
initAccountFileIfNotExisted();
|
initAccountFileIfNotExisted();
|
||||||
|
|
||||||
const mediaGet = require('./service/media_fetcher/media_get');
|
|
||||||
|
|
||||||
function initDir() {
|
function initDir() {
|
||||||
// make sure all dir has been created
|
// make sure all dir has been created
|
||||||
const dirList = [
|
const dirList = [
|
||||||
@@ -33,16 +31,7 @@ function initAccountFileIfNotExisted() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = async function() {
|
module.exports = async function() {
|
||||||
// check if media-get is installed
|
logger.info('Melody 服务启动成功,使用 TuneHub 作为主要音乐源');
|
||||||
const mediaGetInfo = await mediaGet.getMediaGetInfo();
|
|
||||||
if (mediaGetInfo === false) {
|
|
||||||
process.exit(-1);
|
|
||||||
}
|
|
||||||
if (!mediaGetInfo.hasInstallFFmpeg) {
|
|
||||||
logger.error('please install FFmpeg and FFprobe first');
|
|
||||||
process.exit(-1);
|
|
||||||
}
|
|
||||||
logger.info(`[media-get] Version: ${mediaGetInfo.versionInfo}`);
|
|
||||||
|
|
||||||
// TODO check media-get latest version
|
// TODO: 可以在这里添加对 TuneHub 连接性的检查
|
||||||
}
|
}
|
||||||
@@ -242,6 +242,36 @@ async function searchSongFromAllPlatform({
|
|||||||
|
|
||||||
const globalConfig = await configManager.getGlobalConfig();
|
const globalConfig = await configManager.getGlobalConfig();
|
||||||
|
|
||||||
|
// Try TuneHub first
|
||||||
|
const searchKeyword = keyword || `${songName} ${artist}`.trim();
|
||||||
|
if (searchKeyword) {
|
||||||
|
logger.info(`[searchSongFromAllPlatform] Using TuneHub to search: ${searchKeyword}`);
|
||||||
|
const tunehubResult = await require('../music_platform/tunehub').searchSongs(searchKeyword, {
|
||||||
|
aggregate: true,
|
||||||
|
});
|
||||||
|
if (tunehubResult && tunehubResult.result && tunehubResult.result.songs) {
|
||||||
|
logger.info(`[searchSongFromAllPlatform] TuneHub search success, found ${tunehubResult.result.songs.length} songs`);
|
||||||
|
return tunehubResult.result.songs.map(song => {
|
||||||
|
return {
|
||||||
|
songName: song.name || '',
|
||||||
|
artist: song.artist || '',
|
||||||
|
album: song.album || '',
|
||||||
|
duration: song.duration || 0,
|
||||||
|
url: song.url || '',
|
||||||
|
resourceForbidden: song.resourceForbidden || false,
|
||||||
|
source: song.source || '',
|
||||||
|
fromMusicPlatform: true,
|
||||||
|
score: song.score || 0,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
logger.warn(`[searchSongFromAllPlatform] TuneHub search failed or no results, will try media-get as fallback`);
|
||||||
|
} else {
|
||||||
|
logger.info(`[searchSongFromAllPlatform] No search keyword provided, using media-get`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to media-get only if TuneHub fails
|
||||||
|
logger.warn(`[searchSongFromAllPlatform] Falling back to media-get (may be unstable)`);
|
||||||
let searchParams = keyword
|
let searchParams = keyword
|
||||||
? ['-k', `"${keyword}"`]
|
? ['-k', `"${keyword}"`]
|
||||||
: ['--searchSongName', `"${songName}"`, '--searchArtist', `"${artist}"`, '--searchAlbum', `"${album}"`];
|
: ['--searchSongName', `"${songName}"`, '--searchArtist', `"${artist}"`, '--searchAlbum', `"${album}"`];
|
||||||
@@ -255,37 +285,42 @@ async function searchSongFromAllPlatform({
|
|||||||
|
|
||||||
logger.info(`cmdStr: ${getBinPath()} ${searchParams.join(' ')}`);
|
logger.info(`cmdStr: ${getBinPath()} ${searchParams.join(' ')}`);
|
||||||
|
|
||||||
const {code, message} = await cmd(getBinPath(), searchParams);
|
|
||||||
logger.info('-------')
|
|
||||||
logger.info(code);
|
|
||||||
// logger.info(message);
|
|
||||||
logger.info('-------')
|
|
||||||
if (code != 0) {
|
|
||||||
logger.error(`searchSong failed with ${arguments}, err: ${message}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let jsonResponse;
|
|
||||||
try {
|
try {
|
||||||
jsonResponse = JSON.parse(message);
|
const {code, message} = await cmd(getBinPath(), searchParams);
|
||||||
} catch (e) {
|
logger.info('-------')
|
||||||
logger.error(e, message)
|
logger.info(code);
|
||||||
|
// logger.info(message);
|
||||||
|
logger.info('-------')
|
||||||
|
if (code != 0) {
|
||||||
|
logger.error(`searchSong failed with ${arguments}, err: ${message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let jsonResponse;
|
||||||
|
try {
|
||||||
|
jsonResponse = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`[searchSongFromAllPlatform] Failed to parse media-get response: ${e}`, message)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonResponse.map(searchItem => {
|
||||||
|
return {
|
||||||
|
songName: searchItem.Name,
|
||||||
|
artist: searchItem.Artist,
|
||||||
|
album: searchItem.Album,
|
||||||
|
duration: searchItem.Duration,
|
||||||
|
url: searchItem.Url,
|
||||||
|
resourceForbidden: searchItem.ResourceForbidden,
|
||||||
|
source: searchItem.Source,
|
||||||
|
fromMusicPlatform: searchItem.FromMusicPlatform,
|
||||||
|
score: searchItem.Score,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[searchSongFromAllPlatform] media-get crashed or timed out`, error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsonResponse.map(searchItem => {
|
|
||||||
return {
|
|
||||||
songName: searchItem.Name,
|
|
||||||
artist: searchItem.Artist,
|
|
||||||
album: searchItem.Album,
|
|
||||||
duration: searchItem.Duration,
|
|
||||||
url: searchItem.Url,
|
|
||||||
resourceForbidden: searchItem.ResourceForbidden,
|
|
||||||
source: searchItem.Source,
|
|
||||||
fromMusicPlatform: searchItem.FromMusicPlatform,
|
|
||||||
score: searchItem.Score,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
Reference in New Issue
Block a user