6 Commits

Author SHA1 Message Date
c0bcbaec1b time input: replace hand-rolled fields with react-aria-components TimeField
All checks were successful
Build and Push Docker Image / build (push) Successful in 49s
the previous TimeInput was a bespoke two-field widget. correct in behaviour
but off-policy: we don't roll our own ui primitives when a maintained
library solves it. swap for react-aria-components + @internationalized/date
pinned to hourCycle={24}, granularity=minute, shouldForceLeadingZeros so
the output is always strict HH:MM regardless of browser/OS locale.

wrapper lives at src/shared/components/ui/time-input.tsx and keeps the
existing string-based API (value: "HH:MM", onChange(next)) so callers don't
change.

also updates the stack docs: web-stack.md now pins react-aria-components
as THE required library for every date/time ui; iOS and Android entries
mark their canonical component as TBD and explicitly forbid rolling our
own without user sign-off.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:37:03 +02:00
6d8a8fa6d6 drop the subtitle-languages setting, it never influenced extraction
All checks were successful
Build and Push Docker Image / build (push) Successful in 53s
analyzer removes every subtitle unconditionally (see case 'Subtitle' in
decideAction) and the pipeline extracts all of them to sidecars — the config
was purely informational and only subtitles.ts echoed it back as
'keepLanguages' for a subtitle-manager ui that doesn't exist yet. we'll
revive language preferences inside that manager when it ships.

removes: the settings card + ui state, POST /api/settings/subtitle-languages,
the config default, the SUBTITLE_LANGUAGES env mapping, AnalyzerConfig's
subtitleLanguages field, RescanConfig's subtitleLanguages field, every
caller site (scan.ts / execute.ts / review.ts), and the keepLanguages
surface in subtitles.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:26:48 +02:00
c06172f412 migrate existing sqlite dbs to the new columns, don't force a nuke on deploy
All checks were successful
Build and Push Docker Image / build (push) Successful in 52s
upgraded containers (like the unraid one with a persistent ./data volume)
kept their old media_items/media_streams tables, so upsertJellyfinItem hit
"table media_items has no column named original_title" on first scan after
the canonical-language rewrite. sqlite has no native add-column-if-not-exists
so we try/catch each alter, same pattern we had before i deleted the shims.

also backports the older alters (stream_decisions.custom_title, review_plans
subs_extracted/confidence/apple_compat/job_type) so pre-rewrite installs
still converge without a wipe.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:09:45 +02:00
bb4016d05b gitignore scheduled_tasks.lock (scheduled wakeup state)
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m13s
2026-04-13 08:18:08 +02:00
e4c771d39e fix scan page tdz crash: break flush/stopFlushing useCallback cycle
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Prod minified bundle crashed with 'can't access lexical declaration 'o'
before initialization' because flush was memoized with stopFlushing in its
deps, and stopFlushing was memoized with flush in its deps — circular.
In dev this still worked (refs paper over TDZ), but Vite's minifier emitted
the declarations in an order that tripped the temporal dead zone.

Extract the interval-clearing into a plain inline helper (clearFlushTimer)
that both flush and stopFlushing call. flush no longer depends on
stopFlushing; the cycle is gone.
2026-04-13 08:17:57 +02:00
93ed0ac33c fix analyzer + api boundary + perf + scheduler hardening
- analyzer: rewrite checkAudioOrderChanged to compare actual output order, unify assignTargetOrder with a shared sortKeptStreams util in ffmpeg builder
- review: recompute is_noop via full audio removed/reordered/transcode/subs check on toggle, preserve custom_title across rescan by matching (type,lang,stream_index,title), batch pipeline transcode-reasons query to avoid N+1
- validate: add lib/validate.ts with parseId + isOneOf helpers; replace bare Number(c.req.param('id')) with 400 on invalid ids across review/subtitles
- scan: atomic CAS on scan_running config to prevent concurrent scans
- subtitles: path-traversal guard — only unlink sidecars within the media item's directory; log-and-orphan DB entries pointing outside
- schedule: include end minute in window (<= vs <)
- db: add indexes on review_plans(status,is_noop), stream_decisions(plan_id), media_items(series_jellyfin_id,series_name,type), media_streams(item_id,type), subtitle_files(item_id), jobs(status,item_id)
2026-04-13 07:31:48 +02:00