lyrics-transcriber 0.57.1__py3-none-any.whl → 0.59.0__py3-none-any.whl

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,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Lyrics Transcriber Analyzer</title>
8
- <script type="module" crossorigin src="/assets/index-BEnewYea.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-HT4AHF8U.js"></script>
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -16,6 +16,7 @@ class LyricsProviderConfig:
16
16
  """Configuration for lyrics providers."""
17
17
 
18
18
  genius_api_token: Optional[str] = None
19
+ rapidapi_key: Optional[str] = None
19
20
  spotify_cookie: Optional[str] = None
20
21
  lyrics_file: Optional[str] = None
21
22
  cache_dir: Optional[str] = None
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import re
3
3
  from typing import Optional, Dict, Any
4
+ import requests
4
5
  import lyricsgenius
5
6
  from lyrics_transcriber.types import LyricsData, LyricsMetadata
6
7
  from lyrics_transcriber.lyrics.base_lyrics_provider import BaseLyricsProvider, LyricsProviderConfig
@@ -12,6 +13,7 @@ class GeniusProvider(BaseLyricsProvider):
12
13
  def __init__(self, config: LyricsProviderConfig, logger: Optional[logging.Logger] = None):
13
14
  super().__init__(config, logger)
14
15
  self.api_token = config.genius_api_token
16
+ self.rapidapi_key = config.rapidapi_key
15
17
  self.client = None
16
18
  if self.api_token:
17
19
  self.client = lyricsgenius.Genius(
@@ -25,9 +27,17 @@ class GeniusProvider(BaseLyricsProvider):
25
27
  )
26
28
 
27
29
  def _fetch_data_from_source(self, artist: str, title: str) -> Optional[Dict[str, Any]]:
28
- """Fetch raw song data from Genius API."""
30
+ """Fetch raw song data from Genius API or RapidAPI."""
31
+ # Try RapidAPI first if available
32
+ if self.rapidapi_key:
33
+ self.logger.info(f"Trying RapidAPI for {artist} - {title}")
34
+ result = self._fetch_from_rapidapi(artist, title)
35
+ if result:
36
+ return result
37
+
38
+ # Fall back to direct Genius API
29
39
  if not self.client:
30
- self.logger.warning("No Genius API token provided")
40
+ self.logger.warning("No Genius API token provided and RapidAPI failed")
31
41
  return None
32
42
 
33
43
  self.logger.info(f"Searching Genius for {artist} - {title}")
@@ -40,8 +50,186 @@ class GeniusProvider(BaseLyricsProvider):
40
50
  self.logger.error(f"Error fetching from Genius: {str(e)}")
41
51
  return None
42
52
 
53
+ def _fetch_from_rapidapi(self, artist: str, title: str) -> Optional[Dict[str, Any]]:
54
+ """Fetch song data using RapidAPI."""
55
+ try:
56
+ # Step 1: Search for the song
57
+ search_url = "https://genius-song-lyrics1.p.rapidapi.com/search/"
58
+ search_params = {
59
+ "q": f"{artist} {title}",
60
+ "per_page": "10",
61
+ "page": "1"
62
+ }
63
+
64
+ headers = {
65
+ "x-rapidapi-key": self.rapidapi_key,
66
+ "x-rapidapi-host": "genius-song-lyrics1.p.rapidapi.com"
67
+ }
68
+
69
+ self.logger.debug(f"Making RapidAPI search request for '{artist} {title}'")
70
+ search_response = requests.get(search_url, headers=headers, params=search_params, timeout=10)
71
+ search_response.raise_for_status()
72
+
73
+ search_data = search_response.json()
74
+
75
+ # Find the best match from search results
76
+ if not search_data.get("hits"):
77
+ self.logger.warning("No search results from RapidAPI")
78
+ return None
79
+
80
+ best_match = None
81
+ for hit in search_data["hits"]:
82
+ result = hit.get("result", {})
83
+ if result.get("id"):
84
+ best_match = result
85
+ break
86
+
87
+ if not best_match:
88
+ self.logger.warning("No valid song ID found in RapidAPI search results")
89
+ return None
90
+
91
+ song_id = best_match["id"]
92
+ self.logger.debug(f"Found song ID: {song_id}")
93
+
94
+ # Step 2: Fetch lyrics using the song ID
95
+ lyrics_url = "https://genius-song-lyrics1.p.rapidapi.com/song/lyrics/"
96
+ lyrics_params = {"id": str(song_id)}
97
+
98
+ self.logger.debug(f"Making RapidAPI lyrics request for song ID {song_id}")
99
+ lyrics_response = requests.get(lyrics_url, headers=headers, params=lyrics_params, timeout=10)
100
+ lyrics_response.raise_for_status()
101
+
102
+ lyrics_data = lyrics_response.json()
103
+
104
+ # Extract lyrics from the nested response structure
105
+ lyrics_text = self._extract_lyrics_from_rapidapi_response(lyrics_data)
106
+ if not lyrics_text:
107
+ self.logger.warning("No lyrics found in RapidAPI response")
108
+ return None
109
+
110
+ # Create a clean RapidAPI-only response structure
111
+ # Don't mix search metadata (which contains Genius fields) with our clean structure
112
+ rapidapi_response = {
113
+ "title": best_match.get("title", ""),
114
+ "primary_artist": best_match.get("primary_artist", {}),
115
+ "lyrics": lyrics_text,
116
+ "id": song_id,
117
+ "url": best_match.get("url", ""),
118
+ "release_date_for_display": best_match.get("release_date_for_display", ""),
119
+ # Mark this as RapidAPI source
120
+ "_rapidapi_source": True
121
+ }
122
+
123
+ self.logger.info("Successfully fetched lyrics from RapidAPI")
124
+ return rapidapi_response
125
+
126
+ except requests.exceptions.RequestException as e:
127
+ self.logger.error(f"RapidAPI request failed: {str(e)}")
128
+ return None
129
+ except Exception as e:
130
+ self.logger.error(f"Error fetching from RapidAPI: {str(e)}")
131
+ return None
132
+
133
+ def _extract_lyrics_from_rapidapi_response(self, lyrics_data: Dict[str, Any]) -> Optional[str]:
134
+ """Extract lyrics text from RapidAPI response structure."""
135
+ try:
136
+ # Log the actual response structure for debugging
137
+ self.logger.debug(f"RapidAPI response structure: {lyrics_data}")
138
+
139
+ # Try different possible response structures
140
+
141
+ # Structure 1: lyrics.lyrics.body.html (the actual RapidAPI structure)
142
+ nested_lyrics = lyrics_data.get("lyrics", {}).get("lyrics", {})
143
+ if isinstance(nested_lyrics, dict):
144
+ html_content = nested_lyrics.get("body", {}).get("html")
145
+ if html_content:
146
+ return self._clean_html_lyrics(html_content)
147
+
148
+ # Structure 2: lyrics.lyrics (simple string)
149
+ if isinstance(lyrics_data.get("lyrics", {}).get("lyrics"), str):
150
+ return lyrics_data["lyrics"]["lyrics"]
151
+
152
+ # Structure 3: lyrics.body.html (HTML content)
153
+ html_content = lyrics_data.get("lyrics", {}).get("body", {}).get("html")
154
+ if html_content:
155
+ return self._clean_html_lyrics(html_content)
156
+
157
+ # Structure 4: Direct lyrics field
158
+ if isinstance(lyrics_data.get("lyrics"), str):
159
+ return lyrics_data["lyrics"]
160
+
161
+ # Structure 5: body.html at top level
162
+ if lyrics_data.get("body", {}).get("html"):
163
+ return self._clean_html_lyrics(lyrics_data["body"]["html"])
164
+
165
+ # Structure 6: Check if lyrics is a dict with other possible keys
166
+ lyrics_obj = lyrics_data.get("lyrics", {})
167
+ if isinstance(lyrics_obj, dict):
168
+ # Try common alternative keys
169
+ for key in ["text", "content", "plain", "body"]:
170
+ if key in lyrics_obj:
171
+ content = lyrics_obj[key]
172
+ if isinstance(content, str):
173
+ return content
174
+ elif isinstance(content, dict) and "html" in content:
175
+ return self._clean_html_lyrics(content["html"])
176
+ elif isinstance(content, dict) and "text" in content:
177
+ return content["text"]
178
+
179
+ self.logger.warning(f"Unknown RapidAPI response structure: {list(lyrics_data.keys())}")
180
+ if "lyrics" in lyrics_data:
181
+ self.logger.warning(f"Lyrics object structure: {lyrics_data['lyrics']}")
182
+ return None
183
+
184
+ except Exception as e:
185
+ self.logger.error(f"Error extracting lyrics from RapidAPI response: {str(e)}")
186
+ return None
187
+
188
+ def _clean_html_lyrics(self, html_content: str) -> str:
189
+ """Clean HTML content to extract plain text lyrics."""
190
+ import re
191
+
192
+ if not html_content:
193
+ return ""
194
+
195
+ # Remove HTML tags while preserving line breaks
196
+ text = re.sub(r'<br\s*/?>', '\n', html_content) # Convert <br> to newlines
197
+ text = re.sub(r'<[^>]+>', '', text) # Remove all other HTML tags
198
+
199
+ # Decode HTML entities
200
+ text = text.replace('&lt;', '<').replace('&gt;', '>').replace('&amp;', '&')
201
+ text = text.replace('&quot;', '"').replace('&#x27;', "'").replace('&nbsp;', ' ')
202
+
203
+ # Remove section markers but keep the lyrics content
204
+ # Instead of removing entire lines, just remove the square bracket markers
205
+ text = re.sub(r'\[Verse \d+\]', '', text)
206
+ text = re.sub(r'\[Pre-Chorus\]', '', text)
207
+ text = re.sub(r'\[Chorus\]', '', text)
208
+ text = re.sub(r'\[Refrain\]', '', text)
209
+ text = re.sub(r'\[Outro\]', '', text)
210
+ text = re.sub(r'\[Bridge\]', '', text)
211
+ text = re.sub(r'\[Intro\]', '', text)
212
+
213
+ # Clean up multiple consecutive newlines
214
+ text = re.sub(r'\n\s*\n\s*\n+', '\n\n', text)
215
+
216
+ # Clean up leading/trailing whitespace
217
+ text = text.strip()
218
+
219
+ return text
220
+
43
221
  def _convert_result_format(self, raw_data: Dict[str, Any]) -> LyricsData:
44
222
  """Convert Genius's raw API response to standardized format."""
223
+ # Use our explicit source marker for detection
224
+ is_rapidapi = raw_data.get("_rapidapi_source", False)
225
+
226
+ if is_rapidapi:
227
+ return self._convert_rapidapi_format(raw_data)
228
+ else:
229
+ return self._convert_lyricsgenius_format(raw_data)
230
+
231
+ def _convert_lyricsgenius_format(self, raw_data: Dict[str, Any]) -> LyricsData:
232
+ """Convert lyricsgenius format to standardized format."""
45
233
  # Clean the lyrics before processing
46
234
  lyrics = self._clean_lyrics(raw_data.get("lyrics", ""))
47
235
 
@@ -74,6 +262,46 @@ class GeniusProvider(BaseLyricsProvider):
74
262
  "verified_annotations": len(raw_data.get("verified_annotations_by", [])),
75
263
  "verified_contributors": len(raw_data.get("verified_contributors", [])),
76
264
  "external_urls": {"genius": raw_data.get("url")},
265
+ "api_source": "lyricsgenius",
266
+ },
267
+ )
268
+
269
+ # Create segments with words from cleaned lyrics
270
+ segments = self._create_segments_with_words(lyrics, is_synced=False)
271
+
272
+ # Create result object with segments
273
+ return LyricsData(source="genius", segments=segments, metadata=metadata)
274
+
275
+ def _convert_rapidapi_format(self, raw_data: Dict[str, Any]) -> LyricsData:
276
+ """Convert RapidAPI format to standardized format."""
277
+ # Clean the lyrics before processing
278
+ lyrics = self._clean_lyrics(raw_data.get("lyrics", ""))
279
+
280
+ # Extract artist name from primary_artist
281
+ primary_artist = raw_data.get("primary_artist", {})
282
+ artist_name = primary_artist.get("name", "")
283
+
284
+ # Extract release date from release_date_for_display
285
+ release_date = raw_data.get("release_date_for_display")
286
+
287
+ # Create metadata object
288
+ metadata = LyricsMetadata(
289
+ source="genius",
290
+ track_name=raw_data.get("title", ""),
291
+ artist_names=artist_name,
292
+ album_name=raw_data.get("album", {}).get("name") if raw_data.get("album") else None,
293
+ lyrics_provider="genius",
294
+ lyrics_provider_id=str(raw_data.get("id")),
295
+ is_synced=False, # Genius doesn't provide synced lyrics
296
+ provider_metadata={
297
+ "genius_id": raw_data.get("id"),
298
+ "release_date": release_date,
299
+ "page_url": raw_data.get("url"),
300
+ "annotation_count": raw_data.get("annotation_count"),
301
+ "lyrics_state": raw_data.get("lyrics_state"),
302
+ "pyongs_count": raw_data.get("pyongs_count"),
303
+ "external_urls": {"genius": raw_data.get("url")},
304
+ "api_source": "rapidapi",
77
305
  },
78
306
  )
79
307
 
@@ -86,6 +314,19 @@ class GeniusProvider(BaseLyricsProvider):
86
314
  def _clean_lyrics(self, lyrics: str) -> str:
87
315
  """Clean and process lyrics from Genius to remove unwanted content."""
88
316
  self.logger.debug("Starting lyrics cleaning process")
317
+
318
+ # Handle unexpected input types
319
+ if not isinstance(lyrics, str):
320
+ self.logger.warning(f"Expected string for lyrics, got {type(lyrics)}: {repr(lyrics)}")
321
+ if lyrics is None:
322
+ return ""
323
+ # Try to convert to string
324
+ try:
325
+ lyrics = str(lyrics)
326
+ except Exception as e:
327
+ self.logger.error(f"Failed to convert lyrics to string: {e}")
328
+ return ""
329
+
89
330
  original = lyrics
90
331
 
91
332
  lyrics = lyrics.replace("\\n", "\n")
@@ -123,10 +364,20 @@ class GeniusProvider(BaseLyricsProvider):
123
364
  if original != lyrics:
124
365
  self.logger.debug("Removed standalone 'Embed' text")
125
366
 
367
+ # Remove section markers but keep the lyrics content (for non-HTML lyrics)
368
+ # Instead of removing entire lines, just remove the square bracket markers
126
369
  original = lyrics
127
- lyrics = re.sub(r".*?\[.*?\].*?", "", lyrics)
370
+ lyrics = re.sub(r'\[Verse \d+\]', '', lyrics)
371
+ lyrics = re.sub(r'\[Pre-Chorus\]', '', lyrics)
372
+ lyrics = re.sub(r'\[Chorus\]', '', lyrics)
373
+ lyrics = re.sub(r'\[Refrain\]', '', lyrics)
374
+ lyrics = re.sub(r'\[Outro\]', '', lyrics)
375
+ lyrics = re.sub(r'\[Bridge\]', '', lyrics)
376
+ lyrics = re.sub(r'\[Intro\]', '', lyrics)
128
377
  if original != lyrics:
129
- self.logger.debug("Removed lines containing square brackets")
378
+ self.logger.debug("Removed section markers while preserving lyrics content")
379
+
380
+ # Remove common LyricsGenius page elements
130
381
 
131
382
  self.logger.debug("Completed lyrics cleaning process")
132
383
  return lyrics
@@ -31,6 +31,7 @@ class VideoGenerator:
31
31
  self.output_dir = output_dir
32
32
  self.cache_dir = cache_dir
33
33
  self.video_resolution = video_resolution
34
+ self.styles = styles
34
35
  self.logger = logger or logging.getLogger(__name__)
35
36
 
36
37
  # Get background settings from styles, with defaults
@@ -199,6 +200,21 @@ class VideoGenerator:
199
200
  self.logger.error(f"Failed to resize background image: {e.output}")
200
201
  raise
201
202
 
203
+ def _build_ass_filter(self, ass_path: str) -> str:
204
+ """Build ASS filter with font directory support."""
205
+ ass_filter = f"ass={ass_path}"
206
+
207
+ # Get font path from styles configuration
208
+ karaoke_styles = self.styles.get("karaoke", {})
209
+ font_path = karaoke_styles.get("font_path")
210
+
211
+ if font_path and os.path.isfile(font_path):
212
+ font_dir = os.path.dirname(font_path)
213
+ ass_filter += f":fontsdir={font_dir}"
214
+ self.logger.info(f"Returning ASS filter with fonts dir: {ass_filter}")
215
+
216
+ return ass_filter
217
+
202
218
  def _build_ffmpeg_command(self, ass_path: str, audio_path: str, output_path: str) -> List[str]:
203
219
  """Build FFmpeg command for video generation with optimized settings."""
204
220
  width, height = self.video_resolution
@@ -230,11 +246,10 @@ class VideoGenerator:
230
246
  "-i", f"color=c={self.background_color}:s={width}x{height}:r=30"
231
247
  ])
232
248
 
233
- # Add audio input and subtitle overlay
234
249
  cmd.extend([
235
250
  "-i", audio_path,
236
251
  "-c:a", "flac", # Re-encode audio as FLAC
237
- "-vf", f"ass={ass_path}", # Add subtitles
252
+ "-vf", self._build_ass_filter(ass_path), # Add subtitles with font directories
238
253
  "-c:v", self._get_video_codec(),
239
254
  # Video quality settings
240
255
  "-preset", "fast", # Better compression efficiency
@@ -284,12 +299,11 @@ class VideoGenerator:
284
299
  "-i", f"color=c={self.background_color}:s={width}x{height}:r=30"
285
300
  ])
286
301
 
287
- # Add audio input and subtitle overlay
288
302
  cmd.extend([
289
303
  "-i", audio_path,
290
304
  "-c:a", "aac", # Use AAC for audio
291
305
  "-b:a", "128k", # Audio bitrate
292
- "-vf", f"ass={ass_path}", # Add subtitles
306
+ "-vf", self._build_ass_filter(ass_path), # Add subtitles with font directories
293
307
  "-c:v", "libx264", # Use H.264 codec
294
308
  "-profile:v", "baseline", # Most compatible H.264 profile
295
309
  "-level", "3.0", # Compatibility level
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lyrics-transcriber
3
- Version: 0.57.1
3
+ Version: 0.59.0
4
4
  Summary: Automatically create synchronised lyrics files in ASS and MidiCo LRC formats with word-level timestamps, using Whisper and lyrics from Genius and Spotify
5
5
  License: MIT
6
6
  Author: Andrew Beveridge
@@ -1,9 +1,9 @@
1
1
  lyrics_transcriber/__init__.py,sha256=g9ZbJg9U1qo7XzrC25J3bTKcNzzwUJWDVdi_7-hjcM4,412
2
2
  lyrics_transcriber/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- lyrics_transcriber/cli/cli_main.py,sha256=kMWoV_89KRD2XAU39Brs2rdkbQmG6OxrEn7SAh2zCTM,10648
3
+ lyrics_transcriber/cli/cli_main.py,sha256=Tk_PtZyAogsPSrmAD8KNQsPMWFW_patX2XM0EZGaVis,10752
4
4
  lyrics_transcriber/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- lyrics_transcriber/core/config.py,sha256=euwOOtuNbXy4-a1xs8QKdjcf5jXZQle0zf6X1Wthurw,1229
6
- lyrics_transcriber/core/controller.py,sha256=66qwIv-2jEW94wU5RVFRIcfrTyszC-aC_Fcx5dCjG7k,20255
5
+ lyrics_transcriber/core/config.py,sha256=G4Z5kEBMDXRscEiRKbnofAPuFTDB5h1fLJvwxaHaT4I,1268
6
+ lyrics_transcriber/core/controller.py,sha256=Hnt2QCiks3xu27NX5-xALxVaZW9lW1jqN0siq2m11ao,20313
7
7
  lyrics_transcriber/correction/anchor_sequence.py,sha256=Bz08zB8yS8orz73aA5dDyNUgBBU87KtQM6yOZGNDoFI,32228
8
8
  lyrics_transcriber/correction/corrector.py,sha256=wwSLHat4SGKEJffFQVcmSfMN_I8Drv-jpeTkO8ndLu0,20930
9
9
  lyrics_transcriber/correction/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -29,7 +29,7 @@ lyrics_transcriber/frontend/README.md,sha256=-D6CAfKTT7Y0V3EjlZ2fMy7fyctFQ4x2TJ9
29
29
  lyrics_transcriber/frontend/__init__.py,sha256=nW8acRSWTjXoRwGqcTU4w-__X7tMAE0iXL0uihBN3CU,836
30
30
  lyrics_transcriber/frontend/eslint.config.js,sha256=3ADH23ANA4NNBKFy6nCVk65e8bx1DrVd_FIaYNnhuqA,734
31
31
  lyrics_transcriber/frontend/index.html,sha256=KfqJVONzpUyPIwV73nZRiCWlwLnFWeB3z0vzxDPNudU,376
32
- lyrics_transcriber/frontend/package.json,sha256=ymT_LojRz3lHym2cts2amV_qHGUKDhjY2EyI4XXuTac,1182
32
+ lyrics_transcriber/frontend/package.json,sha256=0Ype6MfIJ7iJxzG1KKBiLRYWA6w4s-H6OE9imao7Z34,1182
33
33
  lyrics_transcriber/frontend/public/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
34
34
  lyrics_transcriber/frontend/src/App.tsx,sha256=f1-dp-MU8vap18eAXacwVDO5P4eE2iG9zSvjau-7NJs,6533
35
35
  lyrics_transcriber/frontend/src/api.ts,sha256=UgqPc1jo8DEVgxh3_9Lyf9GBsHYpqMAqsPEE5BzTV4w,6640
@@ -83,14 +83,14 @@ lyrics_transcriber/frontend/update_version.js,sha256=PxkqCnsucXnXiIqutsanVcx00Gq
83
83
  lyrics_transcriber/frontend/vite.config.d.ts,sha256=S5bdGf0pSdKM6A6RNBKwAm3EIeW_bDHYfHtesRtXU7Q,76
84
84
  lyrics_transcriber/frontend/vite.config.js,sha256=P4GuPgRZzwEWPQZpyujUe7eA3mjPoFAe2CgE5sQAXg8,232
85
85
  lyrics_transcriber/frontend/vite.config.ts,sha256=8FdW0dN8zDFqfhQSxX5h7sIu72X2piLYlp_TZYRQvBQ,216
86
- lyrics_transcriber/frontend/web_assets/assets/index-BEnewYea.js,sha256=ZnG1iyUgNqX3Gg9p4TlPYCFBc3vBmtZsLEZCwHP_QN4,1257959
87
- lyrics_transcriber/frontend/web_assets/assets/index-BEnewYea.js.map,sha256=4pt7ACRxm4ESXGPfo24LK3V_QeGJiBnwJ3P9zYFF1jA,2678465
88
- lyrics_transcriber/frontend/web_assets/index.html,sha256=iCKFH8jSOUw3Obz8mdV4OcUE8LS7H9dsttNaYVCLiQc,400
86
+ lyrics_transcriber/frontend/web_assets/assets/index-HT4AHF8U.js,sha256=nKbCXqqGWcXcfH9frPnLAqT8LUbQG7IJW79R1juuz0g,1257959
87
+ lyrics_transcriber/frontend/web_assets/assets/index-HT4AHF8U.js.map,sha256=mIQ6VHnsNXeDQn7aVn_T_KUWhqVcaSK6_NrlRFKDF-o,2678465
88
+ lyrics_transcriber/frontend/web_assets/index.html,sha256=c7kYw9N3wwGxjIjhOLCObcAkSLMt1Jp8D7RPY6xemlM,400
89
89
  lyrics_transcriber/frontend/web_assets/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
90
90
  lyrics_transcriber/frontend/yarn.lock,sha256=wtImLsCO1P1Lpkhc1jAN6IiHQ0As4xn39n0cwKoh4LM,131996
91
- lyrics_transcriber/lyrics/base_lyrics_provider.py,sha256=mqlqssKG2AofvqEU48nCwLnz0FhO9Ee6MNixF6GBnYY,9133
91
+ lyrics_transcriber/lyrics/base_lyrics_provider.py,sha256=LCzmwpBFgSfC6VVY5AtJHmE0OvgjAQyjPnL-dYLLwg4,9172
92
92
  lyrics_transcriber/lyrics/file_provider.py,sha256=WNd6mHMV2FhrnHiWBvxUxPkdVi47mbLE4hXaTYqStTM,4290
93
- lyrics_transcriber/lyrics/genius.py,sha256=SIMFEmD_QbXUB8hpDhRU7AAyVrJbRvKyTWsShA9jecE,5693
93
+ lyrics_transcriber/lyrics/genius.py,sha256=k6Q5B44ry9DpIABy9YPT1r-4dN5cqsvGyZ3TyrbulKM,17022
94
94
  lyrics_transcriber/lyrics/spotify.py,sha256=K7aL_OHdQjhI8ydnHUq8-PUvkyDu2s-et7njiLIBVgY,5457
95
95
  lyrics_transcriber/lyrics/user_input_provider.py,sha256=oNzwjk2bOQYyUXvVqPcbrF8vJU7LLtwTvJTXxtPaQto,1798
96
96
  lyrics_transcriber/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -142,7 +142,7 @@ lyrics_transcriber/output/lyrics_file.py,sha256=_KQyQjCOMIwQdQ0115uEAUIjQWTRmShk
142
142
  lyrics_transcriber/output/plain_text.py,sha256=XARaWcy6MeQeQCUoz0PV_bHoBw5dba-u79bjS7XucnE,3867
143
143
  lyrics_transcriber/output/segment_resizer.py,sha256=rrgcQC28eExSAmGnm6ytkF-E-nH4Fe3gjvpaCD0MCmA,17510
144
144
  lyrics_transcriber/output/subtitles.py,sha256=yQCR7YO3aitKnGRjfAtSwsdi6byfpEZgnCumJO16M2E,19085
145
- lyrics_transcriber/output/video.py,sha256=L_KB33YM4X-EQBRcLIPO4ZqlNEcVwqTWKjaJZVtkN-4,13751
145
+ lyrics_transcriber/output/video.py,sha256=Dk8HGyHti0w9ymubIrFF5fVGAEi6GRpFDg6ifGGE3F8,14361
146
146
  lyrics_transcriber/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  lyrics_transcriber/review/server.py,sha256=WXWyJZJsKm6_HhGxRdP2fD7kyMAmuc_I-Kvqx_uA4NI,14833
148
148
  lyrics_transcriber/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -152,8 +152,8 @@ lyrics_transcriber/transcribers/base_transcriber.py,sha256=T3m4ZCwZ9Bpv6Jvb2hNcn
152
152
  lyrics_transcriber/transcribers/whisper.py,sha256=YcCB1ic9H6zL1GS0jD0emu8-qlcH0QVEjjjYB4aLlIQ,13260
153
153
  lyrics_transcriber/types.py,sha256=wqFrTKhb8qAUB48zH-51_EEGCGrxm0Ji-ETfQumtSKc,27666
154
154
  lyrics_transcriber/utils/word_utils.py,sha256=-cMGpj9UV4F6IsoDKAV2i1aiqSO8eI91HMAm_igtVMk,958
155
- lyrics_transcriber-0.57.1.dist-info/LICENSE,sha256=81R_4XwMZDODHD7JcZeUR8IiCU8AD7Ajl6bmwR9tYDk,1074
156
- lyrics_transcriber-0.57.1.dist-info/METADATA,sha256=F9jLN9OeynKJgr2cfgO8gDMJMTTj2cOmSn_K8WK_ISU,6637
157
- lyrics_transcriber-0.57.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
158
- lyrics_transcriber-0.57.1.dist-info/entry_points.txt,sha256=kcp-bSFkCACAEA0t166Kek0HpaJUXRo5SlF5tVrqNBU,216
159
- lyrics_transcriber-0.57.1.dist-info/RECORD,,
155
+ lyrics_transcriber-0.59.0.dist-info/LICENSE,sha256=81R_4XwMZDODHD7JcZeUR8IiCU8AD7Ajl6bmwR9tYDk,1074
156
+ lyrics_transcriber-0.59.0.dist-info/METADATA,sha256=Qqo8bsJOrzonGfM9jr6Kv-6rWWWHxu7ubTijEMK8CEc,6637
157
+ lyrics_transcriber-0.59.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
158
+ lyrics_transcriber-0.59.0.dist-info/entry_points.txt,sha256=kcp-bSFkCACAEA0t166Kek0HpaJUXRo5SlF5tVrqNBU,216
159
+ lyrics_transcriber-0.59.0.dist-info/RECORD,,