mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-10 13:02:47 +01:00
Added SeriesSearch and RenameSeries jobs.
Add UI controls for new jobs. Skip ignored episodes when doing series/season searches.
This commit is contained in:
parent
1d1bbd3a23
commit
f6c9fa4f95
@ -88,6 +88,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="SeriesSearchJobTest.cs" />
|
||||
<Compile Include="SeasonSearchJobTest.cs" />
|
||||
<Compile Include="EventClientProviderTest.cs" />
|
||||
<Compile Include="CentralDispatchTest.cs" />
|
||||
|
@ -28,6 +28,7 @@ public void SeasonSearch_success()
|
||||
.WhereAll()
|
||||
.Have(e => e.SeriesId = 1)
|
||||
.Have(e => e.SeasonNumber = 1)
|
||||
.Have(e => e.Ignored = false)
|
||||
.Build();
|
||||
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
@ -68,5 +69,37 @@ public void SeasonSearch_no_episodes()
|
||||
Times.Never());
|
||||
ExceptionVerification.ExcpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SeasonSearch_skip_ignored()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.WhereAll()
|
||||
.Have(e => e.SeriesId = 1)
|
||||
.Have(e => e.SeasonNumber = 1)
|
||||
.WhereTheFirst(5)
|
||||
.Have(e => e.Ignored = false)
|
||||
.AndTheRemaining()
|
||||
.Have(e => e.Ignored = true)
|
||||
.Build();
|
||||
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var notification = new ProgressNotification("Season Search");
|
||||
|
||||
mocker.GetMock<EpisodeProvider>()
|
||||
.Setup(c => c.GetEpisodesBySeason(1, 1)).Returns(episodes);
|
||||
|
||||
mocker.GetMock<EpisodeSearchJob>()
|
||||
.Setup(c => c.Start(notification, It.IsAny<int>(), 0)).Verifiable();
|
||||
|
||||
//Act
|
||||
mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
|
||||
Times.Exactly(5));
|
||||
}
|
||||
}
|
||||
}
|
103
NzbDrone.Core.Test/SeriesSearchJobTest.cs
Normal file
103
NzbDrone.Core.Test/SeriesSearchJobTest.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMoq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Model.Notification;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Providers.Indexer;
|
||||
using NzbDrone.Core.Providers.Jobs;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test
|
||||
{
|
||||
[TestFixture]
|
||||
// ReSharper disable InconsistentNaming
|
||||
public class SeriesSearchJobTest : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void SeriesSearch_success()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
.WhereAll()
|
||||
.Have(e => e.SeriesId = 1)
|
||||
.Have(e => e.Ignored = false)
|
||||
.Build();
|
||||
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var notification = new ProgressNotification("Series Search");
|
||||
|
||||
mocker.GetMock<EpisodeProvider>()
|
||||
.Setup(c => c.GetEpisodeBySeries(1)).Returns(episodes);
|
||||
|
||||
mocker.GetMock<EpisodeSearchJob>()
|
||||
.Setup(c => c.Start(notification, It.IsAny<int>(), 0)).Verifiable();
|
||||
|
||||
//Act
|
||||
mocker.Resolve<SeriesSearchJob>().Start(notification, 1, 0);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
|
||||
Times.Exactly(episodes.Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SeriesSearch_no_episodes()
|
||||
{
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
var notification = new ProgressNotification("Series Search");
|
||||
List<Episode> nullList = null;
|
||||
|
||||
mocker.GetMock<EpisodeProvider>()
|
||||
.Setup(c => c.GetEpisodeBySeries(1)).Returns(nullList);
|
||||
|
||||
//Act
|
||||
mocker.Resolve<SeriesSearchJob>().Start(notification, 1, 0);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
|
||||
Times.Never());
|
||||
ExceptionVerification.ExcpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SeriesSearch_skip_ignored()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.WhereAll()
|
||||
.Have(e => e.SeriesId = 1)
|
||||
.WhereTheFirst(5)
|
||||
.Have(e => e.Ignored = false)
|
||||
.AndTheRemaining()
|
||||
.Have(e => e.Ignored = true)
|
||||
.Build();
|
||||
|
||||
var mocker = new AutoMoqer(MockBehavior.Strict);
|
||||
|
||||
var notification = new ProgressNotification("Series Search");
|
||||
|
||||
mocker.GetMock<EpisodeProvider>()
|
||||
.Setup(c => c.GetEpisodeBySeries(1)).Returns(episodes);
|
||||
|
||||
mocker.GetMock<EpisodeSearchJob>()
|
||||
.Setup(c => c.Start(notification, It.IsAny<int>(), 0)).Verifiable();
|
||||
|
||||
//Act
|
||||
mocker.Resolve<SeriesSearchJob>().Start(notification, 1, 0);
|
||||
|
||||
//Assert
|
||||
mocker.VerifyAllMocks();
|
||||
mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
|
||||
Times.Exactly(5));
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,8 @@ private static void BindJobs()
|
||||
_kernel.Bind<IJob>().To<UpdateSceneMappingsJob>().InSingletonScope();
|
||||
_kernel.Bind<IJob>().To<SeasonSearchJob>().InSingletonScope();
|
||||
_kernel.Bind<IJob>().To<RenameSeasonJob>().InSingletonScope();
|
||||
_kernel.Bind<IJob>().To<SeriesSearchJob>().InSingletonScope();
|
||||
_kernel.Bind<IJob>().To<RenameSeriesJob>().InSingletonScope();
|
||||
|
||||
_kernel.Get<JobProvider>().Initialize();
|
||||
_kernel.Get<WebTimer>().StartTimer(30);
|
||||
|
@ -197,6 +197,8 @@
|
||||
<Compile Include="Model\Xbmc\ErrorResult.cs" />
|
||||
<Compile Include="Model\Xbmc\IconType.cs" />
|
||||
<Compile Include="Providers\Core\UdpProvider.cs" />
|
||||
<Compile Include="Providers\Jobs\RenameSeriesJob.cs" />
|
||||
<Compile Include="Providers\Jobs\SeriesSearchJob.cs" />
|
||||
<Compile Include="Providers\Jobs\RenameSeasonJob.cs" />
|
||||
<Compile Include="Providers\Jobs\SeasonSearchJob.cs" />
|
||||
<Compile Include="Providers\Xbmc\ResourceManager.cs" />
|
||||
|
@ -44,7 +44,7 @@ public void Start(ProgressNotification notification, int targetId, int secondary
|
||||
|
||||
if (episodeFiles == null || episodeFiles.Count == 0)
|
||||
{
|
||||
Logger.Warn("No episodes in database found for series: {0} and season: {1}. No", targetId, secondaryTargetId);
|
||||
Logger.Warn("No episodes in database found for series: {0} and season: {1}.", targetId, secondaryTargetId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
56
NzbDrone.Core/Providers/Jobs/RenameSeriesJob.cs
Normal file
56
NzbDrone.Core/Providers/Jobs/RenameSeriesJob.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using Ninject;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Model.Notification;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
|
||||
namespace NzbDrone.Core.Providers.Jobs
|
||||
{
|
||||
public class RenameSeriesJob : IJob
|
||||
{
|
||||
private readonly MediaFileProvider _mediaFileProvider;
|
||||
private readonly DiskScanProvider _diskScanProvider;
|
||||
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Inject]
|
||||
public RenameSeriesJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider)
|
||||
{
|
||||
_mediaFileProvider = mediaFileProvider;
|
||||
_diskScanProvider = diskScanProvider;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Rename Series"; }
|
||||
}
|
||||
|
||||
public int DefaultInterval
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
||||
{
|
||||
if (targetId <= 0)
|
||||
throw new ArgumentOutOfRangeException("targetId");
|
||||
|
||||
Logger.Debug("Getting episodes from database for series: {0}", targetId);
|
||||
var episodeFiles = _mediaFileProvider.GetSeriesFiles(targetId);
|
||||
|
||||
if (episodeFiles == null || episodeFiles.Count == 0)
|
||||
{
|
||||
Logger.Warn("No episodes in database found for series: {0}", targetId);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
{
|
||||
_diskScanProvider.MoveEpisodeFile(episodeFile);
|
||||
}
|
||||
|
||||
notification.CurrentMessage = String.Format("Series rename completed for Series: {0}", targetId);
|
||||
}
|
||||
}
|
||||
}
|
@ -44,13 +44,13 @@ public void Start(ProgressNotification notification, int targetId, int secondary
|
||||
|
||||
if (episodes == null)
|
||||
{
|
||||
Logger.Warn("No episodes in database found for series: {0} and season: {1}. No", targetId, secondaryTargetId);
|
||||
Logger.Warn("No episodes in database found for series: {0} and season: {1}.", targetId, secondaryTargetId);
|
||||
return;
|
||||
}
|
||||
|
||||
//Todo: Search for a full season NZB before individual episodes
|
||||
|
||||
foreach (var episode in episodes)
|
||||
foreach (var episode in episodes.Where(e => !e.Ignored))
|
||||
{
|
||||
_episodeSearchJob.Start(notification, episode.EpisodeId, 0);
|
||||
}
|
||||
|
56
NzbDrone.Core/Providers/Jobs/SeriesSearchJob.cs
Normal file
56
NzbDrone.Core/Providers/Jobs/SeriesSearchJob.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Model.Notification;
|
||||
using NzbDrone.Core.Repository;
|
||||
|
||||
namespace NzbDrone.Core.Providers.Jobs
|
||||
{
|
||||
public class SeriesSearchJob : IJob
|
||||
{
|
||||
private readonly EpisodeProvider _episodeProvider;
|
||||
private readonly EpisodeSearchJob _episodeSearchJob;
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public SeriesSearchJob(EpisodeProvider episodeProvider, EpisodeSearchJob episodeSearchJob)
|
||||
{
|
||||
_episodeProvider = episodeProvider;
|
||||
_episodeSearchJob = episodeSearchJob;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Series Search"; }
|
||||
}
|
||||
|
||||
public int DefaultInterval
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
||||
{
|
||||
if (targetId <= 0)
|
||||
throw new ArgumentOutOfRangeException("targetId");
|
||||
|
||||
Logger.Debug("Getting episodes from database for series: {0}.", targetId);
|
||||
var episodes = _episodeProvider.GetEpisodeBySeries(targetId);
|
||||
|
||||
if (episodes == null)
|
||||
{
|
||||
Logger.Warn("No episodes in database found for series: {0}.", targetId);
|
||||
return;
|
||||
}
|
||||
|
||||
//Todo: Search for a full season NZB before individual episodes
|
||||
|
||||
foreach (var episode in episodes.Where(e => !e.Ignored))
|
||||
{
|
||||
_episodeSearchJob.Start(notification, episode.EpisodeId, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -37,13 +37,5 @@ public JsonResult UpdateInfo(int seriesId)
|
||||
|
||||
return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
|
||||
}
|
||||
|
||||
public JsonResult RenameSeries(int seriesId)
|
||||
{
|
||||
//Syncs the episodes on disk for the specified series
|
||||
//_jobProvider.QueueJob(typeof(UpdateInfoJob), seriesId);
|
||||
|
||||
return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,14 @@ public JsonResult SearchSeason(int seriesId, int seasonNumber)
|
||||
return new JsonResult { Data = "ok" };
|
||||
}
|
||||
|
||||
public JsonResult SearchSeries(int seriesId)
|
||||
{
|
||||
//Syncs the episodes on disk for the specified series
|
||||
_jobProvider.QueueJob(typeof(SeriesSearchJob), seriesId);
|
||||
|
||||
return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
|
||||
}
|
||||
|
||||
public JsonResult Rename(int episodeFileId)
|
||||
{
|
||||
_jobProvider.QueueJob(typeof(RenameEpisodeJob), episodeFileId);
|
||||
@ -46,5 +54,13 @@ public JsonResult RenameSeason(int seriesId, int seasonNumber)
|
||||
|
||||
return new JsonResult { Data = "ok" };
|
||||
}
|
||||
|
||||
public JsonResult RenameSeries(int seriesId)
|
||||
{
|
||||
//Syncs the episodes on disk for the specified series
|
||||
_jobProvider.QueueJob(typeof(RenameSeriesJob), seriesId);
|
||||
|
||||
return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
|
||||
}
|
||||
}
|
||||
}
|
@ -86,7 +86,8 @@
|
||||
<li>@Html.ActionLink("Back to Series List", "Index", "Series")</li>
|
||||
<li>@Ajax.ActionLink("Scan For Episodes on Disk", "SyncEpisodesOnDisk", "Command", new { seriesId = Model.SeriesId }, null)</li>
|
||||
<li>@Ajax.ActionLink("Update Info", "UpdateInfo", "Command", new { seriesId = Model.SeriesId }, null)</li>
|
||||
<li>@Ajax.ActionLink("Rename Series", "RenameSeries", "Command", new { seriesId = Model.SeriesId }, null)</li>
|
||||
<li>@Ajax.ActionLink("Search for Series", "SearchSeries", "Episode", new { seriesId = Model.SeriesId }, null)</li>
|
||||
<li>@Ajax.ActionLink("Rename Series", "RenameSeries", "Episode", new { seriesId = Model.SeriesId }, null)</li>
|
||||
</ul>
|
||||
}
|
||||
@section MainContent{
|
||||
@ -120,7 +121,7 @@
|
||||
//columns.Bound(o => o.Ignored)
|
||||
// .Title("<img src='../../Content/Images/ignoredNeutral.png' class='ignoredEpisodesMaster ignoreEpisode ignoreSeason_" + season + "' title='Click to toggle season ignore status' />")
|
||||
// .ClientTemplate(
|
||||
// "<img src='../../Content/Images/ignoredNeutral.png' class='ignoreEpisode ignoreEpisode_" + season + " ignored' id='<#= EpisodeId #>' title='Click to toggle episode ignore status' />")
|
||||
// "<img src='../../Content/Images/ignoredNeutral.png' class='ignoreEpisode ignoreEpisode_" + season + " ignored' id='<#= EpisodeId #>' title='Click to toggle episode ignore status' />")
|
||||
// .Width(20)
|
||||
// .HtmlAttributes(new { style = "text-align:center" });
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user