@uimaxbai/am-lyrics 1.1.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/demo.webp +0 -0
- package/dist/src/AmLyrics.d.ts +8 -0
- package/dist/src/AmLyrics.d.ts.map +1 -1
- package/dist/src/GoogleService.d.ts +16 -3
- package/dist/src/GoogleService.d.ts.map +1 -1
- package/dist/src/am-lyrics.js +502 -376
- package/dist/src/am-lyrics.js.map +1 -1
- package/dist/src/react.js +502 -376
- package/dist/src/react.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/AmLyrics.ts +617 -432
- package/src/GoogleService.ts +49 -19
package/src/GoogleService.ts
CHANGED
|
@@ -5,9 +5,16 @@ const CONFIG = {
|
|
|
5
5
|
GOOGLE: {
|
|
6
6
|
MAX_RETRIES: 3,
|
|
7
7
|
RETRY_DELAY_MS: 1000,
|
|
8
|
+
FETCH_TIMEOUT_MS: 6000,
|
|
8
9
|
},
|
|
9
10
|
};
|
|
10
11
|
|
|
12
|
+
interface RomanizableLine {
|
|
13
|
+
text?: { text: string; romanizedText?: string }[] | string;
|
|
14
|
+
romanizedText?: string;
|
|
15
|
+
isWordSynced?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
/**
|
|
12
19
|
* Service for translating and romanizing text using Google Translate (unofficial API)
|
|
13
20
|
*/
|
|
@@ -18,6 +25,17 @@ export class GoogleService {
|
|
|
18
25
|
});
|
|
19
26
|
}
|
|
20
27
|
|
|
28
|
+
private static fetchWithTimeout(
|
|
29
|
+
url: string,
|
|
30
|
+
timeoutMs = CONFIG.GOOGLE.FETCH_TIMEOUT_MS,
|
|
31
|
+
): Promise<Response> {
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
34
|
+
return fetch(url, { signal: controller.signal }).finally(() =>
|
|
35
|
+
clearTimeout(timeoutId),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
private static isPurelyLatinScript(text: string): boolean {
|
|
22
40
|
// Basic check for Latin script characters plus common punctuation and numbers
|
|
23
41
|
// eslint-disable-next-line no-control-regex
|
|
@@ -77,7 +95,7 @@ export class GoogleService {
|
|
|
77
95
|
try {
|
|
78
96
|
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${targetLang}&dt=t&q=${encodeURIComponent(joinedText)}`;
|
|
79
97
|
// eslint-disable-next-line no-await-in-loop
|
|
80
|
-
const response = await
|
|
98
|
+
const response = await GoogleService.fetchWithTimeout(url);
|
|
81
99
|
if (!response.ok) throw new Error(`Status ${response.status}`);
|
|
82
100
|
// eslint-disable-next-line no-await-in-loop
|
|
83
101
|
const data = await response.json();
|
|
@@ -158,18 +176,22 @@ export class GoogleService {
|
|
|
158
176
|
return isArray ? finalArray : finalArray[0];
|
|
159
177
|
}
|
|
160
178
|
|
|
161
|
-
static async romanize
|
|
179
|
+
static async romanize<T extends RomanizableLine>(
|
|
180
|
+
originalLyrics: T[] | { data?: T[]; content?: T[] },
|
|
181
|
+
): Promise<T[]> {
|
|
162
182
|
// Determine if we should treat as word-synced (has syllabus) or line-synced
|
|
163
|
-
|
|
164
|
-
const lines = Array.isArray(originalLyrics)
|
|
183
|
+
const lines: T[] = Array.isArray(originalLyrics)
|
|
165
184
|
? originalLyrics
|
|
166
|
-
: originalLyrics.data ||
|
|
185
|
+
: (originalLyrics as { data?: T[]; content?: T[] }).data ||
|
|
186
|
+
(originalLyrics as { data?: T[]; content?: T[] }).content ||
|
|
187
|
+
[];
|
|
167
188
|
|
|
168
|
-
if (!lines
|
|
189
|
+
if (!lines || lines.length === 0)
|
|
190
|
+
return Array.isArray(originalLyrics) ? originalLyrics : [];
|
|
169
191
|
|
|
170
192
|
// Check if word synced
|
|
171
193
|
const isWordSynced = lines.some(
|
|
172
|
-
(l:
|
|
194
|
+
(l: RomanizableLine) =>
|
|
173
195
|
l.isWordSynced !== false && Array.isArray(l.text) && l.text.length > 1,
|
|
174
196
|
);
|
|
175
197
|
|
|
@@ -180,9 +202,11 @@ export class GoogleService {
|
|
|
180
202
|
return this.romanizeLineSynced(lines);
|
|
181
203
|
}
|
|
182
204
|
|
|
183
|
-
static async romanizeWordSynced
|
|
205
|
+
static async romanizeWordSynced<T extends RomanizableLine>(
|
|
206
|
+
lines: T[],
|
|
207
|
+
): Promise<T[]> {
|
|
184
208
|
return Promise.all(
|
|
185
|
-
lines.map(async (line:
|
|
209
|
+
lines.map(async (line: T) => {
|
|
186
210
|
if (
|
|
187
211
|
!line.text ||
|
|
188
212
|
!Array.isArray(line.text) ||
|
|
@@ -192,15 +216,19 @@ export class GoogleService {
|
|
|
192
216
|
return line;
|
|
193
217
|
|
|
194
218
|
// Get the entire line text to romanize together for context-aware pronunciation
|
|
195
|
-
const fullText = line.text
|
|
219
|
+
const fullText = line.text
|
|
220
|
+
.map((s: { text: string }) => s.text)
|
|
221
|
+
.join('');
|
|
196
222
|
|
|
197
223
|
// romanizeTexts expects an array of strings, so we pass an array of one
|
|
198
224
|
const [romanizedFullLine] = await this.romanizeTexts([fullText]);
|
|
199
225
|
|
|
200
|
-
const newSyllabus = line.text.map(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
226
|
+
const newSyllabus = line.text.map(
|
|
227
|
+
(s: { text: string; romanizedText?: string }) => ({
|
|
228
|
+
...s,
|
|
229
|
+
romanizedText: s.romanizedText, // Keep any existing syllabus romanization if provided by API natively
|
|
230
|
+
}),
|
|
231
|
+
);
|
|
204
232
|
|
|
205
233
|
return {
|
|
206
234
|
...line,
|
|
@@ -211,22 +239,24 @@ export class GoogleService {
|
|
|
211
239
|
);
|
|
212
240
|
}
|
|
213
241
|
|
|
214
|
-
static async romanizeLineSynced
|
|
215
|
-
|
|
242
|
+
static async romanizeLineSynced<T extends RomanizableLine>(
|
|
243
|
+
lines: T[],
|
|
244
|
+
): Promise<T[]> {
|
|
245
|
+
const linesToRomanize = lines.map((line: T) => {
|
|
216
246
|
// If already romanized, skip
|
|
217
247
|
if (line.romanizedText) {
|
|
218
248
|
return '';
|
|
219
249
|
}
|
|
220
250
|
// If it's line-synced, it usually has 1 syllable with the full text.
|
|
221
251
|
if (Array.isArray(line.text) && line.text.length > 0) {
|
|
222
|
-
return line.text.map((s:
|
|
252
|
+
return line.text.map((s: { text: string }) => s.text).join('');
|
|
223
253
|
}
|
|
224
254
|
return '';
|
|
225
255
|
});
|
|
226
256
|
|
|
227
257
|
const romanizedLines = await this.romanizeTexts(linesToRomanize);
|
|
228
258
|
|
|
229
|
-
return lines.map((line:
|
|
259
|
+
return lines.map((line: T, index: number) => ({
|
|
230
260
|
...line,
|
|
231
261
|
romanizedText: romanizedLines[index] || '',
|
|
232
262
|
}));
|
|
@@ -255,7 +285,7 @@ export class GoogleService {
|
|
|
255
285
|
const romanizeUrl = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=en&dt=rm&q=${encodeURIComponent(
|
|
256
286
|
text,
|
|
257
287
|
)}`;
|
|
258
|
-
const response = await
|
|
288
|
+
const response = await GoogleService.fetchWithTimeout(romanizeUrl);
|
|
259
289
|
const data = await response.json();
|
|
260
290
|
|
|
261
291
|
// Response format is [[["...","...","...","romanization"]],...]
|