refactor: remove legacy single-root APIs, defer filesystem I/O, enforce POSIX paths

- Remove legacy endpoints: /api/change-folder, /api/index, /api/scan, /api/status,
  /api/playback/resume-positions
- Remove legacy global scanner module-level API from hivescan/scanner.py
- Defer all filesystem validation to background task in server lifespan (macOS-safe)
- CLI and winmain pass raw paths via MEDIAHIVE_ROOTS; no pre-startup validation
- Enforce POSIX paths everywhere (as_posix(), no backslash leakage)
- Remove MEDIAHIVE_PATH and MEDIAHIVE_DEFER_INITIAL_ROOT env vars
- Update frontend api.ts to use per-root resume positions
- Update docs/API.md and docs/multi-index-plan.md
- Fix Python 2 style except clauses in hivescan/utils.py and scanning.py
This commit is contained in:
2026-05-23 22:21:35 +00:00
parent 2f83193ff4
commit 9c75fa4569
25 changed files with 1963 additions and 1150 deletions
+4 -4
View File
@@ -502,7 +502,7 @@ function handleEpisodeHover(key: string, isEntering: boolean) {
// Backdrop URL - only use backdrop_path, fall back to collage (handled in template)
const backdropUrl = computed(() => {
if (props.series.info?.backdrop_path) {
return getCoverUrl(props.series.info.backdrop_path);
return getCoverUrl(props.series.info.backdrop_path, props.series.root_id);
}
return null;
});
@@ -523,7 +523,7 @@ const ratingClass = computed(() => {
// Get season poster
function getSeasonPoster(season: Season): string | undefined {
if (season.poster_path) {
return getCoverUrl(season.poster_path);
return getCoverUrl(season.poster_path, props.series.root_id);
}
return undefined;
}
@@ -536,14 +536,14 @@ function getEpisodeVideoSources(episode: Episode): Array<{ src: string; type: st
: [];
return sources.map((path) => ({
src: getVideoPreviewUrl(getCoverUrl(path)),
src: getVideoPreviewUrl(getCoverUrl(path, props.series.root_id)),
...getVideoSourceAttributes(path),
}));
}
// Collage slice style for season posters
function getCollageSliceStyle(season: Season, index: number) {
const posterUrl = season.poster_path ? getCoverUrl(season.poster_path) : null;
const posterUrl = season.poster_path ? getCoverUrl(season.poster_path, props.series.root_id) : null;
const totalSlices = Math.min(seasonsWithPosters.value.length, 5);
const sliceWidth = 100 / totalSlices;