81 lines
2.5 KiB
JavaScript
Executable File
81 lines
2.5 KiB
JavaScript
Executable File
const fs = require('fs');
|
||
const path = require('path');
|
||
const { API, DOWNLOAD_DIR } = require('./config');
|
||
const { fetchJSON } = require('./network');
|
||
const { formatPersonNames } = require('./utils');
|
||
|
||
async function fetchLyric(songId) {
|
||
try {
|
||
const res = await fetchJSON(`${API.lyric}?id=${songId}`);
|
||
if (res.code !== 200) return null;
|
||
return res.data;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function mergeLrc(lrc, tlyric) {
|
||
if (!lrc) return '';
|
||
if (!tlyric) return lrc;
|
||
|
||
const transMap = new Map();
|
||
for (const line of tlyric.split('\n')) {
|
||
const match = line.match(/^\[(\d+:\d+[\.:]\d+)\](.*)/);
|
||
if (match && match[2].trim()) transMap.set(match[1], match[2].trim());
|
||
}
|
||
|
||
const result = [];
|
||
for (const line of lrc.split('\n')) {
|
||
result.push(line);
|
||
const match = line.match(/^\[(\d+:\d+[\.:]\d+)\]/);
|
||
if (match && transMap.has(match[1])) result.push(`[${match[1]}]${transMap.get(match[1])}`);
|
||
}
|
||
return result.join('\n');
|
||
}
|
||
|
||
function parseCredits(lrcText) {
|
||
const credits = {};
|
||
if (!lrcText) return credits;
|
||
const labels = {
|
||
lyricist: /^(作词|作詞|词|填词|Lyricist|Lyrics? by|Written by)$/i,
|
||
composer: /^(作曲|曲|Composer|Composed by|Music by)$/i,
|
||
arranger: /^(编曲|編曲|Arranger|Arranged by)$/i,
|
||
producer: /^(制作人|製作人|出品人|监制|Producer|Produced by)$/i,
|
||
mixer: /^(混音|Mix(ing)?|Mixed by)$/i,
|
||
};
|
||
for (const raw of lrcText.split('\n')) {
|
||
const line = raw.replace(/^(\s*\[[^\]]*\]\s*)+/, '').trim();
|
||
const match = line.match(/^([^::]{1,12})\s*[::]\s*(.+)$/);
|
||
if (!match) continue;
|
||
const label = match[1].trim();
|
||
const value = formatPersonNames(match[2].trim());
|
||
if (!value) continue;
|
||
for (const [key, pattern] of Object.entries(labels)) {
|
||
if (pattern.test(label) && !credits[key]) {
|
||
credits[key] = value;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return credits;
|
||
}
|
||
|
||
async function saveLyric(songId, fileName) {
|
||
const data = await fetchLyric(songId);
|
||
if (!data?.lrc) {
|
||
console.log(' ⚠️ 未获取到歌词');
|
||
return;
|
||
}
|
||
|
||
const lrcPath = path.join(DOWNLOAD_DIR, fileName + '.lrc');
|
||
fs.writeFileSync(lrcPath, data.lrc, 'utf-8');
|
||
console.log(` 📄 歌词已保存: ${path.basename(lrcPath)}`);
|
||
if (data.tlyric?.trim()) {
|
||
const mergedPath = path.join(DOWNLOAD_DIR, fileName + '.合并翻译.lrc');
|
||
fs.writeFileSync(mergedPath, mergeLrc(data.lrc, data.tlyric), 'utf-8');
|
||
console.log(` 📄 翻译歌词已保存: ${path.basename(mergedPath)}`);
|
||
}
|
||
}
|
||
|
||
module.exports = { fetchLyric, mergeLrc, parseCredits, saveLyric };
|