diff --git a/src/Ombi.Notifications/Agents/DiscordNotification.cs b/src/Ombi.Notifications/Agents/DiscordNotification.cs index 66280ef70..d788b471c 100644 --- a/src/Ombi.Notifications/Agents/DiscordNotification.cs +++ b/src/Ombi.Notifications/Agents/DiscordNotification.cs @@ -20,8 +20,8 @@ namespace Ombi.Notifications.Agents { public DiscordNotification(IDiscordApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, - IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository sub) - : base(sn, r, m, t,s,log, sub) + IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository sub, IMusicRequestRepository music) + : base(sn, r, m, t, s, log, sub, music) { Api = api; Logger = log; @@ -130,12 +130,18 @@ namespace Ombi.Notifications.Agents title = MovieRequest.Title; image = MovieRequest.PosterPath; } - else + else if (model.RequestType == RequestType.TvShow) { user = TvRequest.RequestedUser.UserAlias; title = TvRequest.ParentRequest.Title; image = TvRequest.ParentRequest.PosterPath; } + else if (model.RequestType == RequestType.Album) + { + user = AlbumRequest.RequestedUser.UserAlias; + title = AlbumRequest.Title; + image = AlbumRequest.Cover; + } var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying"; var notification = new NotificationMessage { diff --git a/src/Ombi.Notifications/Agents/EmailNotification.cs b/src/Ombi.Notifications/Agents/EmailNotification.cs index 53046ade0..3ab045e87 100644 --- a/src/Ombi.Notifications/Agents/EmailNotification.cs +++ b/src/Ombi.Notifications/Agents/EmailNotification.cs @@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents public class EmailNotification : BaseNotification, IEmailNotification { public EmailNotification(ISettingsService settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService c, - ILogger log, UserManager um, IRepository sub) : base(settings, r, m, t, c, log, sub) + ILogger log, UserManager um, IRepository sub, IMusicRequestRepository music) : base(settings, r, m, t, c, log, sub, music) { EmailProvider = prov; Logger = log; diff --git a/src/Ombi.Notifications/Agents/MattermostNotification.cs b/src/Ombi.Notifications/Agents/MattermostNotification.cs index 8199d8bfe..9e8a34e3b 100644 --- a/src/Ombi.Notifications/Agents/MattermostNotification.cs +++ b/src/Ombi.Notifications/Agents/MattermostNotification.cs @@ -21,7 +21,7 @@ namespace Ombi.Notifications.Agents public class MattermostNotification : BaseNotification, IMattermostNotification { public MattermostNotification(IMattermostApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s, IRepository sub) : base(sn, r, m, t,s,log, sub) + ISettingsService s, IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/MobileNotification.cs b/src/Ombi.Notifications/Agents/MobileNotification.cs index 8559c043d..c521b99a4 100644 --- a/src/Ombi.Notifications/Agents/MobileNotification.cs +++ b/src/Ombi.Notifications/Agents/MobileNotification.cs @@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents { public MobileNotification(IOneSignalApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository notification, - UserManager um, IRepository sub) : base(sn, r, m, t, s,log, sub) + UserManager um, IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music) { _api = api; _logger = log; diff --git a/src/Ombi.Notifications/Agents/PushbulletNotification.cs b/src/Ombi.Notifications/Agents/PushbulletNotification.cs index 24aa8cd22..0e488bf79 100644 --- a/src/Ombi.Notifications/Agents/PushbulletNotification.cs +++ b/src/Ombi.Notifications/Agents/PushbulletNotification.cs @@ -17,7 +17,7 @@ namespace Ombi.Notifications.Agents public class PushbulletNotification : BaseNotification, IPushbulletNotification { public PushbulletNotification(IPushbulletApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s, IRepository sub) : base(sn, r, m, t,s,log, sub) + ISettingsService s, IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/PushoverNotification.cs b/src/Ombi.Notifications/Agents/PushoverNotification.cs index 5b82eb8a3..95b2a18d3 100644 --- a/src/Ombi.Notifications/Agents/PushoverNotification.cs +++ b/src/Ombi.Notifications/Agents/PushoverNotification.cs @@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents public class PushoverNotification : BaseNotification, IPushoverNotification { public PushoverNotification(IPushoverApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s, IRepository sub) : base(sn, r, m, t, s, log, sub) + ISettingsService s, IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/SlackNotification.cs b/src/Ombi.Notifications/Agents/SlackNotification.cs index 894758591..6c04f5ea6 100644 --- a/src/Ombi.Notifications/Agents/SlackNotification.cs +++ b/src/Ombi.Notifications/Agents/SlackNotification.cs @@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents public class SlackNotification : BaseNotification, ISlackNotification { public SlackNotification(ISlackApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s, IRepository sub) : base(sn, r, m, t, s, log, sub) + ISettingsService s, IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/TelegramNotification.cs b/src/Ombi.Notifications/Agents/TelegramNotification.cs index 827b0b590..7bcda7c7f 100644 --- a/src/Ombi.Notifications/Agents/TelegramNotification.cs +++ b/src/Ombi.Notifications/Agents/TelegramNotification.cs @@ -19,7 +19,7 @@ namespace Ombi.Notifications.Agents public TelegramNotification(ITelegramApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s - , IRepository sub) : base(sn, r, m, t,s,log, sub) + , IRepository sub, IMusicRequestRepository music) : base(sn, r, m, t,s,log, sub, music) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/BaseNotification.cs b/src/Ombi.Notifications/BaseNotification.cs index 507b8059b..287f86455 100644 --- a/src/Ombi.Notifications/BaseNotification.cs +++ b/src/Ombi.Notifications/BaseNotification.cs @@ -19,7 +19,7 @@ namespace Ombi.Notifications.Interfaces public abstract class BaseNotification : INotification where T : Settings.Settings.Models.Settings, new() { protected BaseNotification(ISettingsService settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv, - ISettingsService customization, ILogger> log, IRepository sub) + ISettingsService customization, ILogger> log, IRepository sub, IMusicRequestRepository album) { Settings = settings; TemplateRepository = templateRepo; @@ -30,12 +30,14 @@ namespace Ombi.Notifications.Interfaces CustomizationSettings.ClearCache(); RequestSubscription = sub; _log = log; + AlbumRepository = album; } protected ISettingsService Settings { get; } protected INotificationTemplatesRepository TemplateRepository { get; } protected IMovieRequestRepository MovieRepository { get; } protected ITvRequestRepository TvRepository { get; } + protected IMusicRequestRepository AlbumRepository { get; } protected CustomizationSettings Customization { get; set; } protected IRepository RequestSubscription { get; set; } private ISettingsService CustomizationSettings { get; } @@ -43,6 +45,7 @@ namespace Ombi.Notifications.Interfaces protected ChildRequests TvRequest { get; set; } + protected AlbumRequest AlbumRequest { get; set; } protected MovieRequests MovieRequest { get; set; } protected IQueryable SubsribedUsers { get; private set; } @@ -130,10 +133,14 @@ namespace Ombi.Notifications.Interfaces { MovieRequest = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId); } - else + else if (type == RequestType.TvShow) { TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId); } + else if (type == RequestType.Album) + { + AlbumRequest = await AlbumRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId); + } } private async Task GetConfiguration() @@ -181,11 +188,16 @@ namespace Ombi.Notifications.Interfaces curlys.Setup(model, MovieRequest, Customization); } - else + else if (model.RequestType == RequestType.TvShow) { _log.LogDebug("Notification options: {@model}, Req: {@TvRequest}, Settings: {@Customization}", model, TvRequest, Customization); curlys.Setup(model, TvRequest, Customization); } + else if (model.RequestType == RequestType.Album) + { + _log.LogDebug("Notification options: {@model}, Req: {@AlbumRequest}, Settings: {@Customization}", model, AlbumRequest, Customization); + curlys.Setup(model, AlbumRequest, Customization); + } var parsed = resolver.ParseMessage(template, curlys); return parsed; diff --git a/src/Ombi.Notifications/NotificationMessageCurlys.cs b/src/Ombi.Notifications/NotificationMessageCurlys.cs index 497c49c86..710f64619 100644 --- a/src/Ombi.Notifications/NotificationMessageCurlys.cs +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -47,14 +47,48 @@ namespace Ombi.Notifications if (req?.RequestType == RequestType.Movie) { - PosterImage = string.Format((req?.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase) + PosterImage = string.Format((req?.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase) ? "https://image.tmdb.org/t/p/w300{0}" : "https://image.tmdb.org/t/p/w300/{0}", req?.PosterPath); } else { PosterImage = req?.PosterPath; } - + + AdditionalInformation = opts?.AdditionalInformation ?? string.Empty; + } + + public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s) + { + LoadIssues(opts); + string title; + if (req == null) + { + opts.Substitutes.TryGetValue("Title", out title); + } + else + { + title = req?.Title; + } + ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty; + ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName; + RequestedUser = req?.RequestedUser?.UserName; + if (UserName.IsNullOrEmpty()) + { + // Can be set if it's an issue + UserName = req?.RequestedUser?.UserName; + } + + Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName; + Title = title; + RequestedDate = req?.RequestedDate.ToString("D"); + if (Type.IsNullOrEmpty()) + { + Type = req?.RequestType.Humanize(); + } + Year = req?.ReleaseDate.Year.ToString(); + PosterImage = (req?.Cover.HasValue() ?? false) ? req.Cover : req?.Disk ?? string.Empty; + AdditionalInformation = opts?.AdditionalInformation ?? string.Empty; } diff --git a/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs new file mode 100644 index 000000000..b40eda06b --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Hangfire; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Ombi.Core.Notifications; +using Ombi.Helpers; +using Ombi.Notifications.Models; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Schedule.Jobs.Lidarr +{ + public class LidarrAvailabilityChecker + { + public LidarrAvailabilityChecker(IMusicRequestRepository requests, IRepository albums, ILogger log, + IBackgroundJobClient job, INotificationService notification) + { + _cachedAlbums = albums; + _requestRepository = requests; + _logger = log; + _job = job; + _notificationService = notification; + } + + private readonly IMusicRequestRepository _requestRepository; + private readonly IRepository _cachedAlbums; + private readonly ILogger _logger; + private readonly IBackgroundJobClient _job; + private readonly INotificationService _notificationService; + + public async Task Start() + { + var allAlbumRequests = _requestRepository.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available); + var albumsToUpdate = new List(); + foreach (var request in allAlbumRequests) + { + // Check if we have it cached + var cachedAlbum = await _cachedAlbums.FirstOrDefaultAsync(x => x.ForeignAlbumId.Equals(request.ForeignAlbumId)); + if (cachedAlbum != null) + { + if (cachedAlbum.Monitored && cachedAlbum.FullyAvailable) + { + request.Available = true; + request.MarkedAsAvailable = DateTime.Now; + albumsToUpdate.Add(request); + } + } + } + + foreach (var albumRequest in albumsToUpdate) + { + await _requestRepository.Update(albumRequest); + var recipient = albumRequest.RequestedUser.Email.HasValue() ? albumRequest.RequestedUser.Email : string.Empty; + + _logger.LogDebug("AlbumId: {0}, RequestUser: {1}", albumRequest.Id, recipient); + + _job.Enqueue(() => _notificationService.Publish(new NotificationOptions + { + DateTime = DateTime.Now, + NotificationType = NotificationType.RequestAvailable, + RequestId = albumRequest.Id, + RequestType = RequestType.Album, + Recipient = recipient, + })); + } + } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/LidarrAlbumCache.cs b/src/Ombi.Store/Entities/LidarrAlbumCache.cs index 15d0a53da..d9ceab8a3 100644 --- a/src/Ombi.Store/Entities/LidarrAlbumCache.cs +++ b/src/Ombi.Store/Entities/LidarrAlbumCache.cs @@ -13,5 +13,10 @@ namespace Ombi.Store.Entities public bool Monitored { get; set; } public string Title { get; set; } public decimal PercentOfTracks { get; set; } + + [NotMapped] + public bool PartiallyAvailable => PercentOfTracks != 100 && PercentOfTracks > 0; + [NotMapped] + public bool FullyAvailable => PercentOfTracks == 100; } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/search/music/artistsearch.component.html b/src/Ombi/ClientApp/app/search/music/artistsearch.component.html index 5ea5433f1..77a68a841 100644 --- a/src/Ombi/ClientApp/app/search/music/artistsearch.component.html +++ b/src/Ombi/ClientApp/app/search/music/artistsearch.component.html @@ -51,7 +51,7 @@ --> - diff --git a/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts b/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts index 76a223d09..852e294e3 100644 --- a/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts +++ b/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts @@ -11,6 +11,7 @@ export class ArtistSearchComponent { @Input() public result: ISearchArtistResult; @Input() public defaultPoster: string; + public searchingAlbums: boolean; @Output() public viewAlbumsResult = new EventEmitter(); @@ -18,6 +19,7 @@ export class ArtistSearchComponent { } public viewAllAlbums() { + this.searchingAlbums = true; this.searchService.getAlbumsForArtist(this.result.forignArtistId).subscribe(x => { this.viewAlbumsResult.emit(x); });