karaoke-gen 0.103.1__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 (339) hide show
  1. backend/Dockerfile.base +1 -0
  2. backend/api/routes/admin.py +226 -3
  3. backend/api/routes/push.py +238 -0
  4. backend/api/routes/users.py +14 -3
  5. backend/config.py +12 -1
  6. backend/main.py +2 -1
  7. backend/models/job.py +4 -0
  8. backend/models/user.py +20 -2
  9. backend/services/encoding_interface.py +4 -0
  10. backend/services/gce_encoding/main.py +22 -8
  11. backend/services/job_manager.py +68 -11
  12. backend/services/job_notification_service.py +4 -21
  13. backend/services/push_notification_service.py +409 -0
  14. backend/services/stripe_service.py +2 -2
  15. backend/tests/conftest.py +2 -1
  16. backend/tests/test_admin_delete_outputs.py +352 -0
  17. backend/tests/test_gce_encoding_worker.py +229 -0
  18. backend/tests/test_impersonation.py +18 -3
  19. backend/tests/test_job_notification_service.py +24 -58
  20. backend/tests/test_push_notification_service.py +460 -0
  21. backend/tests/test_push_routes.py +357 -0
  22. backend/tests/test_stripe_service.py +205 -0
  23. backend/tests/test_video_worker_orchestrator.py +189 -0
  24. backend/workers/video_worker_orchestrator.py +23 -0
  25. karaoke_gen/instrumental_review/server.py +145 -35
  26. karaoke_gen/nextjs_frontend/__init__.py +98 -0
  27. karaoke_gen/nextjs_frontend/out/404/index.html +1 -0
  28. karaoke_gen/nextjs_frontend/out/404.html +1 -0
  29. karaoke_gen/nextjs_frontend/out/__next.__PAGE__.txt +9 -0
  30. karaoke_gen/nextjs_frontend/out/__next._full.txt +22 -0
  31. karaoke_gen/nextjs_frontend/out/__next._head.txt +8 -0
  32. karaoke_gen/nextjs_frontend/out/__next._index.txt +9 -0
  33. karaoke_gen/nextjs_frontend/out/__next._tree.txt +2 -0
  34. karaoke_gen/nextjs_frontend/out/_next/static/chunks/01a7f8fe40f1ff47.js +1 -0
  35. karaoke_gen/nextjs_frontend/out/_next/static/chunks/112f346e31f991df.js +4 -0
  36. karaoke_gen/nextjs_frontend/out/_next/static/chunks/16d1a4dd9d8a873a.js +3 -0
  37. karaoke_gen/nextjs_frontend/out/_next/static/chunks/1ab85c362b8b0e86.js +9 -0
  38. karaoke_gen/nextjs_frontend/out/_next/static/chunks/247eb132b7f7b574.js +1 -0
  39. karaoke_gen/nextjs_frontend/out/_next/static/chunks/2b80d15cc95e4818.js +1 -0
  40. karaoke_gen/nextjs_frontend/out/_next/static/chunks/32c7eba5cd46c1bc.js +7 -0
  41. karaoke_gen/nextjs_frontend/out/_next/static/chunks/483f26794eae53d0.js +1 -0
  42. karaoke_gen/nextjs_frontend/out/_next/static/chunks/550c3b02e85f196a.js +1 -0
  43. karaoke_gen/nextjs_frontend/out/_next/static/chunks/55c5ade44387bef8.js +1 -0
  44. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5628d92b5893add2.css +1 -0
  45. karaoke_gen/nextjs_frontend/out/_next/static/chunks/56ebf7665e4341c8.js +7 -0
  46. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5997132b61dec430.js +1 -0
  47. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5ea55255bce3eb9e.js +5 -0
  48. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5eda89a57490b3cd.js +1 -0
  49. karaoke_gen/nextjs_frontend/out/_next/static/chunks/692f5d9e0d700c76.js +3 -0
  50. karaoke_gen/nextjs_frontend/out/_next/static/chunks/71d7a05b14f9f0f4.js +1 -0
  51. karaoke_gen/nextjs_frontend/out/_next/static/chunks/81ac355749ef3302.js +1 -0
  52. karaoke_gen/nextjs_frontend/out/_next/static/chunks/95f7e5934dbb0e5d.js +1 -0
  53. karaoke_gen/nextjs_frontend/out/_next/static/chunks/9bce8f19eaa46940.js +1 -0
  54. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  55. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a9ed54eed3e14c92.js +2 -0
  56. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b35cd41238ecfb17.js +1 -0
  57. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5bc3c3d5ebd49eb.js +1 -0
  58. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5c078c08db5ae32.js +5 -0
  59. karaoke_gen/nextjs_frontend/out/_next/static/chunks/be9c44a178104187.js +1 -0
  60. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c4c840e18cb4861c.js +1 -0
  61. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c645af7d6b65f73e.js +1 -0
  62. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d2c5e2575df784d4.js +1 -0
  63. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d30af02b96d81462.js +1 -0
  64. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d9bdf64f4ec1e9b7.js +7 -0
  65. karaoke_gen/nextjs_frontend/out/_next/static/chunks/dcde6ed684dacd0e.js +5 -0
  66. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e422cbe931246000.js +1 -0
  67. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e483af34fc792d38.js +1 -0
  68. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e57422aad6b897da.js +1 -0
  69. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ef02697fb404726a.js +1 -0
  70. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ff1a16fafef87110.js +1 -0
  71. karaoke_gen/nextjs_frontend/out/_next/static/chunks/turbopack-2d9ca3017a9deedf.js +3 -0
  72. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_buildManifest.js +11 -0
  73. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_clientMiddlewareManifest.json +1 -0
  74. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_ssgManifest.js +1 -0
  75. karaoke_gen/nextjs_frontend/out/_not-found/__next._full.txt +18 -0
  76. karaoke_gen/nextjs_frontend/out/_not-found/__next._head.txt +8 -0
  77. karaoke_gen/nextjs_frontend/out/_not-found/__next._index.txt +9 -0
  78. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.__PAGE__.txt +5 -0
  79. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.txt +4 -0
  80. karaoke_gen/nextjs_frontend/out/_not-found/__next._tree.txt +2 -0
  81. karaoke_gen/nextjs_frontend/out/_not-found/index.html +1 -0
  82. karaoke_gen/nextjs_frontend/out/_not-found/index.txt +18 -0
  83. karaoke_gen/nextjs_frontend/out/admin/__next._full.txt +25 -0
  84. karaoke_gen/nextjs_frontend/out/admin/__next._head.txt +8 -0
  85. karaoke_gen/nextjs_frontend/out/admin/__next._index.txt +9 -0
  86. karaoke_gen/nextjs_frontend/out/admin/__next._tree.txt +2 -0
  87. karaoke_gen/nextjs_frontend/out/admin/__next.admin.__PAGE__.txt +9 -0
  88. karaoke_gen/nextjs_frontend/out/admin/__next.admin.txt +7 -0
  89. karaoke_gen/nextjs_frontend/out/admin/beta/__next._full.txt +25 -0
  90. karaoke_gen/nextjs_frontend/out/admin/beta/__next._head.txt +8 -0
  91. karaoke_gen/nextjs_frontend/out/admin/beta/__next._index.txt +9 -0
  92. karaoke_gen/nextjs_frontend/out/admin/beta/__next._tree.txt +2 -0
  93. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.__PAGE__.txt +9 -0
  94. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.txt +4 -0
  95. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.txt +7 -0
  96. karaoke_gen/nextjs_frontend/out/admin/beta/index.html +1 -0
  97. karaoke_gen/nextjs_frontend/out/admin/beta/index.txt +25 -0
  98. karaoke_gen/nextjs_frontend/out/admin/index.html +1 -0
  99. karaoke_gen/nextjs_frontend/out/admin/index.txt +25 -0
  100. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._full.txt +25 -0
  101. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._head.txt +8 -0
  102. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._index.txt +9 -0
  103. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._tree.txt +2 -0
  104. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.__PAGE__.txt +9 -0
  105. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.txt +4 -0
  106. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.txt +7 -0
  107. karaoke_gen/nextjs_frontend/out/admin/jobs/index.html +1 -0
  108. karaoke_gen/nextjs_frontend/out/admin/jobs/index.txt +25 -0
  109. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._full.txt +25 -0
  110. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._head.txt +8 -0
  111. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._index.txt +9 -0
  112. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._tree.txt +2 -0
  113. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.__PAGE__.txt +9 -0
  114. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.txt +4 -0
  115. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.txt +7 -0
  116. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.html +1 -0
  117. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.txt +25 -0
  118. karaoke_gen/nextjs_frontend/out/admin/searches/__next._full.txt +25 -0
  119. karaoke_gen/nextjs_frontend/out/admin/searches/__next._head.txt +8 -0
  120. karaoke_gen/nextjs_frontend/out/admin/searches/__next._index.txt +9 -0
  121. karaoke_gen/nextjs_frontend/out/admin/searches/__next._tree.txt +2 -0
  122. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.__PAGE__.txt +9 -0
  123. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.txt +4 -0
  124. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.txt +7 -0
  125. karaoke_gen/nextjs_frontend/out/admin/searches/index.html +1 -0
  126. karaoke_gen/nextjs_frontend/out/admin/searches/index.txt +25 -0
  127. karaoke_gen/nextjs_frontend/out/admin/users/__next._full.txt +25 -0
  128. karaoke_gen/nextjs_frontend/out/admin/users/__next._head.txt +8 -0
  129. karaoke_gen/nextjs_frontend/out/admin/users/__next._index.txt +9 -0
  130. karaoke_gen/nextjs_frontend/out/admin/users/__next._tree.txt +2 -0
  131. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.txt +7 -0
  132. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.__PAGE__.txt +9 -0
  133. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.txt +4 -0
  134. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._full.txt +25 -0
  135. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._head.txt +8 -0
  136. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._index.txt +9 -0
  137. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._tree.txt +2 -0
  138. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.txt +7 -0
  139. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.__PAGE__.txt +9 -0
  140. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.txt +4 -0
  141. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.txt +4 -0
  142. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.html +1 -0
  143. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.txt +25 -0
  144. karaoke_gen/nextjs_frontend/out/admin/users/index.html +1 -0
  145. karaoke_gen/nextjs_frontend/out/admin/users/index.txt +25 -0
  146. karaoke_gen/nextjs_frontend/out/app/__next._full.txt +22 -0
  147. karaoke_gen/nextjs_frontend/out/app/__next._head.txt +8 -0
  148. karaoke_gen/nextjs_frontend/out/app/__next._index.txt +9 -0
  149. karaoke_gen/nextjs_frontend/out/app/__next._tree.txt +2 -0
  150. karaoke_gen/nextjs_frontend/out/app/__next.app.__PAGE__.txt +9 -0
  151. karaoke_gen/nextjs_frontend/out/app/__next.app.txt +4 -0
  152. karaoke_gen/nextjs_frontend/out/app/index.html +1 -0
  153. karaoke_gen/nextjs_frontend/out/app/index.txt +22 -0
  154. karaoke_gen/nextjs_frontend/out/app/jobs/__next._full.txt +19 -0
  155. karaoke_gen/nextjs_frontend/out/app/jobs/__next._head.txt +8 -0
  156. karaoke_gen/nextjs_frontend/out/app/jobs/__next._index.txt +9 -0
  157. karaoke_gen/nextjs_frontend/out/app/jobs/__next._tree.txt +2 -0
  158. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  159. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.txt +4 -0
  160. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.txt +4 -0
  161. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.txt +4 -0
  162. karaoke_gen/nextjs_frontend/out/app/jobs/index.html +1 -0
  163. karaoke_gen/nextjs_frontend/out/app/jobs/index.txt +19 -0
  164. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._full.txt +19 -0
  165. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._head.txt +8 -0
  166. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._index.txt +9 -0
  167. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._tree.txt +2 -0
  168. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  169. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.txt +4 -0
  170. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.txt +4 -0
  171. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.txt +4 -0
  172. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.html +1 -0
  173. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.txt +19 -0
  174. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._full.txt +19 -0
  175. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._head.txt +8 -0
  176. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._index.txt +9 -0
  177. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._tree.txt +2 -0
  178. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  179. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.txt +4 -0
  180. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.txt +4 -0
  181. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.txt +4 -0
  182. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.html +1 -0
  183. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.txt +19 -0
  184. karaoke_gen/nextjs_frontend/out/auth/verify/__next._full.txt +22 -0
  185. karaoke_gen/nextjs_frontend/out/auth/verify/__next._head.txt +8 -0
  186. karaoke_gen/nextjs_frontend/out/auth/verify/__next._index.txt +9 -0
  187. karaoke_gen/nextjs_frontend/out/auth/verify/__next._tree.txt +2 -0
  188. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.txt +4 -0
  189. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.__PAGE__.txt +9 -0
  190. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.txt +4 -0
  191. karaoke_gen/nextjs_frontend/out/auth/verify/index.html +1 -0
  192. karaoke_gen/nextjs_frontend/out/auth/verify/index.txt +22 -0
  193. karaoke_gen/nextjs_frontend/out/index.html +1 -0
  194. karaoke_gen/nextjs_frontend/out/index.txt +22 -0
  195. karaoke_gen/nextjs_frontend/out/manifest.webmanifest +31 -0
  196. karaoke_gen/nextjs_frontend/out/order/success/__next._full.txt +22 -0
  197. karaoke_gen/nextjs_frontend/out/order/success/__next._head.txt +8 -0
  198. karaoke_gen/nextjs_frontend/out/order/success/__next._index.txt +9 -0
  199. karaoke_gen/nextjs_frontend/out/order/success/__next._tree.txt +2 -0
  200. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.__PAGE__.txt +9 -0
  201. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.txt +4 -0
  202. karaoke_gen/nextjs_frontend/out/order/success/__next.order.txt +4 -0
  203. karaoke_gen/nextjs_frontend/out/order/success/index.html +1 -0
  204. karaoke_gen/nextjs_frontend/out/order/success/index.txt +22 -0
  205. karaoke_gen/nextjs_frontend/out/payment/success/__next._full.txt +22 -0
  206. karaoke_gen/nextjs_frontend/out/payment/success/__next._head.txt +8 -0
  207. karaoke_gen/nextjs_frontend/out/payment/success/__next._index.txt +9 -0
  208. karaoke_gen/nextjs_frontend/out/payment/success/__next._tree.txt +2 -0
  209. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.__PAGE__.txt +9 -0
  210. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.txt +4 -0
  211. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.txt +4 -0
  212. karaoke_gen/nextjs_frontend/out/payment/success/index.html +1 -0
  213. karaoke_gen/nextjs_frontend/out/payment/success/index.txt +22 -0
  214. karaoke_gen/nextjs_frontend/out/screenshots/email-action_reminder.png +0 -0
  215. karaoke_gen/nextjs_frontend/out/screenshots/email-beta_welcome.png +0 -0
  216. karaoke_gen/nextjs_frontend/out/screenshots/email-job_completion.png +0 -0
  217. karaoke_gen/nextjs_frontend/out/screenshots/example-output.avif +0 -0
  218. karaoke_gen/nextjs_frontend/out/screenshots/homepage-full.png +0 -0
  219. karaoke_gen/nextjs_frontend/out/screenshots/homepage-hero.png +0 -0
  220. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.avif +0 -0
  221. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.png +0 -0
  222. karaoke_gen/nextjs_frontend/out/screenshots/job-dashboard.avif +0 -0
  223. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.avif +0 -0
  224. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.png +0 -0
  225. karaoke_gen/nextjs_frontend/out/sw.js +183 -0
  226. karaoke_gen/utils/cli_args.py +3 -3
  227. karaoke_gen/utils/gen_cli.py +4 -0
  228. karaoke_gen/utils/remote_cli.py +8 -40
  229. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/METADATA +2 -1
  230. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/RECORD +244 -131
  231. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/WHEEL +1 -1
  232. lyrics_transcriber/correction/agentic/agent.py +83 -60
  233. lyrics_transcriber/correction/anchor_sequence.py +48 -3
  234. lyrics_transcriber/correction/corrector.py +92 -58
  235. lyrics_transcriber/review/server.py +165 -33
  236. lyrics_transcriber/utils/tracing.py +214 -0
  237. karaoke_gen/instrumental_review/static/index.html +0 -1695
  238. lyrics_transcriber/frontend/.gitignore +0 -24
  239. lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +0 -935
  240. lyrics_transcriber/frontend/.yarnrc.yml +0 -3
  241. lyrics_transcriber/frontend/README.md +0 -50
  242. lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +0 -210
  243. lyrics_transcriber/frontend/__init__.py +0 -25
  244. lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts +0 -207
  245. lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json +0 -226
  246. lyrics_transcriber/frontend/eslint.config.js +0 -28
  247. lyrics_transcriber/frontend/index.html +0 -22
  248. lyrics_transcriber/frontend/package-lock.json +0 -4553
  249. lyrics_transcriber/frontend/package.json +0 -48
  250. lyrics_transcriber/frontend/playwright.config.ts +0 -69
  251. lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
  252. lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
  253. lyrics_transcriber/frontend/src/App.tsx +0 -243
  254. lyrics_transcriber/frontend/src/api.ts +0 -262
  255. lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +0 -111
  256. lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +0 -114
  257. lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +0 -204
  258. lyrics_transcriber/frontend/src/components/AppHeader.tsx +0 -65
  259. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +0 -180
  260. lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +0 -175
  261. lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +0 -359
  262. lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +0 -281
  263. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +0 -162
  264. lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +0 -257
  265. lyrics_transcriber/frontend/src/components/EditActionBar.tsx +0 -94
  266. lyrics_transcriber/frontend/src/components/EditModal.tsx +0 -720
  267. lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +0 -592
  268. lyrics_transcriber/frontend/src/components/EditWordList.tsx +0 -431
  269. lyrics_transcriber/frontend/src/components/FileUpload.tsx +0 -77
  270. lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +0 -467
  271. lyrics_transcriber/frontend/src/components/Header.tsx +0 -520
  272. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +0 -1526
  273. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +0 -216
  274. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +0 -721
  275. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +0 -80
  276. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +0 -999
  277. lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +0 -51
  278. lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +0 -127
  279. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +0 -67
  280. lyrics_transcriber/frontend/src/components/ModelSelector.tsx +0 -23
  281. lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +0 -177
  282. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +0 -268
  283. lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +0 -336
  284. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +0 -354
  285. lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +0 -64
  286. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +0 -383
  287. lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +0 -131
  288. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +0 -266
  289. lyrics_transcriber/frontend/src/components/WordDivider.tsx +0 -191
  290. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +0 -466
  291. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +0 -56
  292. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +0 -89
  293. lyrics_transcriber/frontend/src/components/shared/constants.ts +0 -30
  294. lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +0 -180
  295. lyrics_transcriber/frontend/src/components/shared/styles.ts +0 -13
  296. lyrics_transcriber/frontend/src/components/shared/types.js +0 -2
  297. lyrics_transcriber/frontend/src/components/shared/types.ts +0 -135
  298. lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +0 -177
  299. lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +0 -78
  300. lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +0 -75
  301. lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +0 -360
  302. lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +0 -110
  303. lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +0 -22
  304. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +0 -537
  305. lyrics_transcriber/frontend/src/main.tsx +0 -11
  306. lyrics_transcriber/frontend/src/theme.ts +0 -406
  307. lyrics_transcriber/frontend/src/types/global.d.ts +0 -9
  308. lyrics_transcriber/frontend/src/types.js +0 -2
  309. lyrics_transcriber/frontend/src/types.ts +0 -199
  310. lyrics_transcriber/frontend/src/validation.ts +0 -132
  311. lyrics_transcriber/frontend/src/vite-env.d.ts +0 -1
  312. lyrics_transcriber/frontend/tsconfig.app.json +0 -26
  313. lyrics_transcriber/frontend/tsconfig.json +0 -25
  314. lyrics_transcriber/frontend/tsconfig.node.json +0 -23
  315. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +0 -1
  316. lyrics_transcriber/frontend/update_version.js +0 -11
  317. lyrics_transcriber/frontend/vite.config.d.ts +0 -2
  318. lyrics_transcriber/frontend/vite.config.js +0 -15
  319. lyrics_transcriber/frontend/vite.config.ts +0 -16
  320. lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
  321. lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
  322. lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
  323. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js +0 -44465
  324. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +0 -1
  325. lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
  326. lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
  327. lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
  328. lyrics_transcriber/frontend/web_assets/index.html +0 -22
  329. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
  330. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +0 -5
  331. lyrics_transcriber/frontend/yarn.lock +0 -3711
  332. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/apple-touch-icon.png +0 -0
  333. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-16x16.png +0 -0
  334. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-32x32.png +0 -0
  335. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon.ico +0 -0
  336. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/nomad-karaoke-logo.svg +0 -0
  337. /lyrics_transcriber/frontend/public/nomad-karaoke-logo.png → /karaoke_gen/nextjs_frontend/out/nomad-logo.png +0 -0
  338. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/entry_points.txt +0 -0
  339. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,268 +0,0 @@
1
- import { useMemo } from 'react'
2
- import { Paper, Typography, Box, IconButton } from '@mui/material'
3
- import { ReferenceViewProps } from './shared/types'
4
- import { calculateReferenceLinePositions } from './shared/utils/referenceLineCalculator'
5
- import { SourceSelector } from './shared/components/SourceSelector'
6
- import { HighlightedText } from './shared/components/HighlightedText'
7
- import { TranscriptionWordPosition } from './shared/types'
8
- import { getWordsFromIds } from './shared/utils/wordUtils'
9
- import ContentCopyIcon from '@mui/icons-material/ContentCopy'
10
- import { styled } from '@mui/material/styles'
11
-
12
- const SegmentControls = styled(Box)({
13
- display: 'flex',
14
- alignItems: 'center',
15
- gap: '2px',
16
- paddingTop: '1px',
17
- paddingRight: '4px'
18
- })
19
-
20
- const TextContainer = styled(Box)({
21
- flex: 1,
22
- minWidth: 0,
23
- })
24
-
25
- export default function ReferenceView({
26
- referenceSources,
27
- anchors,
28
- onElementClick,
29
- onWordClick,
30
- flashingType,
31
- corrected_segments,
32
- currentSource,
33
- onSourceChange,
34
- highlightInfo,
35
- mode,
36
- gaps,
37
- corrections,
38
- onAddLyrics
39
- }: ReferenceViewProps) {
40
- // Get available sources from referenceSources object
41
- const availableSources = useMemo(() =>
42
- Object.keys(referenceSources),
43
- [referenceSources]
44
- )
45
-
46
- // Ensure we always have a valid currentSource
47
- const effectiveCurrentSource = useMemo(() =>
48
- currentSource || (availableSources.length > 0 ? availableSources[0] : ''),
49
- [currentSource, availableSources]
50
- )
51
-
52
- // Create word positions for the reference view
53
- const referenceWordPositions = useMemo(() => {
54
- const positions: TranscriptionWordPosition[] = [];
55
- const allPositions = new Map<number, TranscriptionWordPosition[]>();
56
-
57
- // Map anchor words
58
- anchors?.forEach(anchor => {
59
- const position = anchor.reference_positions[effectiveCurrentSource];
60
- if (position === undefined) return;
61
-
62
- if (!allPositions.has(position)) {
63
- allPositions.set(position, []);
64
- }
65
-
66
- const referenceWords = getWordsFromIds(
67
- referenceSources[effectiveCurrentSource].segments,
68
- anchor.reference_word_ids[effectiveCurrentSource] || []
69
- );
70
-
71
- referenceWords.forEach(word => {
72
- const wordPosition: TranscriptionWordPosition = {
73
- word: {
74
- id: word.id,
75
- text: word.text,
76
- start_time: word.start_time ?? undefined,
77
- end_time: word.end_time ?? undefined
78
- },
79
- type: 'anchor',
80
- sequence: anchor,
81
- isInRange: true
82
- };
83
- allPositions.get(position)!.push(wordPosition);
84
- });
85
- });
86
-
87
- // Map gap words
88
- gaps?.forEach(gap => {
89
- const precedingAnchor = gap.preceding_anchor_id ?
90
- anchors?.find(a => a.id === gap.preceding_anchor_id) :
91
- undefined;
92
- const followingAnchor = gap.following_anchor_id ?
93
- anchors?.find(a => a.id === gap.following_anchor_id) :
94
- undefined;
95
-
96
- const position = precedingAnchor?.reference_positions[effectiveCurrentSource] ??
97
- followingAnchor?.reference_positions[effectiveCurrentSource];
98
-
99
- if (position === undefined) return;
100
-
101
- const gapPosition = precedingAnchor ? position + 1 : position - 1;
102
-
103
- if (!allPositions.has(gapPosition)) {
104
- allPositions.set(gapPosition, []);
105
- }
106
-
107
- const referenceWords = getWordsFromIds(
108
- referenceSources[effectiveCurrentSource].segments,
109
- gap.reference_word_ids[effectiveCurrentSource] || []
110
- );
111
-
112
- referenceWords.forEach(word => {
113
- // Find if this word has a correction
114
- const isWordCorrected = corrections?.some(correction =>
115
- correction.reference_positions?.[effectiveCurrentSource]?.toString() === word.id &&
116
- gap.transcribed_word_ids.includes(correction.word_id)
117
- );
118
-
119
- const wordPosition: TranscriptionWordPosition = {
120
- word: {
121
- id: word.id,
122
- text: word.text,
123
- start_time: word.start_time ?? undefined,
124
- end_time: word.end_time ?? undefined
125
- },
126
- type: 'gap',
127
- sequence: gap,
128
- isInRange: true,
129
- isCorrected: isWordCorrected
130
- };
131
- allPositions.get(gapPosition)!.push(wordPosition);
132
- });
133
- });
134
-
135
- // Sort by position and flatten
136
- Array.from(allPositions.entries())
137
- .sort(([a], [b]) => a - b)
138
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
139
- .forEach(([_, words]) => {
140
- positions.push(...words);
141
- });
142
-
143
- return positions;
144
- }, [anchors, gaps, effectiveCurrentSource, referenceSources, corrections]);
145
-
146
- const { linePositions } = useMemo(() =>
147
- calculateReferenceLinePositions(
148
- corrected_segments,
149
- anchors,
150
- effectiveCurrentSource
151
- ),
152
- [corrected_segments, anchors, effectiveCurrentSource]
153
- )
154
-
155
- // Create a mapping of reference words to their corrections
156
- const referenceCorrections = useMemo(() => {
157
- const correctionMap = new Map<string, string>();
158
-
159
- corrections?.forEach(correction => {
160
- const referencePosition = correction.reference_positions?.[effectiveCurrentSource];
161
- if (referencePosition !== undefined) {
162
- correctionMap.set(referencePosition.toString(), correction.corrected_word);
163
- }
164
- });
165
-
166
- return correctionMap;
167
- }, [corrections, effectiveCurrentSource]);
168
-
169
- // Get the segments for the current source
170
- const currentSourceSegments = referenceSources[effectiveCurrentSource]?.segments || [];
171
-
172
- // Helper function to copy text to clipboard
173
- const copyToClipboard = (text: string) => {
174
- navigator.clipboard.writeText(text);
175
- };
176
-
177
- // Helper function to copy all reference text from current source
178
- const copyAllReferenceText = () => {
179
- const allText = currentSourceSegments
180
- .map(segment => segment.words.map(w => w.text).join(' '))
181
- .join('\n');
182
- copyToClipboard(allText);
183
- };
184
-
185
- return (
186
- <Paper sx={{ p: 0.8, position: 'relative' }}>
187
- <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 0.5 }}>
188
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
189
- <Typography variant="h6" sx={{ fontSize: '0.9rem', mb: 0 }}>
190
- Reference Lyrics
191
- </Typography>
192
- <IconButton
193
- size="small"
194
- onClick={copyAllReferenceText}
195
- sx={{
196
- padding: '2px',
197
- height: '20px',
198
- width: '20px',
199
- minHeight: '20px',
200
- minWidth: '20px'
201
- }}
202
- title="Copy all reference lyrics"
203
- >
204
- <ContentCopyIcon sx={{ fontSize: '1rem' }} />
205
- </IconButton>
206
- </Box>
207
- <SourceSelector
208
- availableSources={availableSources}
209
- currentSource={effectiveCurrentSource}
210
- onSourceChange={onSourceChange}
211
- onAddLyrics={onAddLyrics}
212
- />
213
- </Box>
214
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.2 }}>
215
- {currentSourceSegments.map((segment, index) => (
216
- <Box
217
- key={index}
218
- sx={{
219
- display: 'flex',
220
- alignItems: 'flex-start',
221
- width: '100%',
222
- mb: 0,
223
- '&:hover': {
224
- backgroundColor: (theme) => theme.palette.action.hover
225
- }
226
- }}
227
- >
228
- <SegmentControls>
229
- <IconButton
230
- size="small"
231
- onClick={() => copyToClipboard(segment.words.map(w => w.text).join(' '))}
232
- sx={{
233
- padding: '1px',
234
- height: '18px',
235
- width: '18px',
236
- minHeight: '18px',
237
- minWidth: '18px'
238
- }}
239
- >
240
- <ContentCopyIcon sx={{ fontSize: '0.9rem' }} />
241
- </IconButton>
242
- </SegmentControls>
243
- <TextContainer>
244
- <HighlightedText
245
- wordPositions={referenceWordPositions.filter(wp =>
246
- segment.words.some(w => w.id === wp.word.id)
247
- )}
248
- segments={[segment]}
249
- anchors={anchors}
250
- onElementClick={onElementClick}
251
- onWordClick={onWordClick}
252
- flashingType={flashingType}
253
- highlightInfo={highlightInfo}
254
- mode={mode}
255
- isReference={true}
256
- currentSource={effectiveCurrentSource}
257
- linePositions={linePositions}
258
- referenceCorrections={referenceCorrections}
259
- gaps={gaps}
260
- preserveSegments={true}
261
- />
262
- </TextContainer>
263
- </Box>
264
- ))}
265
- </Box>
266
- </Paper>
267
- )
268
- }
@@ -1,336 +0,0 @@
1
- import {
2
- Dialog,
3
- DialogTitle,
4
- DialogContent,
5
- DialogActions,
6
- IconButton,
7
- Box,
8
- Button,
9
- Typography,
10
- TextField
11
- } from '@mui/material'
12
- import CloseIcon from '@mui/icons-material/Close'
13
- import ContentPasteIcon from '@mui/icons-material/ContentPaste'
14
- import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh'
15
- import ArrowBackIcon from '@mui/icons-material/ArrowBack'
16
- import { LyricsSegment, Word } from '../types'
17
- import { useState, useEffect, useCallback, useMemo } from 'react'
18
- import { nanoid } from 'nanoid'
19
- import ModeSelectionModal from './ModeSelectionModal'
20
- import LyricsSynchronizer from './LyricsSynchronizer'
21
-
22
- // Augment window type for audio functions
23
- declare global {
24
- interface Window {
25
- getAudioDuration?: () => number;
26
- toggleAudioPlayback?: () => void;
27
- isAudioPlaying?: boolean;
28
- }
29
- }
30
-
31
- type ModalMode = 'selection' | 'replace' | 'resync'
32
-
33
- interface ReplaceAllLyricsModalProps {
34
- open: boolean
35
- onClose: () => void
36
- onSave: (newSegments: LyricsSegment[]) => void
37
- onPlaySegment?: (startTime: number) => void
38
- currentTime?: number
39
- setModalSpacebarHandler: (handler: (() => (e: KeyboardEvent) => void) | undefined) => void
40
- existingSegments?: LyricsSegment[] // Current segments for re-sync mode
41
- }
42
-
43
- export default function ReplaceAllLyricsModal({
44
- open,
45
- onClose,
46
- onSave,
47
- onPlaySegment,
48
- currentTime = 0,
49
- setModalSpacebarHandler,
50
- existingSegments = []
51
- }: ReplaceAllLyricsModalProps) {
52
- const [mode, setMode] = useState<ModalMode>('selection')
53
- const [inputText, setInputText] = useState('')
54
- const [newSegments, setNewSegments] = useState<LyricsSegment[]>([])
55
-
56
- // Reset state when modal opens
57
- useEffect(() => {
58
- if (open) {
59
- setMode('selection')
60
- setInputText('')
61
- setNewSegments([])
62
- }
63
- }, [open])
64
-
65
- // Parse the input text to get line and word counts
66
- const parseInfo = useMemo(() => {
67
- if (!inputText.trim()) return { lines: 0, words: 0 }
68
-
69
- const lines = inputText.trim().split('\n').filter(line => line.trim().length > 0)
70
- const totalWords = lines.reduce((count, line) => {
71
- return count + line.trim().split(/\s+/).length
72
- }, 0)
73
-
74
- return { lines: lines.length, words: totalWords }
75
- }, [inputText])
76
-
77
- // Process the input text into segments and words
78
- const processLyrics = useCallback(() => {
79
- if (!inputText.trim()) return
80
-
81
- const lines = inputText.trim().split('\n').filter(line => line.trim().length > 0)
82
- const segments: LyricsSegment[] = []
83
-
84
- lines.forEach((line) => {
85
- const words = line.trim().split(/\s+/).filter(word => word.length > 0)
86
- const segmentWords: Word[] = words.map((wordText) => ({
87
- id: nanoid(),
88
- text: wordText,
89
- start_time: null,
90
- end_time: null,
91
- confidence: 1.0,
92
- created_during_correction: true
93
- }))
94
-
95
- segments.push({
96
- id: nanoid(),
97
- text: line.trim(),
98
- words: segmentWords,
99
- start_time: null,
100
- end_time: null
101
- })
102
- })
103
-
104
- setNewSegments(segments)
105
- setMode('resync') // Go to synchronizer with the new segments
106
- }, [inputText])
107
-
108
- // Handle paste from clipboard
109
- const handlePasteFromClipboard = useCallback(async () => {
110
- try {
111
- const text = await navigator.clipboard.readText()
112
- setInputText(text)
113
- } catch (error) {
114
- console.error('Failed to read from clipboard:', error)
115
- alert('Failed to read from clipboard. Please paste manually.')
116
- }
117
- }, [])
118
-
119
- // Handle modal close
120
- const handleClose = useCallback(() => {
121
- setMode('selection')
122
- setInputText('')
123
- setNewSegments([])
124
- onClose()
125
- }, [onClose])
126
-
127
- // Handle save from synchronizer
128
- const handleSave = useCallback((segments: LyricsSegment[]) => {
129
- onSave(segments)
130
- handleClose()
131
- }, [onSave, handleClose])
132
-
133
- // Handle mode selection
134
- const handleSelectReplace = useCallback(() => {
135
- setMode('replace')
136
- }, [])
137
-
138
- const handleSelectResync = useCallback(() => {
139
- setMode('resync')
140
- }, [])
141
-
142
- // Handle back to selection
143
- const handleBackToSelection = useCallback(() => {
144
- setMode('selection')
145
- setInputText('')
146
- setNewSegments([])
147
- }, [])
148
-
149
- // Determine which segments to use for synchronizer
150
- const segmentsForSync = mode === 'resync' && newSegments.length > 0
151
- ? newSegments
152
- : existingSegments
153
-
154
- // Check if we have existing lyrics
155
- const hasExistingLyrics = existingSegments.length > 0 &&
156
- existingSegments.some(s => s.words.length > 0)
157
-
158
- return (
159
- <>
160
- {/* Mode Selection Modal */}
161
- <ModeSelectionModal
162
- open={open && mode === 'selection'}
163
- onClose={handleClose}
164
- onSelectReplace={handleSelectReplace}
165
- onSelectResync={handleSelectResync}
166
- hasExistingLyrics={hasExistingLyrics}
167
- />
168
-
169
- {/* Replace All Lyrics Modal (Paste Phase) */}
170
- <Dialog
171
- open={open && mode === 'replace'}
172
- onClose={handleClose}
173
- maxWidth="md"
174
- fullWidth
175
- PaperProps={{
176
- sx: {
177
- height: '80vh',
178
- maxHeight: '80vh'
179
- }
180
- }}
181
- >
182
- <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
183
- <IconButton onClick={handleBackToSelection} size="small">
184
- <ArrowBackIcon />
185
- </IconButton>
186
- <Box sx={{ flex: 1 }}>
187
- Replace All Lyrics
188
- </Box>
189
- <IconButton onClick={handleClose} sx={{ ml: 'auto' }}>
190
- <CloseIcon />
191
- </IconButton>
192
- </DialogTitle>
193
-
194
- <DialogContent
195
- dividers
196
- sx={{
197
- display: 'flex',
198
- flexDirection: 'column',
199
- flexGrow: 1,
200
- overflow: 'hidden'
201
- }}
202
- >
203
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, height: '100%' }}>
204
- <Typography variant="h6" gutterBottom>
205
- Paste your new lyrics below:
206
- </Typography>
207
-
208
- <Typography variant="body2" color="text.secondary" gutterBottom>
209
- Each line will become a separate segment. Words will be separated by spaces.
210
- </Typography>
211
-
212
- <Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
213
- <Button
214
- variant="outlined"
215
- onClick={handlePasteFromClipboard}
216
- startIcon={<ContentPasteIcon />}
217
- size="small"
218
- >
219
- Paste from Clipboard
220
- </Button>
221
- <Typography variant="body2" sx={{
222
- alignSelf: 'center',
223
- color: 'text.secondary',
224
- fontWeight: 'medium'
225
- }}>
226
- {parseInfo.lines} lines, {parseInfo.words} words
227
- </Typography>
228
- </Box>
229
-
230
- <TextField
231
- multiline
232
- rows={15}
233
- value={inputText}
234
- onChange={(e) => setInputText(e.target.value)}
235
- placeholder="Paste your lyrics here...&#10;Each line will become a segment&#10;Words will be separated by spaces"
236
- sx={{
237
- flexGrow: 1,
238
- '& .MuiInputBase-root': {
239
- height: '100%',
240
- alignItems: 'flex-start'
241
- }
242
- }}
243
- />
244
- </Box>
245
- </DialogContent>
246
-
247
- <DialogActions>
248
- <Button onClick={handleClose} color="inherit">
249
- Cancel
250
- </Button>
251
- <Button
252
- variant="contained"
253
- onClick={processLyrics}
254
- disabled={!inputText.trim()}
255
- startIcon={<AutoFixHighIcon />}
256
- >
257
- Continue to Sync
258
- </Button>
259
- </DialogActions>
260
- </Dialog>
261
-
262
- {/* Synchronizer Modal */}
263
- <Dialog
264
- open={open && mode === 'resync'}
265
- onClose={handleClose}
266
- maxWidth={false}
267
- fullWidth
268
- PaperProps={{
269
- sx: {
270
- height: '90vh',
271
- margin: '5vh 2vw',
272
- maxWidth: 'calc(100vw - 4vw)',
273
- width: 'calc(100vw - 4vw)'
274
- }
275
- }}
276
- >
277
- <DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
278
- <IconButton onClick={handleBackToSelection} size="small">
279
- <ArrowBackIcon />
280
- </IconButton>
281
- <Box sx={{ flex: 1 }}>
282
- {newSegments.length > 0 ? 'Sync New Lyrics' : 'Re-sync Existing Lyrics'}
283
- </Box>
284
- <IconButton onClick={handleClose} sx={{ ml: 'auto' }}>
285
- <CloseIcon />
286
- </IconButton>
287
- </DialogTitle>
288
-
289
- <DialogContent
290
- dividers
291
- sx={{
292
- display: 'flex',
293
- flexDirection: 'column',
294
- flexGrow: 1,
295
- overflow: 'hidden',
296
- p: 2
297
- }}
298
- >
299
- {segmentsForSync.length > 0 ? (
300
- <LyricsSynchronizer
301
- segments={segmentsForSync}
302
- currentTime={currentTime}
303
- onPlaySegment={onPlaySegment}
304
- onSave={handleSave}
305
- onCancel={handleClose}
306
- setModalSpacebarHandler={setModalSpacebarHandler}
307
- />
308
- ) : (
309
- <Box sx={{
310
- display: 'flex',
311
- flexDirection: 'column',
312
- alignItems: 'center',
313
- justifyContent: 'center',
314
- height: '100%',
315
- gap: 2
316
- }}>
317
- <Typography variant="h6" color="text.secondary">
318
- No lyrics to sync
319
- </Typography>
320
- <Typography variant="body2" color="text.secondary">
321
- Go back and paste new lyrics, or close this modal.
322
- </Typography>
323
- <Button
324
- variant="outlined"
325
- onClick={handleBackToSelection}
326
- startIcon={<ArrowBackIcon />}
327
- >
328
- Back to Selection
329
- </Button>
330
- </Box>
331
- )}
332
- </DialogContent>
333
- </Dialog>
334
- </>
335
- )
336
- }