Skip to content

Commit dc57c4b

Browse files
committed
fix: change datastruct to array to improve data safety and make preview avaliable
1 parent f3e96d2 commit dc57c4b

6 files changed

Lines changed: 77 additions & 28 deletions

File tree

src/components/AMLLWrapper/index.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,47 @@ import {
2626
import { isDarkThemeAtom, lyricLinesAtom } from "$/states/main.ts";
2727
import styles from "./index.module.css";
2828

29+
const parseLineVocalIds = (value?: string | string[]) => {
30+
if (!value) return [];
31+
const parts = Array.isArray(value) ? value : value.split(/[\s,]+/);
32+
return parts.map((v) => v.trim()).filter(Boolean);
33+
};
34+
35+
const mapVocalTagsForPreview = (
36+
vocal: string | string[] | undefined,
37+
vocalTagMap: Map<string, string>,
38+
) => {
39+
if (!vocal) return;
40+
const fallbackParts = Array.isArray(vocal) ? vocal : [vocal];
41+
const normalizedFallback = fallbackParts
42+
.map((v) => v.trim())
43+
.filter(Boolean);
44+
if (vocalTagMap.size === 0) {
45+
return normalizedFallback.length > 0 ? normalizedFallback : undefined;
46+
}
47+
const ids = parseLineVocalIds(vocal);
48+
if (ids.length === 0) return;
49+
let hasMatch = false;
50+
const mapped = ids
51+
.map((id) => {
52+
const value = vocalTagMap.get(id);
53+
if (value && value.trim().length > 0) {
54+
hasMatch = true;
55+
return value;
56+
}
57+
if (vocalTagMap.has(id)) {
58+
hasMatch = true;
59+
}
60+
return id;
61+
})
62+
.map((v) => v.trim())
63+
.filter(Boolean);
64+
if (!hasMatch) {
65+
return normalizedFallback.length > 0 ? normalizedFallback : undefined;
66+
}
67+
return mapped.length > 0 ? mapped : undefined;
68+
};
69+
2970
export const AMLLWrapper = memo(() => {
3071
const originalLyricLines = useAtomValue(lyricLinesAtom);
3172
const currentTime = useAtomValue(currentTimeAtom);
@@ -38,11 +79,15 @@ export const AMLLWrapper = memo(() => {
3879
const playerRef = useRef<LyricPlayerRef>(null);
3980

4081
const lyricLines = useMemo(() => {
82+
const vocalTagMap = new Map(
83+
(originalLyricLines.vocalTags ?? []).map((tag) => [tag.key, tag.value]),
84+
);
4185
return structuredClone(
4286
originalLyricLines.lyricLines.map((line) => ({
4387
...line,
4488
translatedLyric: showTranslationLines ? line.translatedLyric : "",
4589
romanLyric: showRomanLines ? line.romanLyric : "",
90+
vocal: mapVocalTagsForPreview(line.vocal, vocalTagMap),
4691
})),
4792
);
4893
}, [originalLyricLines, showTranslationLines, showRomanLines]);
@@ -80,3 +125,4 @@ export const AMLLWrapper = memo(() => {
80125
});
81126

82127
export default AMLLWrapper;
128+

src/modules/lyric-editor/components/lyric-line-view.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,11 @@ import { RomanWordView } from "./roman-word-view.tsx";
6666

6767
const isDraggingAtom = atom(false);
6868

69-
const parseLineVocalIds = (value?: string) =>
70-
value
71-
? value
72-
.split(/[\s,]+/)
73-
.map((v) => v.trim())
74-
.filter(Boolean)
75-
: [];
69+
const parseLineVocalIds = (value?: string | string[]) => {
70+
if (!value) return [];
71+
const parts = Array.isArray(value) ? value : value.split(/[\s,]+/);
72+
return parts.map((v) => v.trim()).filter(Boolean);
73+
};
7674

7775
// 定义一个派生 Atom,用于计算每一行的显示行号
7876
const lineDisplayNumbersAtom = atom((get) => {
@@ -696,7 +694,7 @@ export const LyricLineView: FC<{
696694
} else {
697695
currentIds.push(id);
698696
}
699-
targetLine.vocal = currentIds.join(",");
697+
targetLine.vocal = currentIds;
700698
});
701699
}}
702700
>
@@ -714,7 +712,7 @@ export const LyricLineView: FC<{
714712
evt.stopPropagation();
715713
editLyricLines((state) => {
716714
const targetLine = state.lyricLines[lineIndex];
717-
targetLine.vocal = allSelected ? "" : vocalTagIds.join(",");
715+
targetLine.vocal = allSelected ? [] : [...vocalTagIds];
718716
});
719717
}}
720718
>

src/modules/project/logic/ttml-parser.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ export function parseLyric(ttmlText: string): TTMLLyric {
8787
});
8888

8989
const itunesLineRomanizations = new Map<string, LineMetadata>();
90+
const parseVocalValue = (value: string | string[] | null | undefined) => {
91+
if (!value) return [];
92+
const parts = Array.isArray(value) ? value : value.split(/[\s,]+/);
93+
return parts.map((v) => v.trim()).filter(Boolean);
94+
};
95+
9096
const itunesWordRomanizations = new Map<string, WordRomanMetadata>();
9197

9298
const romanizationTextElements = ttmlDoc.querySelectorAll(
@@ -269,7 +275,7 @@ export function parseLyric(ttmlText: string): TTMLLyric {
269275
isBG = false,
270276
isDuet = false,
271277
parentItunesKey: string | null = null,
272-
parentVocal: string | null = null,
278+
parentVocal: string | string[] | null = null,
273279
) {
274280
const startTimeAttr = lineEl.getAttribute("begin");
275281
const endTimeAttr = lineEl.getAttribute("end");
@@ -285,6 +291,7 @@ export function parseLyric(ttmlText: string): TTMLLyric {
285291
const lineVocalAttr =
286292
lineEl.getAttribute("amll:vocal") ?? lineEl.getAttribute("vocal");
287293
const lineVocal = lineVocalAttr ?? (isBG ? parentVocal : null);
294+
const parsedLineVocal = parseVocalValue(lineVocal);
288295
const line: LyricLine = {
289296
id: uid(),
290297
words: [],
@@ -298,7 +305,7 @@ export function parseLyric(ttmlText: string): TTMLLyric {
298305
startTime: parsedStartTime,
299306
endTime: parsedEndTime,
300307
ignoreSync: false,
301-
vocal: lineVocal ?? "",
308+
vocal: parsedLineVocal,
302309
};
303310
let haveBg = false;
304311

@@ -353,7 +360,7 @@ export function parseLyric(ttmlText: string): TTMLLyric {
353360
true,
354361
line.isDuet,
355362
itunesKey,
356-
line.vocal ?? null,
363+
line.vocal?.length ? line.vocal : null,
357364
);
358365
haveBg = true;
359366
} else if (role === "x-translation") {

src/modules/project/logic/ttml-writer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ export default function exportTTMLText(
6161
return span;
6262
}
6363

64-
function normalizeVocalValue(vocal?: string | null): string {
64+
function normalizeVocalValue(vocal?: string | string[] | null): string {
6565
if (!vocal) return "";
66-
return vocal
67-
.split(/[\s,]+/)
66+
const parts = Array.isArray(vocal) ? vocal : vocal.split(/[\s,]+/);
67+
return parts
6868
.map((v) => v.trim())
6969
.filter(Boolean)
7070
.join(",");

src/modules/project/modals/VocalTagsEditor.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ import type { LyricLine, TTMLLyric } from "$/types/ttml";
1010
import styles from "./VocalTagsEditor.module.css";
1111

1212
const getLineText = (line: LyricLine) => line.words.map((word) => word.word).join("");
13-
const parseLineVocalIds = (value?: string) =>
14-
value
15-
? value
16-
.split(/[\s,]+/)
17-
.map((v) => v.trim())
18-
.filter(Boolean)
19-
: [];
13+
const parseLineVocalIds = (value?: string | string[]) => {
14+
if (!value) return [];
15+
const parts = Array.isArray(value) ? value : value.split(/[\s,]+/);
16+
return parts.map((v) => v.trim()).filter(Boolean);
17+
};
2018
const getNextVocalId = (ids: string[]) => {
2119
let maxId = 0;
2220
for (const id of ids) {
@@ -41,7 +39,7 @@ const hasDuplicateTag = (
4139
const reassignVocalIds = (draft: TTMLLyric) => {
4240
if (!draft.vocalTags || draft.vocalTags.length === 0) {
4341
draft.lyricLines.forEach((line) => {
44-
line.vocal = "";
42+
line.vocal = [];
4543
});
4644
return;
4745
}
@@ -56,7 +54,7 @@ const reassignVocalIds = (draft: TTMLLyric) => {
5654
const mapped = ids
5755
.map((id) => idMap.get(id))
5856
.filter((value): value is string => !!value);
59-
line.vocal = mapped.join(",");
57+
line.vocal = mapped;
6058
});
6159
};
6260

@@ -123,7 +121,7 @@ export const VocalTagsEditor = () => {
123121
onClick={() => {
124122
setLyricLines((draft) => {
125123
draft.lyricLines.forEach((line) => {
126-
line.vocal = "";
124+
line.vocal = [];
127125
});
128126
});
129127
}}
@@ -137,7 +135,7 @@ export const VocalTagsEditor = () => {
137135
setLyricLines((draft) => {
138136
draft.vocalTags = [];
139137
draft.lyricLines.forEach((line) => {
140-
line.vocal = "";
138+
line.vocal = [];
141139
});
142140
});
143141
}}

src/types/ttml.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export interface LyricLine extends AMLLLyricLine {
6161
// startTime: number;
6262
// endTime: number;
6363
ignoreSync: boolean;
64-
vocal?: string;
64+
vocal?: string | string[];
6565
}
6666

6767
export const newLyricLine = (): LyricLine => ({
@@ -74,5 +74,5 @@ export const newLyricLine = (): LyricLine => ({
7474
startTime: 0,
7575
endTime: 0,
7676
ignoreSync: false,
77-
vocal: "",
77+
vocal: [],
7878
});

0 commit comments

Comments
 (0)