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)
This commit is contained in:
26
server/lib/validate.ts
Normal file
26
server/lib/validate.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { Context } from 'hono';
|
||||
|
||||
/** Parse a route param as a positive integer id. Returns null if invalid. */
|
||||
export function parseId(raw: string | undefined): number | null {
|
||||
if (!raw) return null;
|
||||
const n = Number.parseInt(raw, 10);
|
||||
return Number.isFinite(n) && n > 0 ? n : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a positive integer id param. Returns the id, or responds 400
|
||||
* and returns null. Callers check for null and return the response.
|
||||
*/
|
||||
export function requireId(c: Context, name: string): number | null {
|
||||
const id = parseId(c.req.param(name));
|
||||
if (id == null) {
|
||||
c.status(400);
|
||||
return null;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/** True if value is one of the allowed strings. */
|
||||
export function isOneOf<T extends string>(value: unknown, allowed: readonly T[]): value is T {
|
||||
return typeof value === 'string' && (allowed as readonly string[]).includes(value);
|
||||
}
|
||||
Reference in New Issue
Block a user