refactor(newsletter): ♻️ Media servers + newsletter refactoring (#4463)

* Abstract media servers content into interfaces

* Media server entities into abstract classes

* Abstract media server content repository

* First pass at newsletter refactoring

* Minor code clean up

* Attempt at abstracting repositories (WIP)

* Fixed cast issue

* Corrected the other properties

* A step towards newsletter refactoring

* Clean up leftovers

* Fix broken episodes db interaction

* Save absolute URL for Plex content

Let's be consistent with Emby and Jellyfin

* Fix broken integration with Plex libraries

* Fix error when multiple media servers configured

* Fix newsletter being sent if no movies or episodes

* Fix broken tests

* Remove unneccesary logs

* Expose stored media server URL

No need to recalculate it
+ Plex URL was broken due to an earlier change

* Remove unused variable

* Remove obsolete tests

URLs are now fetched from database directly

* Retro-compatibility for Plex content URL

Solves URL for media synced before absolute URL was saved in PlexServerContent

* chore: added some obsoletes

* fix: removed the unsub link when not present

Co-authored-by: tidusjar <tidusjar@gmail.com>
This commit is contained in:
sephrat 2022-01-31 21:15:31 +01:00 committed by GitHub
commit 0ff0a704ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 595 additions and 1148 deletions

View file

@ -30,26 +30,26 @@ namespace Ombi.Core.Engine
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies(DateTime from, DateTime to)
{
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie && x.AddedAt > from && x.AddedAt < to);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies).Take(30);
}
public IEnumerable<RecentlyAddedMovieModel> GetRecentlyAddedMovies()
{
var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie);
var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie);
var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie);
var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie);
var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie);
return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies);
}
public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(DateTime from, DateTime to, bool groupBySeason)
{
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show && x.AddedAt > from && x.AddedAt < to);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series && x.AddedAt > from && x.AddedAt < to);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series && x.AddedAt > from && x.AddedAt < to);
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason).Take(30);
}
@ -57,9 +57,9 @@ namespace Ombi.Core.Engine
public IEnumerable<RecentlyAddedTvModel> GetRecentlyAddedTv(bool groupBySeason)
{
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series);
var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason);
}
@ -76,7 +76,7 @@ namespace Ombi.Core.Engine
{
continue;
}
if (p.Type == PlexMediaTypeEntity.Movie)
if (p.Type == MediaType.Movie)
{
recentlyAddedLog.Add(new RecentlyAddedLog
{
@ -114,7 +114,7 @@ namespace Ombi.Core.Engine
{
continue;
}
if (e.Type == EmbyMediaType.Movie)
if (e.Type == MediaType.Movie)
{
recentlyAddedLog.Add(new RecentlyAddedLog
{
@ -152,7 +152,7 @@ namespace Ombi.Core.Engine
{
continue;
}
if (e.Type == JellyfinMediaType.Movie)
if (e.Type == MediaType.Movie)
{
recentlyAddedLog.Add(new RecentlyAddedLog
{

View file

@ -32,7 +32,7 @@ namespace Ombi.Core.Rule.Rules.Request
{
var tvRequest = (ChildRequests) obj;
var tvContent = _plexContent.GetAll().Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show);
var tvContent = _plexContent.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series);
// We need to do a check on the TVDBId
var anyMovieDbMatches = await tvContent.FirstOrDefaultAsync(x => x.TheMovieDbId.Length > 0 && x.TheMovieDbId == tvRequest.Id.ToString());
if (anyMovieDbMatches == null)

View file

@ -46,10 +46,10 @@ namespace Ombi.Core.Rule.Rules.Search
}
}
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<PlexEpisode> allEpisodes, EpisodeRequests episode,
SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log)
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<IMediaServerEpisode> allEpisodes, EpisodeRequests episode,
SeasonRequests season, IMediaServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log)
{
PlexEpisode epExists = null;
IMediaServerEpisode epExists = null;
try
{
@ -79,66 +79,6 @@ namespace Ombi.Core.Rule.Rules.Search
log.LogError(e, "Exception thrown when attempting to check if something is available");
}
if (epExists != null)
{
episode.Available = true;
}
}
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<EmbyEpisode> allEpisodes, EpisodeRequests episode,
SeasonRequests season, EmbyContent item, bool useTheMovieDb, bool useTvDb)
{
EmbyEpisode epExists = null;
if (useImdb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.ImdbId == item.ImdbId);
}
if (useTheMovieDb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.TheMovieDbId == item.TheMovieDbId);
}
if (useTvDb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.TvDbId == item.TvDbId);
}
if (epExists != null)
{
episode.Available = true;
}
}
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<JellyfinEpisode> allEpisodes, EpisodeRequests episode,
SeasonRequests season, JellyfinContent item, bool useTheMovieDb, bool useTvDb)
{
JellyfinEpisode epExists = null;
if (useImdb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.ImdbId == item.ImdbId);
}
if (useTheMovieDb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.TheMovieDbId == item.TheMovieDbId);
}
if (useTvDb)
{
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
x.Series.TvDbId == item.TvDbId);
}
if (epExists != null)
{
episode.Available = true;

View file

@ -1,6 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Settings;
@ -13,13 +14,15 @@ namespace Ombi.Core.Rule.Rules.Search
{
public class EmbyAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
{
public EmbyAvailabilityRule(IEmbyContentRepository repo, ISettingsService<EmbySettings> s)
public EmbyAvailabilityRule(IEmbyContentRepository repo, ILogger<EmbyAvailabilityRule> log, ISettingsService<EmbySettings> s)
{
EmbyContentRepository = repo;
Log = log;
EmbySettings = s;
}
private IEmbyContentRepository EmbyContentRepository { get; }
private ILogger Log { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
public async Task<RuleResult> Execute(SearchViewModel obj)
@ -64,19 +67,7 @@ namespace Ombi.Core.Rule.Rules.Search
if (item != null)
{
obj.Available = true;
var s = await EmbySettings.GetSettingsAsync();
if (s.Enable)
{
var server = s.Servers.FirstOrDefault();
if ((server?.ServerHostname ?? string.Empty).HasValue())
{
obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, server?.ServerHostname);
}
else
{
obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, null);
}
}
obj.EmbyUrl = item.Url;
if (obj.Type == RequestType.TvShow)
{
@ -89,7 +80,7 @@ namespace Ombi.Core.Rule.Rules.Search
{
foreach (var episode in season.Episodes)
{
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb);
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
}
}
}

View file

@ -1,6 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Settings;
@ -13,13 +14,15 @@ namespace Ombi.Core.Rule.Rules.Search
{
public class JellyfinAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
{
public JellyfinAvailabilityRule(IJellyfinContentRepository repo, ISettingsService<JellyfinSettings> s)
public JellyfinAvailabilityRule(IJellyfinContentRepository repo, ILogger<JellyfinAvailabilityRule> log, ISettingsService<JellyfinSettings> s)
{
JellyfinContentRepository = repo;
Log = log;
JellyfinSettings = s;
}
private IJellyfinContentRepository JellyfinContentRepository { get; }
private ILogger Log { get; }
private ISettingsService<JellyfinSettings> JellyfinSettings { get; }
public async Task<RuleResult> Execute(SearchViewModel obj)
@ -78,20 +81,7 @@ namespace Ombi.Core.Rule.Rules.Search
useTheMovieDb = true;
}
obj.Available = true;
var s = await JellyfinSettings.GetSettingsAsync();
if (s.Enable)
{
var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null);
if ((server?.ServerHostname ?? string.Empty).HasValue())
{
obj.JellyfinUrl = JellyfinHelper.GetJellyfinMediaUrl(item.JellyfinId, server?.ServerId, server?.ServerHostname);
}
else
{
var firstServer = s.Servers?.FirstOrDefault();
obj.JellyfinUrl = JellyfinHelper.GetJellyfinMediaUrl(item.JellyfinId, firstServer.ServerId, firstServer.FullUri);
}
}
obj.JellyfinUrl = item.Url;
if (obj.Type == RequestType.TvShow)
{
@ -104,7 +94,7 @@ namespace Ombi.Core.Rule.Rules.Search
{
foreach (var episode in season.Episodes)
{
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb);
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
}
}
}

View file

@ -33,7 +33,7 @@ namespace Ombi.Core.Rule.Rules.Search
var useId = false;
var useTvDb = false;
PlexMediaTypeEntity type = ConvertType(obj.Type);
MediaType type = ConvertType(obj.Type);
if (obj.ImdbId.HasValue())
{
@ -90,9 +90,17 @@ namespace Ombi.Core.Rule.Rules.Search
useTheMovieDb = true;
}
obj.Available = true;
obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host);
if (item.Url.StartsWith("http"))
{
obj.PlexUrl = item.Url;
}
else
{
// legacy content
obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host);
}
obj.Quality = item.Quality;
if (obj.Type == RequestType.TvShow)
{
var search = (SearchTvShowViewModel)obj;
@ -115,12 +123,12 @@ namespace Ombi.Core.Rule.Rules.Search
return Success();
}
private PlexMediaTypeEntity ConvertType(RequestType type) =>
private MediaType ConvertType(RequestType type) =>
type switch
{
RequestType.Movie => PlexMediaTypeEntity.Movie,
RequestType.TvShow => PlexMediaTypeEntity.Show,
_ => PlexMediaTypeEntity.Movie,
RequestType.Movie => MediaType.Movie,
RequestType.TvShow => MediaType.Series,
_ => MediaType.Movie,
};
}
}