lyrics-transcriber 0.34.2__py3-none-any.whl → 0.35.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.
Files changed (39) hide show
  1. lyrics_transcriber/core/controller.py +10 -1
  2. lyrics_transcriber/correction/corrector.py +4 -3
  3. lyrics_transcriber/frontend/dist/assets/index-CQCER5Fo.js +181 -0
  4. lyrics_transcriber/frontend/dist/index.html +1 -1
  5. lyrics_transcriber/frontend/src/App.tsx +6 -2
  6. lyrics_transcriber/frontend/src/api.ts +9 -0
  7. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +155 -0
  8. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +1 -1
  9. lyrics_transcriber/frontend/src/components/DetailsModal.tsx +23 -191
  10. lyrics_transcriber/frontend/src/components/EditModal.tsx +407 -0
  11. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +255 -221
  12. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +39 -0
  13. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +35 -264
  14. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +232 -0
  15. lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +64 -0
  16. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +315 -0
  17. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +116 -138
  18. lyrics_transcriber/frontend/src/components/WordEditControls.tsx +116 -0
  19. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +243 -0
  20. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +28 -0
  21. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +52 -0
  22. lyrics_transcriber/frontend/src/components/{constants.ts → shared/constants.ts} +1 -0
  23. lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +137 -0
  24. lyrics_transcriber/frontend/src/components/{styles.ts → shared/styles.ts} +1 -1
  25. lyrics_transcriber/frontend/src/components/shared/types.ts +99 -0
  26. lyrics_transcriber/frontend/src/components/shared/utils/newlineCalculator.ts +37 -0
  27. lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +76 -0
  28. lyrics_transcriber/frontend/src/types.ts +2 -43
  29. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
  30. lyrics_transcriber/lyrics/spotify.py +11 -0
  31. lyrics_transcriber/output/generator.py +28 -11
  32. lyrics_transcriber/review/server.py +38 -12
  33. {lyrics_transcriber-0.34.2.dist-info → lyrics_transcriber-0.35.0.dist-info}/METADATA +1 -1
  34. {lyrics_transcriber-0.34.2.dist-info → lyrics_transcriber-0.35.0.dist-info}/RECORD +37 -24
  35. lyrics_transcriber/frontend/dist/assets/index-DqFgiUni.js +0 -245
  36. lyrics_transcriber/frontend/src/components/DebugPanel.tsx +0 -311
  37. {lyrics_transcriber-0.34.2.dist-info → lyrics_transcriber-0.35.0.dist-info}/LICENSE +0 -0
  38. {lyrics_transcriber-0.34.2.dist-info → lyrics_transcriber-0.35.0.dist-info}/WHEEL +0 -0
  39. {lyrics_transcriber-0.34.2.dist-info → lyrics_transcriber-0.35.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,37 @@
1
+ import { LyricsData, LyricsSegment } from '../../../types'
2
+
3
+ export function calculateNewlineIndices(
4
+ corrected_segments: LyricsSegment[],
5
+ anchors: LyricsData['anchor_sequences'],
6
+ currentSource: 'genius' | 'spotify'
7
+ ): Set<number> {
8
+ return new Set(
9
+ corrected_segments.slice(0, -1).map((segment, segmentIndex) => {
10
+ const segmentText = segment.text.trim()
11
+ const segmentWords = segmentText.split(/\s+/)
12
+ const segmentStartWord = corrected_segments
13
+ .slice(0, segmentIndex)
14
+ .reduce((acc, s) => acc + s.text.trim().split(/\s+/).length, 0)
15
+ const lastWordPosition = segmentStartWord + segmentWords.length - 1
16
+
17
+ const matchingAnchor = anchors.find(a => {
18
+ const start = a.transcription_position
19
+ const end = start + a.length - 1
20
+ return lastWordPosition >= start && lastWordPosition <= end
21
+ })
22
+
23
+ if (matchingAnchor?.reference_positions[currentSource] !== undefined) {
24
+ const anchorWords = matchingAnchor.words
25
+ const wordIndex = anchorWords.findIndex(w =>
26
+ w.toLowerCase() === segmentWords[segmentWords.length - 1].toLowerCase()
27
+ )
28
+
29
+ if (wordIndex !== -1) {
30
+ return matchingAnchor.reference_positions[currentSource] + wordIndex
31
+ }
32
+ }
33
+
34
+ return null
35
+ }).filter((pos): pos is number => pos !== null && pos >= 0)
36
+ )
37
+ }
@@ -0,0 +1,76 @@
1
+ import { LyricsData, LyricsSegment } from '../../../types'
2
+ import { LinePosition } from '../types'
3
+
4
+ export function calculateReferenceLinePositions(
5
+ corrected_segments: LyricsSegment[],
6
+ anchors: LyricsData['anchor_sequences'],
7
+ currentSource: 'genius' | 'spotify'
8
+ ): { linePositions: LinePosition[] } {
9
+ const linePositions: LinePosition[] = []
10
+ let currentReferencePosition = 0
11
+
12
+ // First, find all anchor sequences that cover entire lines
13
+ const fullLineAnchors = anchors.map(anchor => {
14
+ const referencePos = anchor.reference_positions[currentSource]
15
+ if (referencePos === undefined) return null
16
+
17
+ return {
18
+ referenceStart: referencePos,
19
+ referenceLength: anchor.length,
20
+ transcriptionLine: corrected_segments.findIndex((segment, segmentIndex) => {
21
+ const words = segment.words
22
+ if (!words.length) return false
23
+
24
+ // Calculate the absolute position of the first and last words in this segment
25
+ let absolutePosition = 0
26
+ for (let i = 0; i < segmentIndex; i++) {
27
+ absolutePosition += corrected_segments[i].words.length
28
+ }
29
+
30
+ const firstWordPosition = absolutePosition
31
+ const lastWordPosition = absolutePosition + words.length - 1
32
+
33
+ return firstWordPosition >= anchor.transcription_position &&
34
+ lastWordPosition < anchor.transcription_position + anchor.length
35
+ })
36
+ }
37
+ }).filter((a): a is NonNullable<typeof a> => a !== null)
38
+
39
+ // Sort by reference position to process in order
40
+ fullLineAnchors.sort((a, b) => a.referenceStart - b.referenceStart)
41
+
42
+ // Add line positions with padding
43
+ let currentLine = 0
44
+ fullLineAnchors.forEach(anchor => {
45
+ // Add empty lines if needed to match transcription line number
46
+ while (currentLine < anchor.transcriptionLine) {
47
+ linePositions.push({
48
+ position: currentReferencePosition,
49
+ lineNumber: currentLine,
50
+ isEmpty: false
51
+ })
52
+ currentReferencePosition += 1
53
+ currentLine++
54
+ }
55
+
56
+ // Add the actual line position
57
+ linePositions.push({
58
+ position: anchor.referenceStart,
59
+ lineNumber: currentLine
60
+ })
61
+ currentLine++
62
+ })
63
+
64
+ // Add any remaining lines after the last anchor
65
+ while (currentLine < corrected_segments.length) {
66
+ linePositions.push({
67
+ position: currentReferencePosition,
68
+ lineNumber: currentLine,
69
+ isEmpty: false
70
+ })
71
+ currentReferencePosition += 1
72
+ currentLine++
73
+ }
74
+
75
+ return { linePositions }
76
+ }
@@ -89,7 +89,7 @@ export interface CorrectionData {
89
89
  reference_texts: Record<string, string>
90
90
  anchor_sequences: AnchorSequence[]
91
91
  gap_sequences: GapSequence[]
92
- resized_segments: LyricsSegment[]
92
+ resized_segments?: LyricsSegment[]
93
93
  corrected_text: string
94
94
  corrections_made: number
95
95
  confidence: number
@@ -114,45 +114,4 @@ export interface HighlightInfo {
114
114
  type: 'single' | 'gap' | 'anchor'
115
115
  }
116
116
 
117
- export interface AnchorMatchInfo {
118
- segment: string
119
- lastWord: string
120
- normalizedLastWord: string
121
- overlappingAnchors: Array<{
122
- text: string
123
- range: [number, number]
124
- words: string[]
125
- hasMatchingWord: boolean
126
- }>
127
- matchingGap: {
128
- text: string
129
- position: number
130
- length: number
131
- corrections: Array<{
132
- word: string
133
- referencePosition: number | undefined
134
- }>
135
- followingAnchor: {
136
- text: string
137
- position: number | undefined
138
- } | null
139
- } | null
140
- highlightDebug?: Array<{
141
- wordIndex: number
142
- refPos: number | undefined
143
- highlightPos: number | undefined
144
- anchorLength: number
145
- isInRange: boolean
146
- }>
147
- wordPositionDebug?: {
148
- anchorWords: string[]
149
- wordIndex: number
150
- referencePosition: number
151
- finalPosition: number
152
- normalizedWords: {
153
- anchor: string
154
- segment: string
155
- }
156
- }
157
- debugLog?: string[]
158
- }
117
+ export type InteractionMode = 'highlight' | 'details' | 'edit'
@@ -1 +1 @@
1
- {"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/correctionmetrics.tsx","./src/components/debugpanel.tsx","./src/components/detailsmodal.tsx","./src/components/fileupload.tsx","./src/components/lyricsanalyzer.tsx","./src/components/referenceview.tsx","./src/components/transcriptionview.tsx","./src/components/constants.ts","./src/components/styles.ts"],"version":"5.6.3"}
1
+ {"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/audioplayer.tsx","./src/components/correctionmetrics.tsx","./src/components/detailsmodal.tsx","./src/components/editmodal.tsx","./src/components/fileupload.tsx","./src/components/lyricsanalyzer.tsx","./src/components/modeselector.tsx","./src/components/referenceview.tsx","./src/components/reviewchangesmodal.tsx","./src/components/segmentdetailsmodal.tsx","./src/components/timelineeditor.tsx","./src/components/transcriptionview.tsx","./src/components/wordeditcontrols.tsx","./src/components/shared/constants.ts","./src/components/shared/styles.ts","./src/components/shared/types.ts","./src/components/shared/components/highlightedtext.tsx","./src/components/shared/components/sourceselector.tsx","./src/components/shared/components/word.tsx","./src/components/shared/hooks/usewordclick.ts","./src/components/shared/utils/newlinecalculator.ts","./src/components/shared/utils/referencelinecalculator.ts"],"version":"5.6.3"}
@@ -51,6 +51,10 @@ class SpotifyProvider(BaseLyricsProvider):
51
51
  if not line.get("words"):
52
52
  continue
53
53
 
54
+ # Skip lines that are just musical notes
55
+ if not self._clean_lyrics(line["words"]):
56
+ continue
57
+
54
58
  segment = LyricsSegment(
55
59
  text=line["words"],
56
60
  words=[], # TODO: Could potentially split words if needed
@@ -80,3 +84,10 @@ class SpotifyProvider(BaseLyricsProvider):
80
84
  )
81
85
 
82
86
  return LyricsData(source="spotify", lyrics="\n".join(segment.text for segment in segments), segments=segments, metadata=metadata)
87
+
88
+ def _clean_lyrics(self, lyrics: str) -> str:
89
+ """Clean and process lyrics from Spotify to remove unwanted content."""
90
+ # Remove lines that contain only musical note symbols
91
+ if lyrics.strip() == "♪":
92
+ return ""
93
+ return lyrics
@@ -154,17 +154,34 @@ class OutputGenerator:
154
154
 
155
155
  def _get_video_params(self, resolution: str) -> tuple:
156
156
  """Get video parameters: (width, height), font_size, line_height based on video resolution config."""
157
- match resolution:
158
- case "4k":
159
- return (3840, 2160), 250, 250
160
- case "1080p":
161
- return (1920, 1080), 120, 120
162
- case "720p":
163
- return (1280, 720), 100, 100
164
- case "360p":
165
- return (640, 360), 40, 50
166
- case _:
167
- raise ValueError("Invalid video_resolution value. Must be one of: 4k, 1080p, 720p, 360p")
157
+ # Get resolution dimensions
158
+ resolution_map = {
159
+ "4k": (3840, 2160),
160
+ "1080p": (1920, 1080),
161
+ "720p": (1280, 720),
162
+ "360p": (640, 360),
163
+ }
164
+
165
+ if resolution not in resolution_map:
166
+ raise ValueError("Invalid video_resolution value. Must be one of: 4k, 1080p, 720p, 360p")
167
+
168
+ resolution_dims = resolution_map[resolution]
169
+
170
+ # Default font sizes for each resolution
171
+ default_font_sizes = {
172
+ "4k": 250,
173
+ "1080p": 120,
174
+ "720p": 100,
175
+ "360p": 40,
176
+ }
177
+
178
+ # Get font size from styles if available, otherwise use default
179
+ font_size = self.config.styles.get("karaoke", {}).get("font_size", default_font_sizes[resolution])
180
+
181
+ # Line height matches font size for all except 360p
182
+ line_height = 50 if resolution == "360p" else font_size
183
+
184
+ return resolution_dims, font_size, line_height
168
185
 
169
186
  def write_corrections_data(self, correction_result: CorrectionResult, output_prefix: str) -> str:
170
187
  """Write corrections data to JSON file."""
@@ -9,6 +9,8 @@ import os
9
9
  import atexit
10
10
  import urllib.parse
11
11
  from fastapi.staticfiles import StaticFiles
12
+ from fastapi.responses import FileResponse
13
+ from pathlib import Path
12
14
 
13
15
  logger = logging.getLogger(__name__)
14
16
 
@@ -27,22 +29,23 @@ app.add_middleware(
27
29
  current_review: Optional[CorrectionResult] = None
28
30
  review_completed = False
29
31
  vite_process: Optional[subprocess.Popen] = None
32
+ audio_filepath: Optional[str] = None # Add this new global variable
30
33
 
31
34
 
32
35
  def start_vite_server():
33
36
  """Get path to the built frontend assets."""
34
37
  global vite_process # We'll keep this for backwards compatibility
35
-
38
+
36
39
  # Get the path to the built frontend assets
37
40
  current_dir = os.path.dirname(os.path.abspath(__file__))
38
41
  frontend_dir = os.path.abspath(os.path.join(current_dir, "../frontend/dist"))
39
-
42
+
40
43
  if not os.path.exists(frontend_dir):
41
44
  raise FileNotFoundError(f"Frontend assets not found at {frontend_dir}. Ensure the package was built correctly.")
42
-
45
+
43
46
  # Mount the static files
44
47
  app.mount("/", StaticFiles(directory=frontend_dir, html=True), name="frontend")
45
-
48
+
46
49
  logger.info(f"Mounted frontend assets from {frontend_dir}")
47
50
  return None # No process to return since we're serving static files
48
51
 
@@ -86,6 +89,20 @@ async def complete_review(updated_data: Dict[str, Any] = Body(...)):
86
89
  return {"status": "error", "message": str(e)}
87
90
 
88
91
 
92
+ @app.get("/api/audio")
93
+ async def get_audio():
94
+ """Stream the audio file for playback in the browser."""
95
+ if not audio_filepath or not os.path.exists(audio_filepath):
96
+ logger.error(f"Audio file not found at {audio_filepath}")
97
+ return {"error": "Audio file not found"}
98
+
99
+ return FileResponse(
100
+ audio_filepath,
101
+ media_type="audio/mpeg",
102
+ headers={"Accept-Ranges": "bytes", "Content-Disposition": f"attachment; filename={Path(audio_filepath).name}"},
103
+ )
104
+
105
+
89
106
  def start_review_server(correction_result: CorrectionResult) -> CorrectionResult:
90
107
  """
91
108
  Start the review server and wait for completion.
@@ -99,35 +116,44 @@ def start_review_server(correction_result: CorrectionResult) -> CorrectionResult
99
116
  import uvicorn
100
117
  import webbrowser
101
118
  from threading import Thread
119
+ import signal
120
+ import sys
102
121
 
103
- global current_review, review_completed
122
+ global current_review, review_completed, audio_filepath # Add audio_filepath to globals
104
123
  current_review = correction_result
105
124
  review_completed = False
106
125
 
126
+ # Get the audio filepath from the correction result's metadata if available
127
+ audio_filepath = correction_result.metadata.get("audio_filepath") if correction_result.metadata else None
128
+
107
129
  logger.info("Starting review server...")
108
130
 
109
131
  # Start Vite dev server (now just mounts static files)
110
132
  start_vite_server()
111
133
  logger.info("Frontend assets mounted")
112
134
 
135
+ # Create a custom server config
136
+ config = uvicorn.Config(app, host="127.0.0.1", port=8000, log_level="info")
137
+ server = uvicorn.Server(config)
138
+
113
139
  # Start FastAPI server in a separate thread
114
- server_thread = Thread(target=uvicorn.run, args=(app,), kwargs={"host": "127.0.0.1", "port": 8000, "log_level": "info"}, daemon=True)
140
+ server_thread = Thread(target=server.run, daemon=True)
115
141
  server_thread.start()
116
142
  logger.info("Server thread started")
117
143
 
118
- # Open browser
144
+ # Open browser - Updated to use port 8000 instead of 5173
119
145
  base_api_url = "http://localhost:8000/api"
120
146
  encoded_api_url = urllib.parse.quote(base_api_url, safe="")
121
- webbrowser.open(f"http://localhost:5173?baseApiUrl={encoded_api_url}")
147
+ webbrowser.open(f"http://localhost:8000?baseApiUrl={encoded_api_url}")
122
148
  logger.info("Opened browser for review")
123
149
 
124
150
  # Wait for review to complete
125
151
  start_time = time.time()
126
152
  while not review_completed:
127
153
  time.sleep(0.1)
128
- # if time.time() - start_time > 600: # 10 minute timeout
129
- # logger.error("Review timed out after 10 minutes")
130
- # raise TimeoutError("Review did not complete within the expected time frame.")
131
154
 
132
- logger.info("Review completed, returning results")
155
+ logger.info("Review completed, shutting down server...")
156
+ server.should_exit = True
157
+ server_thread.join(timeout=5) # Wait up to 5 seconds for server to shut down
158
+
133
159
  return current_review
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lyrics-transcriber
3
- Version: 0.34.2
3
+ Version: 0.35.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
@@ -3,9 +3,9 @@ lyrics_transcriber/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
3
3
  lyrics_transcriber/cli/cli_main.py,sha256=TFB7CwzgLuwPfoV7ggPPe5dh4WKNcWRoZkCu_WWUcLQ,9818
4
4
  lyrics_transcriber/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  lyrics_transcriber/core/config.py,sha256=y6MsAL0gFz7zRErtRRF81Z0vFOrySIrCw2aKDHExBz8,1160
6
- lyrics_transcriber/core/controller.py,sha256=o3nGoNWFGbeXAKtqbWFArede1UNmCip8U1bn8viVlwo,17493
6
+ lyrics_transcriber/core/controller.py,sha256=iLDbMcn1BD1bTBiT9JDTBlLXs-2Frex-I_CKig3gdqk,17844
7
7
  lyrics_transcriber/correction/anchor_sequence.py,sha256=YpKyY24Va5i4JgzP9ssqlOIkaYu060KaldiehbfgTdk,22200
8
- lyrics_transcriber/correction/corrector.py,sha256=SFEmueWtTUipztVDaV8yTDsKp8XMHBZcZ343Z5NHSLE,13303
8
+ lyrics_transcriber/correction/corrector.py,sha256=RVANu99cX-fmgr70C5aKZKjNOnu8o8NyJVqQ1wRGUqo,13342
9
9
  lyrics_transcriber/correction/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  lyrics_transcriber/correction/handlers/base.py,sha256=Vanmp6ykP5cdejuJ5ttzjP0Wl4JgKBL-mHbo9EFaeVc,1009
11
11
  lyrics_transcriber/correction/handlers/extend_anchor.py,sha256=9rBrZPmc4grMSnCL2ilkcBsWHc05s6RBL9GDyNAplJk,3821
@@ -21,38 +21,51 @@ lyrics_transcriber/correction/phrase_analyzer.py,sha256=dtO_2LjxnPdHJM7De40mYIdH
21
21
  lyrics_transcriber/correction/text_utils.py,sha256=VkOqgZHa9wEqLJdVNi4-KLFojQ6d4lWOGl_Y_vknenU,808
22
22
  lyrics_transcriber/frontend/.gitignore,sha256=lgGIPiVpFVUNSZl9oNQLelLOWUzpF7sikLW8xmsrrqI,248
23
23
  lyrics_transcriber/frontend/README.md,sha256=-D6CAfKTT7Y0V3EjlZ2fMy7fyctFQ4x2TJ9vx6xtccM,1607
24
- lyrics_transcriber/frontend/dist/assets/index-DqFgiUni.js,sha256=YlG1ioU-k-u1Hr6oW5O8bgvarAOtOcU7aEJXYvff3wU,385299
25
- lyrics_transcriber/frontend/dist/index.html,sha256=z35rcF7ZGMM-Fg_47tsylI_WILbh-_ZJF3LNsb4NQqU,400
24
+ lyrics_transcriber/frontend/dist/assets/index-CQCER5Fo.js,sha256=cNVRhdGBCEh8WhvstqPAV2f1W34hR8qNSzUJ-NvJ0aw,424046
25
+ lyrics_transcriber/frontend/dist/index.html,sha256=aicpama1D98ChWrPgrngwqBFhH03Mnx33SWB8jacE9I,400
26
26
  lyrics_transcriber/frontend/dist/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
27
27
  lyrics_transcriber/frontend/eslint.config.js,sha256=3ADH23ANA4NNBKFy6nCVk65e8bx1DrVd_FIaYNnhuqA,734
28
28
  lyrics_transcriber/frontend/index.html,sha256=KfqJVONzpUyPIwV73nZRiCWlwLnFWeB3z0vzxDPNudU,376
29
29
  lyrics_transcriber/frontend/package-lock.json,sha256=-VEaxgVZhB6rbaxiZPy3_qGsMuVlSYxZZg-K3mvhS4A,149189
30
30
  lyrics_transcriber/frontend/package.json,sha256=7WBOIcjE3T8bg9GpJWziPYyhTe724AFnHJOtJi-XCpY,1006
31
31
  lyrics_transcriber/frontend/public/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
32
- lyrics_transcriber/frontend/src/App.tsx,sha256=7160hv2mRVzBTkr7c9bxt4sKEBVexqMQXxLqHl_nrQ0,5942
33
- lyrics_transcriber/frontend/src/api.ts,sha256=grunhu6O_qjo5ohECSTPHQDl4eD3YlsHh6smt19E1AE,1889
34
- lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx,sha256=hYBywAhwY8HkRCBYiT3TQw2tJos7DFLqpRZuPEnOVbg,5335
35
- lyrics_transcriber/frontend/src/components/DebugPanel.tsx,sha256=g1TCRax6XiBgAUGb7_ahjtSUyO0yZ-ZRMxkn2oSIGiQ,15155
36
- lyrics_transcriber/frontend/src/components/DetailsModal.tsx,sha256=5WxBYcdxHl3gXHfdX6ImwwlVXu8UMzPJ-pbckz7vFtg,12664
32
+ lyrics_transcriber/frontend/src/App.tsx,sha256=yUsB9SZvOar0PKBMzmgfbJHv6fJW2mXdBExUZYgSaWY,6035
33
+ lyrics_transcriber/frontend/src/api.ts,sha256=ORzQqlEKkFYrc78qFbOCNsSP6zW_vN2PFT_IiEwiiao,2089
34
+ lyrics_transcriber/frontend/src/components/AudioPlayer.tsx,sha256=v_UBNwIBoll20z7-_yItibIhucpDPaJg6ePZF2Q62d4,4343
35
+ lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx,sha256=Bp8h_x7dOq9lo2lDwj9f6Zf_lE04b6L2169YPUCKup0,5342
36
+ lyrics_transcriber/frontend/src/components/DetailsModal.tsx,sha256=bQmrsneXiMD7ecEAbV_bD8_ZDQaxyV7KGpP5j999k1I,3917
37
+ lyrics_transcriber/frontend/src/components/EditModal.tsx,sha256=m15ahAgWfLqz2q9qyAiFQfNCv3bNH1d2dZbPNE9sJWE,14941
37
38
  lyrics_transcriber/frontend/src/components/FileUpload.tsx,sha256=Q_Y2YvlVGJvucdoDBbbI2pzymycWAprrc7vtSEGuIHs,2375
38
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=DfcdGX593nogI70opQodEj7HwBII-h9IOW-edFlMQ8E,18827
39
- lyrics_transcriber/frontend/src/components/ReferenceView.tsx,sha256=-S-m53IOgeh9qb_lIsNslNNt99gSvVj7DwuwBD7-S-4,11903
40
- lyrics_transcriber/frontend/src/components/TranscriptionView.tsx,sha256=IBK64z6GLbIIfDm6mhWOeKn-vEOPnErV6mgjRUz4OlM,5895
41
- lyrics_transcriber/frontend/src/components/constants.ts,sha256=x45nkGUNzykJEGVNzsyaDBeMuF_nGz4qk5SW0QrbWlk,456
42
- lyrics_transcriber/frontend/src/components/styles.ts,sha256=nWthPdUbz4cHbUL0LjDe-IeNs92KLev9OMsosZWa3Kc,411
39
+ lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=mXZhfK5Us7HLv0jspT9Z5l9P0L2EfyPf3kAN0VmVxus,19173
40
+ lyrics_transcriber/frontend/src/components/ModeSelector.tsx,sha256=bHtjmj5DQx2CwkdL5A4fgLP3XEifu-QecPsMZVdMTmU,1422
41
+ lyrics_transcriber/frontend/src/components/ReferenceView.tsx,sha256=VgeGhDlcO1bqKSU8gBH_d3MBO2_Z50J_kh7iG8QACoM,1941
42
+ lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx,sha256=LokjuN0ukt6ao_ClWX3PCeQlV19V2hvEAWF0SPHzG3M,8974
43
+ lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx,sha256=6ME02FkFwCgDAxW49yW260N4vbr80eAJ332Ex811GOo,1643
44
+ lyrics_transcriber/frontend/src/components/TimelineEditor.tsx,sha256=FABlfssDFKubdFmeEAv4VbvxnxugdlG8jswAUXOqfRQ,11025
45
+ lyrics_transcriber/frontend/src/components/TranscriptionView.tsx,sha256=Zw909OCLJbUCpEOD5N2ts0nLz1oC9nXJhizdGmw8qHk,5486
46
+ lyrics_transcriber/frontend/src/components/WordEditControls.tsx,sha256=5mMztxoYhHwn6cUhLBcBis7fA21h03tlt-U3-9yytO0,3369
47
+ lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx,sha256=hqdJI5zL2JuJgHSQ1IsrDwR_4oZQU4TIGR7PXkGTDKk,10713
48
+ lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx,sha256=f4PZ-XEhGvp4rZAaST_AhkZRDlVkWipYtM0_2ZhSN3c,842
49
+ lyrics_transcriber/frontend/src/components/shared/components/Word.tsx,sha256=xed50sPTI4edKp5fwz9vLyBqTNOU4MbhTe-NEApS3JI,1324
50
+ lyrics_transcriber/frontend/src/components/shared/constants.ts,sha256=25q1qjCwzV-hR72wSb_rJSe4dVuQ0l-piLMoZSpynGQ,488
51
+ lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts,sha256=pgaAC_rhzGS1ppXzmcQ9IH9PSZPcQo1lJJqOJ9OqWjM,5447
52
+ lyrics_transcriber/frontend/src/components/shared/styles.ts,sha256=J1jCSuRqpk1mOFYAqJudhxeozH-q1bi-dsOibLukBJU,411
53
+ lyrics_transcriber/frontend/src/components/shared/types.ts,sha256=AeNIhKUZu9sHhOClDUaBgo1myixLjpkikbuky29UCw4,2928
54
+ lyrics_transcriber/frontend/src/components/shared/utils/newlineCalculator.ts,sha256=vhOP-VS7H_NIK3JSpN_yPjy6qcJqZoA6eDWopOCWB2c,1530
55
+ lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts,sha256=vzXdLDlQ1hKWfco1RB6aLztbjBg1BXL6gend34qXKd4,2753
43
56
  lyrics_transcriber/frontend/src/main.tsx,sha256=gKJOIr1laz68BhgxWz0JXb1LNacA2oxfbypxW_B1USo,139
44
- lyrics_transcriber/frontend/src/types.ts,sha256=nT1-xAmDmXTT1uh69e0tS6nPa1cyyly2VfleiOH71II,3822
57
+ lyrics_transcriber/frontend/src/types.ts,sha256=yv4A8AamI9VPXGqNi7rH6vdUZdDiUhTJsO2016e4u8s,2840
45
58
  lyrics_transcriber/frontend/src/vite-env.d.ts,sha256=ZZlpNvuwQpFfe3SiAPzd5-QQ8ypmmxq5WXz6pLD63bU,38
46
59
  lyrics_transcriber/frontend/tsconfig.app.json,sha256=7aUBVcaBqEtmtfQXsbwsgBxSUng06xzQi5t4QCgWQ3E,665
47
60
  lyrics_transcriber/frontend/tsconfig.json,sha256=AOS5v1AsNPL3wGc8bt58Ybh8HHpbYrlK91q0KIzaSgs,627
48
61
  lyrics_transcriber/frontend/tsconfig.node.json,sha256=oMBhK5xufBrVE7SkbADRxA3pxm8_L9m5YwtCOZSafsc,536
49
- lyrics_transcriber/frontend/tsconfig.tsbuildinfo,sha256=ECcqHaEztFfmI_wXvNu9BufuHvdLAA82k7bhl_DyyAw,437
62
+ lyrics_transcriber/frontend/tsconfig.tsbuildinfo,sha256=NR-Uu3EJ34W4mGOQJT-Vkp_XHVwJxSxh6kIPWCAdH4w,1038
50
63
  lyrics_transcriber/frontend/vite.config.d.ts,sha256=S5bdGf0pSdKM6A6RNBKwAm3EIeW_bDHYfHtesRtXU7Q,76
51
64
  lyrics_transcriber/frontend/vite.config.js,sha256=rJsgKgeHdZ3lUbab4NaNcxVsiUmmtTQee4iPweN5Ktc,165
52
65
  lyrics_transcriber/frontend/vite.config.ts,sha256=TTbbNSKnst0Q4JNuEAQ3PH7mXxD3zXkgzXZBBFnBWkU,161
53
66
  lyrics_transcriber/lyrics/base_lyrics_provider.py,sha256=l61XJCvazt7wb6_vIQ23N8x9Otane8Pac5nvnBVCig8,6563
54
67
  lyrics_transcriber/lyrics/genius.py,sha256=x8dNOygrDRZgwK0v2qK6F6wmqGEIiXe_Edgx-IkNWHA,5003
55
- lyrics_transcriber/lyrics/spotify.py,sha256=9n4n98xS_BrpTPZg-24n0mzyPk9vkdmhy6T8ei8imh4,3599
68
+ lyrics_transcriber/lyrics/spotify.py,sha256=8Abxc7B_1eGPOCHDJ-zVAdhWRvz0nls9LipD7L4fhV8,4004
56
69
  lyrics_transcriber/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
70
  lyrics_transcriber/output/ass/__init__.py,sha256=EYQ45gI7_-vclVgzISL0ML8VgxCdB0odqEyPyiPCIw0,578
58
71
  lyrics_transcriber/output/ass/ass.py,sha256=xHId7Rv5gqmdQ7ZrWQSy46JX7vZcB_BzpZC800DwQk8,74315
@@ -96,22 +109,22 @@ lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf,sha256=WNG5LOQ-uGUF_WWT5aQ
96
109
  lyrics_transcriber/output/fonts/arial.ttf,sha256=NcDzVZ2NtWnjbDEJW4pg1EFkPZX1kTneQOI_ragZuDM,275572
97
110
  lyrics_transcriber/output/fonts/georgia.ttf,sha256=fQuyDGMrtZ6BoIhfVzvSFz9x9zIE3pBY_raM4DIicHI,142964
98
111
  lyrics_transcriber/output/fonts/verdana.ttf,sha256=lu0UlJyktzks_yNbnEHVXBJTgqu-DA08K53WaJfK4Ms,139640
99
- lyrics_transcriber/output/generator.py,sha256=W_wUo3Plt0A_H48WGbti4NeiE6eZAW-iRLwDnEOPkts,7715
112
+ lyrics_transcriber/output/generator.py,sha256=TzgYjppsGKev5Fg-q7JtjTAiTkuKOBE8Ssaf6ZoAwQA,8294
100
113
  lyrics_transcriber/output/lyrics_file.py,sha256=_KQyQjCOMIwQdQ0115uEAUIjQWTRmShkSfQuINPKxaw,3741
101
114
  lyrics_transcriber/output/plain_text.py,sha256=3mYKq0BLYz1rGBD6ROjG2dn6BPuzbn5dxIQbWZVi4ao,3689
102
115
  lyrics_transcriber/output/segment_resizer.py,sha256=b553FCdcjYAl9T1IA5K6ya0pcn1-irD5spmxSc26wnI,17143
103
116
  lyrics_transcriber/output/subtitles.py,sha256=BQy7N_2zdBBWEiHL0NWFz3ZgAerWqQvTLALgxxK3Etk,16920
104
117
  lyrics_transcriber/output/video.py,sha256=kYGeEMYtoJvrGnMuyNpuSmu2DTskGDXBNlrv6ddvC8I,8485
105
118
  lyrics_transcriber/review/__init__.py,sha256=_3Eqw-uXZhOZwo6_sHZLhP9vxAVkLF9EBXduUvPdLjQ,57
106
- lyrics_transcriber/review/server.py,sha256=oGP5NvuvAyZyaYYKST4yLWmGMu_l-ry65DXjgTKAhDg,4588
119
+ lyrics_transcriber/review/server.py,sha256=0WVcB5FaQWi8DeX-QgHZM-3ZIVr4LHiYNysWwKVBGw8,5494
107
120
  lyrics_transcriber/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
121
  lyrics_transcriber/storage/dropbox.py,sha256=Dyam1ULTkoxD1X5trkZ5dGp5XhBGCn998moC8IS9-68,9804
109
122
  lyrics_transcriber/transcribers/audioshake.py,sha256=QzKGimVa6BovlvYFj35CbGpaGePI_DApAJGEBR_JQLc,8709
110
123
  lyrics_transcriber/transcribers/base_transcriber.py,sha256=yPzUWPTCGmzE97H5Rz6g61e-qEGL77ZzUoiBOmswhts,5973
111
124
  lyrics_transcriber/transcribers/whisper.py,sha256=P0kas2_oX16MO1-Qy7U5gl5KQN-RuUIJZz7LsEFLUiE,12906
112
125
  lyrics_transcriber/types.py,sha256=xGf3hkTRcGZTTAjMVIev2i2DOU6co0QGpW8NxvaBQAA,16759
113
- lyrics_transcriber-0.34.2.dist-info/LICENSE,sha256=BiPihPDxhxIPEx6yAxVfAljD5Bhm_XG2teCbPEj_m0Y,1069
114
- lyrics_transcriber-0.34.2.dist-info/METADATA,sha256=0NSOrwR1JM9-gSURz9VRbcEO5ktuCaMZylGQ8ojWrrw,5856
115
- lyrics_transcriber-0.34.2.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
116
- lyrics_transcriber-0.34.2.dist-info/entry_points.txt,sha256=ChnmR13YoalGnC3sHW0TppX5FbhEXntYIha24tVQJ1M,104
117
- lyrics_transcriber-0.34.2.dist-info/RECORD,,
126
+ lyrics_transcriber-0.35.0.dist-info/LICENSE,sha256=BiPihPDxhxIPEx6yAxVfAljD5Bhm_XG2teCbPEj_m0Y,1069
127
+ lyrics_transcriber-0.35.0.dist-info/METADATA,sha256=I23-5rG95JB0m7Ew5hLebDRGZGhkw71q0dXNeXMQ_AE,5856
128
+ lyrics_transcriber-0.35.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
129
+ lyrics_transcriber-0.35.0.dist-info/entry_points.txt,sha256=ChnmR13YoalGnC3sHW0TppX5FbhEXntYIha24tVQJ1M,104
130
+ lyrics_transcriber-0.35.0.dist-info/RECORD,,