refactor(音乐服务): 重构网易云音乐匹配和歌曲同步逻辑
- 将网易云音乐API调用迁移至tunehub服务 - 新增歌曲信息解析和URL处理工具函数 - 改进歌曲匹配逻辑,支持更多来源的URL解析 - 优化下载流程,增加tunehub下载支持
This commit is contained in:
@@ -1,14 +1,27 @@
|
||||
const { searchSong, getSongInfo } = require('../music_platform/wycloud');
|
||||
const { getSongInfo, searchSongs } = require('../music_platform/tunehub');
|
||||
const logger = require('consola');
|
||||
|
||||
function splitArtists(artist) {
|
||||
if (!artist) {
|
||||
return [];
|
||||
}
|
||||
return artist
|
||||
.split(/[、/]/)
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
module.exports = async function findTheBestMatchFromWyCloud(uid, {songName, artist, album, musicPlatformSongId} = {}) {
|
||||
if (musicPlatformSongId) {
|
||||
const songInfo = await getSongInfo(uid, musicPlatformSongId);
|
||||
|
||||
const songInfo = await getSongInfo('netease', musicPlatformSongId);
|
||||
if (songInfo) {
|
||||
return songInfo;
|
||||
return {
|
||||
songId: musicPlatformSongId,
|
||||
songName: songInfo.name || songName,
|
||||
artists: splitArtists(songInfo.artist),
|
||||
album: songInfo.album || album,
|
||||
};
|
||||
}
|
||||
|
||||
if (songName && artist) {
|
||||
return {
|
||||
songId: musicPlatformSongId,
|
||||
@@ -24,12 +37,24 @@ module.exports = async function findTheBestMatchFromWyCloud(uid, {songName, arti
|
||||
if (songName === "" || artist === "") {
|
||||
return null;
|
||||
}
|
||||
const searchLists = await searchSong(uid, songName, artist);
|
||||
logger.info('searchLists', searchLists);
|
||||
if (searchLists === false) {
|
||||
const searchData = await searchSongs(`${songName} ${artist}`, {
|
||||
source: 'netease',
|
||||
limit: 20,
|
||||
aggregate: false,
|
||||
});
|
||||
if (searchData === false || !searchData.results) {
|
||||
logger.warn(`search song failed, no matter, go on`);
|
||||
return null;
|
||||
}
|
||||
const searchLists = searchData.results.map(item => {
|
||||
return {
|
||||
songId: item.id,
|
||||
songName: item.name,
|
||||
artists: splitArtists(item.artist),
|
||||
album: item.album,
|
||||
};
|
||||
});
|
||||
logger.info('searchLists', searchLists);
|
||||
|
||||
let matchSongAndArtist = null;
|
||||
for (const searchItem of searchLists) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { fetchWithUrl, getMetaWithUrl } = require('../media_fetcher');
|
||||
const { fetchWithUrl, getMetaWithUrl, downloadViaSourceUrl } = require('../media_fetcher');
|
||||
const logger = require('consola');
|
||||
const sleep = require('../../utils/sleep');
|
||||
const findTheBestMatchFromWyCloud = require('../search_songs/find_the_best_match_from_wycloud');
|
||||
@@ -11,6 +11,57 @@ const libPath = require('path');
|
||||
const utilFs = require('../../utils/fs');
|
||||
const { downloadFromLocalTmpPath } = require('./download_to_local');
|
||||
const uploadWithRetryThenMatch = require('./upload_to_wycloud_disk_with_retry_then_match');
|
||||
const { getSongInfo, buildSongUrl } = require('../music_platform/tunehub');
|
||||
|
||||
function parseTunehubParams(url) {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
if (!parsed.hostname.includes('music-dl.sayqz.com')) {
|
||||
return null;
|
||||
}
|
||||
const source = parsed.searchParams.get('source');
|
||||
const id = parsed.searchParams.get('id');
|
||||
if (!source || !id) {
|
||||
return null;
|
||||
}
|
||||
return { source, id };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parsePageUrlParams(url) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
if (url.indexOf('music.163.com') >= 0) {
|
||||
const match = url.match(/id=(\d+)/);
|
||||
if (match && match[1]) {
|
||||
return { source: 'netease', id: match[1] };
|
||||
}
|
||||
}
|
||||
if (url.indexOf('y.qq.com') >= 0) {
|
||||
const match = url.match(/songDetail\/([A-Za-z0-9]+)/);
|
||||
if (match && match[1]) {
|
||||
return { source: 'qq', id: match[1] };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildSongInfoFromTunehub(source, info) {
|
||||
return {
|
||||
songName: info.name || '',
|
||||
artist: info.artist || '',
|
||||
album: info.album || '',
|
||||
coverUrl: info.pic || '',
|
||||
duration: 0,
|
||||
fromMusicPlatform: true,
|
||||
resourceForbidden: false,
|
||||
source,
|
||||
audios: info.url ? [{ url: info.url }] : [],
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = async function syncSingleSongWithUrl(uid, url, {
|
||||
songName = "",
|
||||
@@ -19,12 +70,26 @@ module.exports = async function syncSingleSongWithUrl(uid, url, {
|
||||
songFromWyCloud = null
|
||||
} = {}, jobId = 0, jobType = JobType.SyncSongFromUrl, playlistName = "", collectRet) {
|
||||
// step 1. fetch song info
|
||||
const songInfo = await getMetaWithUrl(url);
|
||||
let songInfo = null;
|
||||
let downloadUrl = url;
|
||||
let usedTunehub = false;
|
||||
const tunehubParams = parseTunehubParams(url) || parsePageUrlParams(url);
|
||||
if (tunehubParams) {
|
||||
const tunehubInfo = await getSongInfo(tunehubParams.source, tunehubParams.id);
|
||||
if (tunehubInfo) {
|
||||
usedTunehub = true;
|
||||
songInfo = buildSongInfoFromTunehub(tunehubParams.source, tunehubInfo);
|
||||
downloadUrl = tunehubInfo.url || buildSongUrl(tunehubParams.source, tunehubParams.id);
|
||||
}
|
||||
}
|
||||
if (!songInfo) {
|
||||
songInfo = await getMetaWithUrl(url);
|
||||
logger.info(songInfo);
|
||||
if (songInfo === false || songInfo.isTrial) {
|
||||
logger.error(`fetch song info failed or it's a trial song. ${JSON.stringify(songInfo)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
await updateJobIfNeed(uid, jobId, songInfo, jobType);
|
||||
|
||||
@@ -36,7 +101,7 @@ module.exports = async function syncSingleSongWithUrl(uid, url, {
|
||||
findSongName = songName;
|
||||
findArtist = artist;
|
||||
findAlbum = album;
|
||||
} else if (songInfo.fromMusicPlatform) {
|
||||
} else if (songInfo && songInfo.fromMusicPlatform) {
|
||||
findSongName = songInfo.songName;
|
||||
findArtist = songInfo.artist;
|
||||
findAlbum = songInfo.album;
|
||||
@@ -54,7 +119,13 @@ module.exports = async function syncSingleSongWithUrl(uid, url, {
|
||||
|
||||
// step 3. download
|
||||
// should add meta tag if not matched song on wycloud
|
||||
const path = await fetchWithUrl(url, {songName: songInfo.songName, addMediaTag: songFromWyCloud ? false : true});
|
||||
let path = false;
|
||||
if (usedTunehub && downloadUrl) {
|
||||
path = await downloadViaSourceUrl(downloadUrl);
|
||||
}
|
||||
if (path === false) {
|
||||
path = await fetchWithUrl(url, {songName: songInfo.songName, addMediaTag: songFromWyCloud ? false : true});
|
||||
}
|
||||
if (path === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user