@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.
@@ -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 fetch(url);
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(originalLyrics: any): Promise<any> {
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 || originalLyrics.content;
185
+ : (originalLyrics as { data?: T[]; content?: T[] }).data ||
186
+ (originalLyrics as { data?: T[]; content?: T[] }).content ||
187
+ [];
167
188
 
168
- if (!lines) return originalLyrics;
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: any) =>
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(lines: any[]): Promise<any[]> {
205
+ static async romanizeWordSynced<T extends RomanizableLine>(
206
+ lines: T[],
207
+ ): Promise<T[]> {
184
208
  return Promise.all(
185
- lines.map(async (line: any) => {
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.map((s: any) => s.text).join('');
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((s: any) => ({
201
- ...s,
202
- romanizedText: s.romanizedText, // Keep any existing syllabus romanization if provided by API natively
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(lines: any[]): Promise<any[]> {
215
- const linesToRomanize = lines.map((line: any) => {
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: any) => s.text).join('');
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: any, index: number) => ({
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 fetch(romanizeUrl);
288
+ const response = await GoogleService.fetchWithTimeout(romanizeUrl);
259
289
  const data = await response.json();
260
290
 
261
291
  // Response format is [[["...","...","...","romanization"]],...]