temp: debug
This commit is contained in:
parent
9074f800d6
commit
ecaa7c3e1c
@ -4,24 +4,30 @@ import {
|
||||
buildLexer,
|
||||
expectEOF,
|
||||
fail,
|
||||
kleft,
|
||||
kmid,
|
||||
kright,
|
||||
opt_sc,
|
||||
type Parser,
|
||||
rep,
|
||||
rep_sc,
|
||||
seq,
|
||||
str,
|
||||
tok,
|
||||
type Parser,
|
||||
type Token
|
||||
} from 'typescript-parsec';
|
||||
|
||||
export interface ScriptItem {
|
||||
|
||||
interface ParserScriptItem {
|
||||
start: number;
|
||||
text: string;
|
||||
end: number;
|
||||
translation?: string;
|
||||
words?: ScriptWordsItem[];
|
||||
singer?: number;
|
||||
translation?: string;
|
||||
singer?: string;
|
||||
}
|
||||
|
||||
export interface ScriptItem extends ParserScriptItem{
|
||||
end: number;
|
||||
chorus?: string;
|
||||
}
|
||||
|
||||
@ -32,12 +38,24 @@ export interface ScriptWordsItem {
|
||||
endIndex: number;
|
||||
}
|
||||
|
||||
export interface LrcJsonData {
|
||||
export interface LrcMetaData {
|
||||
ar?: string;
|
||||
ti?: string;
|
||||
al?: string;
|
||||
scripts?: ScriptItem[];
|
||||
au?: string;
|
||||
length?: string;
|
||||
offset?: string;
|
||||
tool?: string;
|
||||
ve?: string;
|
||||
}
|
||||
|
||||
export interface ParsedLrc extends LrcMetaData {
|
||||
scripts?: ParserScriptItem[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface LrcJsonData extends LrcMetaData {
|
||||
scripts?: ScriptItem[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@ -46,10 +64,10 @@ interface IDTag {
|
||||
}
|
||||
|
||||
function convertTimeToMs({
|
||||
mins,
|
||||
secs,
|
||||
decimals
|
||||
}: {
|
||||
mins,
|
||||
secs,
|
||||
decimals
|
||||
}: {
|
||||
mins?: number | string;
|
||||
secs?: number | string;
|
||||
decimals?: string;
|
||||
@ -84,7 +102,9 @@ const alpha = alt_sc(
|
||||
);
|
||||
|
||||
const alphaStr = apply(rep(alpha), (r) => r.join(''));
|
||||
const spaces = rep_sc(str(' '));
|
||||
function spaces<K>(): Parser<K, Token<K>[]> {
|
||||
return rep_sc(str(' '));
|
||||
}
|
||||
|
||||
const unicodeStr = rep(tok('char'));
|
||||
|
||||
@ -100,6 +120,10 @@ function trimmed<K, T>(p: Parser<K, Token<T>[]>): Parser<K, Token<T>[]> {
|
||||
});
|
||||
}
|
||||
|
||||
function padded<K, T>(p: Parser<K, T>): Parser<K, T> {
|
||||
return kmid(spaces(), p, spaces());
|
||||
}
|
||||
|
||||
function anythingTyped(types: string[]) {
|
||||
return types.map((t) => tok(t)).reduce((acc, cur) => alt_sc(cur, acc), fail('no alternatives'));
|
||||
}
|
||||
@ -145,39 +169,60 @@ function tokenParserToText<K, T>(p: Parser<K, Token<T>> | Parser<K, Token<T>[]>)
|
||||
});
|
||||
}
|
||||
|
||||
const singerIndicator = kleft(tok('char'), str(':'));
|
||||
const translateParser = kright(str('|'), unicodeStr);
|
||||
|
||||
function lrcLine(
|
||||
wordDiv = ' ', legacy = false
|
||||
): Parser<unknown, ['script_item', ScriptItem] | ['lrc_tag', IDTag] | ['comment', string] | ['empty', null]> {
|
||||
): Parser<unknown, ['script_item', ParserScriptItem] | ['lrc_tag', IDTag] | ['comment', string] | ['empty', null]> {
|
||||
return alt_sc(
|
||||
legacy ? apply(seq(squareTS, trimmed(rep_sc(anythingTyped(['char', '[', ']', '<', '>'])))), (r) =>
|
||||
['script_item', { start: r[0], text: joinTokens(r[1]) } as any as ScriptItem] // TODO: Complete this
|
||||
) : apply(seq(squareTS, rep_sc(seq(opt_sc(angleTS), trimmed(rep_sc(anythingTyped(['char', '[', ']'])))))), (r) => {
|
||||
const start = r[0];
|
||||
['script_item', { start: r[0], text: joinTokens(r[1]) } as ParserScriptItem] // TODO: Complete this
|
||||
) : apply(
|
||||
seq(
|
||||
squareTS,
|
||||
opt_sc(singerIndicator),
|
||||
rep_sc(
|
||||
seq(
|
||||
opt_sc(angleTS),
|
||||
trimmed(rep_sc(anythingTyped(['char', '[', ']'])))
|
||||
)
|
||||
),
|
||||
opt_sc(trimmed(translateParser))
|
||||
), (r) => {
|
||||
const start = r[0];
|
||||
const singerPart = r[1];
|
||||
const mainPart = r[2];
|
||||
const translatePart = r[3];
|
||||
|
||||
const text = r[1]
|
||||
.map((s) => joinTokens(s[1]))
|
||||
.filter((s) => s.trim().length > 0)
|
||||
.join(wordDiv);
|
||||
const text = mainPart
|
||||
.map((s) => joinTokens(s[1]))
|
||||
.filter((s) => s.trim().length > 0)
|
||||
.join(wordDiv);
|
||||
|
||||
const words = r[1]
|
||||
.filter((s) => joinTokens(s[1]).trim().length > 0)
|
||||
.map((s) => {
|
||||
const wordBegin = s[0];
|
||||
const word = s[1];
|
||||
let ret: Partial<ScriptWordsItem> = { start: wordBegin };
|
||||
if (word[0]) {
|
||||
ret.beginIndex = word[0].pos.columnBegin - 1;
|
||||
}
|
||||
if (word[word.length - 1]) {
|
||||
ret.endIndex = word[word.length - 1].pos.columnEnd;
|
||||
}
|
||||
return ret as ScriptWordsItem; // TODO: Complete this
|
||||
});
|
||||
return ['script_item', { start, text, words } as any as ScriptItem]; // TODO: Complete this
|
||||
}),
|
||||
const words = mainPart
|
||||
.filter((s) => joinTokens(s[1]).trim().length > 0)
|
||||
.map((s) => {
|
||||
const wordBegin = s[0];
|
||||
const word = s[1];
|
||||
let ret: Partial<ScriptWordsItem> = { start: wordBegin };
|
||||
if (word[0]) {
|
||||
ret.beginIndex = word[0].pos.columnBegin - 1;
|
||||
}
|
||||
if (word[word.length - 1]) {
|
||||
ret.endIndex = word[word.length - 1].pos.columnEnd;
|
||||
}
|
||||
return ret as ScriptWordsItem; // TODO: Complete this
|
||||
});
|
||||
|
||||
const singer = singerPart?.text;
|
||||
const translation = translatePart === undefined ? undefined : joinTokens(translatePart);
|
||||
|
||||
return ['script_item', { start, text, words, singer, translation } as ParserScriptItem];
|
||||
}),
|
||||
apply(lrcTag, (r) => ['lrc_tag', r as IDTag]),
|
||||
apply(seq(spaces, str('#'), unicodeStr), (cmt) => ['comment', cmt[2].join('')] as const),
|
||||
apply(spaces, (_) => ['empty', null] as const)
|
||||
apply(seq(spaces(), str('#'), unicodeStr), (cmt) => ['comment', cmt[2].join('')] as const),
|
||||
apply(spaces(), (_) => ['empty', null] as const)
|
||||
);
|
||||
}
|
||||
|
||||
@ -191,7 +236,7 @@ export function dumpToken<T>(t: Token<T> | undefined): string {
|
||||
export function parseLRC(
|
||||
input: string,
|
||||
{ wordDiv, strict, legacy }: { wordDiv?: string; strict?: boolean; legacy?: boolean } = {}
|
||||
): LrcJsonData {
|
||||
): ParsedLrc {
|
||||
const tokenizer = buildLexer([
|
||||
[true, /^\[/gu, '['],
|
||||
[true, /^\]/gu, ']'],
|
||||
@ -231,5 +276,5 @@ export function parseLRC(
|
||||
default:
|
||||
return acc;
|
||||
}
|
||||
}, {} as LrcJsonData);
|
||||
}, {} as ParsedLrc);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ describe('LRC parser test', () => {
|
||||
const test01Text = test01Buffer.toString('utf-8');
|
||||
const test02Buffer = fs.readFileSync('./src/test/resources/test-02.lrc');
|
||||
const test02Text = test02Buffer.toString('utf-8');
|
||||
const test03Buffer = fs.readFileSync('./src/test/resources/test-03.lrc');
|
||||
const test03Text = test03Buffer.toString('utf-8');
|
||||
it('Parses test-01.lrc', () => {
|
||||
const result = parseLRC(test01Text, { wordDiv: '', strict: true });
|
||||
|
||||
@ -28,6 +30,11 @@ describe('LRC parser test', () => {
|
||||
expect(result.scripts!![0].words!![1].beginIndex).toBe("[00:00.00] <00:00.04> When <00:00.16> the".indexOf("the"));
|
||||
expect(result.scripts!![0].words!![1].start).toBe(160);
|
||||
});
|
||||
it('Parses test-03.lrc', () => {
|
||||
const result = parseLRC(test03Text, { wordDiv: ' ', strict: true });
|
||||
console.log(result.scripts);
|
||||
expect(result.scripts!![5].translation).toBe("བྲོ་ར་འདི་ལ་བྲོ་ཅིག་འཁྲབ།");
|
||||
});
|
||||
it('Rejects some invalid LRCs', () => {
|
||||
const cases = [
|
||||
"[<00:00.00>] <00:00.04> When <00:00.16> the",
|
||||
|
77
src/test/resources/test-03.lrc
Normal file
77
src/test/resources/test-03.lrc
Normal file
@ -0,0 +1,77 @@
|
||||
[ti: 雪山之眼]
|
||||
[ar: 洛天依 & 旦增益西]
|
||||
[al: 游四方]
|
||||
[tool: 歌词滚动姬 https://lrc-maker.github.io]
|
||||
[length: 04:17.400]
|
||||
[00:34.280] 浸透了经卷 记忆的呼喊
|
||||
[00:37.800] 雪珠滚落山巅 栽下一个春天
|
||||
[00:47.390] 松石敲响玲珑清脆的银花
|
||||
[00:51.600] 穿过玛瑙的红霞
|
||||
[00:54.430] 在她眼中结编 亘久诗篇
|
||||
[01:05.440] བྲོ་ར་འདི་ལ་བྲོ་ཅིག་འཁྲབ། | 在舞池里舞一舞
|
||||
[01:08.780] 祝祷转过千年 五色经幡飘飞
|
||||
[01:12.040] 奏起悠扬巴叶 任岁月拨弦
|
||||
[01:19.130] གཞས་ར་འདི་ལ་གཞས་གཅིག་བཏང་། 我在歌坛献首歌
|
||||
[01:22.330] 宫殿 塔尖 彩绘 日月 同辉
|
||||
[01:25.810] 那层厚重壁垒化身 蝉翼一片
|
||||
[01:29.110] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[01:30.790] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[01:32.510] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[01:34.120] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[01:35.920] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[01:37.630] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[01:39.350] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[01:41.050] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[01:42.740] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[01:44.630] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[01:46.280] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[01:48.010] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[01:49.600] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[01:51.380] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[01:53.070] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[01:54.820] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[01:58.580] སྔོན་དང་པོ་གྲུབ་ཐོབ་ཐང་སྟོང་རྒྱལ་པོས་མཛད་པའི་མཛད་ཚུལ་དུ། དང་པོ་རྔོན་པའི་ས་སྦྱངས་ས་འདུལ། གཉིས་པ་རྒྱ་ལུའི་བྱིན་འབེབས། གསུམ་པ་ལྷ་མོའི་གླུ་གར་སོགས་རིན་ཆེན་གསུང་མགུར་གཞུང་བཟང་མང་པོ་འདུག་སྟེ། དེ་ཡང་མ་ཉུང་གི་ཚིག་ལ་དུམ་མཚམས་གཅིག་ཞུས་པ་བྱུང་བ་ཡིན་པ་ལགས་སོ། 如祖师唐东杰布所著,一有温巴净地,二有甲鲁祈福,三有仙女歌舞,所著繁多,在此简略献之。
|
||||
[02:24.240] 浸透了经卷 记忆的呼喊
|
||||
[02:27.450] 雪珠滚落山巅 栽下一个春天
|
||||
[02:37.090] 松石敲响玲珑清脆的银花
|
||||
[02:41.280] 穿过玛瑙的红霞
|
||||
[02:44.010] 在她眼中结编 亘久诗篇
|
||||
[02:55.250] བྲོ་ར་འདི་ལ་བྲོ་ཅིག་འཁྲབ། 在舞池里舞一舞
|
||||
[02:58.410] 祝祷转过千年 五色经幡飘飞
|
||||
[03:01.750] 奏起悠扬巴叶 任岁月拨弦
|
||||
[03:08.840] གཞས་ར་འདི་ལ་གཞས་གཅིག་བཏང་། 我在歌坛献首歌
|
||||
[03:12.050] 宫殿 塔尖 彩绘 日月 同辉
|
||||
[03:15.400] 那层厚重壁垒化身 蝉翼一片
|
||||
[03:18.850] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:20.480] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:22.210] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:23.910] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:25.662] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:27.391] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:29.096] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:30.789] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:32.496] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:34.175] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:35.876] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:37.606] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:39.290] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:41.030] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:42.679] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:44.455] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:46.176] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:47.910] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:49.625] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:51.293] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:53.005] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[03:54.742] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[03:56.479] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[03:58.159] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[03:59.859] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[04:01.548] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[04:03.312] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[04:05.026] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[04:06.721] ང་ཚོ་འདི་ལ་འཛོམས་འཛོམས། 我们在此相聚
|
||||
[04:08.479] གཏན་དུ་འཛོམས་རྒྱུ་བྱུང་ན། 希望可以常聚
|
||||
[04:10.175] གཏན་དུ་འཛོམས་པའི་མི་ལ། 在此相聚的人们
|
||||
[04:11.923] སྙུན་གཞི་གོད་ཆགས་མ་གཏོང༌། 祝愿平安富足
|
||||
[04:17.400]
|
Loading…
Reference in New Issue
Block a user