lyrics-transcriber 0.30.1__py3-none-any.whl → 0.32.1__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.
Files changed (84) hide show
  1. lyrics_transcriber/__init__.py +2 -1
  2. lyrics_transcriber/cli/cli_main.py +33 -12
  3. lyrics_transcriber/core/config.py +35 -0
  4. lyrics_transcriber/core/controller.py +85 -121
  5. lyrics_transcriber/correction/anchor_sequence.py +471 -0
  6. lyrics_transcriber/correction/corrector.py +237 -33
  7. lyrics_transcriber/correction/handlers/__init__.py +0 -0
  8. lyrics_transcriber/correction/handlers/base.py +30 -0
  9. lyrics_transcriber/correction/handlers/extend_anchor.py +91 -0
  10. lyrics_transcriber/correction/handlers/levenshtein.py +147 -0
  11. lyrics_transcriber/correction/handlers/no_space_punct_match.py +98 -0
  12. lyrics_transcriber/correction/handlers/relaxed_word_count_match.py +55 -0
  13. lyrics_transcriber/correction/handlers/repeat.py +71 -0
  14. lyrics_transcriber/correction/handlers/sound_alike.py +223 -0
  15. lyrics_transcriber/correction/handlers/syllables_match.py +182 -0
  16. lyrics_transcriber/correction/handlers/word_count_match.py +54 -0
  17. lyrics_transcriber/correction/handlers/word_operations.py +135 -0
  18. lyrics_transcriber/correction/phrase_analyzer.py +426 -0
  19. lyrics_transcriber/correction/text_utils.py +30 -0
  20. lyrics_transcriber/lyrics/base_lyrics_provider.py +5 -81
  21. lyrics_transcriber/lyrics/genius.py +5 -2
  22. lyrics_transcriber/lyrics/spotify.py +3 -3
  23. lyrics_transcriber/output/ass/__init__.py +21 -0
  24. lyrics_transcriber/output/{ass.py → ass/ass.py} +150 -690
  25. lyrics_transcriber/output/ass/ass_specs.txt +732 -0
  26. lyrics_transcriber/output/ass/config.py +37 -0
  27. lyrics_transcriber/output/ass/constants.py +23 -0
  28. lyrics_transcriber/output/ass/event.py +94 -0
  29. lyrics_transcriber/output/ass/formatters.py +132 -0
  30. lyrics_transcriber/output/ass/lyrics_line.py +219 -0
  31. lyrics_transcriber/output/ass/lyrics_screen.py +252 -0
  32. lyrics_transcriber/output/ass/section_detector.py +89 -0
  33. lyrics_transcriber/output/ass/section_screen.py +106 -0
  34. lyrics_transcriber/output/ass/style.py +187 -0
  35. lyrics_transcriber/output/cdg.py +503 -0
  36. lyrics_transcriber/output/cdgmaker/__init__.py +0 -0
  37. lyrics_transcriber/output/cdgmaker/cdg.py +262 -0
  38. lyrics_transcriber/output/cdgmaker/composer.py +1919 -0
  39. lyrics_transcriber/output/cdgmaker/config.py +151 -0
  40. lyrics_transcriber/output/cdgmaker/images/instrumental.png +0 -0
  41. lyrics_transcriber/output/cdgmaker/images/intro.png +0 -0
  42. lyrics_transcriber/output/cdgmaker/pack.py +507 -0
  43. lyrics_transcriber/output/cdgmaker/render.py +346 -0
  44. lyrics_transcriber/output/cdgmaker/transitions/centertexttoplogobottomtext.png +0 -0
  45. lyrics_transcriber/output/cdgmaker/transitions/circlein.png +0 -0
  46. lyrics_transcriber/output/cdgmaker/transitions/circleout.png +0 -0
  47. lyrics_transcriber/output/cdgmaker/transitions/fizzle.png +0 -0
  48. lyrics_transcriber/output/cdgmaker/transitions/largecentertexttoplogo.png +0 -0
  49. lyrics_transcriber/output/cdgmaker/transitions/rectangle.png +0 -0
  50. lyrics_transcriber/output/cdgmaker/transitions/spiral.png +0 -0
  51. lyrics_transcriber/output/cdgmaker/transitions/topleftmusicalnotes.png +0 -0
  52. lyrics_transcriber/output/cdgmaker/transitions/wipein.png +0 -0
  53. lyrics_transcriber/output/cdgmaker/transitions/wipeleft.png +0 -0
  54. lyrics_transcriber/output/cdgmaker/transitions/wipeout.png +0 -0
  55. lyrics_transcriber/output/cdgmaker/transitions/wiperight.png +0 -0
  56. lyrics_transcriber/output/cdgmaker/utils.py +132 -0
  57. lyrics_transcriber/output/fonts/AvenirNext-Bold.ttf +0 -0
  58. lyrics_transcriber/output/fonts/DMSans-VariableFont_opsz,wght.ttf +0 -0
  59. lyrics_transcriber/output/fonts/DMSerifDisplay-Regular.ttf +0 -0
  60. lyrics_transcriber/output/fonts/Oswald-SemiBold.ttf +0 -0
  61. lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf +0 -0
  62. lyrics_transcriber/output/fonts/arial.ttf +0 -0
  63. lyrics_transcriber/output/fonts/georgia.ttf +0 -0
  64. lyrics_transcriber/output/fonts/verdana.ttf +0 -0
  65. lyrics_transcriber/output/generator.py +101 -193
  66. lyrics_transcriber/output/lyrics_file.py +102 -0
  67. lyrics_transcriber/output/plain_text.py +91 -0
  68. lyrics_transcriber/output/segment_resizer.py +416 -0
  69. lyrics_transcriber/output/subtitles.py +328 -302
  70. lyrics_transcriber/output/video.py +219 -0
  71. lyrics_transcriber/review/__init__.py +1 -0
  72. lyrics_transcriber/review/server.py +138 -0
  73. lyrics_transcriber/transcribers/audioshake.py +3 -2
  74. lyrics_transcriber/transcribers/base_transcriber.py +5 -42
  75. lyrics_transcriber/transcribers/whisper.py +3 -4
  76. lyrics_transcriber/types.py +454 -0
  77. {lyrics_transcriber-0.30.1.dist-info → lyrics_transcriber-0.32.1.dist-info}/METADATA +14 -3
  78. lyrics_transcriber-0.32.1.dist-info/RECORD +86 -0
  79. {lyrics_transcriber-0.30.1.dist-info → lyrics_transcriber-0.32.1.dist-info}/WHEEL +1 -1
  80. {lyrics_transcriber-0.30.1.dist-info → lyrics_transcriber-0.32.1.dist-info}/entry_points.txt +1 -0
  81. lyrics_transcriber/correction/base_strategy.py +0 -29
  82. lyrics_transcriber/correction/strategy_diff.py +0 -263
  83. lyrics_transcriber-0.30.1.dist-info/RECORD +0 -25
  84. {lyrics_transcriber-0.30.1.dist-info → lyrics_transcriber-0.32.1.dist-info}/LICENSE +0 -0
@@ -1,263 +0,0 @@
1
- import logging
2
- import difflib
3
- from typing import Any, Dict, List, Optional, Set, Tuple
4
-
5
- from ..transcribers.base_transcriber import TranscriptionData, LyricsSegment, Word, TranscriptionResult
6
- from ..lyrics.base_lyrics_provider import LyricsData
7
- from .base_strategy import CorrectionResult, CorrectionStrategy
8
-
9
-
10
- class DiffBasedCorrector(CorrectionStrategy):
11
- """
12
- Implements word-diff based correction strategy using anchor words
13
- to align and correct transcribed lyrics.
14
-
15
- Key Features:
16
- - Uses multiple reference sources (internet lyrics + optional second transcription)
17
- - Preserves timing information from original transcription
18
- - Provides detailed metadata about corrections made
19
- - Falls back to original words when corrections aren't confident
20
-
21
- Potential Improvements:
22
- 1. Add phonetic matching for better word alignment (e.g., Soundex or Metaphone)
23
- 2. Implement context-aware corrections using surrounding words
24
- 3. Use more sophisticated alignment algorithms (e.g., Smith-Waterman)
25
- 4. Add validation using language models to ensure semantic consistency
26
- 5. Implement word normalization (e.g., handling contractions, punctuation)
27
- """
28
-
29
- def __init__(self, logger: Optional[logging.Logger] = None):
30
- self.logger = logger or logging.getLogger(__name__)
31
-
32
- def _find_anchor_words(self, segments: List[LyricsSegment]) -> Set[str]:
33
- """
34
- Identify potential anchor words from transcribed segments.
35
-
36
- Since we don't have confidence values, we'll use these heuristics:
37
- 1. Words that are longer (more likely to be distinctive)
38
- 2. Words that aren't common stop words
39
- 3. Words that appear multiple times in the same position
40
- """
41
- stop_words = {
42
- "a",
43
- "an",
44
- "and",
45
- "are",
46
- "as",
47
- "at",
48
- "be",
49
- "by",
50
- "for",
51
- "from",
52
- "has",
53
- "he",
54
- "in",
55
- "is",
56
- "it",
57
- "its",
58
- "of",
59
- "on",
60
- "that",
61
- "the",
62
- "to",
63
- "was",
64
- "were",
65
- "will",
66
- "with",
67
- }
68
-
69
- anchors = set()
70
- word_positions = {} # Track words and their relative positions
71
-
72
- for segment in segments:
73
- for i, word in enumerate(segment.words):
74
- word_lower = word.text.lower().strip()
75
-
76
- # Skip very short words and stop words
77
- if len(word_lower) <= 2 or word_lower in stop_words:
78
- continue
79
-
80
- # Track position of this word
81
- if word_lower not in word_positions:
82
- word_positions[word_lower] = []
83
- word_positions[word_lower].append(i)
84
-
85
- # If word appears multiple times in similar positions, it's a good anchor
86
- if len(word_positions[word_lower]) >= 2:
87
- anchors.add(word_lower)
88
-
89
- # Longer words (4+ chars) are more likely to be distinctive
90
- if len(word_lower) >= 4:
91
- anchors.add(word_lower)
92
-
93
- return anchors
94
-
95
- def _align_texts(self, source_text: str, target_text: str) -> List[Tuple[str, str]]:
96
- """
97
- Align two texts using difflib and return word pairs.
98
-
99
- Uses Python's difflib for fuzzy string matching to find the best
100
- alignment between transcribed text and reference lyrics.
101
-
102
- Returns both matching and non-matching word pairs.
103
- """
104
- # Split into words and convert to lowercase for matching
105
- source_words = source_text.lower().split()
106
- target_words = target_text.lower().split()
107
-
108
- # Use SequenceMatcher to find matching blocks
109
- matcher = difflib.SequenceMatcher(None, source_words, target_words)
110
-
111
- # Create alignment pairs for both matching and non-matching sections
112
- alignments = []
113
- i = j = 0
114
-
115
- for block in matcher.get_matching_blocks():
116
- # Add non-matching pairs before this block
117
- while i < block.a and j < block.b:
118
- alignments.append((source_words[i], target_words[j]))
119
- i += 1
120
- j += 1
121
-
122
- # Add matching pairs from this block
123
- for _ in range(block.size):
124
- alignments.append((source_words[i], target_words[j]))
125
- i += 1
126
- j += 1
127
-
128
- # Add any remaining non-matching pairs
129
- while i < len(source_words) and j < len(target_words):
130
- alignments.append((source_words[i], target_words[j]))
131
- i += 1
132
- j += 1
133
-
134
- return alignments
135
-
136
- def _create_correction_mapping(
137
- self, transcription: TranscriptionData, lyrics_results: List[LyricsData], anchor_words: Set[str]
138
- ) -> Dict[str, Dict[str, int]]:
139
- """
140
- Create a mapping of potential corrections based on aligned texts.
141
-
142
- Strategy:
143
- 1. Use anchor words to establish alignment points
144
- 2. Look at words between anchor points in both sources
145
- 3. Build frequency map of potential corrections
146
- 4. Consider timing information when available
147
- """
148
- correction_counts: Dict[str, Dict[str, int]] = {}
149
-
150
- # Get transcription text as list of words
151
- trans_words = [w.text.lower().strip() for segment in transcription.segments for w in segment.words]
152
-
153
- # Process each lyrics source
154
- for lyrics in lyrics_results:
155
- # Split lyrics into words
156
- lyrics_words = lyrics.lyrics.lower().split()
157
-
158
- # Get alignments between transcription and lyrics
159
- alignments = self._align_texts(transcription.text, lyrics.lyrics)
160
-
161
- # Process aligned word pairs
162
- for trans_word, lyrics_word in alignments:
163
- trans_word = trans_word.strip()
164
- lyrics_word = lyrics_word.strip()
165
-
166
- # Skip if words are identical
167
- if trans_word == lyrics_word:
168
- continue
169
-
170
- # Initialize correction mapping for this word if needed
171
- if trans_word not in correction_counts:
172
- correction_counts[trans_word] = {}
173
-
174
- # Count this correction
175
- correction_counts[trans_word][lyrics_word] = correction_counts[trans_word].get(lyrics_word, 0) + 1
176
-
177
- return correction_counts
178
-
179
- def correct(
180
- self,
181
- transcription_results: List[TranscriptionResult],
182
- lyrics_results: List[LyricsData],
183
- ) -> CorrectionResult:
184
- """Apply diff-based correction algorithm."""
185
- self.logger.info("Starting diff-based correction")
186
-
187
- # Sort transcription results by priority
188
- sorted_results = sorted(transcription_results, key=lambda x: x.priority)
189
- if not sorted_results:
190
- raise ValueError("No transcription results available")
191
-
192
- # Use highest priority transcription as primary source
193
- primary_transcription = sorted_results[0].result
194
-
195
- # Find anchor words from all transcriptions
196
- anchor_words = self._find_anchor_words(primary_transcription.segments)
197
- for result in sorted_results[1:]:
198
- anchor_words.update(self._find_anchor_words(result.result.segments))
199
-
200
- # Create correction mapping
201
- corrections = self._create_correction_mapping(primary_transcription, lyrics_results, anchor_words)
202
-
203
- # Apply corrections while preserving timing
204
- corrected_segments = []
205
- corrections_made = 0
206
- source_mapping = {}
207
-
208
- for segment in primary_transcription.segments:
209
- corrected_words = []
210
-
211
- for word in segment.words:
212
- word_lower = word.text.lower().strip()
213
-
214
- # Check if we have a correction for this word
215
- if word_lower in corrections:
216
- # Get the most common correction
217
- possible_corrections = corrections[word_lower]
218
- if possible_corrections:
219
- best_correction = max(possible_corrections.items(), key=lambda x: x[1])[0]
220
-
221
- # Create corrected word with preserved timing
222
- corrected_word = Word(
223
- text=best_correction,
224
- start_time=word.start_time,
225
- end_time=word.end_time,
226
- confidence=None, # We don't have confidence values
227
- )
228
- corrected_words.append(corrected_word)
229
- corrections_made += 1
230
- source_mapping[best_correction] = "internet_lyrics"
231
- continue
232
-
233
- # If no correction made, keep original word
234
- corrected_words.append(word)
235
-
236
- # Create new segment with corrected words
237
- corrected_segment = LyricsSegment(
238
- text=" ".join(w.text for w in corrected_words),
239
- words=corrected_words,
240
- start_time=segment.start_time,
241
- end_time=segment.end_time,
242
- )
243
- corrected_segments.append(corrected_segment)
244
-
245
- # Since we don't have confidence values, use a simpler metric
246
- # based on how many corrections were needed
247
- total_words = sum(len(segment.words) for segment in corrected_segments)
248
- correction_ratio = 1 - (corrections_made / total_words if total_words > 0 else 0)
249
-
250
- return CorrectionResult(
251
- segments=corrected_segments,
252
- text=" ".join(segment.text for segment in corrected_segments),
253
- confidence=correction_ratio, # Use correction ratio as confidence
254
- corrections_made=corrections_made,
255
- source_mapping=source_mapping,
256
- metadata={
257
- "correction_strategy": "diff_based",
258
- "anchor_words_count": len(anchor_words),
259
- "total_words": total_words,
260
- "correction_ratio": correction_ratio,
261
- "primary_source": sorted_results[0].name,
262
- },
263
- )
@@ -1,25 +0,0 @@
1
- lyrics_transcriber/__init__.py,sha256=Hj2HdSBAl6kmiqa5s3MDo_RobkITadzuF-81-ON3awA,180
2
- lyrics_transcriber/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- lyrics_transcriber/cli/cli_main.py,sha256=-h3W9E4P5lHEjIBWiDvY0v7avldhA-cfYoAVwMlv0Zo,8137
4
- lyrics_transcriber/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- lyrics_transcriber/core/controller.py,sha256=k_moklU2NqpHOGxWTRVyImWgX6_dv1NES0j50-FRGxw,13057
6
- lyrics_transcriber/correction/base_strategy.py,sha256=vEKsj19ZNZZkvHRP0J7cZamJWqjLZHbRJ9sN0AyHbAA,867
7
- lyrics_transcriber/correction/corrector.py,sha256=lsXJ1l5sNoZjIU65A3yWTXkOcraz7QP9KU8OUzA_UTc,2147
8
- lyrics_transcriber/correction/strategy_diff.py,sha256=xJTFnmVcuE18zZcitweVaRqB82jCMm9Ey29zAFB4LsI,10188
9
- lyrics_transcriber/lyrics/base_lyrics_provider.py,sha256=s5IDrlT6OudAA_gIlAQzeD0bPqoUFsiYftSQQm7XxOE,7518
10
- lyrics_transcriber/lyrics/genius.py,sha256=zDiv0t2f7wphnPdcyPH6tahXBfOnbE63Nu8eRG0nqg4,3195
11
- lyrics_transcriber/lyrics/spotify.py,sha256=Sic3nPFcpSWW7lE-yr3stb6D5m5WFSQXCwzWj3lW0Ls,3584
12
- lyrics_transcriber/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- lyrics_transcriber/output/ass.py,sha256=b8lnjgXGD1OD1ld_b1xxUmSOf4nSEfz9BpgSkh16R4g,90291
14
- lyrics_transcriber/output/generator.py,sha256=idUsuS01bnaIB5spDFZlxE0wsvJ2I071SmJfXO9BCCk,10870
15
- lyrics_transcriber/output/subtitles.py,sha256=JEehSPl81hxhK6cS6RK4XAC_OLentCxiMCE7UYI9B64,11851
16
- lyrics_transcriber/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- lyrics_transcriber/storage/dropbox.py,sha256=Dyam1ULTkoxD1X5trkZ5dGp5XhBGCn998moC8IS9-68,9804
18
- lyrics_transcriber/transcribers/audioshake.py,sha256=0sXvD1FJYXxISH72n5HaN9fnTxgmaQrqmY1W5Lb6Yu8,8631
19
- lyrics_transcriber/transcribers/base_transcriber.py,sha256=9XWUlBSwBCjKvz7Gs1NT7EIysMyacS-YlvDjpwlqwgI,6985
20
- lyrics_transcriber/transcribers/whisper.py,sha256=QE9Dsb6emGOaFcepJHrECjVdCfAJZRncGj7uXy-0mAk,12942
21
- lyrics_transcriber-0.30.1.dist-info/LICENSE,sha256=BiPihPDxhxIPEx6yAxVfAljD5Bhm_XG2teCbPEj_m0Y,1069
22
- lyrics_transcriber-0.30.1.dist-info/METADATA,sha256=c6P3R-KVxCJ10m-92bezeetdztdB7vvv5RMlTnF4Xbg,5485
23
- lyrics_transcriber-0.30.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
24
- lyrics_transcriber-0.30.1.dist-info/entry_points.txt,sha256=KHZMIwodpv7TQUN9z28G-0knEFsRta9ZBAcIbmBAT40,75
25
- lyrics_transcriber-0.30.1.dist-info/RECORD,,