Added SeriesSearch and RenameSeries jobs.

Add UI controls for new jobs.
Skip ignored episodes when doing series/season searches.
pull/3113/head
Mark McDowall 13 years ago
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 @@ namespace NzbDrone.Core.Test
.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 @@ namespace NzbDrone.Core.Test
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));
}
}
}

@ -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 @@ namespace NzbDrone.Core
_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 @@ namespace NzbDrone.Core.Providers.Jobs
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;
}

@ -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 @@ namespace NzbDrone.Core.Providers.Jobs
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);
}

@ -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 @@ namespace NzbDrone.Web.Controllers
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 @@ namespace NzbDrone.Web.Controllers
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 @@ namespace NzbDrone.Web.Controllers
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…
Cancel
Save