diff --git a/ImmichFrame.Core/Services/IcalCalendarService.cs b/ImmichFrame.Core/Services/IcalCalendarService.cs index e2e5d25e..58e7ccca 100644 --- a/ImmichFrame.Core/Services/IcalCalendarService.cs +++ b/ImmichFrame.Core/Services/IcalCalendarService.cs @@ -1,14 +1,19 @@ +using System.Net.Http.Headers; +using System.Text; using Ical.Net; using ImmichFrame.Core.Interfaces; using ImmichFrame.WebApi.Helpers; +using Microsoft.Extensions.Logging; public class IcalCalendarService : ICalendarService { private readonly IServerSettings _serverSettings; + private readonly ILogger _logger; private readonly ApiCache> _appointmentCache = new(TimeSpan.FromMinutes(15)); - public IcalCalendarService(IServerSettings serverSettings) + public IcalCalendarService(IServerSettings serverSettings, ILogger logger) { + _logger = logger; _serverSettings = serverSettings; } @@ -18,7 +23,9 @@ public async Task> GetAppointments() { var appointments = new List(); - var icals = await GetCalendars(_serverSettings.Webcalendars); + List<(string? auth, string url)> cals = _serverSettings.Webcalendars.Select(x => x.Contains(';') ? (x.Split(';')[0], x.Split(';')[1]) : (null, x.ToString())).ToList(); + + var icals = await GetCalendars(cals); foreach (var ical in icals) { @@ -31,16 +38,26 @@ public async Task> GetAppointments() }); } - public async Task> GetCalendars(IEnumerable calendars) + public async Task> GetCalendars(IEnumerable<(string? auth, string url)> calendars) { var icals = new List(); - foreach (var webcal in calendars) + using (HttpClient client = new HttpClient()) { - string httpUrl = webcal.Replace("webcal://", "https://"); - - using (HttpClient client = new HttpClient()) + foreach (var calendar in calendars) { + _logger.LogDebug($"Loading calendar: {calendar.auth ?? "no auth"} - {calendar.url}"); + client.DefaultRequestHeaders.Authorization = null; + + string httpUrl = calendar.url.Replace("webcal://", "https://"); + + if (!string.IsNullOrEmpty(calendar.auth)) + { + var byteArray = Encoding.ASCII.GetBytes($"{calendar.auth}"); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + } + HttpResponseMessage response = await client.GetAsync(httpUrl); if (response.IsSuccessStatusCode) { @@ -48,12 +65,11 @@ public async Task> GetCalendars(IEnumerable calendars) } else { - throw new Exception("Failed to load calendar data"); + _logger.LogError($"Failed to load calendar data from '{httpUrl}' (Status: {response.StatusCode})"); } } } return icals; } - } \ No newline at end of file diff --git a/ImmichFrame.WebApi/appsettings.Development.json b/ImmichFrame.WebApi/appsettings.Development.json index 0c208ae9..9e26dfee 100644 --- a/ImmichFrame.WebApi/appsettings.Development.json +++ b/ImmichFrame.WebApi/appsettings.Development.json @@ -1,8 +1 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} +{} \ No newline at end of file diff --git a/docs/docs/getting-started/configuration.md b/docs/docs/getting-started/configuration.md index a2612656..0e994623 100644 --- a/docs/docs/getting-started/configuration.md +++ b/docs/docs/getting-started/configuration.md @@ -6,50 +6,50 @@ sidebar_position: 2 ### Settings -| **Section** | **Config-Key** | **Value** | **Default** | **Description** | -| ----------------------- | -------------------------- | ----------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| **Required** | **ImmichServerUrl** | **string** | | **The URL of your Immich server e.g. `http://photos.yourdomain.com` / `http://192.168.0.100:2283`.** | -| **Required** | **ApiKey** | **string** | | **Read more about how to obtain an [Immich API key][immich-api-url].** | -| [Security](#security) | AuthenticationSecret | string | | When set, every client needs to authenticate via Bearer Token and this value. | -| [Filtering](#filtering) | Albums | string[] | [] | UUID of album(s) | -| [Filtering](#filtering) | ExcludedAlbums | string[] | [] | UUID of excluded album(s) | -| [Filtering](#filtering) | People | string[] | [] | UUID of person(s) | -| [Filtering](#filtering) | Rating | int | | Rating of an image in stars, allowed values from -1 to 5. This will only show images with the exact rating you are filtering for. | -| [Filtering](#filtering) | ShowMemories | boolean | false | If this is set, memories are displayed. | -| [Filtering](#filtering) | ShowFavorites | boolean | false | If this is set, favorites are displayed. | -| [Filtering](#filtering) | ShowArchived | boolean | false | If this is set, assets marked archived are displayed. | -| [Filtering](#filtering) | ImagesFromDays | int | | Show images from the last X days. e.g 365 -> show images from the last year | -| [Filtering](#filtering) | ImagesFromDate | Date | | Show images after date. Overwrites the `ImagesFromDays`-Setting | -| [Filtering](#filtering) | ImagesUntilDate | Date | | Show images before date. | -| Caching | RenewImagesDuration | int | 30 | Interval in days. | -| Caching | DownloadImages | boolean | false | \*Client only. | -| Caching | RefreshAlbumPeopleInterval | int | 12 | Interval in hours. Determines how often images are pulled from a person in immich. | -| Image | ImageZoom | boolean | true | Zooms into or out of an image and gives it a touch of life. | -| Image | ImageFill | boolean | false | Whether image should fill available space. Aspect ratio maintained but may be cropped. | -| Image | Interval | int | 45 | Image interval in seconds. How long a image is displayed in the frame. | -| Image | TransitionDuration | float | 2 | Duration in seconds. | -| [Weather](#weather) | WeatherApiKey | string | | Get an API key from [OpenWeatherMap][openweathermap-url]. | -| [Weather](#weather) | UnitSystem | imperial \| metric | imperial | Imperial or metric system. (Fahrenheit or degrees) | -| [Weather](#weather) | Language | string | en | 2 digit ISO code, sets the language of the weather description. | -| [Weather](#weather) | ShowWeatherDescription | boolean | true | Displays the description of the current weather. | -| [Weather](#weather) | WeatherLatLong | boolean | 40.730610,-73.935242 | Set the weather location with lat/lon. | -| Clock | ShowClock | boolean | true | Displays the current time. | -| Clock | ClockFormat | string | hh:mm | Time format. | -| [Calendar](#calendar) | Webcalendars | string[] | [] | A list of webcalendar URIs in the .ics format. e.g. https://calendar.google.com/calendar/ical/XXXXXX/public/basic.ics | -| [Metadata](#metadata) | ShowImageDesc | boolean | true | Displays the description of the current image. | -| [Metadata](#metadata) | ShowPeopleDesc | boolean | true | Displays a comma separated list of names of all the people that are assigned in immich. | -| [Metadata](#metadata) | ShowAlbumName | boolean | true | Displays a comma separated list of names of all the albums for an image. | -| [Metadata](#metadata) | ShowImageLocation | boolean | true | Displays the location of the current image. | -| [Metadata](#metadata) | ImageLocationFormat | string | City,State,Country | | -| [Metadata](#metadata) | ShowPhotoDate | boolean | true | Displays the date of the current image. | -| [Metadata](#metadata) | PhotoDateFormat | string | yyyy-MM-dd | Date format. See [here](https://date-fns.org/v4.1.0/docs/format) for more information. | -| UI | PrimaryColor | string | #f5deb3 | Lets you choose a primary color for your UI. Use hex with alpha value to edit opacity. | -| UI | SecondaryColor | string | #000000 | Lets you choose a secondary color for your UI. (Only used with `style=solid or transition`) Use hex with alpha value to edit opacity. | -| UI | Style | none \| solid \| transition \| blur | none | Background-style of the clock and metadata. | -| UI | Layout | single \| splitview | splitview | Allow two portrait images to be displayed next to each other | -| UI | BaseFontSize | string | 17px | Sets the base font size, uses [standard CSS formats](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size). | -| [Misc](#misc) | ImmichFrameAlbumName | string | | \*Client only. Creates album and stores last 100 photos displayed. | -| [Misc](#misc) | Webhook | string | | Webhook URL to be notified e.g. http://example.com/notify | +| **Section** | **Config-Key** | **Value** | **Default** | **Description** | +| ----------------------- | -------------------------- | ----------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Required** | **ImmichServerUrl** | **string** | | **The URL of your Immich server e.g. `http://photos.yourdomain.com` / `http://192.168.0.100:2283`.** | +| **Required** | **ApiKey** | **string** | | **Read more about how to obtain an [Immich API key][immich-api-url].** | +| [Security](#security) | AuthenticationSecret | string | | When set, every client needs to authenticate via Bearer Token and this value. | +| [Filtering](#filtering) | Albums | string[] | [] | UUID of album(s) | +| [Filtering](#filtering) | ExcludedAlbums | string[] | [] | UUID of excluded album(s) | +| [Filtering](#filtering) | People | string[] | [] | UUID of person(s) | +| [Filtering](#filtering) | Rating | int | | Rating of an image in stars, allowed values from -1 to 5. This will only show images with the exact rating you are filtering for. | +| [Filtering](#filtering) | ShowMemories | boolean | false | If this is set, memories are displayed. | +| [Filtering](#filtering) | ShowFavorites | boolean | false | If this is set, favorites are displayed. | +| [Filtering](#filtering) | ShowArchived | boolean | false | If this is set, assets marked archived are displayed. | +| [Filtering](#filtering) | ImagesFromDays | int | | Show images from the last X days. e.g 365 -> show images from the last year | +| [Filtering](#filtering) | ImagesFromDate | Date | | Show images after date. Overwrites the `ImagesFromDays`-Setting | +| [Filtering](#filtering) | ImagesUntilDate | Date | | Show images before date. | +| Caching | RenewImagesDuration | int | 30 | Interval in days. | +| Caching | DownloadImages | boolean | false | \*Client only. | +| Caching | RefreshAlbumPeopleInterval | int | 12 | Interval in hours. Determines how often images are pulled from a person in immich. | +| Image | ImageZoom | boolean | true | Zooms into or out of an image and gives it a touch of life. | +| Image | ImageFill | boolean | false | Whether image should fill available space. Aspect ratio maintained but may be cropped. | +| Image | Interval | int | 45 | Image interval in seconds. How long a image is displayed in the frame. | +| Image | TransitionDuration | float | 2 | Duration in seconds. | +| [Weather](#weather) | WeatherApiKey | string | | Get an API key from [OpenWeatherMap][openweathermap-url]. | +| [Weather](#weather) | UnitSystem | imperial \| metric | imperial | Imperial or metric system. (Fahrenheit or degrees) | +| [Weather](#weather) | Language | string | en | 2 digit ISO code, sets the language of the weather description. | +| [Weather](#weather) | ShowWeatherDescription | boolean | true | Displays the description of the current weather. | +| [Weather](#weather) | WeatherLatLong | boolean | 40.730610,-73.935242 | Set the weather location with lat/lon. | +| Clock | ShowClock | boolean | true | Displays the current time. | +| Clock | ClockFormat | string | hh:mm | Time format. | +| [Calendar](#calendar) | Webcalendars | string[] | [] | A list of webcalendar URIs in the .ics format, can include basic auth. e.g. username:password;https://calendar.google.com/calendar/ical/XXXXXX/public/basic.ics | +| [Metadata](#metadata) | ShowImageDesc | boolean | true | Displays the description of the current image. | +| [Metadata](#metadata) | ShowPeopleDesc | boolean | true | Displays a comma separated list of names of all the people that are assigned in immich. | +| [Metadata](#metadata) | ShowAlbumName | boolean | true | Displays a comma separated list of names of all the albums for an image. | +| [Metadata](#metadata) | ShowImageLocation | boolean | true | Displays the location of the current image. | +| [Metadata](#metadata) | ImageLocationFormat | string | City,State,Country | | +| [Metadata](#metadata) | ShowPhotoDate | boolean | true | Displays the date of the current image. | +| [Metadata](#metadata) | PhotoDateFormat | string | yyyy-MM-dd | Date format. See [here](https://date-fns.org/v4.1.0/docs/format) for more information. | +| UI | PrimaryColor | string | #f5deb3 | Lets you choose a primary color for your UI. Use hex with alpha value to edit opacity. | +| UI | SecondaryColor | string | #000000 | Lets you choose a secondary color for your UI. (Only used with `style=solid or transition`) Use hex with alpha value to edit opacity. | +| UI | Style | none \| solid \| transition \| blur | none | Background-style of the clock and metadata. | +| UI | Layout | single \| splitview | splitview | Allow two portrait images to be displayed next to each other | +| UI | BaseFontSize | string | 17px | Sets the base font size, uses [standard CSS formats](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size). | +| [Misc](#misc) | ImmichFrameAlbumName | string | | \*Client only. Creates album and stores last 100 photos displayed. | +| [Misc](#misc) | Webhook | string | | Webhook URL to be notified e.g. http://example.com/notify | ### Security Basic authentication can be added via this setting. It is **NOT** recommended to expose immichFrame to the public web, if you still choose to do so, you can set this to a secure secret. Every client needs to authenticate itself with this secret. This can be done in the Webclient via input field or via URL-Parameter. The URL-Parameter will look like this: `?authsecret=[MYSECRET]` @@ -65,6 +65,11 @@ Weather is enabled by entering an API key. Get yours free from [OpenWeatherMap][ ### Calendar If you are using Google Calendar, more information can be found [here](https://support.google.com/calendar/answer/37648?hl=en#zippy=%2Cget-your-calendar-view-only). +Calendar supports basic authentication: +Example: +No Auth: `https://calendar.google.com/calendar/ical/XXXXXX/public/basic.ics` +With Auth: `username:password;https://calendar.google.com/calendar/ical/XXXXXX/public/basic.ics` + ### Metadata Needs documentation