diff --git a/src/server/api/auth.py b/src/server/api/auth.py index aa3019a..c1717d4 100644 --- a/src/server/api/auth.py +++ b/src/server/api/auth.py @@ -70,6 +70,12 @@ async def setup_auth(req: SetupRequest): config.scheduler.enabled = req.scheduler_enabled if req.scheduler_interval_minutes is not None: config.scheduler.interval_minutes = req.scheduler_interval_minutes + if req.scheduler_schedule_time is not None: + config.scheduler.schedule_time = req.scheduler_schedule_time + if req.scheduler_schedule_days is not None: + config.scheduler.schedule_days = req.scheduler_schedule_days + if req.scheduler_auto_download_after_rescan is not None: + config.scheduler.auto_download_after_rescan = req.scheduler_auto_download_after_rescan # Update logging configuration if req.logging_level: diff --git a/src/server/models/auth.py b/src/server/models/auth.py index a786d2e..6881002 100644 --- a/src/server/models/auth.py +++ b/src/server/models/auth.py @@ -62,7 +62,16 @@ class SetupRequest(BaseModel): default=True, description="Enable/disable scheduler" ) scheduler_interval_minutes: Optional[int] = Field( - default=60, ge=1, description="Scheduler interval in minutes" + default=60, ge=1, description="Scheduler interval in minutes (legacy)" + ) + scheduler_schedule_time: Optional[str] = Field( + default="03:00", description="Daily run time in HH:MM format" + ) + scheduler_schedule_days: Optional[list] = Field( + default=None, description="Days of week to run scheduler (mon-sun)" + ) + scheduler_auto_download_after_rescan: Optional[bool] = Field( + default=False, description="Auto-download missing episodes after rescan" ) # Logging configuration diff --git a/src/server/web/templates/setup.html b/src/server/web/templates/setup.html index 63536d4..d7c812d 100644 --- a/src/server/web/templates/setup.html +++ b/src/server/web/templates/setup.html @@ -202,6 +202,47 @@ line-height: 1.4; } + .scheduler-days-row { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-top: 0.25rem; + } + + .scheduler-day-toggle-label { + display: flex; + align-items: center; + gap: 0.25rem; + cursor: pointer; + padding: 0.3rem 0.6rem; + border: 2px solid var(--color-border); + border-radius: 6px; + font-size: 0.85rem; + font-weight: 500; + background: var(--color-surface); + color: var(--color-text-secondary); + transition: all 0.15s ease; + user-select: none; + } + + .scheduler-day-toggle-label input[type="checkbox"] { + display: none; + } + + .scheduler-day-toggle-label:has(input:checked) { + border-color: var(--color-primary); + background: rgba(var(--color-primary-rgb), 0.12); + color: var(--color-primary); + } + + details.form-advanced > summary { + cursor: pointer; + color: var(--color-text-secondary); + font-size: 0.85rem; + margin-top: 0.5rem; + user-select: none; + } + .setup-button { width: 100%; padding: 0.75rem; @@ -390,11 +431,66 @@
Automatically check for new episodes
- - + +
+
+
+ +
+ + + + + + + +
+
Scheduler runs at the selected time on checked days. Uncheck all to disable scheduling.
+
+
+
+
+ +
+
+
+ Advanced +
+
+ + +
Deprecated: only used if cron scheduling is not configured.
+
+
+
@@ -673,7 +769,10 @@ name: document.getElementById('name').value.trim(), data_dir: document.getElementById('data_dir').value.trim(), scheduler_enabled: document.getElementById('scheduler_enabled').checked, - scheduler_interval_minutes: parseInt(document.getElementById('scheduler_interval_minutes').value), + scheduler_schedule_time: document.getElementById('scheduler_schedule_time').value || '03:00', + scheduler_schedule_days: Array.from(document.querySelectorAll('.scheduler-day-setup-cb:checked')).map(cb => cb.value), + scheduler_auto_download_after_rescan: document.getElementById('scheduler_auto_download').checked, + scheduler_interval_minutes: parseInt(document.getElementById('scheduler_interval_minutes').value) || 60, logging_level: document.getElementById('logging_level').value, logging_file: document.getElementById('logging_file').value.trim() || null, logging_max_bytes: document.getElementById('logging_max_bytes').value ?