fixes and improvements

This commit is contained in:
2026-05-06 16:33:02 +02:00
parent d8d80867ce
commit 5277f21577
20 changed files with 577 additions and 222 deletions
+69 -7
View File
@@ -1,5 +1,5 @@
import { useMemo } from "react";
import { useNavigate } from "react-router-dom";
import { useEffect, useMemo } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { DataGrid } from "@mui/x-data-grid";
import type { GridColDef } from "@mui/x-data-grid";
import {
@@ -28,6 +28,8 @@ import {
} from "../hooks/useMedia";
import { usePersistentState } from "../hooks/usePersistentState";
import type { MediaItem } from "../types";
import { useMonitoringSettings } from "../hooks/useSettings";
import { useCounts, useLibraries } from "../hooks/useDashboard";
function formatDuration(seconds: number | null | undefined): string {
if (seconds == null || Number.isNaN(seconds)) return "-";
@@ -64,11 +66,26 @@ function defaultMediaTabState(): MediaTabState {
export function Media() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const isMobile = useMediaQuery("(max-width: 900px)");
const { data: status } = useMediaStatus();
const buildIndex = useBuildIndex();
const stopBuildIndex = useStopBuildIndex();
const forceStopBuildIndex = useForceStopBuildIndex();
const { data: machines } = useMonitoringSettings();
const jellyfinMachines = useMemo(
() =>
(machines ?? []).filter(
(machine) => machine.enabled && machine.services.includes("jellyfin"),
),
[machines],
);
const selectedMachineId =
searchParams.get("machine_id") || jellyfinMachines[0]?.id || "";
const { data: counts } = useCounts(selectedMachineId || undefined);
const { data: libraries } = useLibraries(selectedMachineId || undefined);
const { data: status } = useMediaStatus(selectedMachineId || undefined);
const buildIndex = useBuildIndex(selectedMachineId || undefined);
const stopBuildIndex = useStopBuildIndex(selectedMachineId || undefined);
const forceStopBuildIndex = useForceStopBuildIndex(
selectedMachineId || undefined,
);
const [mediaState, setMediaState] = usePersistentState<MediaTabState>(
MEDIA_TAB_STATE_KEY,
@@ -79,6 +96,19 @@ export function Media() {
setMediaState((current) => ({ ...current, ...patch }));
const limit = 100;
useEffect(() => {
if (!searchParams.get("machine_id") && selectedMachineId) {
setSearchParams(
(current) => {
const next = new URLSearchParams(current);
next.set("machine_id", selectedMachineId);
return next;
},
{ replace: true },
);
}
}, [searchParams, selectedMachineId, setSearchParams]);
const { data: queryResult, isLoading } = useMediaDataQuery({
types,
search,
@@ -87,6 +117,7 @@ export function Media() {
sort_order: sortOrder,
limit,
offset,
machineId: selectedMachineId || undefined,
enabled: status?.exists ?? false,
});
@@ -155,7 +186,30 @@ export function Media() {
spacing={1.5}
sx={{ alignItems: "center", flexWrap: "wrap" }}
>
<Typography variant="h5">Media</Typography>
<Typography variant="h5">Jellyfin</Typography>
<FormControl size="small" sx={{ minWidth: 220 }}>
<InputLabel>Machine</InputLabel>
<Select
label="Machine"
value={selectedMachineId}
onChange={(e) =>
setSearchParams(
(current) => {
const next = new URLSearchParams(current);
next.set("machine_id", String(e.target.value));
return next;
},
{ replace: true },
)
}
>
{jellyfinMachines.map((machine) => (
<MenuItem key={machine.id} value={machine.id}>
{machine.name}
</MenuItem>
))}
</Select>
</FormControl>
{status?.exists ? (
<Typography variant="body2" color="text.secondary">
Index: {status.item_count.toLocaleString()} items
@@ -168,6 +222,14 @@ export function Media() {
No index built yet.
</Alert>
)}
{counts && (
<Typography variant="body2" color="text.secondary">
Library stats: {counts.movies.toLocaleString()} movies ·{" "}
{counts.series.toLocaleString()} series ·{" "}
{counts.episodes.toLocaleString()} episodes ·{" "}
{(libraries?.length ?? 0).toLocaleString()} libraries
</Typography>
)}
<Button
variant="outlined"
onClick={() => buildIndex.mutate()}