2022-05-12 02:45:43 +08:00

89 lines
2.5 KiB
TypeScript

import { FetchLyricResponse } from '@/shared/api/Track'
export function lyricParser(lrc: FetchLyricResponse) {
return {
lyric: parseLyric(lrc?.lrc?.lyric || ''),
tlyric: parseLyric(lrc?.tlyric?.lyric || ''),
lyricuser: lrc.lyricUser,
transuser: lrc.transUser,
}
}
/**
* @see {@link https://regexr.com/6e52n}
*/
const extractLrcRegex =
/^(?<lyricTimestamps>(?:\[.+?\])+)(?!\[)(?<content>.+)$/gm
const extractTimestampRegex = /\[(?<min>\d+):(?<sec>\d+)(?:\.|:)*(?<ms>\d+)*\]/g
interface ParsedLyric {
time: number
rawTime: string
content: string
}
function parseLyric(lrc: string): ParsedLyric[] {
// A sorted list of parsed lyric and its timestamp.
const parsedLyrics: ParsedLyric[] = []
// Find the appropriate index to push our parsed lyric.
const binarySearch = (lyric: ParsedLyric) => {
const time = lyric.time
let low = 0
let high = parsedLyrics.length - 1
while (low <= high) {
const mid = Math.floor((low + high) / 2)
const midTime = parsedLyrics[mid].time
if (midTime === time) {
return mid
} else if (midTime < time) {
low = mid + 1
} else {
high = mid - 1
}
}
return low
}
function trimContent(content: string): string {
const t = content.trim()
return t.length < 1 ? content : t
}
for (const line of lrc.trim().matchAll(extractLrcRegex)) {
const { lyricTimestamps, content } = line.groups as {
lyricTimestamps: string
content: string
}
if (content === '纯音乐,请欣赏') continue
if (
content.match(
// https://regexr.com/6j8pf
/.*(?<role>作曲|作词|编曲|制作|Producers|Producer|Produced|贝斯|工程师|吉他|合成器|助理|编程|制作|和声|母带|人声|鼓|混音|中提琴|编写|Talkbox|钢琴|出版|录音|发行|出品|键盘|弦乐|设计|监制|原曲|演唱|声明|版权|封面|插画|统筹|企划|填词|原唱|后期|和音|琵琶).*[::]\s*(?<name>.*)/
)
) {
continue
}
for (const timestamp of lyricTimestamps.matchAll(extractTimestampRegex)) {
const { min, sec, ms } = timestamp.groups as {
min: string
sec: string
ms: string
}
const rawTime = timestamp[0]
const time = Number(min) * 60 + Number(sec) + Number(ms ?? 0) * 0.001
const parsedLyric = { rawTime, time, content: trimContent(content) }
parsedLyrics.splice(binarySearch(parsedLyric), 0, parsedLyric)
}
}
return parsedLyrics
}