karaoke-gen 0.105.4__py3-none-any.whl → 0.107.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 (322) hide show
  1. backend/api/routes/users.py +14 -3
  2. backend/config.py +3 -0
  3. backend/services/encoding_interface.py +4 -0
  4. backend/services/job_notification_service.py +4 -21
  5. backend/tests/test_job_notification_service.py +24 -58
  6. backend/tests/test_video_worker_orchestrator.py +189 -0
  7. backend/workers/video_worker_orchestrator.py +7 -0
  8. karaoke_gen/instrumental_review/server.py +145 -35
  9. karaoke_gen/nextjs_frontend/__init__.py +98 -0
  10. karaoke_gen/nextjs_frontend/out/404/index.html +1 -0
  11. karaoke_gen/nextjs_frontend/out/404.html +1 -0
  12. karaoke_gen/nextjs_frontend/out/__next.__PAGE__.txt +9 -0
  13. karaoke_gen/nextjs_frontend/out/__next._full.txt +22 -0
  14. karaoke_gen/nextjs_frontend/out/__next._head.txt +8 -0
  15. karaoke_gen/nextjs_frontend/out/__next._index.txt +9 -0
  16. karaoke_gen/nextjs_frontend/out/__next._tree.txt +2 -0
  17. karaoke_gen/nextjs_frontend/out/_next/static/chunks/01a7f8fe40f1ff47.js +1 -0
  18. karaoke_gen/nextjs_frontend/out/_next/static/chunks/112f346e31f991df.js +4 -0
  19. karaoke_gen/nextjs_frontend/out/_next/static/chunks/16d1a4dd9d8a873a.js +3 -0
  20. karaoke_gen/nextjs_frontend/out/_next/static/chunks/1ab85c362b8b0e86.js +9 -0
  21. karaoke_gen/nextjs_frontend/out/_next/static/chunks/247eb132b7f7b574.js +1 -0
  22. karaoke_gen/nextjs_frontend/out/_next/static/chunks/2b80d15cc95e4818.js +1 -0
  23. karaoke_gen/nextjs_frontend/out/_next/static/chunks/32c7eba5cd46c1bc.js +7 -0
  24. karaoke_gen/nextjs_frontend/out/_next/static/chunks/483f26794eae53d0.js +1 -0
  25. karaoke_gen/nextjs_frontend/out/_next/static/chunks/550c3b02e85f196a.js +1 -0
  26. karaoke_gen/nextjs_frontend/out/_next/static/chunks/55c5ade44387bef8.js +1 -0
  27. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5628d92b5893add2.css +1 -0
  28. karaoke_gen/nextjs_frontend/out/_next/static/chunks/56ebf7665e4341c8.js +7 -0
  29. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5997132b61dec430.js +1 -0
  30. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5ea55255bce3eb9e.js +5 -0
  31. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5eda89a57490b3cd.js +1 -0
  32. karaoke_gen/nextjs_frontend/out/_next/static/chunks/692f5d9e0d700c76.js +3 -0
  33. karaoke_gen/nextjs_frontend/out/_next/static/chunks/71d7a05b14f9f0f4.js +1 -0
  34. karaoke_gen/nextjs_frontend/out/_next/static/chunks/81ac355749ef3302.js +1 -0
  35. karaoke_gen/nextjs_frontend/out/_next/static/chunks/95f7e5934dbb0e5d.js +1 -0
  36. karaoke_gen/nextjs_frontend/out/_next/static/chunks/9bce8f19eaa46940.js +1 -0
  37. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  38. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a9ed54eed3e14c92.js +2 -0
  39. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b35cd41238ecfb17.js +1 -0
  40. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5bc3c3d5ebd49eb.js +1 -0
  41. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5c078c08db5ae32.js +5 -0
  42. karaoke_gen/nextjs_frontend/out/_next/static/chunks/be9c44a178104187.js +1 -0
  43. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c4c840e18cb4861c.js +1 -0
  44. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c645af7d6b65f73e.js +1 -0
  45. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d2c5e2575df784d4.js +1 -0
  46. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d30af02b96d81462.js +1 -0
  47. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d9bdf64f4ec1e9b7.js +7 -0
  48. karaoke_gen/nextjs_frontend/out/_next/static/chunks/dcde6ed684dacd0e.js +5 -0
  49. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e422cbe931246000.js +1 -0
  50. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e483af34fc792d38.js +1 -0
  51. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e57422aad6b897da.js +1 -0
  52. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ef02697fb404726a.js +1 -0
  53. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ff1a16fafef87110.js +1 -0
  54. karaoke_gen/nextjs_frontend/out/_next/static/chunks/turbopack-2d9ca3017a9deedf.js +3 -0
  55. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_buildManifest.js +11 -0
  56. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_clientMiddlewareManifest.json +1 -0
  57. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_ssgManifest.js +1 -0
  58. karaoke_gen/nextjs_frontend/out/_not-found/__next._full.txt +18 -0
  59. karaoke_gen/nextjs_frontend/out/_not-found/__next._head.txt +8 -0
  60. karaoke_gen/nextjs_frontend/out/_not-found/__next._index.txt +9 -0
  61. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.__PAGE__.txt +5 -0
  62. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.txt +4 -0
  63. karaoke_gen/nextjs_frontend/out/_not-found/__next._tree.txt +2 -0
  64. karaoke_gen/nextjs_frontend/out/_not-found/index.html +1 -0
  65. karaoke_gen/nextjs_frontend/out/_not-found/index.txt +18 -0
  66. karaoke_gen/nextjs_frontend/out/admin/__next._full.txt +25 -0
  67. karaoke_gen/nextjs_frontend/out/admin/__next._head.txt +8 -0
  68. karaoke_gen/nextjs_frontend/out/admin/__next._index.txt +9 -0
  69. karaoke_gen/nextjs_frontend/out/admin/__next._tree.txt +2 -0
  70. karaoke_gen/nextjs_frontend/out/admin/__next.admin.__PAGE__.txt +9 -0
  71. karaoke_gen/nextjs_frontend/out/admin/__next.admin.txt +7 -0
  72. karaoke_gen/nextjs_frontend/out/admin/beta/__next._full.txt +25 -0
  73. karaoke_gen/nextjs_frontend/out/admin/beta/__next._head.txt +8 -0
  74. karaoke_gen/nextjs_frontend/out/admin/beta/__next._index.txt +9 -0
  75. karaoke_gen/nextjs_frontend/out/admin/beta/__next._tree.txt +2 -0
  76. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.__PAGE__.txt +9 -0
  77. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.txt +4 -0
  78. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.txt +7 -0
  79. karaoke_gen/nextjs_frontend/out/admin/beta/index.html +1 -0
  80. karaoke_gen/nextjs_frontend/out/admin/beta/index.txt +25 -0
  81. karaoke_gen/nextjs_frontend/out/admin/index.html +1 -0
  82. karaoke_gen/nextjs_frontend/out/admin/index.txt +25 -0
  83. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._full.txt +25 -0
  84. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._head.txt +8 -0
  85. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._index.txt +9 -0
  86. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._tree.txt +2 -0
  87. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.__PAGE__.txt +9 -0
  88. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.txt +4 -0
  89. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.txt +7 -0
  90. karaoke_gen/nextjs_frontend/out/admin/jobs/index.html +1 -0
  91. karaoke_gen/nextjs_frontend/out/admin/jobs/index.txt +25 -0
  92. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._full.txt +25 -0
  93. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._head.txt +8 -0
  94. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._index.txt +9 -0
  95. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._tree.txt +2 -0
  96. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.__PAGE__.txt +9 -0
  97. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.txt +4 -0
  98. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.txt +7 -0
  99. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.html +1 -0
  100. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.txt +25 -0
  101. karaoke_gen/nextjs_frontend/out/admin/searches/__next._full.txt +25 -0
  102. karaoke_gen/nextjs_frontend/out/admin/searches/__next._head.txt +8 -0
  103. karaoke_gen/nextjs_frontend/out/admin/searches/__next._index.txt +9 -0
  104. karaoke_gen/nextjs_frontend/out/admin/searches/__next._tree.txt +2 -0
  105. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.__PAGE__.txt +9 -0
  106. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.txt +4 -0
  107. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.txt +7 -0
  108. karaoke_gen/nextjs_frontend/out/admin/searches/index.html +1 -0
  109. karaoke_gen/nextjs_frontend/out/admin/searches/index.txt +25 -0
  110. karaoke_gen/nextjs_frontend/out/admin/users/__next._full.txt +25 -0
  111. karaoke_gen/nextjs_frontend/out/admin/users/__next._head.txt +8 -0
  112. karaoke_gen/nextjs_frontend/out/admin/users/__next._index.txt +9 -0
  113. karaoke_gen/nextjs_frontend/out/admin/users/__next._tree.txt +2 -0
  114. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.txt +7 -0
  115. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.__PAGE__.txt +9 -0
  116. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.txt +4 -0
  117. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._full.txt +25 -0
  118. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._head.txt +8 -0
  119. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._index.txt +9 -0
  120. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._tree.txt +2 -0
  121. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.txt +7 -0
  122. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.__PAGE__.txt +9 -0
  123. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.txt +4 -0
  124. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.txt +4 -0
  125. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.html +1 -0
  126. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.txt +25 -0
  127. karaoke_gen/nextjs_frontend/out/admin/users/index.html +1 -0
  128. karaoke_gen/nextjs_frontend/out/admin/users/index.txt +25 -0
  129. karaoke_gen/nextjs_frontend/out/app/__next._full.txt +22 -0
  130. karaoke_gen/nextjs_frontend/out/app/__next._head.txt +8 -0
  131. karaoke_gen/nextjs_frontend/out/app/__next._index.txt +9 -0
  132. karaoke_gen/nextjs_frontend/out/app/__next._tree.txt +2 -0
  133. karaoke_gen/nextjs_frontend/out/app/__next.app.__PAGE__.txt +9 -0
  134. karaoke_gen/nextjs_frontend/out/app/__next.app.txt +4 -0
  135. karaoke_gen/nextjs_frontend/out/app/index.html +1 -0
  136. karaoke_gen/nextjs_frontend/out/app/index.txt +22 -0
  137. karaoke_gen/nextjs_frontend/out/app/jobs/__next._full.txt +19 -0
  138. karaoke_gen/nextjs_frontend/out/app/jobs/__next._head.txt +8 -0
  139. karaoke_gen/nextjs_frontend/out/app/jobs/__next._index.txt +9 -0
  140. karaoke_gen/nextjs_frontend/out/app/jobs/__next._tree.txt +2 -0
  141. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  142. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.txt +4 -0
  143. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.txt +4 -0
  144. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.txt +4 -0
  145. karaoke_gen/nextjs_frontend/out/app/jobs/index.html +1 -0
  146. karaoke_gen/nextjs_frontend/out/app/jobs/index.txt +19 -0
  147. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._full.txt +19 -0
  148. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._head.txt +8 -0
  149. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._index.txt +9 -0
  150. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._tree.txt +2 -0
  151. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  152. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.txt +4 -0
  153. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.txt +4 -0
  154. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.txt +4 -0
  155. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.html +1 -0
  156. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.txt +19 -0
  157. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._full.txt +19 -0
  158. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._head.txt +8 -0
  159. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._index.txt +9 -0
  160. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._tree.txt +2 -0
  161. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  162. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.txt +4 -0
  163. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.txt +4 -0
  164. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.txt +4 -0
  165. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.html +1 -0
  166. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.txt +19 -0
  167. karaoke_gen/nextjs_frontend/out/auth/verify/__next._full.txt +22 -0
  168. karaoke_gen/nextjs_frontend/out/auth/verify/__next._head.txt +8 -0
  169. karaoke_gen/nextjs_frontend/out/auth/verify/__next._index.txt +9 -0
  170. karaoke_gen/nextjs_frontend/out/auth/verify/__next._tree.txt +2 -0
  171. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.txt +4 -0
  172. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.__PAGE__.txt +9 -0
  173. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.txt +4 -0
  174. karaoke_gen/nextjs_frontend/out/auth/verify/index.html +1 -0
  175. karaoke_gen/nextjs_frontend/out/auth/verify/index.txt +22 -0
  176. karaoke_gen/nextjs_frontend/out/index.html +1 -0
  177. karaoke_gen/nextjs_frontend/out/index.txt +22 -0
  178. karaoke_gen/nextjs_frontend/out/manifest.webmanifest +31 -0
  179. karaoke_gen/nextjs_frontend/out/order/success/__next._full.txt +22 -0
  180. karaoke_gen/nextjs_frontend/out/order/success/__next._head.txt +8 -0
  181. karaoke_gen/nextjs_frontend/out/order/success/__next._index.txt +9 -0
  182. karaoke_gen/nextjs_frontend/out/order/success/__next._tree.txt +2 -0
  183. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.__PAGE__.txt +9 -0
  184. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.txt +4 -0
  185. karaoke_gen/nextjs_frontend/out/order/success/__next.order.txt +4 -0
  186. karaoke_gen/nextjs_frontend/out/order/success/index.html +1 -0
  187. karaoke_gen/nextjs_frontend/out/order/success/index.txt +22 -0
  188. karaoke_gen/nextjs_frontend/out/payment/success/__next._full.txt +22 -0
  189. karaoke_gen/nextjs_frontend/out/payment/success/__next._head.txt +8 -0
  190. karaoke_gen/nextjs_frontend/out/payment/success/__next._index.txt +9 -0
  191. karaoke_gen/nextjs_frontend/out/payment/success/__next._tree.txt +2 -0
  192. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.__PAGE__.txt +9 -0
  193. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.txt +4 -0
  194. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.txt +4 -0
  195. karaoke_gen/nextjs_frontend/out/payment/success/index.html +1 -0
  196. karaoke_gen/nextjs_frontend/out/payment/success/index.txt +22 -0
  197. karaoke_gen/nextjs_frontend/out/screenshots/email-action_reminder.png +0 -0
  198. karaoke_gen/nextjs_frontend/out/screenshots/email-beta_welcome.png +0 -0
  199. karaoke_gen/nextjs_frontend/out/screenshots/email-job_completion.png +0 -0
  200. karaoke_gen/nextjs_frontend/out/screenshots/example-output.avif +0 -0
  201. karaoke_gen/nextjs_frontend/out/screenshots/homepage-full.png +0 -0
  202. karaoke_gen/nextjs_frontend/out/screenshots/homepage-hero.png +0 -0
  203. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.avif +0 -0
  204. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.png +0 -0
  205. karaoke_gen/nextjs_frontend/out/screenshots/job-dashboard.avif +0 -0
  206. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.avif +0 -0
  207. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.png +0 -0
  208. karaoke_gen/nextjs_frontend/out/sw.js +183 -0
  209. karaoke_gen/utils/cli_args.py +3 -3
  210. karaoke_gen/utils/gen_cli.py +4 -0
  211. karaoke_gen/utils/remote_cli.py +8 -40
  212. {karaoke_gen-0.105.4.dist-info → karaoke_gen-0.107.0.dist-info}/METADATA +1 -1
  213. {karaoke_gen-0.105.4.dist-info → karaoke_gen-0.107.0.dist-info}/RECORD +227 -121
  214. {karaoke_gen-0.105.4.dist-info → karaoke_gen-0.107.0.dist-info}/WHEEL +1 -1
  215. lyrics_transcriber/correction/agentic/agent.py +83 -60
  216. lyrics_transcriber/correction/anchor_sequence.py +48 -3
  217. lyrics_transcriber/correction/corrector.py +92 -58
  218. lyrics_transcriber/review/server.py +165 -33
  219. lyrics_transcriber/utils/tracing.py +214 -0
  220. karaoke_gen/instrumental_review/static/index.html +0 -1721
  221. lyrics_transcriber/frontend/.gitignore +0 -24
  222. lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +0 -935
  223. lyrics_transcriber/frontend/.yarnrc.yml +0 -3
  224. lyrics_transcriber/frontend/README.md +0 -50
  225. lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +0 -210
  226. lyrics_transcriber/frontend/__init__.py +0 -25
  227. lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts +0 -207
  228. lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json +0 -226
  229. lyrics_transcriber/frontend/eslint.config.js +0 -28
  230. lyrics_transcriber/frontend/index.html +0 -22
  231. lyrics_transcriber/frontend/package-lock.json +0 -4553
  232. lyrics_transcriber/frontend/package.json +0 -48
  233. lyrics_transcriber/frontend/playwright.config.ts +0 -69
  234. lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
  235. lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
  236. lyrics_transcriber/frontend/src/App.tsx +0 -243
  237. lyrics_transcriber/frontend/src/api.ts +0 -262
  238. lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +0 -111
  239. lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +0 -114
  240. lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +0 -204
  241. lyrics_transcriber/frontend/src/components/AppHeader.tsx +0 -65
  242. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +0 -180
  243. lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +0 -175
  244. lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +0 -359
  245. lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +0 -281
  246. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +0 -162
  247. lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +0 -257
  248. lyrics_transcriber/frontend/src/components/EditActionBar.tsx +0 -94
  249. lyrics_transcriber/frontend/src/components/EditModal.tsx +0 -720
  250. lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +0 -592
  251. lyrics_transcriber/frontend/src/components/EditWordList.tsx +0 -431
  252. lyrics_transcriber/frontend/src/components/FileUpload.tsx +0 -77
  253. lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +0 -467
  254. lyrics_transcriber/frontend/src/components/Header.tsx +0 -520
  255. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +0 -1526
  256. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +0 -216
  257. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +0 -721
  258. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +0 -80
  259. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +0 -999
  260. lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +0 -51
  261. lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +0 -127
  262. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +0 -67
  263. lyrics_transcriber/frontend/src/components/ModelSelector.tsx +0 -23
  264. lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +0 -177
  265. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +0 -268
  266. lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +0 -336
  267. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +0 -354
  268. lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +0 -64
  269. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +0 -383
  270. lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +0 -131
  271. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +0 -266
  272. lyrics_transcriber/frontend/src/components/WordDivider.tsx +0 -191
  273. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +0 -466
  274. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +0 -56
  275. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +0 -89
  276. lyrics_transcriber/frontend/src/components/shared/constants.ts +0 -30
  277. lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +0 -180
  278. lyrics_transcriber/frontend/src/components/shared/styles.ts +0 -13
  279. lyrics_transcriber/frontend/src/components/shared/types.js +0 -2
  280. lyrics_transcriber/frontend/src/components/shared/types.ts +0 -135
  281. lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +0 -177
  282. lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +0 -78
  283. lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +0 -75
  284. lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +0 -360
  285. lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +0 -110
  286. lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +0 -22
  287. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +0 -537
  288. lyrics_transcriber/frontend/src/main.tsx +0 -11
  289. lyrics_transcriber/frontend/src/theme.ts +0 -406
  290. lyrics_transcriber/frontend/src/types/global.d.ts +0 -9
  291. lyrics_transcriber/frontend/src/types.js +0 -2
  292. lyrics_transcriber/frontend/src/types.ts +0 -199
  293. lyrics_transcriber/frontend/src/validation.ts +0 -132
  294. lyrics_transcriber/frontend/src/vite-env.d.ts +0 -1
  295. lyrics_transcriber/frontend/tsconfig.app.json +0 -26
  296. lyrics_transcriber/frontend/tsconfig.json +0 -25
  297. lyrics_transcriber/frontend/tsconfig.node.json +0 -23
  298. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +0 -1
  299. lyrics_transcriber/frontend/update_version.js +0 -11
  300. lyrics_transcriber/frontend/vite.config.d.ts +0 -2
  301. lyrics_transcriber/frontend/vite.config.js +0 -15
  302. lyrics_transcriber/frontend/vite.config.ts +0 -16
  303. lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
  304. lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
  305. lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
  306. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js +0 -44465
  307. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +0 -1
  308. lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
  309. lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
  310. lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
  311. lyrics_transcriber/frontend/web_assets/index.html +0 -22
  312. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
  313. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +0 -5
  314. lyrics_transcriber/frontend/yarn.lock +0 -3711
  315. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/apple-touch-icon.png +0 -0
  316. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-16x16.png +0 -0
  317. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-32x32.png +0 -0
  318. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon.ico +0 -0
  319. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/nomad-karaoke-logo.svg +0 -0
  320. /lyrics_transcriber/frontend/public/nomad-karaoke-logo.png → /karaoke_gen/nextjs_frontend/out/nomad-logo.png +0 -0
  321. {karaoke_gen-0.105.4.dist-info → karaoke_gen-0.107.0.dist-info}/entry_points.txt +0 -0
  322. {karaoke_gen-0.105.4.dist-info → karaoke_gen-0.107.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,720 +0,0 @@
1
- import {
2
- Dialog,
3
- DialogTitle,
4
- DialogContent,
5
- DialogActions,
6
- IconButton,
7
- Box,
8
- CircularProgress,
9
- Typography,
10
- useMediaQuery,
11
- useTheme
12
- } from '@mui/material'
13
- import CloseIcon from '@mui/icons-material/Close'
14
- import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'
15
- import StopIcon from '@mui/icons-material/Stop'
16
- import { LyricsSegment, Word } from '../types'
17
- import { useState, useEffect, useCallback, useMemo, memo } from 'react'
18
- import { nanoid } from 'nanoid'
19
- import useManualSync from '../hooks/useManualSync'
20
- import EditTimelineSection from './EditTimelineSection'
21
- import EditWordList from './EditWordList'
22
- import EditActionBar from './EditActionBar'
23
-
24
- // Extract TimelineSection into a separate memoized component
25
- interface TimelineSectionProps {
26
- words: Word[]
27
- timeRange: { start: number, end: number }
28
- originalSegment: LyricsSegment
29
- editedSegment: LyricsSegment
30
- currentTime: number
31
- isManualSyncing: boolean
32
- syncWordIndex: number
33
- isSpacebarPressed: boolean
34
- onWordUpdate: (index: number, updates: Partial<Word>) => void
35
- onPlaySegment?: (startTime: number) => void
36
- startManualSync: () => void
37
- isGlobal: boolean
38
- onTapStart?: () => void
39
- onTapEnd?: () => void
40
- }
41
-
42
- const MemoizedTimelineSection = memo(function TimelineSection({
43
- words,
44
- timeRange,
45
- originalSegment,
46
- editedSegment,
47
- currentTime,
48
- isManualSyncing,
49
- syncWordIndex,
50
- isSpacebarPressed,
51
- onWordUpdate,
52
- onPlaySegment,
53
- startManualSync,
54
- isGlobal,
55
- onTapStart,
56
- onTapEnd
57
- }: TimelineSectionProps) {
58
- return (
59
- <EditTimelineSection
60
- words={words}
61
- startTime={timeRange.start}
62
- endTime={timeRange.end}
63
- originalStartTime={originalSegment.start_time}
64
- originalEndTime={originalSegment.end_time}
65
- currentStartTime={editedSegment.start_time}
66
- currentEndTime={editedSegment.end_time}
67
- currentTime={currentTime}
68
- isManualSyncing={isManualSyncing}
69
- syncWordIndex={syncWordIndex}
70
- isSpacebarPressed={isSpacebarPressed}
71
- onWordUpdate={onWordUpdate}
72
- onPlaySegment={onPlaySegment}
73
- startManualSync={startManualSync}
74
- isGlobal={isGlobal}
75
- onTapStart={onTapStart}
76
- onTapEnd={onTapEnd}
77
- />
78
- )
79
- })
80
-
81
- // Extract WordList into a separate memoized component
82
- interface WordListProps {
83
- words: Word[]
84
- onWordUpdate: (index: number, updates: Partial<Word>) => void
85
- onSplitWord: (index: number) => void
86
- onMergeWords: (index: number) => void
87
- onAddWord: (index?: number) => void
88
- onRemoveWord: (index: number) => void
89
- onSplitSegment?: (wordIndex: number) => void
90
- onAddSegment?: (beforeIndex: number) => void
91
- onMergeSegment?: (mergeWithNext: boolean) => void
92
- isGlobal: boolean
93
- }
94
-
95
- const MemoizedWordList = memo(function WordList({
96
- words,
97
- onWordUpdate,
98
- onSplitWord,
99
- onMergeWords,
100
- onAddWord,
101
- onRemoveWord,
102
- onSplitSegment,
103
- onAddSegment,
104
- onMergeSegment,
105
- isGlobal
106
- }: WordListProps) {
107
- return (
108
- <EditWordList
109
- words={words}
110
- onWordUpdate={onWordUpdate}
111
- onSplitWord={onSplitWord}
112
- onMergeWords={onMergeWords}
113
- onAddWord={onAddWord}
114
- onRemoveWord={onRemoveWord}
115
- onSplitSegment={onSplitSegment}
116
- onAddSegment={onAddSegment}
117
- onMergeSegment={onMergeSegment}
118
- isGlobal={isGlobal}
119
- />
120
- )
121
- })
122
-
123
- // Extract ActionBar into a separate memoized component
124
- interface ActionBarProps {
125
- onReset: () => void
126
- onRevertToOriginal?: () => void
127
- onDelete?: () => void
128
- onClose: () => void
129
- onSave: () => void
130
- editedSegment: LyricsSegment | null
131
- originalTranscribedSegment?: LyricsSegment | null
132
- isGlobal: boolean
133
- }
134
-
135
- const MemoizedActionBar = memo(function ActionBar({
136
- onReset,
137
- onRevertToOriginal,
138
- onDelete,
139
- onClose,
140
- onSave,
141
- editedSegment,
142
- originalTranscribedSegment,
143
- isGlobal
144
- }: ActionBarProps) {
145
- return (
146
- <EditActionBar
147
- onReset={onReset}
148
- onRevertToOriginal={onRevertToOriginal}
149
- onDelete={onDelete}
150
- onClose={onClose}
151
- onSave={onSave}
152
- editedSegment={editedSegment}
153
- originalTranscribedSegment={originalTranscribedSegment}
154
- isGlobal={isGlobal}
155
- />
156
- )
157
- })
158
-
159
- interface EditModalProps {
160
- open: boolean
161
- onClose: () => void
162
- segment: LyricsSegment | null
163
- segmentIndex: number | null
164
- originalSegment: LyricsSegment | null
165
- onSave: (updatedSegment: LyricsSegment) => void
166
- onPlaySegment?: (startTime: number) => void
167
- currentTime?: number
168
- onDelete?: (segmentIndex: number) => void
169
- onAddSegment?: (segmentIndex: number) => void
170
- onSplitSegment?: (segmentIndex: number, afterWordIndex: number) => void
171
- onMergeSegment?: (segmentIndex: number, mergeWithNext: boolean) => void
172
- setModalSpacebarHandler: (handler: (() => (e: KeyboardEvent) => void) | undefined) => void
173
- originalTranscribedSegment?: LyricsSegment | null
174
- isGlobal?: boolean
175
- isLoading?: boolean
176
- }
177
-
178
- export default function EditModal({
179
- open,
180
- onClose,
181
- segment,
182
- segmentIndex,
183
- originalSegment,
184
- onSave,
185
- onPlaySegment,
186
- currentTime = 0,
187
- onDelete,
188
- onAddSegment,
189
- onSplitSegment,
190
- onMergeSegment,
191
- setModalSpacebarHandler,
192
- originalTranscribedSegment,
193
- isGlobal = false,
194
- isLoading = false
195
- }: EditModalProps) {
196
- // console.log('EditModal - Render', {
197
- // open,
198
- // isGlobal,
199
- // isLoading,
200
- // hasSegment: !!segment,
201
- // segmentIndex,
202
- // hasOriginalSegment: !!originalSegment,
203
- // hasOriginalTranscribedSegment: !!originalTranscribedSegment
204
- // });
205
-
206
- const theme = useTheme()
207
- const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
208
-
209
- const [editedSegment, setEditedSegment] = useState<LyricsSegment | null>(segment)
210
- const [isPlaying, setIsPlaying] = useState(false)
211
-
212
- // Define updateSegment first since the hook depends on it
213
- const updateSegment = useCallback((newWords: Word[]) => {
214
- if (!editedSegment) return;
215
-
216
- const validStartTimes = newWords.map(w => w.start_time).filter((t): t is number => t !== null)
217
- const validEndTimes = newWords.map(w => w.end_time).filter((t): t is number => t !== null)
218
-
219
- const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null
220
- const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null
221
-
222
- setEditedSegment({
223
- ...editedSegment,
224
- words: newWords,
225
- text: newWords.map(w => w.text).join(' '),
226
- start_time: segmentStartTime,
227
- end_time: segmentEndTime
228
- })
229
- }, [editedSegment])
230
-
231
- // Use the manual sync hook
232
- const {
233
- isManualSyncing,
234
- syncWordIndex,
235
- startManualSync,
236
- cleanupManualSync,
237
- handleSpacebar,
238
- isSpacebarPressed,
239
- handleTapStart,
240
- handleTapEnd
241
- } = useManualSync({
242
- editedSegment,
243
- currentTime,
244
- onPlaySegment,
245
- updateSegment
246
- })
247
-
248
- const handleClose = useCallback(() => {
249
- // console.log('EditModal - handleClose called');
250
- cleanupManualSync()
251
- onClose()
252
- }, [onClose, cleanupManualSync])
253
-
254
- // Update the spacebar handler when modal state changes
255
- useEffect(() => {
256
- const spacebarHandler = handleSpacebar // Capture the current handler
257
-
258
- if (open) {
259
- // console.log('EditModal - Setting up modal spacebar handler', {
260
- // hasPlaySegment: !!onPlaySegment,
261
- // editedSegmentId: editedSegment?.id,
262
- // handlerFunction: spacebarHandler.toString().slice(0, 100),
263
- // isLoading
264
- // })
265
-
266
- // Create a function that will be called by the global event listeners
267
- const handleKeyEvent = (e: KeyboardEvent) => {
268
- if (e.code === 'Space') {
269
- spacebarHandler(e)
270
- }
271
- }
272
-
273
- setModalSpacebarHandler(() => handleKeyEvent)
274
-
275
- // Only cleanup when the effect is re-run or the modal is closed
276
- return () => {
277
- if (!open) {
278
- // console.log('EditModal - Cleanup: clearing modal spacebar handler')
279
- setModalSpacebarHandler(undefined)
280
- }
281
- }
282
- }
283
- }, [
284
- open,
285
- handleSpacebar,
286
- setModalSpacebarHandler,
287
- editedSegment?.id,
288
- onPlaySegment,
289
- isLoading
290
- ])
291
-
292
- // Update isPlaying when currentTime changes
293
- useEffect(() => {
294
- if (editedSegment) {
295
- const startTime = editedSegment.start_time ?? 0
296
- const endTime = editedSegment.end_time ?? 0
297
- const isWithinSegment = currentTime >= startTime && currentTime <= endTime
298
-
299
- setIsPlaying(isWithinSegment && window.isAudioPlaying === true)
300
- }
301
- }, [currentTime, editedSegment])
302
-
303
- // All useEffect hooks
304
- useEffect(() => {
305
- // console.log('EditModal - segment changed', {
306
- // hasSegment: !!segment,
307
- // segmentId: segment?.id,
308
- // wordCount: segment?.words.length
309
- // });
310
- setEditedSegment(segment)
311
- }, [segment])
312
-
313
- // Auto-stop sync if we go past the end time
314
- useEffect(() => {
315
- if (!editedSegment) return
316
-
317
- const endTime = editedSegment.end_time ?? 0
318
-
319
- if (window.isAudioPlaying && currentTime > endTime) {
320
- // console.log('Stopping playback: current time exceeded end time')
321
- window.toggleAudioPlayback?.()
322
- cleanupManualSync()
323
- }
324
-
325
- }, [isManualSyncing, editedSegment, currentTime, cleanupManualSync])
326
-
327
- // Add a function to get safe time values
328
- const getSafeTimeRange = useCallback((segment: LyricsSegment | null) => {
329
- if (!segment) return { start: 0, end: 1 }; // Default 1-second range
330
- const start = segment.start_time ?? 0;
331
- const end = segment.end_time ?? (start + 1);
332
- return { start, end };
333
- }, [])
334
-
335
- // Define all handler functions with useCallback before the early return
336
- const handleWordChange = useCallback((index: number, updates: Partial<Word>) => {
337
- if (!editedSegment) return;
338
- const newWords = [...editedSegment.words]
339
- newWords[index] = {
340
- ...newWords[index],
341
- ...updates
342
- }
343
- updateSegment(newWords)
344
- }, [editedSegment, updateSegment])
345
-
346
- const handleAddWord = useCallback((index?: number) => {
347
- if (!editedSegment) return;
348
- const newWords = [...editedSegment.words]
349
- let newWord: Word
350
-
351
- if (index === undefined) {
352
- // Add at end
353
- const lastWord = newWords[newWords.length - 1]
354
- const lastEndTime = lastWord.end_time ?? 0
355
- newWord = {
356
- id: nanoid(),
357
- text: '',
358
- start_time: lastEndTime,
359
- end_time: lastEndTime + 0.5,
360
- confidence: 1.0
361
- }
362
- newWords.push(newWord)
363
- } else {
364
- // Add between words
365
- const prevWord = newWords[index]
366
- const nextWord = newWords[index + 1]
367
- const midTime = prevWord ?
368
- (nextWord ?
369
- ((prevWord.end_time ?? 0) + (nextWord.start_time ?? 0)) / 2 :
370
- (prevWord.end_time ?? 0) + 0.5
371
- ) :
372
- (nextWord ? (nextWord.start_time ?? 0) - 0.5 : 0)
373
-
374
- newWord = {
375
- id: nanoid(),
376
- text: '',
377
- start_time: midTime - 0.25,
378
- end_time: midTime + 0.25,
379
- confidence: 1.0
380
- }
381
- newWords.splice(index + 1, 0, newWord)
382
- }
383
-
384
- updateSegment(newWords)
385
- }, [editedSegment, updateSegment])
386
-
387
- const handleSplitWord = useCallback((index: number) => {
388
- if (!editedSegment) return;
389
- const word = editedSegment.words[index]
390
- const startTime = word.start_time ?? 0
391
- const endTime = word.end_time ?? startTime + 0.5
392
- const totalDuration = endTime - startTime
393
-
394
- // Split on any number of spaces and filter out empty strings
395
- const words = word.text.split(/\s+/).filter(w => w.length > 0)
396
-
397
- if (words.length <= 1) {
398
- // If no spaces found, split the word in half as before
399
- const firstHalf = word.text.slice(0, Math.ceil(word.text.length / 2))
400
- const secondHalf = word.text.slice(Math.ceil(word.text.length / 2))
401
- words[0] = firstHalf
402
- words[1] = secondHalf
403
- }
404
-
405
- // Calculate time per word
406
- const timePerWord = totalDuration / words.length
407
-
408
- // Create new word objects with evenly distributed times
409
- const newWords = words.map((text, i) => ({
410
- id: nanoid(),
411
- text,
412
- start_time: startTime + (i * timePerWord),
413
- end_time: startTime + ((i + 1) * timePerWord),
414
- confidence: 1.0
415
- }))
416
-
417
- // Replace the original word with the new words
418
- const allWords = [...editedSegment.words]
419
- allWords.splice(index, 1, ...newWords)
420
-
421
- updateSegment(allWords)
422
- }, [editedSegment, updateSegment])
423
-
424
- const handleMergeWords = useCallback((index: number) => {
425
- if (!editedSegment) return;
426
- if (index >= editedSegment.words.length - 1) return
427
-
428
- const word1 = editedSegment.words[index]
429
- const word2 = editedSegment.words[index + 1]
430
- const newWords = [...editedSegment.words]
431
-
432
- newWords.splice(index, 2, {
433
- id: nanoid(),
434
- text: `${word1.text} ${word2.text}`.trim(),
435
- start_time: word1.start_time ?? null,
436
- end_time: word2.end_time ?? null,
437
- confidence: 1.0
438
- })
439
-
440
- updateSegment(newWords)
441
- }, [editedSegment, updateSegment])
442
-
443
- const handleRemoveWord = useCallback((index: number) => {
444
- if (!editedSegment) return;
445
- const newWords = editedSegment.words.filter((_, i) => i !== index)
446
- updateSegment(newWords)
447
- }, [editedSegment, updateSegment])
448
-
449
- const handleReset = useCallback(() => {
450
- if (!originalSegment) return
451
-
452
- console.log('EditModal - Resetting to original:', {
453
- isGlobal,
454
- originalSegmentId: originalSegment.id,
455
- originalWordCount: originalSegment.words.length
456
- })
457
-
458
- setEditedSegment(JSON.parse(JSON.stringify(originalSegment)))
459
- }, [originalSegment, isGlobal])
460
-
461
- const handleRevertToOriginal = useCallback(() => {
462
- if (!originalTranscribedSegment) return
463
-
464
- console.log('EditModal - Reverting to original transcribed:', {
465
- isGlobal,
466
- originalTranscribedSegmentId: originalTranscribedSegment.id,
467
- originalTranscribedWordCount: originalTranscribedSegment.words.length
468
- })
469
-
470
- setEditedSegment(JSON.parse(JSON.stringify(originalTranscribedSegment)))
471
- }, [originalTranscribedSegment, isGlobal])
472
-
473
- const handleSave = useCallback(() => {
474
- if (!editedSegment || !segment) return;
475
-
476
- console.log('EditModal - Saving segment:', {
477
- isGlobal,
478
- segmentIndex,
479
- originalText: segment?.text,
480
- editedText: editedSegment.text,
481
- wordCount: editedSegment.words.length,
482
- firstWord: editedSegment.words[0],
483
- lastWord: editedSegment.words[editedSegment.words.length - 1],
484
- timeRange: `${editedSegment.start_time?.toFixed(4) ?? 'N/A'} - ${editedSegment.end_time?.toFixed(4) ?? 'N/A'}`
485
- })
486
- onSave(editedSegment)
487
- onClose()
488
- }, [editedSegment, isGlobal, segmentIndex, segment, onSave, onClose])
489
-
490
- const handleDelete = useCallback(() => {
491
- if (segmentIndex !== null) {
492
- onDelete?.(segmentIndex)
493
- onClose()
494
- }
495
- }, [segmentIndex, onDelete, onClose])
496
-
497
- const handleSplitSegment = useCallback((wordIndex: number) => {
498
- if (segmentIndex !== null && editedSegment) {
499
- handleSave() // Save current changes first
500
- onSplitSegment?.(segmentIndex, wordIndex)
501
- }
502
- }, [segmentIndex, editedSegment, handleSave, onSplitSegment])
503
-
504
- const handleMergeSegment = useCallback((mergeWithNext: boolean) => {
505
- if (segmentIndex !== null && editedSegment) {
506
- handleSave() // Save current changes first
507
- onMergeSegment?.(segmentIndex, mergeWithNext)
508
- onClose()
509
- }
510
- }, [segmentIndex, editedSegment, handleSave, onMergeSegment, onClose])
511
-
512
- // Handle play/stop button click
513
- const handlePlayButtonClick = useCallback(() => {
514
- if (!segment?.start_time || !onPlaySegment) return
515
-
516
- if (isPlaying) {
517
- // Stop playback
518
- if (window.toggleAudioPlayback) {
519
- window.toggleAudioPlayback()
520
- }
521
- } else {
522
- // Start playback
523
- onPlaySegment(segment.start_time)
524
- }
525
- }, [segment?.start_time, onPlaySegment, isPlaying])
526
-
527
- // Calculate timeRange before the early return
528
- const timeRange = useMemo(() => {
529
- if (!editedSegment) return { start: 0, end: 1 };
530
- return getSafeTimeRange(editedSegment);
531
- }, [getSafeTimeRange, editedSegment]);
532
-
533
- // Memoize the dialog title to prevent re-renders
534
- const dialogTitle = useMemo(() => {
535
- // console.log('EditModal - Rendering dialog title', { isLoading, isGlobal });
536
-
537
- if (isLoading) {
538
- return (
539
- <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
540
- <Box sx={{ flex: 1, display: 'flex', alignItems: 'center', gap: 1 }}>
541
- Loading {isGlobal ? 'All Words' : `Segment ${segmentIndex}`}...
542
- </Box>
543
- <IconButton onClick={onClose} sx={{ ml: 'auto' }}>
544
- <CloseIcon />
545
- </IconButton>
546
- </DialogTitle>
547
- );
548
- }
549
-
550
- if (!segment) return null;
551
-
552
- return (
553
- <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
554
- <Box sx={{ flex: 1, display: 'flex', alignItems: 'center', gap: 1 }}>
555
- Edit {isGlobal ? 'All Words' : `Segment ${segmentIndex}`}
556
- {segment?.start_time !== null && onPlaySegment && (
557
- <IconButton
558
- size="small"
559
- onClick={handlePlayButtonClick}
560
- sx={{ padding: '4px' }}
561
- >
562
- {isPlaying ? (
563
- <StopIcon />
564
- ) : (
565
- <PlayCircleOutlineIcon />
566
- )}
567
- </IconButton>
568
- )}
569
- </Box>
570
- <IconButton onClick={onClose} sx={{ ml: 'auto' }}>
571
- <CloseIcon />
572
- </IconButton>
573
- </DialogTitle>
574
- );
575
- }, [isGlobal, segmentIndex, segment, onPlaySegment, handlePlayButtonClick, isPlaying, onClose, isLoading])
576
-
577
- // Early return after all hooks and function definitions
578
- if (!isLoading && (!segment || !editedSegment || !originalSegment)) {
579
- // console.log('EditModal - Early return: missing required data', {
580
- // hasSegment: !!segment,
581
- // hasEditedSegment: !!editedSegment,
582
- // hasOriginalSegment: !!originalSegment,
583
- // isLoading
584
- // });
585
- return null;
586
- }
587
- if (!isLoading && !isGlobal && segmentIndex === null) {
588
- // console.log('EditModal - Early return: non-global mode with null segmentIndex');
589
- return null;
590
- }
591
-
592
- // console.log('EditModal - Rendering dialog content', {
593
- // isLoading,
594
- // hasEditedSegment: !!editedSegment,
595
- // hasOriginalSegment: !!originalSegment
596
- // });
597
-
598
- return (
599
- <Dialog
600
- open={open}
601
- onClose={handleClose}
602
- maxWidth="md"
603
- fullWidth
604
- fullScreen={isMobile}
605
- onKeyDown={(e) => {
606
- if (e.key === 'Enter' && !e.shiftKey && !isLoading) {
607
- e.preventDefault()
608
- handleSave()
609
- }
610
- }}
611
- PaperProps={{
612
- sx: {
613
- height: isMobile ? '100%' : '90vh',
614
- margin: isMobile ? 0 : '5vh 0'
615
- }
616
- }}
617
- >
618
- {dialogTitle}
619
-
620
- <DialogContent
621
- dividers
622
- sx={{
623
- display: 'flex',
624
- flexDirection: 'column',
625
- flexGrow: 1,
626
- overflow: 'hidden',
627
- position: 'relative'
628
- }}
629
- >
630
- {isLoading && (
631
- <Box sx={{
632
- display: 'flex',
633
- flexDirection: 'column',
634
- alignItems: 'center',
635
- justifyContent: 'center',
636
- height: '100%',
637
- width: '100%',
638
- position: 'absolute',
639
- top: 0,
640
- left: 0,
641
- backgroundColor: (theme) => theme.palette.mode === 'dark'
642
- ? 'rgba(30, 41, 59, 0.95)' // slate-800 with opacity for dark mode
643
- : 'rgba(248, 250, 252, 0.95)', // light background for light mode
644
- zIndex: 10
645
- }}>
646
- <CircularProgress size={60} thickness={4} />
647
- <Typography variant="h6" sx={{ mt: 2, fontWeight: 'bold' }}>
648
- Loading {isGlobal ? 'all words' : 'segment'}...
649
- </Typography>
650
- <Typography variant="body2" sx={{ mt: 1, maxWidth: '80%', textAlign: 'center' }}>
651
- {isGlobal ? 'This may take a few seconds for songs with many words.' : 'Please wait...'}
652
- </Typography>
653
- </Box>
654
- )}
655
-
656
- {!isLoading && editedSegment && originalSegment && (
657
- <>
658
- <MemoizedTimelineSection
659
- words={editedSegment.words}
660
- timeRange={timeRange}
661
- originalSegment={originalSegment}
662
- editedSegment={editedSegment}
663
- currentTime={currentTime}
664
- isManualSyncing={isManualSyncing}
665
- syncWordIndex={syncWordIndex}
666
- isSpacebarPressed={isSpacebarPressed}
667
- onWordUpdate={handleWordChange}
668
- onPlaySegment={onPlaySegment}
669
- startManualSync={startManualSync}
670
- isGlobal={isGlobal}
671
- onTapStart={handleTapStart}
672
- onTapEnd={handleTapEnd}
673
- />
674
-
675
- <MemoizedWordList
676
- words={editedSegment.words}
677
- onWordUpdate={handleWordChange}
678
- onSplitWord={handleSplitWord}
679
- onMergeWords={handleMergeWords}
680
- onAddWord={handleAddWord}
681
- onRemoveWord={handleRemoveWord}
682
- onSplitSegment={handleSplitSegment}
683
- onAddSegment={onAddSegment}
684
- onMergeSegment={handleMergeSegment}
685
- isGlobal={isGlobal}
686
- />
687
- </>
688
- )}
689
-
690
- {!isLoading && (!editedSegment || !originalSegment) && (
691
- <Box sx={{
692
- display: 'flex',
693
- alignItems: 'center',
694
- justifyContent: 'center',
695
- height: '100%'
696
- }}>
697
- <Typography variant="h6">
698
- No segment data available
699
- </Typography>
700
- </Box>
701
- )}
702
- </DialogContent>
703
-
704
- <DialogActions>
705
- {!isLoading && editedSegment && (
706
- <MemoizedActionBar
707
- onReset={handleReset}
708
- onRevertToOriginal={handleRevertToOriginal}
709
- onDelete={handleDelete}
710
- onClose={handleClose}
711
- onSave={handleSave}
712
- editedSegment={editedSegment}
713
- originalTranscribedSegment={originalTranscribedSegment}
714
- isGlobal={isGlobal}
715
- />
716
- )}
717
- </DialogActions>
718
- </Dialog>
719
- )
720
- }