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,360 +0,0 @@
1
- import { nanoid } from 'nanoid'
2
- import { CorrectionData, LyricsSegment } from '../../../types'
3
-
4
- export const addSegmentBefore = (
5
- data: CorrectionData,
6
- beforeIndex: number
7
- ): CorrectionData => {
8
- const newData = { ...data }
9
- const beforeSegment = newData.corrected_segments[beforeIndex]
10
-
11
- // Create new segment starting 1 second before the target segment
12
- // Use 0 as default if start_time is null
13
- const newStartTime = Math.max(0, (beforeSegment.start_time ?? 1) - 1)
14
- const newEndTime = newStartTime + 1
15
-
16
- const newSegment: LyricsSegment = {
17
- id: nanoid(),
18
- text: "REPLACE",
19
- start_time: newStartTime,
20
- end_time: newEndTime,
21
- words: [{
22
- id: nanoid(),
23
- text: "REPLACE",
24
- start_time: newStartTime,
25
- end_time: newEndTime,
26
- confidence: 1.0
27
- }]
28
- }
29
-
30
- // Insert the new segment before the current one
31
- newData.corrected_segments.splice(beforeIndex, 0, newSegment)
32
-
33
- return newData
34
- }
35
-
36
- export const splitSegment = (
37
- data: CorrectionData,
38
- segmentIndex: number,
39
- afterWordIndex: number
40
- ): CorrectionData | null => {
41
- const newData = { ...data }
42
- const segment = newData.corrected_segments[segmentIndex]
43
-
44
- // Split the words array
45
- const firstHalfWords = segment.words.slice(0, afterWordIndex + 1)
46
- const secondHalfWords = segment.words.slice(afterWordIndex + 1)
47
-
48
- if (secondHalfWords.length === 0) return null // Nothing to split
49
-
50
- const lastFirstWord = firstHalfWords[firstHalfWords.length - 1]
51
- const firstSecondWord = secondHalfWords[0]
52
- const lastSecondWord = secondHalfWords[secondHalfWords.length - 1]
53
-
54
- // Create two segments from the split
55
- const firstSegment: LyricsSegment = {
56
- ...segment,
57
- words: firstHalfWords,
58
- text: firstHalfWords.map(w => w.text).join(' '),
59
- end_time: lastFirstWord.end_time ?? null
60
- }
61
-
62
- const secondSegment: LyricsSegment = {
63
- id: nanoid(),
64
- words: secondHalfWords,
65
- text: secondHalfWords.map(w => w.text).join(' '),
66
- start_time: firstSecondWord.start_time ?? null,
67
- end_time: lastSecondWord.end_time ?? null
68
- }
69
-
70
- // Replace the original segment with the two new segments
71
- newData.corrected_segments.splice(segmentIndex, 1, firstSegment, secondSegment)
72
-
73
- return newData
74
- }
75
-
76
- export const deleteSegment = (
77
- data: CorrectionData,
78
- segmentIndex: number
79
- ): CorrectionData => {
80
- const newData = { ...data }
81
- const deletedSegment = newData.corrected_segments[segmentIndex]
82
-
83
- // Remove segment
84
- newData.corrected_segments = newData.corrected_segments.filter((_, index) => index !== segmentIndex)
85
-
86
- // Update anchor sequences to remove references to deleted words
87
- newData.anchor_sequences = newData.anchor_sequences.map(anchor => ({
88
- ...anchor,
89
- transcribed_word_ids: anchor.transcribed_word_ids.filter(wordId =>
90
- !deletedSegment.words.some(deletedWord => deletedWord.id === wordId)
91
- )
92
- }))
93
-
94
- // Update gap sequences to remove references to deleted words
95
- newData.gap_sequences = newData.gap_sequences.map(gap => ({
96
- ...gap,
97
- transcribed_word_ids: gap.transcribed_word_ids.filter(wordId =>
98
- !deletedSegment.words.some(deletedWord => deletedWord.id === wordId)
99
- )
100
- }))
101
-
102
- return newData
103
- }
104
-
105
- export const updateSegment = (
106
- data: CorrectionData,
107
- segmentIndex: number,
108
- updatedSegment: LyricsSegment
109
- ): CorrectionData => {
110
- const newData = { ...data }
111
-
112
- // Ensure new words have IDs
113
- updatedSegment.words = updatedSegment.words.map(word => ({
114
- ...word,
115
- id: word.id || nanoid()
116
- }))
117
-
118
- newData.corrected_segments[segmentIndex] = updatedSegment
119
-
120
- return newData
121
- }
122
-
123
- export function mergeSegment(data: CorrectionData, segmentIndex: number, mergeWithNext: boolean): CorrectionData {
124
- const segments = [...data.corrected_segments]
125
- const targetIndex = mergeWithNext ? segmentIndex + 1 : segmentIndex - 1
126
-
127
- // Check if target segment exists
128
- if (targetIndex < 0 || targetIndex >= segments.length) {
129
- return data
130
- }
131
-
132
- const baseSegment = segments[segmentIndex]
133
- const targetSegment = segments[targetIndex]
134
-
135
- // Create merged segment
136
- const mergedSegment: LyricsSegment = {
137
- id: nanoid(),
138
- words: mergeWithNext
139
- ? [...baseSegment.words, ...targetSegment.words]
140
- : [...targetSegment.words, ...baseSegment.words],
141
- text: mergeWithNext
142
- ? `${baseSegment.text} ${targetSegment.text}`
143
- : `${targetSegment.text} ${baseSegment.text}`,
144
- start_time: Math.min(
145
- baseSegment.start_time ?? Infinity,
146
- targetSegment.start_time ?? Infinity
147
- ),
148
- end_time: Math.max(
149
- baseSegment.end_time ?? -Infinity,
150
- targetSegment.end_time ?? -Infinity
151
- )
152
- }
153
-
154
- // Replace the two segments with the merged one
155
- const minIndex = Math.min(segmentIndex, targetIndex)
156
- segments.splice(minIndex, 2, mergedSegment)
157
-
158
- return {
159
- ...data,
160
- corrected_segments: segments
161
- }
162
- }
163
-
164
- export function findAndReplace(
165
- data: CorrectionData,
166
- findText: string,
167
- replaceText: string,
168
- options: { caseSensitive: boolean, useRegex: boolean, fullTextMode?: boolean } = {
169
- caseSensitive: false,
170
- useRegex: false,
171
- fullTextMode: false
172
- }
173
- ): CorrectionData {
174
- const newData = { ...data }
175
-
176
- // If full text mode is enabled, perform replacements across word boundaries
177
- if (options.fullTextMode) {
178
- newData.corrected_segments = data.corrected_segments.map(segment => {
179
- // Create a pattern for the full segment text
180
- let pattern: RegExp
181
-
182
- if (options.useRegex) {
183
- pattern = new RegExp(findText, options.caseSensitive ? 'g' : 'gi')
184
- } else {
185
- const escapedFindText = findText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
186
- pattern = new RegExp(escapedFindText, options.caseSensitive ? 'g' : 'gi')
187
- }
188
-
189
- // Get the full segment text
190
- const segmentText = segment.text
191
-
192
- // If no matches, return the segment unchanged
193
- if (!pattern.test(segmentText)) {
194
- return segment
195
- }
196
-
197
- // Reset pattern for replacement
198
- pattern.lastIndex = 0
199
-
200
- // Replace in the full segment text
201
- const newSegmentText = segmentText.replace(pattern, replaceText)
202
-
203
- // Split the new text into words
204
- const newWordTexts = newSegmentText.trim().split(/\s+/).filter(text => text.length > 0)
205
-
206
- // Create new word objects
207
- // We'll try to preserve original word IDs and timing info where possible
208
- const newWords = []
209
-
210
- // If we have the same number of words, we can preserve IDs and timing
211
- if (newWordTexts.length === segment.words.length) {
212
- for (let i = 0; i < newWordTexts.length; i++) {
213
- newWords.push({
214
- ...segment.words[i],
215
- text: newWordTexts[i]
216
- })
217
- }
218
- }
219
- // If we have fewer words than before, some words were removed
220
- else if (newWordTexts.length < segment.words.length) {
221
- // Try to map new words to old words
222
- let oldWordIndex = 0
223
- for (let i = 0; i < newWordTexts.length; i++) {
224
- // Find the next non-empty old word
225
- while (oldWordIndex < segment.words.length &&
226
- segment.words[oldWordIndex].text.trim() === '') {
227
- oldWordIndex++
228
- }
229
-
230
- if (oldWordIndex < segment.words.length) {
231
- newWords.push({
232
- ...segment.words[oldWordIndex],
233
- text: newWordTexts[i]
234
- })
235
- oldWordIndex++
236
- } else {
237
- // If we run out of old words, create new ones
238
- newWords.push({
239
- id: nanoid(),
240
- text: newWordTexts[i],
241
- start_time: null,
242
- end_time: null
243
- })
244
- }
245
- }
246
- }
247
- // If we have more words than before, some words were added
248
- else {
249
- // Try to preserve original words where possible
250
- for (let i = 0; i < newWordTexts.length; i++) {
251
- if (i < segment.words.length) {
252
- newWords.push({
253
- ...segment.words[i],
254
- text: newWordTexts[i]
255
- })
256
- } else {
257
- // For new words, create new IDs
258
- newWords.push({
259
- id: nanoid(),
260
- text: newWordTexts[i],
261
- start_time: null,
262
- end_time: null
263
- })
264
- }
265
- }
266
- }
267
-
268
- return {
269
- ...segment,
270
- words: newWords,
271
- text: newSegmentText
272
- }
273
- })
274
- }
275
- // Word-level replacement (original implementation)
276
- else {
277
- newData.corrected_segments = data.corrected_segments.map(segment => {
278
- // Replace in each word
279
- let newWords = segment.words.map(word => {
280
- let pattern: RegExp
281
-
282
- if (options.useRegex) {
283
- // Create regex with or without case sensitivity
284
- pattern = new RegExp(findText, options.caseSensitive ? 'g' : 'gi')
285
- } else {
286
- // Escape special regex characters for literal search
287
- const escapedFindText = findText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
288
- pattern = new RegExp(escapedFindText, options.caseSensitive ? 'g' : 'gi')
289
- }
290
-
291
- return {
292
- ...word,
293
- text: word.text.replace(pattern, replaceText)
294
- }
295
- });
296
-
297
- // Filter out words that have become empty
298
- newWords = newWords.filter(word => word.text.trim() !== '');
299
-
300
- // Update segment text
301
- return {
302
- ...segment,
303
- words: newWords,
304
- text: newWords.map(w => w.text).join(' ')
305
- }
306
- });
307
- }
308
-
309
- // Filter out segments that have no words left
310
- newData.corrected_segments = newData.corrected_segments.filter(segment => segment.words.length > 0);
311
-
312
- return newData
313
- }
314
-
315
- /**
316
- * Deletes a word from a segment in the correction data
317
- * @param data The correction data
318
- * @param wordId The ID of the word to delete
319
- * @returns Updated correction data with the word removed
320
- */
321
- export function deleteWord(
322
- data: CorrectionData,
323
- wordId: string
324
- ): CorrectionData {
325
- // Find the segment containing this word
326
- const segmentIndex = data.corrected_segments.findIndex(segment =>
327
- segment.words.some(word => word.id === wordId)
328
- );
329
-
330
- if (segmentIndex === -1) {
331
- // Word not found, return data unchanged
332
- return data;
333
- }
334
-
335
- const segment = data.corrected_segments[segmentIndex];
336
- const wordIndex = segment.words.findIndex(word => word.id === wordId);
337
-
338
- if (wordIndex === -1) {
339
- // Word not found in segment (shouldn't happen), return data unchanged
340
- return data;
341
- }
342
-
343
- // Create a new segment with the word removed
344
- const updatedWords = segment.words.filter((_, index) => index !== wordIndex);
345
-
346
- if (updatedWords.length > 0) {
347
- // Update the segment with the word removed
348
- const updatedSegment = {
349
- ...segment,
350
- words: updatedWords,
351
- text: updatedWords.map(w => w.text).join(' ')
352
- };
353
-
354
- // Update the data
355
- return updateSegment(data, segmentIndex, updatedSegment);
356
- } else {
357
- // If the segment would be empty, delete the entire segment
358
- return deleteSegment(data, segmentIndex);
359
- }
360
- }
@@ -1,110 +0,0 @@
1
- import { LyricsSegment, Word, CorrectionData } from '../../../types';
2
-
3
- /**
4
- * Apply the timing offset to a single timestamp
5
- * @param time The original timestamp in seconds
6
- * @param offsetMs The offset in milliseconds
7
- * @returns The adjusted timestamp in seconds
8
- */
9
- export const applyOffsetToTime = (time: number | null, offsetMs: number): number | null => {
10
- if (time === null) return null;
11
- // Convert ms to seconds and add to the time
12
- return time + (offsetMs / 1000);
13
- };
14
-
15
- /**
16
- * Apply the timing offset to a word
17
- * @param word The original word object
18
- * @param offsetMs The offset in milliseconds
19
- * @returns A new word object with adjusted timestamps
20
- */
21
- export const applyOffsetToWord = (word: Word, offsetMs: number): Word => {
22
- if (offsetMs === 0) return word;
23
-
24
- return {
25
- ...word,
26
- start_time: applyOffsetToTime(word.start_time, offsetMs),
27
- end_time: applyOffsetToTime(word.end_time, offsetMs)
28
- };
29
- };
30
-
31
- /**
32
- * Apply the timing offset to all words in a segment
33
- * Also updates the segment's start and end times based on the first and last word
34
- * @param segment The original segment
35
- * @param offsetMs The offset in milliseconds
36
- * @returns A new segment with adjusted timestamps
37
- */
38
- export const applyOffsetToSegment = (segment: LyricsSegment, offsetMs: number): LyricsSegment => {
39
- if (offsetMs === 0) return segment;
40
-
41
- const adjustedWords = segment.words.map(word => applyOffsetToWord(word, offsetMs));
42
-
43
- // Update segment start/end times based on first/last word
44
- const validStartTimes = adjustedWords.map(w => w.start_time).filter((t): t is number => t !== null);
45
- const validEndTimes = adjustedWords.map(w => w.end_time).filter((t): t is number => t !== null);
46
-
47
- const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null;
48
- const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null;
49
-
50
- return {
51
- ...segment,
52
- words: adjustedWords,
53
- start_time: segmentStartTime,
54
- end_time: segmentEndTime
55
- };
56
- };
57
-
58
- /**
59
- * Apply the timing offset to the entire correction data
60
- * This creates a new data object with all timestamps adjusted by the offset
61
- * @param data The original correction data
62
- * @param offsetMs The offset in milliseconds
63
- * @returns A new correction data object with all timestamps adjusted
64
- */
65
- export const applyOffsetToCorrectionData = (data: CorrectionData, offsetMs: number): CorrectionData => {
66
- console.log(`[TIMING] applyOffsetToCorrectionData called with offset: ${offsetMs}ms`);
67
-
68
- if (offsetMs === 0) {
69
- console.log('[TIMING] Offset is 0, returning original data');
70
- return data;
71
- }
72
-
73
- // Log some examples of original timestamps
74
- if (data.corrected_segments.length > 0) {
75
- const firstSegment = data.corrected_segments[0];
76
- console.log(`[TIMING] First segment before offset - id: ${firstSegment.id}`);
77
- console.log(`[TIMING] - start_time: ${firstSegment.start_time}, end_time: ${firstSegment.end_time}`);
78
-
79
- if (firstSegment.words.length > 0) {
80
- const firstWord = firstSegment.words[0];
81
- const lastWord = firstSegment.words[firstSegment.words.length - 1];
82
- console.log(`[TIMING] - first word "${firstWord.text}" time: ${firstWord.start_time} -> ${firstWord.end_time}`);
83
- console.log(`[TIMING] - last word "${lastWord.text}" time: ${lastWord.start_time} -> ${lastWord.end_time}`);
84
- }
85
- }
86
-
87
- const result = {
88
- ...data,
89
- corrected_segments: data.corrected_segments.map(segment =>
90
- applyOffsetToSegment(segment, offsetMs)
91
- )
92
- };
93
-
94
- // Log some examples of adjusted timestamps
95
- if (result.corrected_segments.length > 0) {
96
- const firstSegment = result.corrected_segments[0];
97
- console.log(`[TIMING] First segment AFTER offset - id: ${firstSegment.id}`);
98
- console.log(`[TIMING] - start_time: ${firstSegment.start_time}, end_time: ${firstSegment.end_time}`);
99
-
100
- if (firstSegment.words.length > 0) {
101
- const firstWord = firstSegment.words[0];
102
- const lastWord = firstSegment.words[firstSegment.words.length - 1];
103
- console.log(`[TIMING] - first word "${firstWord.text}" time: ${firstWord.start_time} -> ${firstWord.end_time}`);
104
- console.log(`[TIMING] - last word "${lastWord.text}" time: ${lastWord.start_time} -> ${lastWord.end_time}`);
105
- }
106
- }
107
-
108
- console.log(`[TIMING] Finished applying offset of ${offsetMs}ms to data`);
109
- return result;
110
- };
@@ -1,22 +0,0 @@
1
- import { Word, LyricsSegment } from '../../../types'
2
-
3
- /**
4
- * Find a Word object by its ID within an array of segments
5
- */
6
- export function findWordById(segments: LyricsSegment[], wordId: string): Word | undefined {
7
- for (const segment of segments) {
8
- const word = segment.words.find(w => w.id === wordId)
9
- if (word) return word
10
- }
11
- return undefined
12
- }
13
-
14
- /**
15
- * Convert an array of word IDs to their corresponding Word objects
16
- * Filters out any IDs that don't match to valid words
17
- */
18
- export function getWordsFromIds(segments: LyricsSegment[], wordIds: string[]): Word[] {
19
- return wordIds
20
- .map(id => findWordById(segments, id))
21
- .filter((word): word is Word => word !== undefined)
22
- }