feat: add scheduled metadata refresh for libraries

Add metadata_refresh_mode (manual/hourly/daily/weekly) to libraries,
with automatic scheduling via the indexer. Includes API support,
backoffice UI controls, i18n translations, and DB migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 10:51:52 +01:00
parent 5a224c48c0
commit fe5de3d5c1
8 changed files with 143 additions and 10 deletions

View File

@@ -12,6 +12,7 @@ interface LibraryActionsProps {
watcherEnabled: boolean;
metadataProvider: string | null;
fallbackMetadataProvider: string | null;
metadataRefreshMode: string;
onUpdate?: () => void;
}
@@ -22,6 +23,7 @@ export function LibraryActions({
watcherEnabled,
metadataProvider,
fallbackMetadataProvider,
metadataRefreshMode,
onUpdate
}: LibraryActionsProps) {
const { t } = useTranslation();
@@ -48,6 +50,7 @@ export function LibraryActions({
const scanMode = formData.get("scan_mode") as string;
const newMetadataProvider = (formData.get("metadata_provider") as string) || null;
const newFallbackProvider = (formData.get("fallback_metadata_provider") as string) || null;
const newMetadataRefreshMode = formData.get("metadata_refresh_mode") as string;
try {
const [response] = await Promise.all([
@@ -58,6 +61,7 @@ export function LibraryActions({
monitor_enabled: monitorEnabled,
scan_mode: scanMode,
watcher_enabled: watcherEnabled,
metadata_refresh_mode: newMetadataRefreshMode,
}),
}),
fetch(`/api/libraries/${libraryId}/metadata-provider`, {
@@ -181,6 +185,20 @@ export function LibraryActions({
</select>
</div>
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground">{t("libraryActions.metadataRefreshSchedule")}</label>
<select
name="metadata_refresh_mode"
defaultValue={metadataRefreshMode}
className="text-sm border border-border rounded-lg px-2 py-1 bg-background"
>
<option value="manual">{t("monitoring.manual")}</option>
<option value="hourly">{t("monitoring.hourly")}</option>
<option value="daily">{t("monitoring.daily")}</option>
<option value="weekly">{t("monitoring.weekly")}</option>
</select>
</div>
{saveError && (
<p className="text-xs text-destructive bg-destructive/10 px-2 py-1.5 rounded-lg break-all">
{saveError}

View File

@@ -131,6 +131,7 @@ export default async function LibrariesPage() {
watcherEnabled={lib.watcher_enabled}
metadataProvider={lib.metadata_provider}
fallbackMetadataProvider={lib.fallback_metadata_provider}
metadataRefreshMode={lib.metadata_refresh_mode}
/>
</div>
</CardHeader>
@@ -169,6 +170,11 @@ export default async function LibrariesPage() {
{t("libraries.nextScan", { time: formatNextScan(lib.next_scan_at, t("libraries.imminent")) })}
</span>
)}
{lib.metadata_refresh_mode !== "manual" && lib.next_metadata_refresh_at && (
<span className="text-xs text-muted-foreground ml-auto" title={t("libraries.nextMetadataRefresh", { time: formatNextScan(lib.next_metadata_refresh_at, t("libraries.imminent")) })}>
{t("libraries.nextMetadataRefreshShort", { time: formatNextScan(lib.next_metadata_refresh_at, t("libraries.imminent")) })}
</span>
)}
</div>
{/* Actions */}