diff --git a/ImmichFrame.Core/Helpers/CalendarExtensionMethods.cs b/ImmichFrame.Core/Helpers/CalendarExtensionMethods.cs index 19066902..c6f5e6e6 100644 --- a/ImmichFrame.Core/Helpers/CalendarExtensionMethods.cs +++ b/ImmichFrame.Core/Helpers/CalendarExtensionMethods.cs @@ -1,26 +1,32 @@ -using Ical.Net.CalendarComponents; +using Ical.Net.CalendarComponents; using Ical.Net.DataTypes; using ImmichFrame.Core.Interfaces; using ImmichFrame.Core.Models; - namespace ImmichFrame.WebApi.Helpers { public static class CalendarExtensionMethods { public static IAppointment ToAppointment(this Occurrence occurrence) { - if (occurrence.Source.GetType() == typeof(CalendarEvent)) { - return ((CalendarEvent)occurrence.Source).ToAppointment(); + string summary = ""; + string description = ""; + string location = ""; + + if (occurrence.Source is CalendarEvent calEvent) + { + summary = calEvent.Summary; + description = calEvent.Description ?? ""; + location = calEvent.Location ?? ""; } return new Appointment { - //Summary = occurrence.Period.Duration.Summary, - //Description = occurrence.Source.Description, + Summary = summary, + Description = description, StartTime = occurrence.Period.StartTime.AsSystemLocal, Duration = occurrence.Period.Duration, EndTime = occurrence.Period.EndTime.AsSystemLocal, - Location = "" + Location = location }; } public static IAppointment ToAppointment(this CalendarEvent calEvent) @@ -28,11 +34,11 @@ public static IAppointment ToAppointment(this CalendarEvent calEvent) return new Appointment { Summary = calEvent.Summary, - Description = calEvent.Description, + Description = calEvent.Description ?? "", StartTime = calEvent.Start.AsSystemLocal, Duration = calEvent.Duration, EndTime = calEvent.End.AsSystemLocal, - Location = calEvent.Location + Location = calEvent.Location ?? "" }; } } diff --git a/ImmichFrame.Core/Interfaces/IServerBehaviorSettings.cs b/ImmichFrame.Core/Interfaces/IServerBehaviorSettings.cs index 100abf39..d5f3f14e 100644 --- a/ImmichFrame.Core/Interfaces/IServerBehaviorSettings.cs +++ b/ImmichFrame.Core/Interfaces/IServerBehaviorSettings.cs @@ -3,6 +3,7 @@ namespace ImmichFrame.Core.Interfaces public interface IServerBehaviorSettings { public List Webcalendars { get; } + public int CalendarDaysAhead { get; } public int RefreshAlbumPeopleInterval { get; } public string? WeatherApiKey { get; } public string? WeatherLatLong { get; } diff --git a/ImmichFrame.Core/Services/IcalCalendarService.cs b/ImmichFrame.Core/Services/IcalCalendarService.cs index 56ef89d1..eb962ee5 100644 --- a/ImmichFrame.Core/Services/IcalCalendarService.cs +++ b/ImmichFrame.Core/Services/IcalCalendarService.cs @@ -47,14 +47,18 @@ public async Task> GetAppointments() var icals = await GetCalendars(cals); + // Clamp to a sane range: never negative, and cap well below DateTime overflow. + var daysAhead = Math.Clamp(_serverSettings.CalendarDaysAhead, 0, 3650); + var endDate = DateTime.Today.AddDays(daysAhead + 1); + foreach (var ical in icals) { var calendar = Calendar.Load(ical); - - appointments.AddRange(calendar.GetOccurrences(DateTime.Today, DateTime.Today.AddDays(1)).Select(x => x.ToAppointment())); + appointments.AddRange(calendar.GetOccurrences(DateTime.Today, endDate) + .Select(x => x.ToAppointment())); } - return appointments; + return appointments.OrderBy(x => x.StartTime).ToList(); }); } @@ -90,4 +94,4 @@ public async Task> GetCalendars(IEnumerable<(string? auth, string u return icals; } -} \ No newline at end of file +} diff --git a/ImmichFrame.WebApi/Helpers/Config/ServerSettingsV1.cs b/ImmichFrame.WebApi/Helpers/Config/ServerSettingsV1.cs index 076f36da..fed09782 100644 --- a/ImmichFrame.WebApi/Helpers/Config/ServerSettingsV1.cs +++ b/ImmichFrame.WebApi/Helpers/Config/ServerSettingsV1.cs @@ -24,6 +24,7 @@ public class ServerSettingsV1 : IConfigSettable public List Tags { get; set; } = new List(); public int? Rating { get; set; } public List Webcalendars { get; set; } = new List(); + public int CalendarDaysAhead { get; set; } = 0; public int RefreshAlbumPeopleInterval { get; set; } = 12; public string? WeatherApiKey { get; set; } = string.Empty; public string? UnitSystem { get; set; } = "imperial"; @@ -101,6 +102,7 @@ public void ValidateAndInitialize() { } class GeneralSettingsV1Adapter(ServerSettingsV1 _delegate) : IGeneralSettings { public List Webcalendars => _delegate.Webcalendars; + public int CalendarDaysAhead => _delegate.CalendarDaysAhead; public int RefreshAlbumPeopleInterval => _delegate.RefreshAlbumPeopleInterval; public string? WeatherApiKey => _delegate.WeatherApiKey; public string? WeatherLatLong => _delegate.WeatherLatLong; diff --git a/ImmichFrame.WebApi/Models/ServerSettings.cs b/ImmichFrame.WebApi/Models/ServerSettings.cs index 74d0fb8e..3bbdbc8c 100644 --- a/ImmichFrame.WebApi/Models/ServerSettings.cs +++ b/ImmichFrame.WebApi/Models/ServerSettings.cs @@ -66,6 +66,7 @@ public class GeneralSettings : IGeneralSettings, IConfigSettable public string Layout { get; set; } = "splitview"; public int RenewImagesDuration { get; set; } = 30; public List Webcalendars { get; set; } = new(); + public int CalendarDaysAhead { get; set; } = 0; public int RefreshAlbumPeopleInterval { get; set; } = 12; public string? WeatherApiKey { get; set; } = string.Empty; public string? UnitSystem { get; set; } = "imperial"; diff --git a/immichFrame.Web/src/lib/components/elements/appointments.svelte b/immichFrame.Web/src/lib/components/elements/appointments.svelte index 645402a5..9fa38b95 100644 --- a/immichFrame.Web/src/lib/components/elements/appointments.svelte +++ b/immichFrame.Web/src/lib/components/elements/appointments.svelte @@ -4,43 +4,38 @@ import { format } from 'date-fns'; import { configStore } from '$lib/stores/config.store'; import { clientIdentifierStore } from '$lib/stores/persist.store'; - api.init(); - function formatDates(startTime: string, endTime: string) { let startDate = new Date(startTime); let endDate = new Date(endTime); - let sameDay = startDate.getDate() == endDate.getDate(); - + let sameDay = startDate.toDateString() == endDate.toDateString(); + let today = new Date(); + let isToday = startDate.toDateString() == today.toDateString(); let clockFormat = $configStore.clockFormat ?? 'HH:mm'; let clockDateFormat = $configStore.clockDateFormat ?? 'eee, MMM d'; let fullFormat = clockDateFormat + ' ' + clockFormat; - if (sameDay) { - return format(startDate, clockFormat) + ' - ' + format(endDate, clockFormat); + if (isToday) { + return format(startDate, clockFormat) + ' - ' + format(endDate, clockFormat); + } + return format(startDate, clockDateFormat) + ' ' + format(startDate, clockFormat) + ' - ' + format(endDate, clockFormat); } - return format(startDate, fullFormat) + ' - ' + format(endDate, fullFormat); } - let appointments: api.IAppointment[] = $state() as api.IAppointment[]; - onMount(() => { GetAppointments(); const appointmentInterval = setInterval(() => GetAppointments(), 10 * 60 * 1000); //every 10 minutes - return () => { clearInterval(appointmentInterval); }; }); - async function GetAppointments() { let appointmentRequest = await api.getAppointments({ clientIdentifier: $clientIdentifierStore }); if (appointmentRequest.status == 200) { appointments = appointmentRequest.data; - appointments = appointmentRequest.data.sort((a, b) => { return new Date(a.startTime ?? '').getTime() - new Date(b.startTime ?? '').getTime(); });