we subbing now bois #73

Merged
quoije merged 5 commits from 2026 into prod 2026-01-25 02:02:20 -05:00
quoije commented 2026-01-25 02:02:13 -05:00 (Migrated from github.com)

Note

Introduces end-to-end subtitles and quality selection across model, APIs, admin UI, and player.

  • Model: add video_file_low, subtitles[] plus legacy subtitle fields maintained for back-compat
  • API:
    • New GET/HEAD /api/subtitles/:id(/:subtitleId) to stream VTT with JWT/qs/cookie auth
    • Movies: POST /api/movies/:id/subtitles (upload .srt/.vtt, auto-convert SRT→VTT), DELETE /api/movies/:id/subtitles/:subtitleId; list/get now include subtitles; add/patch accept video_file_low and subtitle metadata; cache cleared on updates
    • Video: GET /api/video/:id supports ?quality=low to serve video_file_low
  • Player: adds quality toggle UI (high/low) with persistence; probes/uses ?quality=low; injects <track> from /api/subtitles/... with tokenized URLs; applies tracks on source switch
  • Admin UI: fields for video_file_low; subtitle upload, listing, removal; badges show "Low file" and "Subtitles"; add form wires initial subtitle upload
  • Python video server: supports ?quality=low selection of video_file_low
  • Misc: mount /api/subtitles; add subtitles/* to .gitignore; README disclaimer and Python README SSL run example

Written by Cursor Bugbot for commit 406a4f0bb3. This will update automatically on new commits. Configure here.

<!-- CURSOR_SUMMARY --> > [!NOTE] > Introduces end-to-end subtitles and quality selection across model, APIs, admin UI, and player. > > - Model: add `video_file_low`, `subtitles[]` plus legacy subtitle fields maintained for back-compat > - API: > - New `GET/HEAD /api/subtitles/:id(/:subtitleId)` to stream VTT with JWT/qs/cookie auth > - Movies: `POST /api/movies/:id/subtitles` (upload .srt/.vtt, auto-convert SRT→VTT), `DELETE /api/movies/:id/subtitles/:subtitleId`; list/get now include `subtitles`; add/patch accept `video_file_low` and subtitle metadata; cache cleared on updates > - Video: `GET /api/video/:id` supports `?quality=low` to serve `video_file_low` > - Player: adds quality toggle UI (high/low) with persistence; probes/uses `?quality=low`; injects `<track>` from `/api/subtitles/...` with tokenized URLs; applies tracks on source switch > - Admin UI: fields for `video_file_low`; subtitle upload, listing, removal; badges show "Low file" and "Subtitles"; add form wires initial subtitle upload > - Python video server: supports `?quality=low` selection of `video_file_low` > - Misc: mount `/api/subtitles`; add `subtitles/*` to `.gitignore`; README disclaimer and Python README SSL run example > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 406a4f0bb3a17e0e701f6d8bba1cb2eafe21f41e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
cursor[bot] (Migrated from github.com) reviewed 2026-01-25 02:10:04 -05:00
cursor[bot] (Migrated from github.com) left a comment

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Cursor Bugbot has reviewed your changes and found 3 potential issues. <sup>Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the [Cursor dashboard](https://www.cursor.com/dashboard?tab=bugbot).</sup> ### This PR is being reviewed by Cursor Bugbot <details> <summary>Details</summary> You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle. To receive Bugbot reviews on all of your PRs, visit the [Cursor dashboard](https://www.cursor.com/dashboard?tab=bugbot) to activate Pro and start your 14-day free trial. </details>
@@ -65,0 +110,4 @@
const file = typeof movie?.subtitle_file === "string" ? movie.subtitle_file.trim() : "";
if (!file) return null;
return {
_id: "legacy",
cursor[bot] (Migrated from github.com) commented 2026-01-25 02:10:04 -05:00

Duplicate identical functions for boolean parsing

Low Severity

The parseSubtitleDefault function (lines 78-86) and parseBooleanFlag function (lines 88-96) are completely identical implementations. Both parse boolean values from string inputs using the exact same logic (handling "true", "1", "yes", "on" for true, etc.). One function should be removed and the other reused in both places where they're currently called.

Fix in Cursor Fix in Web

### Duplicate identical functions for boolean parsing **Low Severity** <!-- DESCRIPTION START --> The `parseSubtitleDefault` function (lines 78-86) and `parseBooleanFlag` function (lines 88-96) are completely identical implementations. Both parse boolean values from string inputs using the exact same logic (handling `"true"`, `"1"`, `"yes"`, `"on"` for true, etc.). One function should be removed and the other reused in both places where they're currently called. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: e8232935-88e0-46aa-a11d-f87144aa4467 --> <!-- LOCATIONS START routes/movies.js#L77-L96 LOCATIONS END --> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjZkNTQ2MzE1LTRlMjEtNDc2OS05NTQ1LTc5YTNlMWM3MTY4NiIsImVuY3J5cHRpb25LZXkiOiJScDBtWV83TVA0cGhHaExqTk1qcTMxMFRMNjRkT1ptTXA1STlJbzJhYTU0IiwiYnJhbmNoIjoiMjAyNiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.Tj54I4d2hItocuhS5JBzM2-O2aW-J410ubBLfiKqPZr-0bxe47_Bio6DKJWXXjSPSHRgrUNInPX1YpqOspKmGX1vfLjblvVJZnQsMP1wr8pOW6r-nFnb9yWbOyHFdQDC9xxYqbbL_mW78DA38rof9b7dzleH0sRPWVtuS7zL7_Lx6-yLpa7aW9EMcm8w9L_-tnNVzCCZp2-dUpBmmvliS52uNPkvY-w7UoUkTb95WbKSTNCcTuHi9pcrOH1DdIIdr4yVaqdFqOwlndFp2GeWzvOrGbz5EqFjxL3E_OOUt0gxQPYHRIug8KSoofBYehEkrm3lSTOeIfUyLBX3eFp_Mw" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-cursor-light.svg"><img alt="Fix in Cursor" src="https://cursor.com/fix-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjZkNTQ2MzE1LTRlMjEtNDc2OS05NTQ1LTc5YTNlMWM3MTY4NiIsImVuY3J5cHRpb25LZXkiOiJScDBtWV83TVA0cGhHaExqTk1qcTMxMFRMNjRkT1ptTXA1STlJbzJhYTU0IiwiYnJhbmNoIjoiMjAyNiIsInJlcG9Pd25lciI6InF1b2lqZSIsInJlcG9OYW1lIjoib3NjYXJzLXBvb2wiLCJwck51bWJlciI6NzMsImNvbW1pdFNoYSI6IjQwNmE0ZjBiYjNhMTdlMGU3MDFmNmQ4YmJhMWNiMmVhZmUyMWY0MWUiLCJwcm92aWRlciI6ImdpdGh1YiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.bwaj7A2IDeyIJhlMwBvMDTlSe6utkA_s6CP2TFd-oI260RkzQ4swy6QFu0PN-XWzyUE2JiLOtbvH92C3hdxuzxgDkNUSPeu0qvLASkd4gzY4w0GKxVm7Ss0_b_UiCf52SOMOWoqImNunYo8hhdfETCGTaq-S9jmNvLHRWKjX8AAmRAct8p6aI1wC0Hc8zituGKge5fCBr2lLs46wKIu6-Xpfsei5lXsqL4d3MG0E5_Aaquogm760B-TWsOIy8lE5raelJmto4HULL5Cu0AxrmML_Gkq4KIZWI2QHpYWr9V5KShkUEE5jHMI8ijb5C0Qhi37WWsOP8Ot4czcHrUWm3A" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-web-light.svg"><img alt="Fix in Web" src="https://cursor.com/fix-in-web.svg"></picture></a>
cursor[bot] (Migrated from github.com) commented 2026-01-25 02:10:04 -05:00

Failed SRT conversion leaks uploaded file on disk

Low Severity

When SRT to VTT conversion fails in the subtitle upload handler, the uploaded SRT file at req.file.path is not cleaned up. The convertSrtToVtt function only deletes the original file after successful conversion, so if readFile or writeFile throws (e.g., invalid encoding, disk full), the catch block returns a 400 error without deleting the orphaned file. Over time, failed conversions could accumulate orphaned files on disk.

Fix in Cursor Fix in Web

### Failed SRT conversion leaks uploaded file on disk **Low Severity** <!-- DESCRIPTION START --> When SRT to VTT conversion fails in the subtitle upload handler, the uploaded SRT file at `req.file.path` is not cleaned up. The `convertSrtToVtt` function only deletes the original file after successful conversion, so if `readFile` or `writeFile` throws (e.g., invalid encoding, disk full), the catch block returns a 400 error without deleting the orphaned file. Over time, failed conversions could accumulate orphaned files on disk. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: ref1_2113dbc0-0525-4bb5-9dbb-32444c80baf3 --> <!-- LOCATIONS START routes/movies.js#L618-L624 LOCATIONS END --> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmY4YTAwNzZmLWVhYzktNDUyZS1iNzMyLWI0YTlhYzE5N2VjMiIsImVuY3J5cHRpb25LZXkiOiJna3loaVE5SU9mZmhDRFYzQjRIQm50RjYzU0NyZ19LXzFtZXRreWMzWkljIiwiYnJhbmNoIjoiMjAyNiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.dVuuQKP7HyoShA2P652TOm66ol0N49HVrHOwdOCfJ_k__vfL3tuPHPjAo2jDWffTJmjA-Nf3QTSyyTFxc77clewavPsQGym2yRLze6pO_md6FKGuj9l5FlXPN8WU57KEOfQpDHMUnTyzQzpTHK3YObwxBPIgXlvifCVsIm2jzYKR18obAAeeCT6tfhEjzMhlkZ4a_2GhuhSFdc-XLQh23q5jVESNLu0tSMfv4iDqDbi6K90oWncB_D82IantWAkFtyRdBPBWylKVS87SfF9mdrVHcZMn2oBJGXMATq0GkSx2E_wyhcvt4AE2L1PMsr5xUndXdV8e_f0tYHLYyIrPww" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-cursor-light.svg"><img alt="Fix in Cursor" src="https://cursor.com/fix-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmY4YTAwNzZmLWVhYzktNDUyZS1iNzMyLWI0YTlhYzE5N2VjMiIsImVuY3J5cHRpb25LZXkiOiJna3loaVE5SU9mZmhDRFYzQjRIQm50RjYzU0NyZ19LXzFtZXRreWMzWkljIiwiYnJhbmNoIjoiMjAyNiIsInJlcG9Pd25lciI6InF1b2lqZSIsInJlcG9OYW1lIjoib3NjYXJzLXBvb2wiLCJwck51bWJlciI6NzMsImNvbW1pdFNoYSI6IjQwNmE0ZjBiYjNhMTdlMGU3MDFmNmQ4YmJhMWNiMmVhZmUyMWY0MWUiLCJwcm92aWRlciI6ImdpdGh1YiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.mouSMrGKiGp0p7nS8MDK9Srd6A9Uhpd1CiXYx9GKtgEZSwriBBKYOrxICTjhRRmUL0Nx_IYiX3bxxU3k2qOMarGaMfNdrfFDU8oPQ2QtKeaODi-YfuCE-hNdMvbs2kAvYnaovcJmVfz7rTzBDgVXTdpDq2sAUuIiidAE0GCsjSq0FS_lTi5r5DOluFPTMA7XiLLyGALV2wa8PO5hzE4xZkzyTdS7jtTkMvq6qKmUP5EGnTPLfhpCYI27QZ9yUj6fLfdiSeJ-pdTGYt1XHcy7qSIxadgyZGlY8AubOrOaZJdt0_jO6rPE-2MQaqy-qm-PBtwbjmpb8cVpoT5bjgMYMA" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-web-light.svg"><img alt="Fix in Web" src="https://cursor.com/fix-in-web.svg"></picture></a>
cursor[bot] (Migrated from github.com) commented 2026-01-25 02:10:04 -05:00

Movie deletion orphans associated subtitle files on disk

Medium Severity

When movies are deleted via the /delete endpoint, the associated subtitle files stored on disk in SUBTITLE_FILES_DIR are not removed. The endpoint queries movies with only select("imdb_id") and then calls Movie.deleteMany() without first retrieving or cleaning up the subtitles array file paths. This commit introduces subtitle file uploads but doesn't integrate cleanup into the movie deletion flow, causing subtitle files to accumulate indefinitely as movies are deleted.

Fix in Cursor Fix in Web

### Movie deletion orphans associated subtitle files on disk **Medium Severity** <!-- DESCRIPTION START --> When movies are deleted via the `/delete` endpoint, the associated subtitle files stored on disk in `SUBTITLE_FILES_DIR` are not removed. The endpoint queries movies with only `select("imdb_id")` and then calls `Movie.deleteMany()` without first retrieving or cleaning up the `subtitles` array file paths. This commit introduces subtitle file uploads but doesn't integrate cleanup into the movie deletion flow, causing subtitle files to accumulate indefinitely as movies are deleted. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: ref2_681f0297-bcc5-47ca-8f39-f6e838d45b73 --> <!-- LOCATIONS START routes/movies.js#L755-L759 LOCATIONS END --> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjYzZjllZDNjLWJlYTUtNGFmMy05MmNhLTUyMDA0ZDE2YzhiNCIsImVuY3J5cHRpb25LZXkiOiJhekRoY3hhbTlCb3JXX1V4bzBqSHQ4ZHprbjkzWUJCWmdpb2NjRnVYSDdzIiwiYnJhbmNoIjoiMjAyNiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.yW3cruYedER9TgoOPSuZZpW9Tkgr6qSh2cT7D3aJJb-LmdgjY5JzVDyftKaUv7jMm7j-wqP4MaggnRHc0YhXF6PivW-13_xl4QHKM1UP0klzHEDALTB9O-kFpGAv_7Q_IwUJbIf0uCEDRGi5AHBl2pAs2BcN34tyXfN0HIcHcHW8bjJSBR0-0bRpMsm03gwE32fabDFLwckolUkdoYu3AQbJvo7slMkXg491HCtSD0weGW_LEbH1AE0bIlavxRPHDifa17pTCgESWRBoH4GXPkUh-z-O4UAoNr3SqlmLWTC1_rJgP8hEUTiqmpJaU6Uq-jtc3TUe_tMe98JD6LLvXA" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-cursor-light.svg"><img alt="Fix in Cursor" src="https://cursor.com/fix-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjYzZjllZDNjLWJlYTUtNGFmMy05MmNhLTUyMDA0ZDE2YzhiNCIsImVuY3J5cHRpb25LZXkiOiJhekRoY3hhbTlCb3JXX1V4bzBqSHQ4ZHprbjkzWUJCWmdpb2NjRnVYSDdzIiwiYnJhbmNoIjoiMjAyNiIsInJlcG9Pd25lciI6InF1b2lqZSIsInJlcG9OYW1lIjoib3NjYXJzLXBvb2wiLCJwck51bWJlciI6NzMsImNvbW1pdFNoYSI6IjQwNmE0ZjBiYjNhMTdlMGU3MDFmNmQ4YmJhMWNiMmVhZmUyMWY0MWUiLCJwcm92aWRlciI6ImdpdGh1YiJ9LCJpYXQiOjE3NjkzMjUwMDMsImV4cCI6MTc3MTkxNzAwM30.hgznBaQfqEPS1bdrhXuRt8-uL6I4tpy0vMAamt5pz94fQxL28PVgh2k3OQ6uwNmpOX5NrsqLZz7CjhfhZbOgOrFTCrED6PeUCHq-kt2upr7kus-cgHpj4_dleKgwZe3KxQkE-5geUu5nsN_0fqb-34kZZEgYf7w16q2QRfQX6Cq8X2YJWZbZKMcAh8BtOWPpSd_uAesWAoz-7XLR1KBEHS3sSs5A0ZuYzvXBcVY4x3ze_sFf5BwQaGWj-fEl4z8bXRddHMlcgJx63OUfbfxQxhFYRxAWZUg4kRUTsz-LQGB1thLsaguMVLIARr3a3f3TVtsKhB8-A2mgSKaUnOEbpg" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-web-light.svg"><img alt="Fix in Web" src="https://cursor.com/fix-in-web.svg"></picture></a>
Sign in to join this conversation.