From fc61687e82e7d54e9b1d9dde78dd8d551a86deb1 Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Tue, 13 Apr 2021 10:01:15 +0100 Subject: [PATCH] New: Calendar iCal feed includes Digital Release events --- .../Calendar/iCal/CalendarLinkModalContent.js | 2 +- .../Calendar/CalendarFeedModule.cs | 140 ------------------ .../Calendar/LegacyCalendarFeedModule.cs | 38 +++++ .../Calendar/CalendarFeedModule.cs | 30 +++- 4 files changed, 62 insertions(+), 148 deletions(-) delete mode 100644 src/NzbDrone.Api/Calendar/CalendarFeedModule.cs create mode 100644 src/NzbDrone.Api/Calendar/LegacyCalendarFeedModule.cs diff --git a/frontend/src/Calendar/iCal/CalendarLinkModalContent.js b/frontend/src/Calendar/iCal/CalendarLinkModalContent.js index ef6a3dc96..68c2c7195 100644 --- a/frontend/src/Calendar/iCal/CalendarLinkModalContent.js +++ b/frontend/src/Calendar/iCal/CalendarLinkModalContent.js @@ -22,7 +22,7 @@ function getUrls(state) { tags } = state; - let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/calendar/Radarr.ics?`; + let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/v3/calendar/Radarr.ics?`; if (unmonitored) { icalUrl += 'unmonitored=true&'; diff --git a/src/NzbDrone.Api/Calendar/CalendarFeedModule.cs b/src/NzbDrone.Api/Calendar/CalendarFeedModule.cs deleted file mode 100644 index 5803dbfd6..000000000 --- a/src/NzbDrone.Api/Calendar/CalendarFeedModule.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ical.Net; -using Ical.Net.CalendarComponents; -using Ical.Net.DataTypes; -using Ical.Net.Serialization; -using Nancy; -using Nancy.Responses; -using NzbDrone.Common.Extensions; -using NzbDrone.Core.Movies; -using NzbDrone.Core.Tags; - -namespace NzbDrone.Api.Calendar -{ - public class CalendarFeedModule : NzbDroneFeedModule - { - private readonly IMovieService _movieService; - private readonly ITagService _tagService; - - public CalendarFeedModule(IMovieService movieService, ITagService tagService) - : base("calendar") - { - _movieService = movieService; - _tagService = tagService; - - Get("/NzbDrone.ics", options => GetCalendarFeed()); - Get("/Sonarr.ics", options => GetCalendarFeed()); - Get("/Radarr.ics", options => GetCalendarFeed()); - } - - private object GetCalendarFeed() - { - var pastDays = 7; - var futureDays = 28; - var start = DateTime.Today.AddDays(-pastDays); - var end = DateTime.Today.AddDays(futureDays); - var unmonitored = false; - - //var premiersOnly = false; - var tags = new List(); - - // TODO: Remove start/end parameters in v3, they don't work well for iCal - var queryStart = Request.Query.Start; - var queryEnd = Request.Query.End; - var queryPastDays = Request.Query.PastDays; - var queryFutureDays = Request.Query.FutureDays; - var queryUnmonitored = Request.Query.Unmonitored; - - // var queryPremiersOnly = Request.Query.PremiersOnly; - var queryTags = Request.Query.Tags; - - if (queryStart.HasValue) - { - start = DateTime.Parse(queryStart.Value); - } - - if (queryEnd.HasValue) - { - end = DateTime.Parse(queryEnd.Value); - } - - if (queryPastDays.HasValue) - { - pastDays = int.Parse(queryPastDays.Value); - start = DateTime.Today.AddDays(-pastDays); - } - - if (queryFutureDays.HasValue) - { - futureDays = int.Parse(queryFutureDays.Value); - end = DateTime.Today.AddDays(futureDays); - } - - if (queryUnmonitored.HasValue) - { - unmonitored = bool.Parse(queryUnmonitored.Value); - } - - //if (queryPremiersOnly.HasValue) - //{ - // premiersOnly = bool.Parse(queryPremiersOnly.Value); - //} - if (queryTags.HasValue) - { - var tagInput = (string)queryTags.Value.ToString(); - tags.AddRange(tagInput.Split(',').Select(_tagService.GetTag).Select(t => t.Id)); - } - - var movies = _movieService.GetMoviesBetweenDates(start, end, unmonitored); - var calendar = new Ical.Net.Calendar - { - ProductId = "-//radarr.video//Radarr//EN" - }; - - var calendarName = "Radarr Movies Calendar"; - calendar.AddProperty(new CalendarProperty("NAME", calendarName)); - calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName)); - - foreach (var movie in movies.OrderBy(v => v.Added)) - { - if (tags.Any() && tags.None(movie.Tags.Contains)) - { - continue; - } - - CreateEvent(calendar, movie, true); - CreateEvent(calendar, movie, false); - } - - var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext()); - var icalendar = serializer.SerializeToString(calendar); - - return new TextResponse(icalendar, "text/calendar"); - } - - private void CreateEvent(Ical.Net.Calendar calendar, Movie movie, bool cinemasRelease) - { - var date = cinemasRelease ? movie.InCinemas : movie.PhysicalRelease; - if (!date.HasValue) - { - return; - } - - var occurrence = calendar.Create(); - occurrence.Uid = "NzbDrone_movie_" + movie.Id + (cinemasRelease ? "_cinemas" : "_physical"); - occurrence.Status = movie.Status == MovieStatusType.Announced ? EventStatus.Tentative : EventStatus.Confirmed; - - occurrence.Start = new CalDateTime(date.Value); - occurrence.End = occurrence.Start; - occurrence.IsAllDay = true; - - occurrence.Description = movie.Overview; - occurrence.Categories = new List() { movie.Studio }; - - var physicalText = "(Physical Release)"; - occurrence.Summary = $"{movie.Title} " + (cinemasRelease ? "(Theatrical Release)" : physicalText); - } - } -} diff --git a/src/NzbDrone.Api/Calendar/LegacyCalendarFeedModule.cs b/src/NzbDrone.Api/Calendar/LegacyCalendarFeedModule.cs new file mode 100644 index 000000000..91515f906 --- /dev/null +++ b/src/NzbDrone.Api/Calendar/LegacyCalendarFeedModule.cs @@ -0,0 +1,38 @@ +using System.Text; +using Nancy; +using Nancy.Responses; + +namespace NzbDrone.Api.Calendar +{ + public class LegacyCalendarFeedModule : NzbDroneFeedModule + { + public LegacyCalendarFeedModule() + : base("calendar") + { + Get("/NzbDrone.ics", options => GetCalendarFeed()); + Get("/Sonarr.ics", options => GetCalendarFeed()); + Get("/Radarr.ics", options => GetCalendarFeed()); + } + + private object GetCalendarFeed() + { + string queryString = ConvertQueryParams(Request.Query); + var url = string.Format("/feed/v3/calendar/Radarr.ics?{0}", queryString); + return Response.AsRedirect(url, RedirectResponse.RedirectType.Permanent); + } + + private string ConvertQueryParams(DynamicDictionary query) + { + var sb = new StringBuilder(); + + foreach (var key in query) + { + var value = query[key]; + + sb.AppendFormat("&{0}={1}", key, value); + } + + return sb.ToString().Trim('&'); + } + } +} diff --git a/src/Radarr.Api.V3/Calendar/CalendarFeedModule.cs b/src/Radarr.Api.V3/Calendar/CalendarFeedModule.cs index d46cd9957..64a6d6693 100644 --- a/src/Radarr.Api.V3/Calendar/CalendarFeedModule.cs +++ b/src/Radarr.Api.V3/Calendar/CalendarFeedModule.cs @@ -94,8 +94,9 @@ namespace Radarr.Api.V3.Calendar continue; } - CreateEvent(calendar, movie, true); - CreateEvent(calendar, movie, false); + CreateEvent(calendar, movie, "cinematic"); + CreateEvent(calendar, movie, "digital"); + CreateEvent(calendar, movie, "physical"); } var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext()); @@ -104,16 +105,32 @@ namespace Radarr.Api.V3.Calendar return new TextResponse(icalendar, "text/calendar"); } - private void CreateEvent(Ical.Net.Calendar calendar, Movie movie, bool cinemasRelease) + private void CreateEvent(Ical.Net.Calendar calendar, Movie movie, string releaseType) { - var date = cinemasRelease ? movie.InCinemas : movie.PhysicalRelease; + var date = movie.InCinemas; + string eventType = "_cinemas"; + string summaryText = "(Theatrical Release)"; + + if (releaseType == "digital") + { + date = movie.DigitalRelease; + eventType = "_digital"; + summaryText = "(Digital Release)"; + } + else if (releaseType == "physical") + { + date = movie.PhysicalRelease; + eventType = "_physical"; + summaryText = "(Physical Release)"; + } + if (!date.HasValue) { return; } var occurrence = calendar.Create(); - occurrence.Uid = "Radarr_movie_" + movie.Id + (cinemasRelease ? "_cinemas" : "_physical"); + occurrence.Uid = "Radarr_movie_" + movie.Id + eventType; occurrence.Status = movie.Status == MovieStatusType.Announced ? EventStatus.Tentative : EventStatus.Confirmed; occurrence.Start = new CalDateTime(date.Value); @@ -123,8 +140,7 @@ namespace Radarr.Api.V3.Calendar occurrence.Description = movie.Overview; occurrence.Categories = new List() { movie.Studio }; - var physicalText = "(Physical Release)"; - occurrence.Summary = $"{movie.Title} " + (cinemasRelease ? "(Theatrical Release)" : physicalText); + occurrence.Summary = $"{movie.Title} " + summaryText; } } }