过滤嵌入、下载的翻译、罗马音歌词时间标签(#1358)
parent
a3b8f31b1e
commit
23f118fb1a
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
- Windows、MacOS平台下的字体列表改用原生方式获取,现在Windows平台下能显示当前已安装的更多类型字体了(注:MacOS平台未测,可用性未知)
|
- Windows、MacOS平台下的字体列表改用原生方式获取,现在Windows平台下能显示当前已安装的更多类型字体了(注:MacOS平台未测,可用性未知)
|
||||||
- 移除桌面歌词窗口透明边距,在Linux下的桌面歌词可以完全拖到贴合屏幕边缘了
|
- 移除桌面歌词窗口透明边距,在Linux下的桌面歌词可以完全拖到贴合屏幕边缘了
|
||||||
|
- 过滤嵌入、下载的翻译、罗马音歌词时间标签,与主歌词时间不匹配的歌词将被丢弃,防止出现原歌词与翻译歌词顺序错乱的问题(#1358)
|
||||||
|
|
||||||
### 修复
|
### 修复
|
||||||
|
|
||||||
|
|
|
@ -148,19 +148,22 @@ const saveMeta = (downloadInfo: LX.Download.ListItem) => {
|
||||||
: Promise.resolve(null),
|
: Promise.resolve(null),
|
||||||
]
|
]
|
||||||
void Promise.all(tasks).then(([imgUrl, lyrics]) => {
|
void Promise.all(tasks).then(([imgUrl, lyrics]) => {
|
||||||
let lyric: null | string = null
|
const lrcData = {
|
||||||
if (lyrics?.lyric) {
|
lrc: '',
|
||||||
lyric = fixKgLyric(lyrics.lyric)
|
tlrc: null as string | null,
|
||||||
if (appSetting['download.isEmbedLyricT'] && lyrics.tlyric) lyric += '\n' + lyrics.tlyric + '\n'
|
rlrc: null as string | null,
|
||||||
if (appSetting['download.isEmbedLyricR'] && lyrics.rlyric) lyric += '\n' + lyrics.rlyric + '\n'
|
}
|
||||||
|
if (lyrics) {
|
||||||
|
lrcData.lrc = lyrics.lyric
|
||||||
|
if (appSetting['download.isEmbedLyricT'] && lyrics.tlyric) lrcData.tlrc = lyrics.tlyric
|
||||||
|
if (appSetting['download.isEmbedLyricR'] && lyrics.rlyric) lrcData.rlrc = lyrics.rlyric
|
||||||
}
|
}
|
||||||
void window.lx.worker.download.writeMeta(downloadInfo.metadata.filePath, {
|
void window.lx.worker.download.writeMeta(downloadInfo.metadata.filePath, {
|
||||||
title: downloadInfo.metadata.musicInfo.name,
|
title: downloadInfo.metadata.musicInfo.name,
|
||||||
artist: downloadInfo.metadata.musicInfo.singer,
|
artist: downloadInfo.metadata.musicInfo.singer,
|
||||||
album: downloadInfo.metadata.musicInfo.meta.albumName,
|
album: downloadInfo.metadata.musicInfo.meta.albumName,
|
||||||
APIC: imgUrl,
|
APIC: imgUrl,
|
||||||
lyrics: lyric,
|
}, lrcData)
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +180,13 @@ const downloadLyric = (downloadInfo: LX.Download.ListItem) => {
|
||||||
}).then(lrcs => {
|
}).then(lrcs => {
|
||||||
if (lrcs.lyric) {
|
if (lrcs.lyric) {
|
||||||
lrcs.lyric = fixKgLyric(lrcs.lyric)
|
lrcs.lyric = fixKgLyric(lrcs.lyric)
|
||||||
let lyric = lrcs.lyric
|
const lrcData = {
|
||||||
if (appSetting['download.isDownloadTLrc'] && lrcs.tlyric) lyric += '\n' + lrcs.tlyric + '\n'
|
lrc: lrcs.lyric,
|
||||||
if (appSetting['download.isDownloadRLrc'] && lrcs.rlyric) lyric += '\n' + lrcs.rlyric + '\n'
|
tlrc: appSetting['download.isDownloadTLrc'] && lrcs.tlyric ? lrcs.tlyric : null,
|
||||||
void window.lx.worker.download.saveLrc(downloadInfo.metadata.filePath.replace(/(mp3|flac|ape|wav)$/, 'lrc'),
|
rlrc: appSetting['download.isDownloadRLrc'] && lrcs.rlyric ? lrcs.rlyric : null,
|
||||||
lyric, appSetting['download.lrcFormat'])
|
}
|
||||||
|
void window.lx.worker.download.saveLrc(lrcData, downloadInfo.metadata.filePath.replace(/(mp3|flac|ape|wav)$/, 'lrc'),
|
||||||
|
appSetting['download.lrcFormat'])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { setMeta } from '@common/utils/musicMeta'
|
import { setMeta } from '@common/utils/musicMeta'
|
||||||
|
import { mergeLyrics } from './lrcTool'
|
||||||
|
|
||||||
export const writeMeta = (filePath: string, meta: LX.Music.MusicFileMeta) => {
|
export const writeMeta = (filePath: string, meta: Omit<LX.Music.MusicFileMeta, 'lyrics'>, lyricData: { lrc: string, tlrc: string | null, rlrc: string | null }) => {
|
||||||
setMeta(filePath, meta)
|
setMeta(filePath, { ...meta, lyrics: mergeLyrics(lyricData.lrc, lyricData.tlrc, lyricData.rlrc) || null })
|
||||||
}
|
}
|
||||||
|
|
||||||
export { saveLrc } from './utils'
|
export { saveLrc } from './utils'
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
const timeFieldExp = /^(?:\[[\d:.]+\])+/g
|
||||||
|
const timeExp = /\d{1,3}(:\d{1,3}){0,2}(?:\.\d{1,3})/g
|
||||||
|
|
||||||
|
const t_rxp_1 = /^0+(\d+)/
|
||||||
|
const t_rxp_2 = /:0+(\d+)/g
|
||||||
|
const t_rxp_3 = /\.0+(\d+)/
|
||||||
|
const formatTimeLabel = (label: string) => {
|
||||||
|
return label.replace(t_rxp_1, '$1')
|
||||||
|
.replace(t_rxp_2, ':$1')
|
||||||
|
.replace(t_rxp_3, '.$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterExtendedLyricLabel = (lrcTimeLabels: Set<string>, extendedLyric: string) => {
|
||||||
|
const extendedLines = extendedLyric.split(/\r\n|\n|\r/)
|
||||||
|
const lines: string[] = []
|
||||||
|
for (let i = 0; i < extendedLines.length; i++) {
|
||||||
|
let line = extendedLines[i].trim()
|
||||||
|
let result = timeFieldExp.exec(line)
|
||||||
|
if (!result) continue
|
||||||
|
|
||||||
|
const timeField = result[0]
|
||||||
|
const text = line.replace(timeFieldExp, '').trim()
|
||||||
|
if (!text) continue
|
||||||
|
let times = timeField.match(timeExp)
|
||||||
|
if (times == null) continue
|
||||||
|
|
||||||
|
const newTimes = times.filter(time => {
|
||||||
|
const timeStr = formatTimeLabel(time)
|
||||||
|
return lrcTimeLabels.has(timeStr)
|
||||||
|
})
|
||||||
|
if (newTimes.length != times.length) {
|
||||||
|
if (!newTimes.length) continue
|
||||||
|
line = `[${newTimes.join('][')}]${text}`
|
||||||
|
}
|
||||||
|
lines.push(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseLrcTimeLabel = (lrc: string) => {
|
||||||
|
const lines = lrc.split(/\r\n|\n|\r/)
|
||||||
|
const linesSet = new Set<string>()
|
||||||
|
const length = lines.length
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
const line = lines[i].trim()
|
||||||
|
let result = timeFieldExp.exec(line)
|
||||||
|
if (result) {
|
||||||
|
const timeField = result[0]
|
||||||
|
const text = line.replace(timeFieldExp, '').trim()
|
||||||
|
if (text) {
|
||||||
|
const times = timeField.match(timeExp)
|
||||||
|
if (times == null) continue
|
||||||
|
for (let time of times) {
|
||||||
|
linesSet.add(formatTimeLabel(time))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return linesSet
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const mergeLyrics = (lrc: string, tlrc: string | null, rlrc: string | null) => {
|
||||||
|
if (!tlrc && !rlrc) return lrc
|
||||||
|
|
||||||
|
const lrcTimeLabels = parseLrcTimeLabel(lrc)
|
||||||
|
// console.log(lrcTimeLabels)
|
||||||
|
if (tlrc) lrc += `\n\n${filterExtendedLyricLabel(lrcTimeLabels, tlrc)}\n`
|
||||||
|
if (rlrc) lrc += `\n\n${filterExtendedLyricLabel(lrcTimeLabels, rlrc)}\n`
|
||||||
|
// console.log(lrc)
|
||||||
|
return lrc
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { DOWNLOAD_STATUS, QUALITYS } from '@common/constants'
|
import { DOWNLOAD_STATUS, QUALITYS } from '@common/constants'
|
||||||
import { filterFileName } from '@common/utils/common'
|
import { filterFileName } from '@common/utils/common'
|
||||||
import { joinPath } from '@common/utils/nodejs'
|
import { joinPath } from '@common/utils/nodejs'
|
||||||
|
import { mergeLyrics } from './lrcTool'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,8 +10,9 @@ import fs from 'fs'
|
||||||
* @param {*} lrc
|
* @param {*} lrc
|
||||||
* @param {*} format
|
* @param {*} format
|
||||||
*/
|
*/
|
||||||
export const saveLrc = async(filePath: string, lrc: string, format: LX.LyricFormat) => {
|
export const saveLrc = async(lrcData: { lrc: string, tlrc: string | null, rlrc: string | null }, filePath: string, format: LX.LyricFormat) => {
|
||||||
const iconv = await import('iconv-lite')
|
const iconv = await import('iconv-lite')
|
||||||
|
const lrc = mergeLyrics(lrcData.lrc, lrcData.tlrc, lrcData.rlrc)
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 'gbk':
|
case 'gbk':
|
||||||
fs.writeFile(filePath, iconv.encode(lrc, 'gbk', { addBOM: true }), err => {
|
fs.writeFile(filePath, iconv.encode(lrc, 'gbk', { addBOM: true }), err => {
|
||||||
|
|
Loading…
Reference in New Issue