|
|
@ -9,6 +9,8 @@ using MailKit;
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
|
|
using Ombi.Api.Lidarr;
|
|
|
|
|
|
|
|
using Ombi.Api.Lidarr.Models;
|
|
|
|
using Ombi.Api.TheMovieDb;
|
|
|
|
using Ombi.Api.TheMovieDb;
|
|
|
|
using Ombi.Api.TheMovieDb.Models;
|
|
|
|
using Ombi.Api.TheMovieDb.Models;
|
|
|
|
using Ombi.Api.TvMaze;
|
|
|
|
using Ombi.Api.TvMaze;
|
|
|
@ -18,6 +20,7 @@ using Ombi.Notifications;
|
|
|
|
using Ombi.Notifications.Models;
|
|
|
|
using Ombi.Notifications.Models;
|
|
|
|
using Ombi.Notifications.Templates;
|
|
|
|
using Ombi.Notifications.Templates;
|
|
|
|
using Ombi.Settings.Settings.Models;
|
|
|
|
using Ombi.Settings.Settings.Models;
|
|
|
|
|
|
|
|
using Ombi.Settings.Settings.Models.External;
|
|
|
|
using Ombi.Settings.Settings.Models.Notifications;
|
|
|
|
using Ombi.Settings.Settings.Models.Notifications;
|
|
|
|
using Ombi.Store.Entities;
|
|
|
|
using Ombi.Store.Entities;
|
|
|
|
using Ombi.Store.Repository;
|
|
|
|
using Ombi.Store.Repository;
|
|
|
@ -29,7 +32,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> addedLog,
|
|
|
|
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> addedLog,
|
|
|
|
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService<CustomizationSettings> custom,
|
|
|
|
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService<CustomizationSettings> custom,
|
|
|
|
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
|
|
|
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
|
|
|
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log)
|
|
|
|
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log,
|
|
|
|
|
|
|
|
ILidarrApi lidarrApi, IRepository<LidarrAlbumCache> albumCache, ISettingsService<LidarrSettings> lidarrSettings)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_plex = plex;
|
|
|
|
_plex = plex;
|
|
|
|
_emby = emby;
|
|
|
|
_emby = emby;
|
|
|
@ -46,6 +50,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
_customizationSettings.ClearCache();
|
|
|
|
_customizationSettings.ClearCache();
|
|
|
|
_newsletterSettings.ClearCache();
|
|
|
|
_newsletterSettings.ClearCache();
|
|
|
|
_log = log;
|
|
|
|
_log = log;
|
|
|
|
|
|
|
|
_lidarrApi = lidarrApi;
|
|
|
|
|
|
|
|
_lidarrAlbumRepository = albumCache;
|
|
|
|
|
|
|
|
_lidarrSettings = lidarrSettings;
|
|
|
|
|
|
|
|
_lidarrSettings.ClearCache();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private readonly IPlexContentRepository _plex;
|
|
|
|
private readonly IPlexContentRepository _plex;
|
|
|
@ -60,6 +68,9 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
private readonly ISettingsService<NewsletterSettings> _newsletterSettings;
|
|
|
|
private readonly ISettingsService<NewsletterSettings> _newsletterSettings;
|
|
|
|
private readonly UserManager<OmbiUser> _userManager;
|
|
|
|
private readonly UserManager<OmbiUser> _userManager;
|
|
|
|
private readonly ILogger _log;
|
|
|
|
private readonly ILogger _log;
|
|
|
|
|
|
|
|
private readonly ILidarrApi _lidarrApi;
|
|
|
|
|
|
|
|
private readonly IRepository<LidarrAlbumCache> _lidarrAlbumRepository;
|
|
|
|
|
|
|
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
|
|
|
|
|
|
|
|
|
|
|
public async Task Start(NewsletterSettings settings, bool test)
|
|
|
|
public async Task Start(NewsletterSettings settings, bool test)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -87,21 +98,26 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
// Get the Content
|
|
|
|
// Get the Content
|
|
|
|
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
|
|
|
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
|
|
|
var embyContent = _emby.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 addedLog = _recentlyAddedLog.GetAll();
|
|
|
|
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
|
|
|
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 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 =
|
|
|
|
var addedPlexEpisodesLogIds =
|
|
|
|
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
|
|
|
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
|
|
|
var addedEmbyEpisodesLogIds =
|
|
|
|
var addedEmbyEpisodesLogIds =
|
|
|
|
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
|
|
|
|
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Filter out the ones that we haven't sent yet
|
|
|
|
// 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 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 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("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
|
|
|
|
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
|
|
|
|
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
|
|
|
|
|
|
|
|
_log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count());
|
|
|
|
|
|
|
|
|
|
|
|
var plexEpisodesToSend =
|
|
|
|
var plexEpisodesToSend =
|
|
|
|
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds);
|
|
|
|
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 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 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();
|
|
|
|
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
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
|
|
|
|
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings);
|
|
|
|
if (body.IsNullOrEmpty())
|
|
|
|
if (body.IsNullOrEmpty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
return;
|
|
|
@ -298,7 +315,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
return resolver.ParseMessage(template, curlys);
|
|
|
|
return resolver.ParseMessage(template, curlys);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, NewsletterSettings settings)
|
|
|
|
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend,
|
|
|
|
|
|
|
|
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
|
@ -340,6 +358,24 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
sb.Append("</table>");
|
|
|
|
sb.Append("</table>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (albums.Any() && !settings.DisableMusic)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
sb.Append("<h1 style=\"text-align: center; max-width: 1042px;\">New Albums</h1><br /><br />");
|
|
|
|
|
|
|
|
sb.Append(
|
|
|
|
|
|
|
|
"<table class=\"movies-table\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
|
|
|
|
|
|
|
sb.Append("<tr>");
|
|
|
|
|
|
|
|
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
|
|
|
|
|
|
|
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
|
|
|
|
|
|
|
sb.Append("<tr>");
|
|
|
|
|
|
|
|
await ProcessAlbums(albums, sb);
|
|
|
|
|
|
|
|
sb.Append("</tr>");
|
|
|
|
|
|
|
|
sb.Append("</table>");
|
|
|
|
|
|
|
|
sb.Append("</td>");
|
|
|
|
|
|
|
|
sb.Append("</tr>");
|
|
|
|
|
|
|
|
sb.Append("</table>");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
return sb.ToString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -382,6 +418,40 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private async Task ProcessAlbums(HashSet<LidarrAlbumCache> 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("</tr>");
|
|
|
|
|
|
|
|
sb.Append("<tr>");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task ProcessEmbyMovies(IQueryable<EmbyContent> embyContent, StringBuilder sb)
|
|
|
|
private async Task ProcessEmbyMovies(IQueryable<EmbyContent> 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 + "...</p>";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
AddParagraph(sb, summary);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AddGenres(sb, $"Type: {info.albumType}");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb)
|
|
|
|
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var series = new List<PlexServerContent>();
|
|
|
|
var series = new List<PlexServerContent>();
|
|
|
|