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,466 +0,0 @@
1
- import { Typography, Box, useMediaQuery, useTheme } from '@mui/material'
2
- import { WordComponent } from './Word'
3
- import { useWordClick } from '../hooks/useWordClick'
4
- import {
5
- AnchorSequence,
6
- GapSequence,
7
- HighlightInfo,
8
- InteractionMode,
9
- LyricsSegment,
10
- Word,
11
- WordCorrection
12
- } from '../../../types'
13
- import { ModalContent } from '../../LyricsAnalyzer'
14
- import type { FlashType, LinePosition, TranscriptionWordPosition, WordClickInfo } from '../types'
15
- import React from 'react'
16
- import ContentCopyIcon from '@mui/icons-material/ContentCopy'
17
- import IconButton from '@mui/material/IconButton'
18
- import { getWordsFromIds } from '../utils/wordUtils'
19
- import CorrectedWordWithActions from '../../CorrectedWordWithActions'
20
-
21
- export interface HighlightedTextProps {
22
- text?: string
23
- segments?: LyricsSegment[]
24
- wordPositions: TranscriptionWordPosition[]
25
- anchors: AnchorSequence[]
26
- highlightInfo: HighlightInfo | null
27
- mode: InteractionMode
28
- onElementClick: (content: ModalContent) => void
29
- onWordClick?: (info: WordClickInfo) => void
30
- flashingType: FlashType
31
- isReference?: boolean
32
- currentSource?: string
33
- preserveSegments?: boolean
34
- linePositions?: LinePosition[]
35
- currentTime?: number
36
- referenceCorrections?: Map<string, string>
37
- gaps?: GapSequence[]
38
- flashingHandler?: string | null
39
- corrections?: WordCorrection[]
40
- // Review mode props for agentic corrections
41
- reviewMode?: boolean
42
- onRevertCorrection?: (wordId: string) => void
43
- onEditCorrection?: (wordId: string) => void
44
- onAcceptCorrection?: (wordId: string) => void
45
- onShowCorrectionDetail?: (wordId: string) => void
46
- }
47
-
48
- export function HighlightedText({
49
- text,
50
- segments,
51
- wordPositions = [] as TranscriptionWordPosition[],
52
- anchors,
53
- highlightInfo,
54
- mode,
55
- onElementClick,
56
- onWordClick,
57
- flashingType,
58
- isReference,
59
- currentSource = '',
60
- preserveSegments = false,
61
- linePositions = [],
62
- currentTime = 0,
63
- referenceCorrections = new Map(),
64
- gaps = [],
65
- flashingHandler,
66
- corrections = [],
67
- reviewMode = false,
68
- onRevertCorrection,
69
- onEditCorrection,
70
- onAcceptCorrection,
71
- onShowCorrectionDetail,
72
- }: HighlightedTextProps) {
73
- const theme = useTheme()
74
- const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
75
-
76
- const { handleWordClick } = useWordClick({
77
- mode,
78
- onElementClick,
79
- onWordClick,
80
- isReference,
81
- currentSource,
82
- gaps,
83
- anchors,
84
- corrections
85
- })
86
-
87
- const shouldWordFlash = (wordPos: TranscriptionWordPosition | { word: string; id: string }): boolean => {
88
- if (!flashingType) {
89
- return false;
90
- }
91
-
92
- if ('type' in wordPos) {
93
- // Add handler-specific flashing
94
- if (flashingType === 'handler' && flashingHandler) {
95
- console.log('Checking handler flash for word:', wordPos.word.text);
96
- console.log('Current flashingHandler:', flashingHandler);
97
- console.log('Word ID:', wordPos.word.id);
98
-
99
- const shouldFlash = corrections.some(correction =>
100
- correction.handler === flashingHandler &&
101
- (correction.corrected_word_id === wordPos.word.id ||
102
- correction.word_id === wordPos.word.id)
103
- );
104
-
105
- console.log('Should flash:', shouldFlash);
106
- return shouldFlash;
107
- }
108
-
109
- const gap = wordPos.sequence as GapSequence
110
- const isCorrected = (
111
- // Check corrections array for this word
112
- corrections.some(correction =>
113
- (correction.word_id === wordPos.word.id ||
114
- correction.corrected_word_id === wordPos.word.id) &&
115
- gap.transcribed_word_ids.includes(correction.word_id)
116
- ) ||
117
- // Also check if marked as corrected in wordPos
118
- wordPos.isCorrected
119
- )
120
-
121
- return Boolean(
122
- (flashingType === 'anchor' && wordPos.type === 'anchor') ||
123
- (flashingType === 'corrected' && isCorrected) ||
124
- (flashingType === 'uncorrected' && wordPos.type === 'gap' && !isCorrected) ||
125
- (flashingType === 'word' && (
126
- // For anchors
127
- (highlightInfo?.type === 'anchor' && wordPos.type === 'anchor' &&
128
- (isReference && currentSource && highlightInfo.sequence
129
- ? getWordsFromIds(segments || [],
130
- (highlightInfo.sequence as AnchorSequence).reference_word_ids[currentSource] || []
131
- ).some(w => w.id === wordPos.word.id)
132
- : getWordsFromIds(segments || [],
133
- (highlightInfo.sequence as AnchorSequence).transcribed_word_ids
134
- ).some(w => w.id === wordPos.word.id)
135
- )) ||
136
- // For gaps
137
- (highlightInfo?.type === 'gap' && wordPos.type === 'gap' &&
138
- (isReference && currentSource && highlightInfo.sequence
139
- ? getWordsFromIds(segments || [],
140
- (highlightInfo.sequence as GapSequence).reference_word_ids[currentSource] || []
141
- ).some(w => w.id === wordPos.word.id)
142
- : getWordsFromIds(segments || [],
143
- (highlightInfo.sequence as GapSequence).transcribed_word_ids
144
- ).some(w => w.id === wordPos.word.id))
145
- ) ||
146
- // For corrections
147
- (highlightInfo?.type === 'correction' && isReference && currentSource &&
148
- highlightInfo.correction?.reference_positions?.[currentSource]?.toString() === wordPos.word.id)
149
- ))
150
- )
151
- }
152
- return false
153
- }
154
-
155
- const shouldHighlightWord = (wordPos: TranscriptionWordPosition | { word: string; id: string }): boolean => {
156
- // Don't highlight words in reference view
157
- if (isReference) return false
158
-
159
- if ('type' in wordPos && currentTime !== undefined && 'start_time' in wordPos.word) {
160
- const word = wordPos.word as Word
161
- return word.start_time !== null &&
162
- word.end_time !== null &&
163
- currentTime >= word.start_time &&
164
- currentTime <= word.end_time
165
- }
166
- return false
167
- }
168
-
169
- const handleCopyLine = (text: string) => {
170
- navigator.clipboard.writeText(text);
171
- };
172
-
173
- const renderContent = () => {
174
- if (wordPositions && !segments) {
175
- return wordPositions.map((wordPos, index) => {
176
- // Find correction for this word
177
- const correction = corrections?.find(c =>
178
- c.corrected_word_id === wordPos.word.id ||
179
- c.word_id === wordPos.word.id
180
- );
181
-
182
- // Use CorrectedWordWithActions for agentic corrections
183
- if (correction && correction.handler === 'AgenticCorrector') {
184
- return (
185
- <React.Fragment key={wordPos.word.id}>
186
- <CorrectedWordWithActions
187
- word={wordPos.word.text}
188
- originalWord={correction.original_word}
189
- correction={{
190
- originalWord: correction.original_word,
191
- handler: correction.handler,
192
- confidence: correction.confidence,
193
- source: correction.source,
194
- reason: correction.reason
195
- }}
196
- shouldFlash={shouldWordFlash(wordPos)}
197
- showActions={reviewMode && !isMobile}
198
- onRevert={() => onRevertCorrection?.(wordPos.word.id)}
199
- onEdit={() => onEditCorrection?.(wordPos.word.id)}
200
- onAccept={() => onAcceptCorrection?.(wordPos.word.id)}
201
- onClick={() => {
202
- if (isMobile) {
203
- onShowCorrectionDetail?.(wordPos.word.id)
204
- } else {
205
- handleWordClick(
206
- wordPos.word.text,
207
- wordPos.word.id,
208
- wordPos.type === 'anchor' ? wordPos.sequence as AnchorSequence : undefined,
209
- wordPos.type === 'gap' ? wordPos.sequence as GapSequence : undefined
210
- )
211
- }
212
- }}
213
- />
214
- {index < wordPositions.length - 1 && ' '}
215
- </React.Fragment>
216
- );
217
- }
218
-
219
- // Default rendering with WordComponent
220
- return (
221
- <React.Fragment key={wordPos.word.id}>
222
- <WordComponent
223
- key={`${wordPos.word.id}-${index}`}
224
- word={wordPos.word.text}
225
- shouldFlash={shouldWordFlash(wordPos)}
226
- isAnchor={wordPos.type === 'anchor'}
227
- isCorrectedGap={wordPos.isCorrected}
228
- isUncorrectedGap={wordPos.type === 'gap' && !wordPos.isCorrected}
229
- isCurrentlyPlaying={shouldHighlightWord(wordPos)}
230
- onClick={() => handleWordClick(
231
- wordPos.word.text,
232
- wordPos.word.id,
233
- wordPos.type === 'anchor' ? wordPos.sequence as AnchorSequence : undefined,
234
- wordPos.type === 'gap' ? wordPos.sequence as GapSequence : undefined
235
- )}
236
- correction={correction ? {
237
- originalWord: correction.original_word,
238
- handler: correction.handler,
239
- confidence: correction.confidence,
240
- source: correction.source,
241
- reason: correction.reason
242
- } : null}
243
- />
244
- {index < wordPositions.length - 1 && ' '}
245
- </React.Fragment>
246
- );
247
- })
248
- } else if (segments) {
249
- return segments.map((segment) => (
250
- <Box key={segment.id} sx={{
251
- display: 'flex',
252
- alignItems: 'flex-start',
253
- mb: 0
254
- }}>
255
- <Box sx={{ flex: 1 }}>
256
- {segment.words.map((word, wordIndex) => {
257
- const wordPos = wordPositions.find((pos: TranscriptionWordPosition) =>
258
- pos.word.id === word.id
259
- );
260
-
261
- const anchor = wordPos?.type === 'anchor' ? anchors?.find(a =>
262
- (a.reference_word_ids[currentSource] || []).includes(word.id)
263
- ) : undefined;
264
-
265
- const hasCorrection = referenceCorrections.has(word.id);
266
- const isUncorrectedGap = wordPos?.type === 'gap' && !hasCorrection;
267
-
268
- const sequence = wordPos?.type === 'gap' ? wordPos.sequence as GapSequence : undefined;
269
-
270
- // Find correction information
271
- const correction = corrections?.find(c =>
272
- c.corrected_word_id === word.id ||
273
- c.word_id === word.id
274
- );
275
-
276
- // Use CorrectedWordWithActions for agentic corrections
277
- if (correction && correction.handler === 'AgenticCorrector') {
278
- return (
279
- <React.Fragment key={word.id}>
280
- <CorrectedWordWithActions
281
- word={word.text}
282
- originalWord={correction.original_word}
283
- correction={{
284
- originalWord: correction.original_word,
285
- handler: correction.handler,
286
- confidence: correction.confidence,
287
- source: correction.source,
288
- reason: correction.reason
289
- }}
290
- shouldFlash={shouldWordFlash(wordPos || { word: word.text, id: word.id })}
291
- showActions={reviewMode && !isMobile}
292
- onRevert={() => onRevertCorrection?.(word.id)}
293
- onEdit={() => onEditCorrection?.(word.id)}
294
- onAccept={() => onAcceptCorrection?.(word.id)}
295
- onClick={() => {
296
- if (isMobile) {
297
- onShowCorrectionDetail?.(word.id)
298
- } else {
299
- handleWordClick(word.text, word.id, anchor, sequence)
300
- }
301
- }}
302
- />
303
- {wordIndex < segment.words.length - 1 && ' '}
304
- </React.Fragment>
305
- );
306
- }
307
-
308
- const correctionInfo = correction ? {
309
- originalWord: correction.original_word,
310
- handler: correction.handler,
311
- confidence: correction.confidence,
312
- source: correction.source,
313
- reason: correction.reason
314
- } : null;
315
-
316
- return (
317
- <React.Fragment key={word.id}>
318
- <WordComponent
319
- word={word.text}
320
- shouldFlash={shouldWordFlash(wordPos || { word: word.text, id: word.id })}
321
- isAnchor={Boolean(anchor)}
322
- isCorrectedGap={hasCorrection}
323
- isUncorrectedGap={isUncorrectedGap}
324
- isCurrentlyPlaying={shouldHighlightWord(wordPos || { word: word.text, id: word.id })}
325
- onClick={() => handleWordClick(word.text, word.id, anchor, sequence)}
326
- correction={correctionInfo}
327
- />
328
- {wordIndex < segment.words.length - 1 && ' '}
329
- </React.Fragment>
330
- );
331
- })}
332
- </Box>
333
- </Box>
334
- ));
335
- } else if (text) {
336
- const lines = text.split('\n')
337
- let wordCount = 0
338
-
339
- return lines.map((line, lineIndex) => {
340
- const currentLinePosition = linePositions?.find(pos => pos.position === wordCount)
341
- if (currentLinePosition?.isEmpty) {
342
- wordCount++
343
- return (
344
- <Box key={`empty-${lineIndex}`} sx={{
345
- display: 'flex',
346
- alignItems: 'flex-start',
347
- mb: 0,
348
- lineHeight: 1
349
- }}>
350
- <Typography
351
- component="span"
352
- sx={{
353
- color: 'text.secondary',
354
- width: '2em',
355
- minWidth: '2em',
356
- textAlign: 'right',
357
- marginRight: 1,
358
- userSelect: 'none',
359
- fontFamily: 'monospace',
360
- paddingTop: '1px',
361
- fontSize: '0.8rem',
362
- lineHeight: 1
363
- }}
364
- >
365
- {currentLinePosition.lineNumber}
366
- </Typography>
367
- <Box sx={{ width: '18px' }} />
368
- <Box sx={{ flex: 1, height: '1em' }} />
369
- </Box>
370
- )
371
- }
372
-
373
- const words = line.split(' ')
374
- const lineWords: React.ReactNode[] = []
375
-
376
- words.forEach((word, wordIndex) => {
377
- if (word === '') return null
378
- if (/^\s+$/.test(word)) {
379
- return lineWords.push(<span key={`space-${lineIndex}-${wordIndex}`}> </span>)
380
- }
381
-
382
- const wordId = `${currentSource}-word-${wordCount}`
383
- wordCount++
384
-
385
- const anchor = currentSource ? anchors?.find(a =>
386
- a.reference_word_ids[currentSource]?.includes(wordId)
387
- ) : undefined
388
-
389
- const hasCorrection = referenceCorrections.has(wordId)
390
-
391
- lineWords.push(
392
- <WordComponent
393
- key={wordId}
394
- word={word}
395
- shouldFlash={shouldWordFlash({ word, id: wordId })}
396
- isAnchor={Boolean(anchor)}
397
- isCorrectedGap={hasCorrection}
398
- isUncorrectedGap={false}
399
- isCurrentlyPlaying={shouldHighlightWord({ word, id: wordId })}
400
- onClick={() => handleWordClick(word, wordId, anchor, undefined)}
401
- />
402
- )
403
- })
404
-
405
- return (
406
- <Box key={`line-${lineIndex}`} sx={{
407
- display: 'flex',
408
- alignItems: 'flex-start',
409
- mb: 0,
410
- lineHeight: 1
411
- }}>
412
- <Typography
413
- component="span"
414
- sx={{
415
- color: 'text.secondary',
416
- width: '2em',
417
- minWidth: '2em',
418
- textAlign: 'right',
419
- marginRight: 1,
420
- userSelect: 'none',
421
- fontFamily: 'monospace',
422
- paddingTop: '1px',
423
- fontSize: '0.8rem',
424
- lineHeight: 1
425
- }}
426
- >
427
- {currentLinePosition?.lineNumber ?? lineIndex}
428
- </Typography>
429
- <IconButton
430
- size="small"
431
- onClick={() => handleCopyLine(line)}
432
- sx={{
433
- padding: '1px',
434
- marginRight: 0.5,
435
- height: '18px',
436
- width: '18px',
437
- minHeight: '18px',
438
- minWidth: '18px'
439
- }}
440
- >
441
- <ContentCopyIcon sx={{ fontSize: '0.9rem' }} />
442
- </IconButton>
443
- <Box sx={{ flex: 1 }}>
444
- {lineWords}
445
- </Box>
446
- </Box>
447
- )
448
- })
449
- }
450
- return null
451
- }
452
-
453
- return (
454
- <Typography
455
- component="div"
456
- sx={{
457
- fontFamily: 'monospace',
458
- whiteSpace: preserveSegments ? 'normal' : 'pre-wrap',
459
- margin: 0,
460
- lineHeight: 1.5
461
- }}
462
- >
463
- {renderContent()}
464
- </Typography>
465
- )
466
- }
@@ -1,56 +0,0 @@
1
- import { Box, Button } from '@mui/material'
2
- import AddIcon from '@mui/icons-material/Add'
3
-
4
- export interface SourceSelectorProps {
5
- currentSource: string
6
- onSourceChange: (source: string) => void
7
- availableSources: string[]
8
- onAddLyrics?: () => void
9
- }
10
-
11
- export function SourceSelector({ currentSource, onSourceChange, availableSources, onAddLyrics }: SourceSelectorProps) {
12
- return (
13
- <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.3, alignItems: 'center' }}>
14
- {availableSources.map((source) => (
15
- <Button
16
- key={source}
17
- size="small"
18
- variant={currentSource === source ? 'contained' : 'outlined'}
19
- onClick={() => onSourceChange(source)}
20
- sx={{
21
- mr: 0,
22
- py: 0.2,
23
- px: 0.8,
24
- minWidth: 'auto',
25
- fontSize: '0.7rem',
26
- lineHeight: 1.2
27
- }}
28
- >
29
- {/* Capitalize first letter of source */}
30
- {source.charAt(0).toUpperCase() + source.slice(1)}
31
- </Button>
32
- ))}
33
- {onAddLyrics && (
34
- <Button
35
- size="small"
36
- variant="outlined"
37
- onClick={onAddLyrics}
38
- startIcon={<AddIcon sx={{ fontSize: '0.9rem' }} />}
39
- sx={{
40
- mr: 0,
41
- py: 0.2,
42
- px: 0.8,
43
- minWidth: 'auto',
44
- fontSize: '0.7rem',
45
- lineHeight: 1.2,
46
- '& .MuiButton-startIcon': {
47
- marginLeft: '-5px',
48
- marginRight: '1px',
49
- marginTop: '-1px'
50
- }
51
- }}
52
- >New</Button>
53
- )}
54
- </Box>
55
- )
56
- }
@@ -1,89 +0,0 @@
1
- import React from 'react'
2
- import { COLORS } from '../constants'
3
- import { HighlightedWord } from '../styles'
4
- import { WordProps } from '../types'
5
- import { Tooltip } from '@mui/material'
6
-
7
- export const WordComponent = React.memo(function Word({
8
- word,
9
- shouldFlash,
10
- isAnchor,
11
- isCorrectedGap,
12
- isUncorrectedGap,
13
- isCurrentlyPlaying,
14
- padding = '1px 3px',
15
- onClick,
16
- correction
17
- }: WordProps) {
18
- if (/^\s+$/.test(word)) {
19
- return word
20
- }
21
-
22
- const backgroundColor = isCurrentlyPlaying
23
- ? COLORS.playing
24
- : shouldFlash
25
- ? COLORS.highlighted
26
- : isAnchor
27
- ? COLORS.anchor
28
- : isCorrectedGap
29
- ? COLORS.corrected
30
- : isUncorrectedGap
31
- ? COLORS.uncorrectedGap
32
- : 'transparent'
33
-
34
- const wordElement = (
35
- <HighlightedWord
36
- shouldFlash={shouldFlash}
37
- style={{
38
- backgroundColor,
39
- padding,
40
- cursor: 'pointer',
41
- borderRadius: '2px',
42
- color: isCurrentlyPlaying ? '#ffffff' : 'inherit',
43
- textDecoration: correction ? 'underline dotted' : 'none',
44
- textUnderlineOffset: '2px',
45
- fontSize: '0.85rem',
46
- lineHeight: 1.2
47
- }}
48
- sx={{
49
- textDecorationColor: correction ? 'text.disabled' : 'inherit', // Theme-aware underline color
50
- '&:hover': {
51
- backgroundColor: (theme) => theme.palette.mode === 'dark'
52
- ? 'rgba(248, 250, 252, 0.08)' // light hover for dark mode
53
- : 'rgba(30, 41, 59, 0.08)' // dark hover for light mode
54
- }
55
- }}
56
- onClick={onClick}
57
- >
58
- {word}
59
- </HighlightedWord>
60
- )
61
-
62
- if (correction) {
63
- const tooltipContent = (
64
- <>
65
- <strong>Original:</strong> "{correction.originalWord}"<br />
66
- <strong>Corrected by:</strong> {correction.handler}<br />
67
- <strong>Source:</strong> {correction.source}<br />
68
- {correction.reason && (
69
- <>
70
- <strong>Reason:</strong> {correction.reason}<br />
71
- </>
72
- )}
73
- {correction.confidence !== undefined && correction.confidence > 0 && (
74
- <>
75
- <strong>Confidence:</strong> {(correction.confidence * 100).toFixed(0)}%<br />
76
- </>
77
- )}
78
- </>
79
- )
80
-
81
- return (
82
- <Tooltip title={tooltipContent} arrow placement="top">
83
- {wordElement}
84
- </Tooltip>
85
- )
86
- }
87
-
88
- return wordElement
89
- })
@@ -1,30 +0,0 @@
1
- import { keyframes } from '@mui/system'
2
-
3
- // Dark theme colors matching karaoke-gen globals.css
4
- export const COLORS = {
5
- anchor: 'rgba(59, 130, 246, 0.25)', // Blue tint for dark mode
6
- corrected: 'rgba(34, 197, 94, 0.25)', // Green tint for dark mode
7
- uncorrectedGap: 'rgba(249, 115, 22, 0.25)', // Orange tint for dark mode
8
- highlighted: 'rgba(251, 191, 36, 0.4)', // Amber highlight for dark mode
9
- playing: '#3b82f6', // Blue-500
10
- // Text colors (matching karaoke-gen)
11
- textPrimary: '#e5e5e5', // matches karaoke-gen --text
12
- textSecondary: '#888888', // matches karaoke-gen --text-muted
13
- textMuted: '#666666',
14
- // Background colors (matching karaoke-gen globals.css)
15
- background: '#0f0f0f', // matches karaoke-gen --bg
16
- backgroundPaper: '#1a1a1a', // matches karaoke-gen --card
17
- backgroundElevated: '#252525', // matches karaoke-gen --secondary
18
- border: '#2a2a2a', // matches karaoke-gen --card-border
19
- } as const
20
-
21
- export const flashAnimation = keyframes`
22
- 0%, 100% {
23
- opacity: 1;
24
- background-color: inherit;
25
- }
26
- 50% {
27
- opacity: 0.6;
28
- background-color: ${COLORS.highlighted};
29
- }
30
- `