diff --git a/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs b/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs
index 51e920b15..09b7d9858 100644
--- a/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs
+++ b/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs
@@ -1,4 +1,5 @@
using System.Text;
+using Ombi.Helpers;
namespace Ombi.Schedule.Jobs.Ombi
{
@@ -22,13 +23,20 @@ namespace Ombi.Schedule.Jobs.Ombi
protected virtual void AddMediaServerUrl(StringBuilder sb, string mediaurl, string url)
{
- sb.Append("
");
- sb.Append("");
- sb.AppendFormat("", mediaurl);
- sb.AppendFormat("", url);
- sb.Append("");
- sb.Append(" | ");
- sb.Append("
");
+ if (url.HasValue())
+ {
+ sb.Append("");
+ sb.Append(
+ "");
+ sb.AppendFormat("", mediaurl);
+ sb.AppendFormat(
+ "",
+ url);
+ sb.Append("");
+ sb.Append(" | ");
+ sb.Append("
");
+ }
+
sb.Append("");
sb.Append("");
}
@@ -44,9 +52,9 @@ namespace Ombi.Schedule.Jobs.Ombi
{
sb.Append("");
sb.Append("");
- sb.AppendFormat("", url);
+ if(url.HasValue()) sb.AppendFormat("", url);
sb.AppendFormat("{0}", title);
- sb.Append("");
+ if (url.HasValue()) sb.Append("");
sb.Append(" | ");
sb.Append("
");
}
diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs
index 6e89d167e..f152f6b4b 100644
--- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs
+++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs
@@ -9,6 +9,8 @@ using MailKit;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
+using Ombi.Api.Lidarr;
+using Ombi.Api.Lidarr.Models;
using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Api.TvMaze;
@@ -18,6 +20,7 @@ using Ombi.Notifications;
using Ombi.Notifications.Models;
using Ombi.Notifications.Templates;
using Ombi.Settings.Settings.Models;
+using Ombi.Settings.Settings.Models.External;
using Ombi.Settings.Settings.Models.Notifications;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
@@ -29,7 +32,8 @@ namespace Ombi.Schedule.Jobs.Ombi
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository addedLog,
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService custom,
ISettingsService emailSettings, INotificationTemplatesRepository templateRepo,
- UserManager um, ISettingsService newsletter, ILogger log)
+ UserManager um, ISettingsService newsletter, ILogger log,
+ ILidarrApi lidarrApi, IRepository albumCache, ISettingsService lidarrSettings)
{
_plex = plex;
_emby = emby;
@@ -46,6 +50,10 @@ namespace Ombi.Schedule.Jobs.Ombi
_customizationSettings.ClearCache();
_newsletterSettings.ClearCache();
_log = log;
+ _lidarrApi = lidarrApi;
+ _lidarrAlbumRepository = albumCache;
+ _lidarrSettings = lidarrSettings;
+ _lidarrSettings.ClearCache();
}
private readonly IPlexContentRepository _plex;
@@ -60,6 +68,9 @@ namespace Ombi.Schedule.Jobs.Ombi
private readonly ISettingsService _newsletterSettings;
private readonly UserManager _userManager;
private readonly ILogger _log;
+ private readonly ILidarrApi _lidarrApi;
+ private readonly IRepository _lidarrAlbumRepository;
+ private readonly ISettingsService _lidarrSettings;
public async Task Start(NewsletterSettings settings, bool test)
{
@@ -87,21 +98,26 @@ namespace Ombi.Schedule.Jobs.Ombi
// Get the Content
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
+ var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking();
var addedLog = _recentlyAddedLog.GetAll();
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
+ var addedAlbumLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album).Select(x => x.AlbumId);
var addedPlexEpisodesLogIds =
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
var addedEmbyEpisodesLogIds =
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
+
// Filter out the ones that we haven't sent yet
var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && x.HasTheMovieDb && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && x.HasTheMovieDb && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
+ var lidarrContentAlbumsToSend = lidarrContent.Where(x => !addedAlbumLogIds.Contains(x.ForeignAlbumId)).ToHashSet();
_log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
+ _log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count());
var plexEpisodesToSend =
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds);
@@ -117,11 +133,12 @@ namespace Ombi.Schedule.Jobs.Ombi
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie ).OrderByDescending(x => x.AddedAt).Take(10);
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
- body = await BuildHtml(plexm, embym, plext, embyt, settings);
+ var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
+ body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings);
}
else
{
- body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
+ body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings);
if (body.IsNullOrEmpty())
{
return;
@@ -298,7 +315,8 @@ namespace Ombi.Schedule.Jobs.Ombi
return resolver.ParseMessage(template, curlys);
}
- private async Task BuildHtml(IQueryable plexContentToSend, IQueryable embyContentToSend, HashSet plexEpisodes, HashSet embyEp, NewsletterSettings settings)
+ private async Task BuildHtml(IQueryable plexContentToSend, IQueryable embyContentToSend,
+ HashSet plexEpisodes, HashSet embyEp, HashSet albums, NewsletterSettings settings)
{
var sb = new StringBuilder();
@@ -340,6 +358,24 @@ namespace Ombi.Schedule.Jobs.Ombi
sb.Append("");
}
+
+ if (albums.Any() && !settings.DisableMusic)
+ {
+ sb.Append("New Albums
");
+ sb.Append(
+ "");
+ sb.Append("");
+ sb.Append("");
+ sb.Append("");
+ sb.Append("");
+ await ProcessAlbums(albums, sb);
+ sb.Append(" ");
+ sb.Append(" ");
+ sb.Append(" | ");
+ sb.Append("
");
+ sb.Append("
");
+ }
+
return sb.ToString();
}
@@ -382,6 +418,40 @@ namespace Ombi.Schedule.Jobs.Ombi
}
}
}
+ private async Task ProcessAlbums(HashSet albumsToSend, StringBuilder sb)
+ {
+ var settings = await _lidarrSettings.GetSettingsAsync();
+ int count = 0;
+ var ordered = albumsToSend.OrderByDescending(x => x.AddedAt);
+ foreach (var content in ordered)
+ {
+ var info = await _lidarrApi.GetAlbumByForeignId(content.ForeignAlbumId, settings.ApiKey, settings.FullUri);
+ if (info == null)
+ {
+ continue;
+ }
+ try
+ {
+ CreateAlbumHtmlContent(sb, info);
+ count += 1;
+ }
+ catch (Exception e)
+ {
+ _log.LogError(e, "Error when Processing Lidarr Album {0}", info.title);
+ }
+ finally
+ {
+ EndLoopHtml(sb);
+ }
+
+ if (count == 2)
+ {
+ count = 0;
+ sb.Append("");
+ sb.Append("");
+ }
+ }
+ }
private async Task ProcessEmbyMovies(IQueryable embyContent, StringBuilder sb)
{
@@ -467,6 +537,41 @@ namespace Ombi.Schedule.Jobs.Ombi
}
}
+ private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info)
+ {
+ var cover = info.images
+ .FirstOrDefault(x => x.coverType.Equals("cover", StringComparison.InvariantCultureIgnoreCase))?.url;
+ if (cover.IsNullOrEmpty())
+ {
+ cover = info.remoteCover;
+ }
+ AddBackgroundInsideTable(sb, cover);
+ var disk = info.images
+ .FirstOrDefault(x => x.coverType.Equals("disc", StringComparison.InvariantCultureIgnoreCase))?.url;
+ if (disk.IsNullOrEmpty())
+ {
+ disk = info.remoteCover;
+ }
+ AddPosterInsideTable(sb, disk);
+
+ AddMediaServerUrl(sb, string.Empty, string.Empty);
+ AddInfoTable(sb);
+
+ var releaseDate = $"({info.releaseDate.Year})";
+
+ AddTitle(sb, string.Empty, $"{info.title} {releaseDate}");
+
+ var summary = info.artist?.artistName ?? string.Empty;
+ if (summary.Length > 280)
+ {
+ summary = summary.Remove(280);
+ summary = summary + "...";
+ }
+ AddParagraph(sb, summary);
+
+ AddGenres(sb, $"Type: {info.albumType}");
+ }
+
private async Task ProcessPlexTv(HashSet plexContent, StringBuilder sb)
{
var series = new List();
diff --git a/src/Ombi.Settings/Settings/Models/Notifications/NewsletterSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/NewsletterSettings.cs
index e79f3182c..3f6416af5 100644
--- a/src/Ombi.Settings/Settings/Models/Notifications/NewsletterSettings.cs
+++ b/src/Ombi.Settings/Settings/Models/Notifications/NewsletterSettings.cs
@@ -6,6 +6,7 @@ namespace Ombi.Settings.Settings.Models.Notifications
{
public bool DisableTv { get; set; }
public bool DisableMovies { get; set; }
+ public bool DisableMusic { get; set; }
public bool Enabled { get; set; }
public List ExternalEmails { get; set; } = new List();
}
diff --git a/src/Ombi.Store/Entities/LidarrAlbumCache.cs b/src/Ombi.Store/Entities/LidarrAlbumCache.cs
index d9ceab8a3..03099face 100644
--- a/src/Ombi.Store/Entities/LidarrAlbumCache.cs
+++ b/src/Ombi.Store/Entities/LidarrAlbumCache.cs
@@ -13,6 +13,7 @@ namespace Ombi.Store.Entities
public bool Monitored { get; set; }
public string Title { get; set; }
public decimal PercentOfTracks { get; set; }
+ public DateTime AddedAt { get; set; }
[NotMapped]
public bool PartiallyAvailable => PercentOfTracks != 100 && PercentOfTracks > 0;
diff --git a/src/Ombi.Store/Entities/RecentlyAddedLog.cs b/src/Ombi.Store/Entities/RecentlyAddedLog.cs
index 1ef091149..782d89e3f 100644
--- a/src/Ombi.Store/Entities/RecentlyAddedLog.cs
+++ b/src/Ombi.Store/Entities/RecentlyAddedLog.cs
@@ -11,18 +11,21 @@ namespace Ombi.Store.Entities
public int ContentId { get; set; } // This is dependant on the type, it's either TMDBID or TVDBID
public int? EpisodeNumber { get; set; }
public int? SeasonNumber { get; set; }
+ public string AlbumId { get; set; }
public DateTime AddedAt { get; set; }
}
public enum RecentlyAddedType
{
Plex = 0,
- Emby = 1
+ Emby = 1,
+ Lidarr = 2
}
public enum ContentType
{
Parent = 0,
- Episode = 1
+ Episode = 1,
+ Album = 2,
}
}
\ No newline at end of file
diff --git a/src/Ombi/ClientApp/app/requests/music/musicrequests.component.html b/src/Ombi/ClientApp/app/requests/music/musicrequests.component.html
index 43819ad76..c89c2be0a 100644
--- a/src/Ombi/ClientApp/app/requests/music/musicrequests.component.html
+++ b/src/Ombi/ClientApp/app/requests/music/musicrequests.component.html
@@ -189,7 +189,7 @@
-
+
diff --git a/src/Ombi/ClientApp/app/search/music/albumsearch.component.html b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html
index b23a73221..1581c9a35 100644
--- a/src/Ombi/ClientApp/app/search/music/albumsearch.component.html
+++ b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html
@@ -68,13 +68,13 @@
+ -->
@@ -93,11 +93,9 @@
| translate }}
-
-
-
+
-
\ No newline at end of file
+
+
+
+
+
diff --git a/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts b/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts
index 0f9a373e2..9dac4aa8b 100644
--- a/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts
+++ b/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
import { AuthService } from "../../auth/auth.service";
-import { IRequestEngineResult } from "../../interfaces";
+import { IIssueCategory, IRequestEngineResult } from "../../interfaces";
import { ISearchAlbumResult } from "../../interfaces/ISearchMusicResult";
import { NotificationService, RequestService } from "../../services";
@@ -14,7 +14,15 @@ export class AlbumSearchComponent {
@Input() public result: ISearchAlbumResult;
public engineResult: IRequestEngineResult;
- @Input() public defaultPoster: string;
+ @Input() public defaultPoster: string;
+
+ @Input() public issueCategories: IIssueCategory[];
+ @Input() public issuesEnabled: boolean;
+ public issuesBarVisible = false;
+ public issueRequestTitle: string;
+ public issueRequestId: number;
+ public issueProviderId: string;
+ public issueCategorySelected: IIssueCategory;
@Output() public setSearch = new EventEmitter();
@@ -29,6 +37,14 @@ export class AlbumSearchComponent {
this.setSearch.emit(artistId);
}
+ public reportIssue(catId: IIssueCategory, req: ISearchAlbumResult) {
+ this.issueRequestId = req.id;
+ this.issueRequestTitle = req.title + `(${req.releaseDate.getFullYear})`;
+ this.issueCategorySelected = catId;
+ this.issuesBarVisible = true;
+ this.issueProviderId = req.id.toString();
+ }
+
public request(searchResult: ISearchAlbumResult) {
searchResult.requested = true;
searchResult.requestProcessing = true;