From 48c0a94a47979396b91f6f270a4a7e4011d075c8 Mon Sep 17 00:00:00 2001 From: Harvey <64276030+HabiRabbu@users.noreply.github.com> Date: Sun, 5 Apr 2026 02:52:28 +0100 Subject: [PATCH] fix: increase sync time default/max + minimizable sync notif (#12) --- backend/api/v1/schemas/settings.py | 2 +- backend/core/tasks.py | 23 ++- .../lib/components/CacheSyncIndicator.svelte | 186 ++++++++++++------ .../settings/SettingsLibrarySync.svelte | 15 +- frontend/src/lib/stores/syncStatus.svelte.ts | 13 ++ frontend/src/routes/library/+page.svelte | 39 +++- 6 files changed, 198 insertions(+), 80 deletions(-) diff --git a/backend/api/v1/schemas/settings.py b/backend/api/v1/schemas/settings.py index 65c32cf..6c716f6 100644 --- a/backend/api/v1/schemas/settings.py +++ b/backend/api/v1/schemas/settings.py @@ -160,7 +160,7 @@ class LocalFilesVerifyResponse(AppStruct): class LidarrSettings(AppStruct): - sync_frequency: Literal["manual", "5min", "10min", "30min", "1hr"] = "10min" + sync_frequency: Literal["manual", "5min", "10min", "30min", "1hr", "6hr", "12hr", "24hr", "3d", "7d"] = "24hr" last_sync: int | None = None last_sync_success: bool = True diff --git a/backend/core/tasks.py b/backend/core/tasks.py index 535ec44..e0fc8b1 100644 --- a/backend/core/tasks.py +++ b/backend/core/tasks.py @@ -98,16 +98,19 @@ async def sync_library_periodically( if sync_freq == "manual": await asyncio.sleep(3600) continue - elif sync_freq == "5min": - interval = 300 - elif sync_freq == "10min": - interval = 600 - elif sync_freq == "30min": - interval = 1800 - elif sync_freq == "1hr": - interval = 3600 - else: - interval = 600 + + freq_to_seconds = { + "5min": 300, + "10min": 600, + "30min": 1800, + "1hr": 3600, + "6hr": 21600, + "12hr": 43200, + "24hr": 86400, + "3d": 259200, + "7d": 604800, + } + interval = freq_to_seconds.get(sync_freq, 86400) await asyncio.sleep(interval) diff --git a/frontend/src/lib/components/CacheSyncIndicator.svelte b/frontend/src/lib/components/CacheSyncIndicator.svelte index e2c51fb..a9b3dd8 100644 --- a/frontend/src/lib/components/CacheSyncIndicator.svelte +++ b/frontend/src/lib/components/CacheSyncIndicator.svelte @@ -1,7 +1,18 @@ {#if syncStatus.showIndicator}
-
-
-
+ {#if syncStatus.isMinimized} + + -
- - {#if syncStatus.isActive} -
-
-
- -
- {#if syncStatus.totalItems === 0} - Cached ✓ - {:else} - {syncStatus.processedItems} / {syncStatus.totalItems} - {syncStatus.progress}% - {/if} -
- - {#if syncStatus.currentItem} -
- {syncStatus.currentItem} + {pillLabel} + + + + {:else} + +
+
+
+ {#if isComplete} +
+ +
+ Sync Complete + {:else if syncStatus.error} +
+ +
+ Sync Failed + {:else} +
+ +
+
+ {syncStatus.phaseLabel} + {#if syncStatus.phaseNumber > 0} + + {syncStatus.phaseNumber}/{syncStatus.totalPhases} + + {/if} +
+ {/if}
- {/if} - {/if} +
+ + +
+
- {#if syncStatus.error} -

{syncStatus.error}

- {/if} -
+ {#if syncStatus.isActive} +
+
+
+ +
+ {#if syncStatus.totalItems === 0} + Cached ✓ + {:else} + {syncStatus.processedItems} / {syncStatus.totalItems} + {syncStatus.progress}% + {/if} +
+ + {#if syncStatus.currentItem} +
+ {syncStatus.currentItem} +
+ {/if} + {/if} + + {#if syncStatus.error} +

{syncStatus.error}

+ {/if} +
+ {/if}
{/if} diff --git a/frontend/src/lib/components/settings/SettingsLibrarySync.svelte b/frontend/src/lib/components/settings/SettingsLibrarySync.svelte index 5f65f7e..eb32b85 100644 --- a/frontend/src/lib/components/settings/SettingsLibrarySync.svelte +++ b/frontend/src/lib/components/settings/SettingsLibrarySync.svelte @@ -6,7 +6,7 @@ import { onDestroy } from 'svelte'; interface LibrarySyncSettings { - sync_frequency: 'manual' | '5min' | '10min' | '30min' | '1hr'; + sync_frequency: 'manual' | '5min' | '10min' | '30min' | '1hr' | '6hr' | '12hr' | '24hr' | '3d' | '7d'; last_sync: number | null; last_sync_success: boolean; } @@ -85,10 +85,19 @@
Sync Frequency
diff --git a/frontend/src/lib/stores/syncStatus.svelte.ts b/frontend/src/lib/stores/syncStatus.svelte.ts index 7f1c38d..3f92c66 100644 --- a/frontend/src/lib/stores/syncStatus.svelte.ts +++ b/frontend/src/lib/stores/syncStatus.svelte.ts @@ -48,6 +48,7 @@ const AUTO_HIDE_ERROR_MS = 6000; function createSyncStatusStore() { let status = $state({ ...EMPTY_STATUS }); let isDismissed = $state(false); + let isMinimized = $state(false); let showIndicator = $state(false); let connectionMode = $state<'sse' | 'polling'>('sse'); @@ -81,6 +82,7 @@ function createSyncStatusStore() { if (newStatus.is_syncing && !wasSyncing) { isDismissed = false; + isMinimized = false; } if (wasSyncing && !newStatus.is_syncing && !newStatus.error_message && browser) { @@ -254,6 +256,9 @@ function createSyncStatusStore() { get showIndicator() { return showIndicator && !isDismissed; }, + get isMinimized() { + return isMinimized; + }, get connectionMode() { return connectionMode; }, @@ -289,6 +294,14 @@ function createSyncStatusStore() { isDismissed = true; }, + minimize(): void { + isMinimized = true; + }, + + expand(): void { + isMinimized = false; + }, + checkStatus(): void { void fetchStatus(); } diff --git a/frontend/src/routes/library/+page.svelte b/frontend/src/routes/library/+page.svelte index b5fa3d4..9059b69 100644 --- a/frontend/src/routes/library/+page.svelte +++ b/frontend/src/routes/library/+page.svelte @@ -13,7 +13,7 @@ import { API } from '$lib/constants'; import { isAbortError } from '$lib/utils/errorHandling'; import type { Artist, Album } from '$lib/types'; - import { CircleX, X, RefreshCw, ChevronRight, Search, Loader2 } from 'lucide-svelte'; + import { CircleX, X, RefreshCw, ChevronRight, Search, Loader2, Settings2 } from 'lucide-svelte'; const CIRCUIT_BREAKER_CODE = 'CIRCUIT_BREAKER_OPEN'; @@ -71,6 +71,7 @@ let syncing = false; let error: string | null = null; let errorCode: string | null = null; + let syncFrequencyLabel: string | null = null; let currentAlbumPage = 1; let sortBy = 'date_added'; @@ -88,13 +89,36 @@ $: isConnectionError = errorCode === CIRCUIT_BREAKER_CODE || (error != null && /connection|DNS|not configured/i.test(error)); + const FREQ_LABELS: Record = { + manual: 'Manual sync only', + '5min': 'Auto-syncs every 5 minutes', + '10min': 'Auto-syncs every 10 minutes', + '30min': 'Auto-syncs every 30 minutes', + '1hr': 'Auto-syncs every hour', + '6hr': 'Auto-syncs every 6 hours', + '12hr': 'Auto-syncs every 12 hours', + '24hr': 'Auto-syncs every 24 hours', + '3d': 'Auto-syncs every 3 days', + '7d': 'Auto-syncs every 7 days' + }; + onMount(() => { recentlyAddedStore.initialize(); loadArtists(); fetchAlbums(); loadStats(); + loadSyncFrequency(); }); + async function loadSyncFrequency() { + try { + const data = await api.global.get<{ sync_frequency: string }>('/api/v1/settings/lidarr'); + syncFrequencyLabel = FREQ_LABELS[data.sync_frequency] ?? null; + } catch { + // Silently omit frequency hint if settings can't be loaded + } + } + async function loadArtists() { try { const url = API.library.artists(ARTIST_CAROUSEL_LIMIT, 0, 'name', 'asc'); @@ -266,6 +290,19 @@ {stats.artist_count} artists • {stats.album_count} albums • Last sync: {lastSyncText} {/if}

+ {#if syncFrequencyLabel} +

+ {syncFrequencyLabel} + + + +

+ {/if}