forked from miao-moe/QZMusic_PC
fork(fix): Clone AMLL 并修复 BUG
- 将AMLL Clone到本以地进行修复和优化(emm虽然这很不优雅但是暂时无时间做子模块和Fork) - 修复在当前播放歌词行不可见的视口Seek会出现滚动偏移的问题
This commit is contained in:
136
amll-local/packages/lyric/test/lys.test.ts
Normal file
136
amll-local/packages/lyric/test/lys.test.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseLys, stringifyLys } from "../src/formats/lys";
|
||||
|
||||
describe("lys", () => {
|
||||
it("parses basic word-timestamped line", () => {
|
||||
const lines = parseLys("[0]Hello(1000,500) World(1500,500)");
|
||||
|
||||
expect(lines).toHaveLength(1);
|
||||
expect(lines[0].startTime).toBe(1000);
|
||||
expect(lines[0].endTime).toBe(2000);
|
||||
expect(lines[0].isBG).toBe(false);
|
||||
expect(lines[0].isDuet).toBe(false);
|
||||
expect(lines[0].words.map((w) => w.word)).toEqual(["Hello", " World"]);
|
||||
});
|
||||
|
||||
it("parses bg + duet flags from prop and strips bg wrappers", () => {
|
||||
const lines = parseLys("[8](Hello(1000,500)World(1500,500))");
|
||||
|
||||
expect(lines).toHaveLength(1);
|
||||
expect(lines[0].isBG).toBe(true);
|
||||
expect(lines[0].isDuet).toBe(true);
|
||||
expect(lines[0].words.map((w) => w.word).join("")).toBe("HelloWorld");
|
||||
});
|
||||
|
||||
it("handles CRLF and ignores lines without valid prop prefix", () => {
|
||||
const lines = parseLys(
|
||||
"no prop\r\n#comment\r\n{meta:true}\r\n[4]Hello(1000,500)World(1500,500)",
|
||||
);
|
||||
|
||||
expect(lines).toHaveLength(1);
|
||||
expect(lines[0].startTime).toBe(1000);
|
||||
expect(lines[0].endTime).toBe(2000);
|
||||
});
|
||||
|
||||
it("ignores lines with bad word timestamps", () => {
|
||||
const lines = parseLys(
|
||||
"[0]Hello(1000,500)\n[0]Bad(a,b)\n[0]AlsoBad(1000,-10)\n[0]World(2000,500)",
|
||||
);
|
||||
|
||||
expect(lines).toHaveLength(2);
|
||||
expect(lines[0].words.map((w) => w.word).join("")).toBe("Hello");
|
||||
expect(lines[1].words.map((w) => w.word).join("")).toBe("World");
|
||||
});
|
||||
|
||||
it("ignores empty lines and lines with only whitespace", () => {
|
||||
const lines = parseLys(
|
||||
"[0] \n[3]\n[0]Hello(1000,500) World(1500,500)\n \n\n[0]Next(2000,500) line(2500,500)\n \n",
|
||||
);
|
||||
expect(lines).toHaveLength(2);
|
||||
expect(lines[0].words[0].word).toBe("Hello");
|
||||
expect(lines[1].words[0].word).toBe("Next");
|
||||
});
|
||||
|
||||
it("stringifies words and preserves spaces", () => {
|
||||
const result = stringifyLys([
|
||||
{
|
||||
startTime: 1000,
|
||||
endTime: 2000,
|
||||
words: [
|
||||
{ startTime: 1000, endTime: 1500, word: "Hello", romanWord: "" },
|
||||
{ startTime: 0, endTime: 0, word: " ", romanWord: "" },
|
||||
{ startTime: 1500, endTime: 2000, word: "World", romanWord: "" },
|
||||
],
|
||||
translatedLyric: "",
|
||||
romanLyric: "",
|
||||
isBG: false,
|
||||
isDuet: false,
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toBe("[4]Hello (1000,500)World(1500,500)");
|
||||
});
|
||||
|
||||
it("stringifies props according to duet/background presence", () => {
|
||||
const result = stringifyLys([
|
||||
{
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
words: [{ startTime: 1000, endTime: 1500, word: "A", romanWord: "" }],
|
||||
translatedLyric: "",
|
||||
romanLyric: "",
|
||||
isBG: true,
|
||||
isDuet: true,
|
||||
},
|
||||
{
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
words: [{ startTime: 2000, endTime: 2500, word: "B", romanWord: "" }],
|
||||
translatedLyric: "",
|
||||
romanLyric: "",
|
||||
isBG: false,
|
||||
isDuet: false,
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toBe("[8]A(1000,500)\n[4]B(2000,500)");
|
||||
});
|
||||
|
||||
it("normalizes invalid timestamps when stringifying", () => {
|
||||
const result = stringifyLys([
|
||||
{
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
words: [
|
||||
{
|
||||
startTime: Number.NaN,
|
||||
endTime: Number.POSITIVE_INFINITY,
|
||||
word: "Hello",
|
||||
romanWord: "",
|
||||
},
|
||||
{
|
||||
startTime: -1,
|
||||
endTime: -2,
|
||||
word: "World",
|
||||
romanWord: "",
|
||||
},
|
||||
],
|
||||
translatedLyric: "",
|
||||
romanLyric: "",
|
||||
isBG: false,
|
||||
isDuet: false,
|
||||
},
|
||||
]);
|
||||
|
||||
expect(result).toBe("[4]Hello(0,0)World(0,0)");
|
||||
});
|
||||
|
||||
it("keeps parse -> stringify -> parse stable for content and timing", () => {
|
||||
const input = "[4]Hello(1000,500) World(1500,500)\n[8](Again(3000,500))";
|
||||
const first = parseLys(input);
|
||||
const text = stringifyLys(first);
|
||||
const second = parseLys(text);
|
||||
|
||||
expect(second).toEqual(first);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user