mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-12-10 00:47:15 -06:00
feat(availability): ✨ Add the option for the *arr to take media availability priority
feat(availability): ✨ Add the option for the *arr to take media availability priority
This commit is contained in:
commit
c6b7512245
@ -4,11 +4,14 @@ using Moq;
|
||||
using Moq.AutoMock;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Schedule.Jobs;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Ombi.Tests;
|
||||
using System.Collections.Generic;
|
||||
@ -177,15 +180,190 @@ namespace Ombi.Schedule.Tests
|
||||
_mocker.Verify<INotificationHelper>(x => x.Notify(It.Is<NotificationOptions>(x => x.NotificationType == Helpers.NotificationType.PartiallyAvailable && x.RequestId == 1)), Times.Once);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_WhenRadarrDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = false, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, false);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_WhenScanForAvailabilityDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = false, PrioritizeArrAvailability = true });
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, false);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_WhenPrioritizeArrAvailabilityDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = false });
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, false);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_WhenNotInCache_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache>().AsQueryable().BuildMock());
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, false);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_WhenInCacheWithFile_ReturnsTrue()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache> { new RadarrCache { TheMovieDbId = 123, HasFile = true, HasRegular = true } }.AsQueryable().BuildMock());
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, false);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToRadarr_4K_WhenInCacheWith4K_ReturnsTrue()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache> { new RadarrCache { TheMovieDbId = 123, HasFile = true, Has4K = true } }.AsQueryable().BuildMock());
|
||||
|
||||
var result = await subject.TestShouldDeferToRadarr(123, true);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToSonarr_WhenSonarrDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = false, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
|
||||
var result = await subject.TestShouldDeferToSonarr(456);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToSonarr_WhenScanForAvailabilityDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = true, ScanForAvailability = false, PrioritizeArrAvailability = true });
|
||||
|
||||
var result = await subject.TestShouldDeferToSonarr(456);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToSonarr_WhenPrioritizeArrAvailabilityDisabled_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = false });
|
||||
|
||||
var result = await subject.TestShouldDeferToSonarr(456);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToSonarr_WhenNoEpisodesInCache_ReturnsFalse()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<SonarrEpisodeCache>, IQueryable<SonarrEpisodeCache>>(x => x.GetAll())
|
||||
.Returns(new List<SonarrEpisodeCache>().AsQueryable().BuildMock());
|
||||
|
||||
var result = await subject.TestShouldDeferToSonarr(456);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldDeferToSonarr_WhenEpisodesInCacheWithFile_ReturnsTrue()
|
||||
{
|
||||
var subject = CreateSubjectWithArrDependencies();
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<SonarrEpisodeCache>, IQueryable<SonarrEpisodeCache>>(x => x.GetAll())
|
||||
.Returns(new List<SonarrEpisodeCache> { new SonarrEpisodeCache { TvDbId = 456, HasFile = true } }.AsQueryable().BuildMock());
|
||||
|
||||
var result = await subject.TestShouldDeferToSonarr(456);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
private TestAvailabilityCheckerWithArrSupport CreateSubjectWithArrDependencies()
|
||||
{
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings());
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings());
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache>().AsQueryable().BuildMock());
|
||||
_mocker.Setup<IExternalRepository<SonarrEpisodeCache>, IQueryable<SonarrEpisodeCache>>(x => x.GetAll())
|
||||
.Returns(new List<SonarrEpisodeCache>().AsQueryable().BuildMock());
|
||||
|
||||
return _mocker.CreateInstance<TestAvailabilityCheckerWithArrSupport>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TestAvailabilityChecker : AvailabilityChecker
|
||||
{
|
||||
public TestAvailabilityChecker(ITvRequestRepository tvRequest, INotificationHelper notification, ILogger log, INotificationHubService notificationHubService) : base(tvRequest, notification, log, notificationHubService)
|
||||
public TestAvailabilityChecker(ITvRequestRepository tvRequest, INotificationHelper notification, ILogger log, INotificationHubService notificationHubService) : base(tvRequest, notification, log, notificationHubService, null, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public new Task ProcessTvShow(IQueryable<IBaseMediaServerEpisode> seriesEpisodes, ChildRequests child) => base.ProcessTvShow(seriesEpisodes, child);
|
||||
}
|
||||
|
||||
public class TestAvailabilityCheckerWithArrSupport : AvailabilityChecker
|
||||
{
|
||||
public TestAvailabilityCheckerWithArrSupport(
|
||||
ITvRequestRepository tvRequest,
|
||||
INotificationHelper notification,
|
||||
ILogger log,
|
||||
INotificationHubService notificationHubService,
|
||||
ISettingsService<RadarrSettings> radarrSettings,
|
||||
ISettingsService<SonarrSettings> sonarrSettings,
|
||||
IExternalRepository<RadarrCache> radarrCache,
|
||||
IExternalRepository<SonarrEpisodeCache> sonarrEpisodeCache)
|
||||
: base(tvRequest, notification, log, notificationHubService, radarrSettings, sonarrSettings, radarrCache, sonarrEpisodeCache)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<bool> TestShouldDeferToRadarr(int theMovieDbId, bool is4K) => base.ShouldDeferToRadarr(theMovieDbId, is4K);
|
||||
public Task<bool> TestShouldDeferToSonarr(int tvDbId) => base.ShouldDeferToSonarr(tvDbId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ using Ombi.Core.Services;
|
||||
using Ombi.Tests;
|
||||
using Moq.AutoMock;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Notifications.Models;
|
||||
|
||||
namespace Ombi.Schedule.Tests
|
||||
@ -241,6 +243,126 @@ namespace Ombi.Schedule.Tests
|
||||
Assert.True(request.SeasonRequests[0].Episodes[0].Available);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ProcessMovies_ShouldNotMarkAvailable_WhenRadarrPriorityEnabled_AndInRadarrCache()
|
||||
{
|
||||
// Setup Radarr priority
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache> { new RadarrCache { TheMovieDbId = 123, HasFile = true, HasRegular = true } }.AsQueryable().BuildMock());
|
||||
|
||||
var request = new MovieRequests
|
||||
{
|
||||
ImdbId = "test",
|
||||
TheMovieDbId = 123
|
||||
};
|
||||
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_mocker.Setup<IPlexContentRepository, Task<PlexServerContent>>(x => x.Get("test", ProviderType.ImdbId)).ReturnsAsync(new PlexServerContent());
|
||||
|
||||
await _subject.Execute(null);
|
||||
|
||||
// Should NOT mark as available because Radarr has priority
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(request.Available, Is.False);
|
||||
Assert.That(request.MarkedAsAvailable, Is.Null);
|
||||
});
|
||||
|
||||
_mocker.Verify<IMovieRequestRepository>(x => x.SaveChangesAsync(), Times.Never);
|
||||
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Never);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ProcessMovies_ShouldMarkAvailable_WhenRadarrPriorityDisabled_AndInPlex()
|
||||
{
|
||||
// Setup Radarr priority disabled
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = false });
|
||||
|
||||
var request = new MovieRequests
|
||||
{
|
||||
ImdbId = "test"
|
||||
};
|
||||
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_mocker.Setup<IPlexContentRepository, Task<PlexServerContent>>(x => x.Get("test", ProviderType.ImdbId)).ReturnsAsync(new PlexServerContent());
|
||||
|
||||
await _subject.Execute(null);
|
||||
|
||||
// Should mark as available because priority is disabled
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(request.Available, Is.True);
|
||||
Assert.That(request.MarkedAsAvailable, Is.Not.Null);
|
||||
});
|
||||
|
||||
_mocker.Verify<IMovieRequestRepository>(x => x.SaveChangesAsync(), Times.Once);
|
||||
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ProcessMovies_ShouldMarkAvailable_WhenRadarrPriorityEnabled_ButNotInRadarrCache()
|
||||
{
|
||||
// Setup Radarr priority enabled but content not in cache
|
||||
_mocker.Setup<ISettingsService<RadarrSettings>, Task<RadarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new RadarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<RadarrCache>, IQueryable<RadarrCache>>(x => x.GetAll())
|
||||
.Returns(new List<RadarrCache>().AsQueryable().BuildMock());
|
||||
|
||||
var request = new MovieRequests
|
||||
{
|
||||
ImdbId = "test",
|
||||
TheMovieDbId = 123
|
||||
};
|
||||
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_mocker.Setup<IPlexContentRepository, Task<PlexServerContent>>(x => x.Get("test", ProviderType.ImdbId)).ReturnsAsync(new PlexServerContent());
|
||||
|
||||
await _subject.Execute(null);
|
||||
|
||||
// Should mark as available because content is not in Radarr cache
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(request.Available, Is.True);
|
||||
Assert.That(request.MarkedAsAvailable, Is.Not.Null);
|
||||
});
|
||||
|
||||
_mocker.Verify<IMovieRequestRepository>(x => x.SaveChangesAsync(), Times.Once);
|
||||
_mocker.Verify<INotificationHelper>(x => x.Notify(It.IsAny<NotificationOptions>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ProcessTv_ShouldNotMarkAvailable_WhenSonarrPriorityEnabled_AndInSonarrCache()
|
||||
{
|
||||
// Setup Sonarr priority
|
||||
_mocker.Setup<ISettingsService<SonarrSettings>, Task<SonarrSettings>>(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new SonarrSettings { Enabled = true, ScanForAvailability = true, PrioritizeArrAvailability = true });
|
||||
_mocker.Setup<IExternalRepository<SonarrEpisodeCache>, IQueryable<SonarrEpisodeCache>>(x => x.GetAll())
|
||||
.Returns(new List<SonarrEpisodeCache> { new SonarrEpisodeCache { TvDbId = 99, HasFile = true } }.AsQueryable().BuildMock());
|
||||
|
||||
var request = CreateChildRequest(null, 33, 99);
|
||||
_mocker.Setup<ITvRequestRepository, IQueryable<ChildRequests>>(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable().BuildMock());
|
||||
_mocker.Setup<IPlexContentRepository, IQueryable<IMediaServerEpisode>>(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
||||
{
|
||||
new PlexEpisode
|
||||
{
|
||||
Series = new PlexServerContent
|
||||
{
|
||||
TheMovieDbId = 33.ToString(),
|
||||
Title = "abc"
|
||||
},
|
||||
EpisodeNumber = 1,
|
||||
SeasonNumber = 2,
|
||||
}
|
||||
}.AsQueryable().BuildMock());
|
||||
|
||||
await _subject.Execute(null);
|
||||
|
||||
// Should NOT mark as available because Sonarr has priority
|
||||
Assert.That(request.SeasonRequests[0].Episodes[0].Available, Is.False);
|
||||
// Save is called at the end of ProcessTv, but episodes should not be marked available
|
||||
_mocker.Verify<ITvRequestRepository>(x => x.Save(), Times.Once);
|
||||
}
|
||||
|
||||
private ChildRequests CreateChildRequest(string imdbId, int theMovieDbId, int tvdbId)
|
||||
{
|
||||
return new ChildRequests
|
||||
|
||||
@ -5,11 +5,14 @@ using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Schedule.Jobs
|
||||
@ -20,14 +23,26 @@ namespace Ombi.Schedule.Jobs
|
||||
protected readonly INotificationHelper _notificationService;
|
||||
protected readonly ILogger _log;
|
||||
protected readonly INotificationHubService NotificationHubService;
|
||||
protected readonly ISettingsService<RadarrSettings> _radarrSettings;
|
||||
protected readonly ISettingsService<SonarrSettings> _sonarrSettings;
|
||||
protected readonly IExternalRepository<RadarrCache> _radarrCache;
|
||||
protected readonly IExternalRepository<SonarrEpisodeCache> _sonarrEpisodeCache;
|
||||
|
||||
public AvailabilityChecker(ITvRequestRepository tvRequest, INotificationHelper notification,
|
||||
ILogger log, INotificationHubService notificationHubService)
|
||||
ILogger log, INotificationHubService notificationHubService,
|
||||
ISettingsService<RadarrSettings> radarrSettings = null,
|
||||
ISettingsService<SonarrSettings> sonarrSettings = null,
|
||||
IExternalRepository<RadarrCache> radarrCache = null,
|
||||
IExternalRepository<SonarrEpisodeCache> sonarrEpisodeCache = null)
|
||||
{
|
||||
_tvRepo = tvRequest;
|
||||
_notificationService = notification;
|
||||
_log = log;
|
||||
NotificationHubService = notificationHubService;
|
||||
_radarrSettings = radarrSettings;
|
||||
_sonarrSettings = sonarrSettings;
|
||||
_radarrCache = radarrCache;
|
||||
_sonarrEpisodeCache = sonarrEpisodeCache;
|
||||
}
|
||||
|
||||
protected async Task ProcessTvShow(IQueryable<IBaseMediaServerEpisode> seriesEpisodes, ChildRequests child)
|
||||
@ -100,5 +115,67 @@ namespace Ombi.Schedule.Jobs
|
||||
await _notificationService.Notify(notification);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<bool> ShouldDeferToRadarr(int theMovieDbId, bool is4K)
|
||||
{
|
||||
// If no Radarr settings service injected, don't defer
|
||||
if (_radarrSettings == null || _radarrCache == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var radarrSettings = await _radarrSettings.GetSettingsAsync();
|
||||
|
||||
// Check if Radarr is enabled, scanning for availability, and prioritizing *Arr availability
|
||||
if (radarrSettings == null || !radarrSettings.Enabled || !radarrSettings.ScanForAvailability || !radarrSettings.PrioritizeArrAvailability)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if content exists in Radarr cache with HasFile = true
|
||||
var cachedMovie = await _radarrCache.GetAll()
|
||||
.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (cachedMovie == null)
|
||||
{
|
||||
// Content not in Radarr cache at all, allow media server to mark as available
|
||||
return false;
|
||||
}
|
||||
|
||||
// If is4K, check Has4K property; otherwise check HasRegular or HasFile
|
||||
if (is4K)
|
||||
{
|
||||
return cachedMovie.Has4K;
|
||||
}
|
||||
else
|
||||
{
|
||||
return cachedMovie.HasRegular || cachedMovie.HasFile;
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<bool> ShouldDeferToSonarr(int tvDbId)
|
||||
{
|
||||
// If no Sonarr settings service injected, don't defer
|
||||
if (_sonarrSettings == null || _sonarrEpisodeCache == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sonarrSettings = await _sonarrSettings.GetSettingsAsync();
|
||||
|
||||
// Check if Sonarr is enabled, scanning for availability, and prioritizing *Arr availability
|
||||
if (sonarrSettings == null || !sonarrSettings.Enabled || !sonarrSettings.ScanForAvailability || !sonarrSettings.PrioritizeArrAvailability)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if any episodes exist in Sonarr cache with HasFile = true
|
||||
var hasAnyEpisodes = await _sonarrEpisodeCache.GetAll()
|
||||
.Where(x => x.TvDbId == tvDbId && x.HasFile)
|
||||
.AnyAsync();
|
||||
|
||||
return hasAnyEpisodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Services;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
@ -19,8 +21,10 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||
public class EmbyAvaliabilityChecker : AvailabilityChecker, IEmbyAvaliabilityChecker
|
||||
{
|
||||
public EmbyAvaliabilityChecker(IEmbyContentRepository repo, ITvRequestRepository t, IMovieRequestRepository m,
|
||||
INotificationHelper n, ILogger<EmbyAvaliabilityChecker> log, INotificationHubService notification, IFeatureService featureService)
|
||||
: base(t, n, log, notification)
|
||||
INotificationHelper n, ILogger<EmbyAvaliabilityChecker> log, INotificationHubService notification, IFeatureService featureService,
|
||||
ISettingsService<RadarrSettings> radarrSettings, ISettingsService<SonarrSettings> sonarrSettings,
|
||||
IExternalRepository<RadarrCache> radarrCache, IExternalRepository<SonarrEpisodeCache> sonarrEpisodeCache)
|
||||
: base(t, n, log, notification, radarrSettings, sonarrSettings, radarrCache, sonarrEpisodeCache)
|
||||
{
|
||||
_repo = repo;
|
||||
_movieRepo = m;
|
||||
@ -66,11 +70,22 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we should defer to Radarr for 4K availability
|
||||
var shouldDeferRadarr4K = has4kRequest && await ShouldDeferToRadarr(movie.TheMovieDbId, true);
|
||||
// Check if we should defer to Radarr for regular availability
|
||||
var shouldDeferRadarrRegular = await ShouldDeferToRadarr(movie.TheMovieDbId, false);
|
||||
|
||||
if (shouldDeferRadarr4K && shouldDeferRadarrRegular)
|
||||
{
|
||||
_log.LogInformation("Movie request {0} - {1} found in Emby but deferring to Radarr availability", movie?.Title ?? string.Empty, movie.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
_log.LogInformation("We have found the request {0} on Emby, sending the notification", movie?.Title ?? string.Empty);
|
||||
|
||||
var notify = false;
|
||||
|
||||
if (has4kRequest && embyContent.Has4K && !movie.Available4K)
|
||||
if (has4kRequest && embyContent.Has4K && !movie.Available4K && !shouldDeferRadarr4K)
|
||||
{
|
||||
movie.Available4K = true;
|
||||
movie.MarkedAsAvailable4K = DateTime.Now;
|
||||
@ -78,7 +93,7 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||
}
|
||||
|
||||
// If we have a non-4k version or we don't care about versions, then mark as available
|
||||
if (!movie.Available && ( !feature4kEnabled || embyContent.Quality != null ))
|
||||
if (!movie.Available && ( !feature4kEnabled || embyContent.Quality != null ) && !shouldDeferRadarrRegular)
|
||||
{
|
||||
movie.Available = true;
|
||||
movie.MarkedAsAvailable = DateTime.Now;
|
||||
@ -154,6 +169,13 @@ namespace Ombi.Schedule.Jobs.Emby
|
||||
x.Series.Title == child.Title);
|
||||
}
|
||||
|
||||
// Check if we should defer to Sonarr for this TV show
|
||||
if (await ShouldDeferToSonarr(tvDbId))
|
||||
{
|
||||
_log.LogInformation("TV request {0} - {1} found in Emby but deferring to Sonarr availability", child.Title, child.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
await ProcessTvShow(seriesEpisodes, child);
|
||||
}
|
||||
|
||||
|
||||
@ -32,10 +32,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Services;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
@ -46,8 +48,10 @@ namespace Ombi.Schedule.Jobs.Jellyfin
|
||||
public class JellyfinAvaliabilityChecker : AvailabilityChecker, IJellyfinAvaliabilityChecker
|
||||
{
|
||||
public JellyfinAvaliabilityChecker(IJellyfinContentRepository repo, ITvRequestRepository t, IMovieRequestRepository m,
|
||||
INotificationHelper n, ILogger<JellyfinAvaliabilityChecker> log, INotificationHubService notification, IFeatureService featureService)
|
||||
: base(t, n, log, notification)
|
||||
INotificationHelper n, ILogger<JellyfinAvaliabilityChecker> log, INotificationHubService notification, IFeatureService featureService,
|
||||
ISettingsService<RadarrSettings> radarrSettings, ISettingsService<SonarrSettings> sonarrSettings,
|
||||
IExternalRepository<RadarrCache> radarrCache, IExternalRepository<SonarrEpisodeCache> sonarrEpisodeCache)
|
||||
: base(t, n, log, notification, radarrSettings, sonarrSettings, radarrCache, sonarrEpisodeCache)
|
||||
{
|
||||
_repo = repo;
|
||||
_movieRepo = m;
|
||||
@ -93,11 +97,22 @@ namespace Ombi.Schedule.Jobs.Jellyfin
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we should defer to Radarr for 4K availability
|
||||
var shouldDeferRadarr4K = has4kRequest && await ShouldDeferToRadarr(movie.TheMovieDbId, true);
|
||||
// Check if we should defer to Radarr for regular availability
|
||||
var shouldDeferRadarrRegular = await ShouldDeferToRadarr(movie.TheMovieDbId, false);
|
||||
|
||||
if (shouldDeferRadarr4K && shouldDeferRadarrRegular)
|
||||
{
|
||||
_log.LogInformation("Movie request {0} - {1} found in Jellyfin but deferring to Radarr availability", movie?.Title ?? string.Empty, movie.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
_log.LogInformation("We have found the request {0} on Jellyfin, sending the notification", movie?.Title ?? string.Empty);
|
||||
|
||||
var notify = false;
|
||||
|
||||
if (has4kRequest && jellyfinContent.Has4K && !movie.Available4K)
|
||||
if (has4kRequest && jellyfinContent.Has4K && !movie.Available4K && !shouldDeferRadarr4K)
|
||||
{
|
||||
movie.Available4K = true;
|
||||
movie.MarkedAsAvailable4K = DateTime.Now;
|
||||
@ -105,7 +120,7 @@ namespace Ombi.Schedule.Jobs.Jellyfin
|
||||
}
|
||||
|
||||
// If we have a non-4k version or we don't care about versions, then mark as available
|
||||
if (!movie.Available && ( !feature4kEnabled || jellyfinContent.Quality != null ))
|
||||
if (!movie.Available && ( !feature4kEnabled || jellyfinContent.Quality != null ) && !shouldDeferRadarrRegular)
|
||||
{
|
||||
movie.Available = true;
|
||||
movie.MarkedAsAvailable = DateTime.Now;
|
||||
@ -182,6 +197,13 @@ namespace Ombi.Schedule.Jobs.Jellyfin
|
||||
x.Series.Title == child.Title);
|
||||
}
|
||||
|
||||
// Check if we should defer to Sonarr for this TV show
|
||||
if (await ShouldDeferToSonarr(tvDbId))
|
||||
{
|
||||
_log.LogInformation("TV request {0} - {1} found in Jellyfin but deferring to Sonarr availability", child.Title, child.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
await ProcessTvShow(seriesEpisodes, child);
|
||||
}
|
||||
|
||||
|
||||
@ -6,10 +6,12 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Services;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
@ -21,8 +23,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||
public class PlexAvailabilityChecker : AvailabilityChecker, IPlexAvailabilityChecker
|
||||
{
|
||||
public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies,
|
||||
INotificationHelper notification, ILogger<PlexAvailabilityChecker> log, INotificationHubService notificationHubService, IFeatureService featureService)
|
||||
: base(tvRequest, notification, log, notificationHubService)
|
||||
INotificationHelper notification, ILogger<PlexAvailabilityChecker> log, INotificationHubService notificationHubService, IFeatureService featureService,
|
||||
ISettingsService<RadarrSettings> radarrSettings, ISettingsService<SonarrSettings> sonarrSettings,
|
||||
IExternalRepository<RadarrCache> radarrCache, IExternalRepository<SonarrEpisodeCache> sonarrEpisodeCache)
|
||||
: base(tvRequest, notification, log, notificationHubService, radarrSettings, sonarrSettings, radarrCache, sonarrEpisodeCache)
|
||||
{
|
||||
_repo = repo;
|
||||
_movieRepo = movies;
|
||||
@ -104,6 +108,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||
x.Series.Title == child.Title);
|
||||
}
|
||||
|
||||
// Check if we should defer to Sonarr for this TV show
|
||||
if (await ShouldDeferToSonarr(tvDbId))
|
||||
{
|
||||
_log.LogInformation($"[PAC] - TV request {child.Title} - {child.Id} found in Plex but deferring to Sonarr availability");
|
||||
continue;
|
||||
}
|
||||
|
||||
await ProcessTvShow(seriesEpisodes, child);
|
||||
}
|
||||
|
||||
@ -138,11 +149,22 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we should defer to Radarr for 4K availability
|
||||
var shouldDeferRadarr4K = has4kRequest && await ShouldDeferToRadarr(movie.TheMovieDbId, true);
|
||||
// Check if we should defer to Radarr for regular availability
|
||||
var shouldDeferRadarrRegular = await ShouldDeferToRadarr(movie.TheMovieDbId, false);
|
||||
|
||||
if (shouldDeferRadarr4K && shouldDeferRadarrRegular)
|
||||
{
|
||||
_log.LogInformation($"[PAC] - Movie request {movie.Title} - {movie.Id} found in Plex but deferring to Radarr availability");
|
||||
continue;
|
||||
}
|
||||
|
||||
_log.LogInformation($"[PAC] - Movie request {movie.Title} - {movie.Id} is now available, sending notification");
|
||||
|
||||
var notify = false;
|
||||
|
||||
if (has4kRequest && item.Has4K && !movie.Available4K && feature4kEnabled)
|
||||
if (has4kRequest && item.Has4K && !movie.Available4K && feature4kEnabled && !shouldDeferRadarr4K)
|
||||
{
|
||||
movie.Available4K = true;
|
||||
movie.Approved4K = true;
|
||||
@ -151,7 +173,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||
notify = true;
|
||||
}
|
||||
|
||||
if (!feature4kEnabled && !movie.Available)
|
||||
if (!feature4kEnabled && !movie.Available && !shouldDeferRadarrRegular)
|
||||
{
|
||||
movie.Available = true;
|
||||
movie.MarkedAsAvailable = DateTime.Now;
|
||||
@ -160,7 +182,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||
}
|
||||
|
||||
// If we have a non-4k versison then mark as available
|
||||
if (item.Quality != null && !movie.Available)
|
||||
if (item.Quality != null && !movie.Available && !shouldDeferRadarrRegular)
|
||||
{
|
||||
movie.Available = true;
|
||||
movie.Approved = true;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
public bool AddOnly { get; set; }
|
||||
public string MinimumAvailability { get; set; }
|
||||
public bool ScanForAvailability { get; set; }
|
||||
public bool PrioritizeArrAvailability { get; set; }
|
||||
public int? Tag { get; set; }
|
||||
public bool SendUserTags { get; set; }
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
public int LanguageProfile { get; set; }
|
||||
public int LanguageProfileAnime { get; set; }
|
||||
public bool ScanForAvailability { get; set; }
|
||||
public bool PrioritizeArrAvailability { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@ -147,6 +147,7 @@ export interface ISonarrSettings extends IExternalSettings {
|
||||
languageProfile: number;
|
||||
languageProfileAnime: number;
|
||||
scanForAvailability: boolean;
|
||||
prioritizeArrAvailability: boolean;
|
||||
sendUserTags: boolean;
|
||||
tag: number | null;
|
||||
animeTag: number | null;
|
||||
@ -161,6 +162,7 @@ export interface IRadarrSettings extends IExternalSettings {
|
||||
addOnly: boolean;
|
||||
minimumAvailability: string;
|
||||
scanForAvailability: boolean;
|
||||
prioritizeArrAvailability: boolean;
|
||||
tag: number | null;
|
||||
sendUserTags: boolean;
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import { MatIconModule } from "@angular/material/icon";
|
||||
import { MatInputModule } from "@angular/material/input";
|
||||
import { MatSnackBarModule } from "@angular/material/snack-bar";
|
||||
import { ImageBackgroundComponent } from "app/components";
|
||||
import { TranslateModule } from "@ngx-translate/core";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@ -30,7 +31,8 @@ import { ImageBackgroundComponent } from "app/components";
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatSnackBarModule,
|
||||
ImageBackgroundComponent
|
||||
ImageBackgroundComponent,
|
||||
TranslateModule
|
||||
]
|
||||
})
|
||||
export class TokenResetPasswordComponent implements OnInit {
|
||||
|
||||
@ -8,6 +8,10 @@
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="prioritizeArrAvailability">Prioritize Radarr Availability</mat-slide-toggle>
|
||||
<small><br>When enabled, Radarr availability takes priority over media server availability</small>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="sendUserTags" id="sendUserTags">Add the user as a tag</mat-slide-toggle>
|
||||
<small><br>This will add the username of the requesting user as a tag in Radarr. If the tag doesn't exist, Ombi will create it.</small>
|
||||
|
||||
@ -78,7 +78,8 @@ export class RadarrComponent implements OnInit, OnDestroy {
|
||||
port: [x.settings.radarr.port],
|
||||
addOnly: [x.settings.radarr.addOnly],
|
||||
minimumAvailability: [x.settings.radarr.minimumAvailability],
|
||||
scanForAvailability: [x.settings.radarr.scanForAvailability]
|
||||
scanForAvailability: [x.settings.radarr.scanForAvailability],
|
||||
prioritizeArrAvailability: [x.settings.radarr.prioritizeArrAvailability]
|
||||
}),
|
||||
radarr4K: fb.group({
|
||||
enabled: [x.settings.radarr4K.enabled],
|
||||
@ -93,7 +94,8 @@ export class RadarrComponent implements OnInit, OnDestroy {
|
||||
port: [x.settings.radarr4K.port],
|
||||
addOnly: [x.settings.radarr4K.addOnly],
|
||||
minimumAvailability: [x.settings.radarr4K.minimumAvailability],
|
||||
scanForAvailability: [x.settings.radarr4K.scanForAvailability]
|
||||
scanForAvailability: [x.settings.radarr4K.scanForAvailability],
|
||||
prioritizeArrAvailability: [x.settings.radarr4K.prioritizeArrAvailability]
|
||||
}),
|
||||
}))
|
||||
)
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="prioritizeArrAvailability">Prioritize Sonarr Availability</mat-slide-toggle>
|
||||
<small><br>When enabled, Sonarr availability takes priority over media server availability</small>
|
||||
</div>
|
||||
<div class="md-form-field">
|
||||
<mat-slide-toggle formControlName="sendUserTags" id="sendUserTags">Add the user as a tag</mat-slide-toggle>
|
||||
<small><br>This will add the username of the requesting user as a tag in Sonarr. If the tag doesn't exist, Ombi will create it.</small>
|
||||
|
||||
@ -107,6 +107,7 @@ export class SonarrComponent implements OnInit {
|
||||
languageProfile: [settings.languageProfile],
|
||||
languageProfileAnime: [settings.languageProfileAnime],
|
||||
scanForAvailability: [settings.scanForAvailability],
|
||||
prioritizeArrAvailability: [settings.prioritizeArrAvailability],
|
||||
sendUserTags: [settings.sendUserTags],
|
||||
tag: [settings.tag],
|
||||
animeTag: [settings.animeTag]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user