feat(同步任务): 增加从URL提取songId的功能并优化媒体获取重试机制

在sync_jobs.js中添加从网易云音乐URL提取songId的逻辑,避免冗余匹配
在media_fetcher/index.js中增加重试机制和超时控制,提高媒体获取的稳定性
This commit is contained in:
史悦
2026-01-08 15:33:40 +08:00
parent 916a595a63
commit b3ac229e91
2 changed files with 66 additions and 34 deletions

View File

@@ -92,6 +92,20 @@ async function createJob(req, res) {
}
}
// 如果前端没有传递 songId尝试从 URL 中提取
if (!songId) {
logger.info(`[sync_jobs] No songId provided, trying to extract from URL: ${url}`);
// 支持网易云音乐PC版和手机版
if (url.indexOf('music.163.com') >= 0 || url.indexOf('m.music.163.com') >= 0) {
const match = url.match(/id=(\d+)/);
if (match && match[1]) {
songId = match[1];
logger.info(`[sync_jobs] Extracted netease songId from URL: ${songId}`);
}
}
// TODO: 支持其他音乐平台 (QQ音乐等)
}
if (songId) {
// 直接传递songId给后续处理避免冗余的网易云匹配
// 如果后续需要可以根据songId进行精确匹配

View File

@@ -212,45 +212,63 @@ async function getMetaWithUrl(url) {
// Fallback to media-get only if TuneHub fails or URL format not supported
logger.warn(`[getMetaWithUrl] Falling back to media-get for ${url} (may be unstable)`);
let args = ['-u', `"${url}"`, '-m', '--infoFormat=json', '-l=silence'];
try {
const {code, message} = await cmd(getBinPath(), args);
logger.info('-------')
logger.info(code);
// logger.info(message);
logger.info('-------')
if (code != 0) {
logger.error(`getMetaWithUrl failed with ${url}, err: ${message}`);
return false;
}
let meta;
// 增加重试机制和超时控制
const maxRetries = 2;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
meta = JSON.parse(message);
} catch (e) {
logger.error(`[getMetaWithUrl] Failed to parse media-get response: ${e}`, message)
return false;
}
logger.info(`[getMetaWithUrl] Attempt ${attempt}/${maxRetries} for ${url}`);
const {code, message} = await cmd(getBinPath(), ['-u', `"${url}"`, '-m', '--infoFormat=json', '-l=silence', '--timeout=30']);
logger.info('-------')
logger.info(code);
// logger.info(message);
logger.info('-------')
if (code != 0) {
logger.error(`getMetaWithUrl failed with ${url}, err: ${message}`);
if (attempt === maxRetries) {
return false;
}
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
return {
songName: meta.title,
artist: meta.artist,
album: meta.album,
duration: meta.duration,
coverUrl: meta.cover_url,
publicTime: meta.public_time,
isTrial: meta.is_trial,
resourceType: meta.resource_type,
audios: meta.audios,
fromMusicPlatform: meta.from_music_platform,
resourceForbidden: meta.resource_forbidden,
source: meta.source
let meta;
try {
meta = JSON.parse(message);
} catch (e) {
logger.error(`[getMetaWithUrl] Failed to parse media-get response: ${e}`, message);
if (attempt === maxRetries) {
return false;
}
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
return {
songName: meta.title,
artist: meta.artist,
album: meta.album,
duration: meta.duration,
coverUrl: meta.cover_url,
publicTime: meta.public_time,
isTrial: meta.is_trial,
resourceType: meta.resource_type,
audios: meta.audios,
fromMusicPlatform: meta.from_music_platform,
resourceForbidden: meta.resource_forbidden,
source: meta.source
}
} catch (error) {
logger.error(`[getMetaWithUrl] media-get crashed or timed out for ${url}`, error);
if (attempt === maxRetries) {
return false;
}
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
} catch (error) {
logger.error(`[getMetaWithUrl] media-get crashed or timed out for ${url}`, error);
return false;
}
return false;
}
async function searchSongFromAllPlatform({