karaoke-gen 0.90.1__py3-none-any.whl → 0.96.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 (187) hide show
  1. backend/.coveragerc +20 -0
  2. backend/.gitignore +37 -0
  3. backend/Dockerfile +43 -0
  4. backend/Dockerfile.base +74 -0
  5. backend/README.md +242 -0
  6. backend/__init__.py +0 -0
  7. backend/api/__init__.py +0 -0
  8. backend/api/dependencies.py +457 -0
  9. backend/api/routes/__init__.py +0 -0
  10. backend/api/routes/admin.py +742 -0
  11. backend/api/routes/audio_search.py +903 -0
  12. backend/api/routes/auth.py +348 -0
  13. backend/api/routes/file_upload.py +2076 -0
  14. backend/api/routes/health.py +344 -0
  15. backend/api/routes/internal.py +435 -0
  16. backend/api/routes/jobs.py +1610 -0
  17. backend/api/routes/review.py +652 -0
  18. backend/api/routes/themes.py +162 -0
  19. backend/api/routes/users.py +1014 -0
  20. backend/config.py +172 -0
  21. backend/main.py +133 -0
  22. backend/middleware/__init__.py +5 -0
  23. backend/middleware/audit_logging.py +124 -0
  24. backend/models/__init__.py +0 -0
  25. backend/models/job.py +519 -0
  26. backend/models/requests.py +123 -0
  27. backend/models/theme.py +153 -0
  28. backend/models/user.py +254 -0
  29. backend/models/worker_log.py +164 -0
  30. backend/pyproject.toml +29 -0
  31. backend/quick-check.sh +93 -0
  32. backend/requirements.txt +29 -0
  33. backend/run_tests.sh +60 -0
  34. backend/services/__init__.py +0 -0
  35. backend/services/audio_analysis_service.py +243 -0
  36. backend/services/audio_editing_service.py +278 -0
  37. backend/services/audio_search_service.py +702 -0
  38. backend/services/auth_service.py +630 -0
  39. backend/services/credential_manager.py +792 -0
  40. backend/services/discord_service.py +172 -0
  41. backend/services/dropbox_service.py +301 -0
  42. backend/services/email_service.py +1093 -0
  43. backend/services/encoding_interface.py +454 -0
  44. backend/services/encoding_service.py +405 -0
  45. backend/services/firestore_service.py +512 -0
  46. backend/services/flacfetch_client.py +573 -0
  47. backend/services/gce_encoding/README.md +72 -0
  48. backend/services/gce_encoding/__init__.py +22 -0
  49. backend/services/gce_encoding/main.py +589 -0
  50. backend/services/gce_encoding/requirements.txt +16 -0
  51. backend/services/gdrive_service.py +356 -0
  52. backend/services/job_logging.py +258 -0
  53. backend/services/job_manager.py +842 -0
  54. backend/services/job_notification_service.py +271 -0
  55. backend/services/local_encoding_service.py +590 -0
  56. backend/services/local_preview_encoding_service.py +407 -0
  57. backend/services/lyrics_cache_service.py +216 -0
  58. backend/services/metrics.py +413 -0
  59. backend/services/packaging_service.py +287 -0
  60. backend/services/rclone_service.py +106 -0
  61. backend/services/storage_service.py +209 -0
  62. backend/services/stripe_service.py +275 -0
  63. backend/services/structured_logging.py +254 -0
  64. backend/services/template_service.py +330 -0
  65. backend/services/theme_service.py +469 -0
  66. backend/services/tracing.py +543 -0
  67. backend/services/user_service.py +721 -0
  68. backend/services/worker_service.py +558 -0
  69. backend/services/youtube_service.py +112 -0
  70. backend/services/youtube_upload_service.py +445 -0
  71. backend/tests/__init__.py +4 -0
  72. backend/tests/conftest.py +224 -0
  73. backend/tests/emulator/__init__.py +7 -0
  74. backend/tests/emulator/conftest.py +88 -0
  75. backend/tests/emulator/test_e2e_cli_backend.py +1053 -0
  76. backend/tests/emulator/test_emulator_integration.py +356 -0
  77. backend/tests/emulator/test_style_loading_direct.py +436 -0
  78. backend/tests/emulator/test_worker_logs_direct.py +229 -0
  79. backend/tests/emulator/test_worker_logs_subcollection.py +443 -0
  80. backend/tests/requirements-test.txt +10 -0
  81. backend/tests/requirements.txt +6 -0
  82. backend/tests/test_admin_email_endpoints.py +411 -0
  83. backend/tests/test_api_integration.py +460 -0
  84. backend/tests/test_api_routes.py +93 -0
  85. backend/tests/test_audio_analysis_service.py +294 -0
  86. backend/tests/test_audio_editing_service.py +386 -0
  87. backend/tests/test_audio_search.py +1398 -0
  88. backend/tests/test_audio_services.py +378 -0
  89. backend/tests/test_auth_firestore.py +231 -0
  90. backend/tests/test_config_extended.py +68 -0
  91. backend/tests/test_credential_manager.py +377 -0
  92. backend/tests/test_dependencies.py +54 -0
  93. backend/tests/test_discord_service.py +244 -0
  94. backend/tests/test_distribution_services.py +820 -0
  95. backend/tests/test_dropbox_service.py +472 -0
  96. backend/tests/test_email_service.py +492 -0
  97. backend/tests/test_emulator_integration.py +322 -0
  98. backend/tests/test_encoding_interface.py +412 -0
  99. backend/tests/test_file_upload.py +1739 -0
  100. backend/tests/test_flacfetch_client.py +632 -0
  101. backend/tests/test_gdrive_service.py +524 -0
  102. backend/tests/test_instrumental_api.py +431 -0
  103. backend/tests/test_internal_api.py +343 -0
  104. backend/tests/test_job_creation_regression.py +583 -0
  105. backend/tests/test_job_manager.py +339 -0
  106. backend/tests/test_job_manager_notifications.py +329 -0
  107. backend/tests/test_job_notification_service.py +443 -0
  108. backend/tests/test_jobs_api.py +273 -0
  109. backend/tests/test_local_encoding_service.py +423 -0
  110. backend/tests/test_local_preview_encoding_service.py +567 -0
  111. backend/tests/test_main.py +87 -0
  112. backend/tests/test_models.py +918 -0
  113. backend/tests/test_packaging_service.py +382 -0
  114. backend/tests/test_requests.py +201 -0
  115. backend/tests/test_routes_jobs.py +282 -0
  116. backend/tests/test_routes_review.py +337 -0
  117. backend/tests/test_services.py +556 -0
  118. backend/tests/test_services_extended.py +112 -0
  119. backend/tests/test_storage_service.py +448 -0
  120. backend/tests/test_style_upload.py +261 -0
  121. backend/tests/test_template_service.py +295 -0
  122. backend/tests/test_theme_service.py +516 -0
  123. backend/tests/test_unicode_sanitization.py +522 -0
  124. backend/tests/test_upload_api.py +256 -0
  125. backend/tests/test_validate.py +156 -0
  126. backend/tests/test_video_worker_orchestrator.py +847 -0
  127. backend/tests/test_worker_log_subcollection.py +509 -0
  128. backend/tests/test_worker_logging.py +365 -0
  129. backend/tests/test_workers.py +1116 -0
  130. backend/tests/test_workers_extended.py +178 -0
  131. backend/tests/test_youtube_service.py +247 -0
  132. backend/tests/test_youtube_upload_service.py +568 -0
  133. backend/validate.py +173 -0
  134. backend/version.py +27 -0
  135. backend/workers/README.md +597 -0
  136. backend/workers/__init__.py +11 -0
  137. backend/workers/audio_worker.py +618 -0
  138. backend/workers/lyrics_worker.py +683 -0
  139. backend/workers/render_video_worker.py +483 -0
  140. backend/workers/screens_worker.py +525 -0
  141. backend/workers/style_helper.py +198 -0
  142. backend/workers/video_worker.py +1277 -0
  143. backend/workers/video_worker_orchestrator.py +701 -0
  144. backend/workers/worker_logging.py +278 -0
  145. karaoke_gen/instrumental_review/static/index.html +7 -4
  146. karaoke_gen/karaoke_finalise/karaoke_finalise.py +6 -1
  147. karaoke_gen/utils/__init__.py +163 -8
  148. karaoke_gen/video_background_processor.py +9 -4
  149. {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/METADATA +1 -1
  150. {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/RECORD +186 -41
  151. lyrics_transcriber/correction/agentic/providers/config.py +9 -5
  152. lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +1 -51
  153. lyrics_transcriber/correction/corrector.py +192 -130
  154. lyrics_transcriber/correction/operations.py +24 -9
  155. lyrics_transcriber/frontend/package-lock.json +2 -2
  156. lyrics_transcriber/frontend/package.json +1 -1
  157. lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +1 -1
  158. lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +11 -7
  159. lyrics_transcriber/frontend/src/components/EditActionBar.tsx +31 -5
  160. lyrics_transcriber/frontend/src/components/EditModal.tsx +28 -10
  161. lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +123 -27
  162. lyrics_transcriber/frontend/src/components/EditWordList.tsx +112 -60
  163. lyrics_transcriber/frontend/src/components/Header.tsx +90 -76
  164. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +53 -31
  165. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +44 -13
  166. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +66 -50
  167. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +124 -30
  168. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +1 -1
  169. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +12 -5
  170. lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +3 -3
  171. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +1 -1
  172. lyrics_transcriber/frontend/src/components/WordDivider.tsx +11 -7
  173. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +4 -2
  174. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +103 -1
  175. lyrics_transcriber/frontend/src/theme.ts +42 -15
  176. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
  177. lyrics_transcriber/frontend/vite.config.js +5 -0
  178. lyrics_transcriber/frontend/web_assets/assets/{index-BECn1o8Q.js → index-BSMgOq4Z.js} +6959 -5782
  179. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +1 -0
  180. lyrics_transcriber/frontend/web_assets/index.html +6 -2
  181. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +5 -0
  182. lyrics_transcriber/output/generator.py +17 -3
  183. lyrics_transcriber/output/video.py +60 -95
  184. lyrics_transcriber/frontend/web_assets/assets/index-BECn1o8Q.js.map +0 -1
  185. {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/WHEEL +0 -0
  186. {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/entry_points.txt +0 -0
  187. {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/licenses/LICENSE +0 -0
@@ -353,6 +353,106 @@ export default function useManualSync({
353
353
  }
354
354
  }, [handleKeyDown, handleKeyUp])
355
355
 
356
+ // Touch-friendly handlers for mobile (simulates spacebar press/release)
357
+ const handleTapStart = useCallback(() => {
358
+ if (!isManualSyncing || !editedSegment || isSpacebarPressed || isPaused) return
359
+
360
+ console.log('useManualSync - Touch/tap started', {
361
+ syncWordIndex,
362
+ currentTime: currentTimeRef.current
363
+ })
364
+
365
+ setIsSpacebarPressed(true)
366
+
367
+ // Record the start time of the current word
368
+ wordStartTimeRef.current = currentTimeRef.current
369
+
370
+ // Record when the tap started (for tap detection)
371
+ spacebarPressTimeRef.current = Date.now()
372
+
373
+ // Update the word's start time immediately
374
+ if (syncWordIndex < editedSegment.words.length) {
375
+ const newWords = [...wordsRef.current]
376
+ const currentWord = newWords[syncWordIndex]
377
+ const currentStartTime = currentTimeRef.current
378
+
379
+ // Set the start time for the current word
380
+ currentWord.start_time = currentStartTime
381
+
382
+ // Handle the end time of the previous word (if it exists)
383
+ if (syncWordIndex > 0) {
384
+ const previousWord = newWords[syncWordIndex - 1]
385
+ if (previousWord.start_time !== null) {
386
+ const timeSincePreviousStart = currentStartTime - previousWord.start_time
387
+
388
+ const needsAdjustment = previousWord.end_time === null ||
389
+ (previousWord.end_time !== null && previousWord.end_time > currentStartTime)
390
+
391
+ if (needsAdjustment) {
392
+ if (timeSincePreviousStart > 1.0) {
393
+ previousWord.end_time = previousWord.start_time + 0.5
394
+ } else {
395
+ previousWord.end_time = currentStartTime - 0.005
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ // Update our ref
402
+ wordsRef.current = newWords
403
+
404
+ // Mark that we need to update the segment
405
+ needsSegmentUpdateRef.current = true
406
+ }
407
+ }, [isManualSyncing, editedSegment, syncWordIndex, isSpacebarPressed, isPaused])
408
+
409
+ const handleTapEnd = useCallback(() => {
410
+ if (!isManualSyncing || !editedSegment || !isSpacebarPressed || isPaused) return
411
+
412
+ const pressDuration = spacebarPressTimeRef.current ? Date.now() - spacebarPressTimeRef.current : 0
413
+ const isTap = pressDuration < TAP_THRESHOLD_MS
414
+
415
+ console.log('useManualSync - Touch/tap ended', {
416
+ syncWordIndex,
417
+ pressDuration: `${pressDuration}ms`,
418
+ isTap
419
+ })
420
+
421
+ setIsSpacebarPressed(false)
422
+
423
+ if (syncWordIndex < editedSegment.words.length) {
424
+ const newWords = [...wordsRef.current]
425
+ const currentWord = newWords[syncWordIndex]
426
+
427
+ // Set the end time for the current word based on whether it was a tap or hold
428
+ if (isTap) {
429
+ const defaultEndTime = (wordStartTimeRef.current || currentTimeRef.current) + DEFAULT_WORD_DURATION
430
+ currentWord.end_time = defaultEndTime
431
+ } else {
432
+ currentWord.end_time = currentTimeRef.current
433
+ }
434
+
435
+ // Update our ref
436
+ wordsRef.current = newWords
437
+
438
+ // Move to the next word
439
+ if (syncWordIndex === editedSegment.words.length - 1) {
440
+ // If this was the last word, finish manual sync
441
+ console.log('useManualSync - Completed manual sync for all words')
442
+ setIsManualSyncing(false)
443
+ setSyncWordIndex(-1)
444
+ wordStartTimeRef.current = null
445
+ spacebarPressTimeRef.current = null
446
+ } else {
447
+ // Otherwise, move to the next word
448
+ setSyncWordIndex(syncWordIndex + 1)
449
+ }
450
+
451
+ // Mark that we need to update the segment
452
+ needsSegmentUpdateRef.current = true
453
+ }
454
+ }, [isManualSyncing, editedSegment, syncWordIndex, isSpacebarPressed, isPaused])
455
+
356
456
  const startManualSync = useCallback(() => {
357
457
  if (isManualSyncing) {
358
458
  cleanupManualSync()
@@ -430,6 +530,8 @@ export default function useManualSync({
430
530
  resumeManualSync,
431
531
  cleanupManualSync,
432
532
  handleSpacebar,
433
- isSpacebarPressed
533
+ isSpacebarPressed,
534
+ handleTapStart,
535
+ handleTapEnd
434
536
  }
435
537
  }
@@ -16,7 +16,7 @@ const darkColors = {
16
16
  action: {
17
17
  active: '#f8fafc',
18
18
  hover: 'rgba(248, 250, 252, 0.08)',
19
- selected: 'rgba(249, 115, 22, 0.16)',
19
+ selected: 'rgba(255, 122, 204, 0.16)',
20
20
  disabled: '#64748b',
21
21
  disabledBackground: 'rgba(100, 116, 139, 0.12)',
22
22
  },
@@ -38,24 +38,26 @@ const lightColors = {
38
38
  action: {
39
39
  active: '#1e293b',
40
40
  hover: 'rgba(30, 41, 59, 0.08)',
41
- selected: 'rgba(249, 115, 22, 0.16)',
41
+ selected: 'rgba(255, 122, 204, 0.16)',
42
42
  disabled: '#94a3b8',
43
43
  disabledBackground: 'rgba(148, 163, 184, 0.12)',
44
44
  },
45
45
  };
46
46
 
47
- // Shared colors
47
+ // Shared colors - Nomad Karaoke brand palette
48
+ // Primary: Brand Pink (#ff7acc), Secondary: Brand Purple (#8b5cf6)
49
+ // See docs/BRAND-STYLE-GUIDE.md for full brand guidelines
48
50
  const sharedColors = {
49
51
  primary: {
50
- main: '#f97316',
51
- light: '#fb923c',
52
- dark: '#ea580c',
52
+ main: '#ff7acc',
53
+ light: '#ff8fd4',
54
+ dark: '#ff5bb8',
53
55
  contrastText: '#ffffff',
54
56
  },
55
57
  secondary: {
56
- main: '#6366f1',
57
- light: '#818cf8',
58
- dark: '#4f46e5',
58
+ main: '#8b5cf6',
59
+ light: '#a78bfa',
60
+ dark: '#7c3aed',
59
61
  contrastText: '#ffffff',
60
62
  },
61
63
  error: {
@@ -140,7 +142,7 @@ export function createAppTheme(mode: 'dark' | 'light'): Theme {
140
142
  borderColor: colors.divider,
141
143
  '&:hover': {
142
144
  borderColor: sharedColors.primary.main,
143
- backgroundColor: 'rgba(249, 115, 22, 0.08)',
145
+ backgroundColor: 'rgba(255, 122, 204, 0.08)',
144
146
  },
145
147
  },
146
148
  },
@@ -158,19 +160,44 @@ export function createAppTheme(mode: 'dark' | 'light'): Theme {
158
160
  MuiTextField: {
159
161
  styleOverrides: {
160
162
  root: {
161
- '& .MuiInputBase-root': { minHeight: '32px', backgroundColor: colors.background.default },
163
+ '& .MuiInputBase-root': {
164
+ minHeight: '32px',
165
+ backgroundColor: colors.background.default,
166
+ },
162
167
  '& .MuiOutlinedInput-root': {
168
+ backgroundColor: colors.background.default,
163
169
  '& fieldset': { borderColor: colors.divider },
164
170
  '&:hover fieldset': { borderColor: colors.text.secondary },
165
171
  '&.Mui-focused fieldset': { borderColor: sharedColors.primary.main },
166
172
  },
173
+ '& .MuiFilledInput-root': {
174
+ backgroundColor: colors.background.default,
175
+ '&:hover': { backgroundColor: colors.background.elevated },
176
+ '&.Mui-focused': { backgroundColor: colors.background.default },
177
+ },
178
+ },
179
+ },
180
+ },
181
+ MuiOutlinedInput: {
182
+ styleOverrides: {
183
+ root: {
184
+ backgroundColor: colors.background.default,
185
+ },
186
+ input: {
187
+ backgroundColor: 'transparent',
167
188
  },
168
189
  },
169
190
  },
170
191
  MuiInputBase: {
171
192
  styleOverrides: {
172
- root: { color: colors.text.primary },
173
- input: { '&::placeholder': { color: colors.text.disabled, opacity: 1 } },
193
+ root: {
194
+ color: colors.text.primary,
195
+ backgroundColor: colors.background.default,
196
+ },
197
+ input: {
198
+ '&::placeholder': { color: colors.text.disabled, opacity: 1 },
199
+ backgroundColor: 'transparent',
200
+ },
174
201
  },
175
202
  },
176
203
  MuiDialog: {
@@ -210,7 +237,7 @@ export function createAppTheme(mode: 'dark' | 'light'): Theme {
210
237
  '&:hover': { backgroundColor: colors.action.hover },
211
238
  '&.Mui-selected': {
212
239
  backgroundColor: colors.action.selected,
213
- '&:hover': { backgroundColor: 'rgba(249, 115, 22, 0.24)' },
240
+ '&:hover': { backgroundColor: 'rgba(255, 122, 204, 0.24)' },
214
241
  },
215
242
  },
216
243
  },
@@ -288,7 +315,7 @@ export function createAppTheme(mode: 'dark' | 'light'): Theme {
288
315
  '&:hover': { backgroundColor: colors.action.hover },
289
316
  '&.Mui-selected': {
290
317
  backgroundColor: colors.action.selected,
291
- '&:hover': { backgroundColor: 'rgba(249, 115, 22, 0.24)' },
318
+ '&:hover': { backgroundColor: 'rgba(255, 122, 204, 0.24)' },
292
319
  },
293
320
  },
294
321
  },
@@ -1 +1 @@
1
- {"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/theme.ts","./src/types.ts","./src/validation.ts","./src/vite-env.d.ts","./src/components/aifeedbackmodal.tsx","./src/components/addlyricsmodal.tsx","./src/components/agenticcorrectionmetrics.tsx","./src/components/audioplayer.tsx","./src/components/correctedwordwithactions.tsx","./src/components/correctionannotationmodal.tsx","./src/components/correctiondetailcard.tsx","./src/components/correctionmetrics.tsx","./src/components/durationtimelineview.tsx","./src/components/editactionbar.tsx","./src/components/editmodal.tsx","./src/components/edittimelinesection.tsx","./src/components/editwordlist.tsx","./src/components/fileupload.tsx","./src/components/findreplacemodal.tsx","./src/components/header.tsx","./src/components/lyricsanalyzer.tsx","./src/components/metricsdashboard.tsx","./src/components/modeselectionmodal.tsx","./src/components/modeselector.tsx","./src/components/modelselector.tsx","./src/components/previewvideosection.tsx","./src/components/referenceview.tsx","./src/components/replacealllyricsmodal.tsx","./src/components/reviewchangesmodal.tsx","./src/components/segmentdetailsmodal.tsx","./src/components/timelineeditor.tsx","./src/components/timingoffsetmodal.tsx","./src/components/transcriptionview.tsx","./src/components/worddivider.tsx","./src/components/lyricssynchronizer/synccontrols.tsx","./src/components/lyricssynchronizer/timelinecanvas.tsx","./src/components/lyricssynchronizer/upcomingwordsbar.tsx","./src/components/lyricssynchronizer/index.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/keyboardhandlers.ts","./src/components/shared/utils/localstorage.ts","./src/components/shared/utils/referencelinecalculator.ts","./src/components/shared/utils/segmentoperations.ts","./src/components/shared/utils/timingutils.ts","./src/components/shared/utils/wordutils.ts","./src/hooks/usemanualsync.ts","./src/types/global.d.ts"],"version":"5.6.3"}
1
+ {"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/theme.ts","./src/types.ts","./src/validation.ts","./src/vite-env.d.ts","./src/components/aifeedbackmodal.tsx","./src/components/addlyricsmodal.tsx","./src/components/agenticcorrectionmetrics.tsx","./src/components/appheader.tsx","./src/components/audioplayer.tsx","./src/components/correctedwordwithactions.tsx","./src/components/correctionannotationmodal.tsx","./src/components/correctiondetailcard.tsx","./src/components/correctionmetrics.tsx","./src/components/durationtimelineview.tsx","./src/components/editactionbar.tsx","./src/components/editmodal.tsx","./src/components/edittimelinesection.tsx","./src/components/editwordlist.tsx","./src/components/fileupload.tsx","./src/components/findreplacemodal.tsx","./src/components/header.tsx","./src/components/lyricsanalyzer.tsx","./src/components/metricsdashboard.tsx","./src/components/modeselectionmodal.tsx","./src/components/modeselector.tsx","./src/components/modelselector.tsx","./src/components/previewvideosection.tsx","./src/components/referenceview.tsx","./src/components/replacealllyricsmodal.tsx","./src/components/reviewchangesmodal.tsx","./src/components/segmentdetailsmodal.tsx","./src/components/timelineeditor.tsx","./src/components/timingoffsetmodal.tsx","./src/components/transcriptionview.tsx","./src/components/worddivider.tsx","./src/components/lyricssynchronizer/synccontrols.tsx","./src/components/lyricssynchronizer/timelinecanvas.tsx","./src/components/lyricssynchronizer/upcomingwordsbar.tsx","./src/components/lyricssynchronizer/index.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/keyboardhandlers.ts","./src/components/shared/utils/localstorage.ts","./src/components/shared/utils/referencelinecalculator.ts","./src/components/shared/utils/segmentoperations.ts","./src/components/shared/utils/timingutils.ts","./src/components/shared/utils/wordutils.ts","./src/hooks/usemanualsync.ts","./src/types/global.d.ts"],"version":"5.6.3"}
@@ -3,6 +3,11 @@ import react from '@vitejs/plugin-react';
3
3
  // https://vite.dev/config/
4
4
  export default defineConfig({
5
5
  plugins: [react()],
6
+ server: {
7
+ port: 5173,
8
+ // Enable CORS for local development
9
+ cors: true,
10
+ },
6
11
  build: {
7
12
  minify: false,
8
13
  sourcemap: true,