1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-12 11:15:43 +02:00

Merge branch 'master' of git://github.com/kayone/NzbDrone

This commit is contained in:
Mark McDowall 2011-05-26 22:02:55 -07:00
commit fc7d3da540
21 changed files with 761 additions and 333 deletions

View File

@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMoq;
using FizzWare.NBuilder;
using MbUnit.Framework;
using Moq;
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 EpisodeSearchJobTest : TestBase
{
[Test]
public void ParseResult_should_return_after_match()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.Build();
var episode = Builder<Episode>.CreateNew().Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(true);
mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(It.IsAny<EpisodeParseResult>())).Returns(true);
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()), Times.Once());
}
[Test]
public void higher_quality_should_be_called_first()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
.WhereTheFirst(1).Has(c => c.Quality = QualityTypes.Bluray1080p)
.AndTheNext(1).Has(c => c.Quality = QualityTypes.DVD)
.Build();
var episode = Builder<Episode>.CreateNew().Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(parseResults[0])).Returns(true);
mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(parseResults[0])).Returns(true);
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(parseResults[0]), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(parseResults[0]), Times.Once());
}
[Test]
public void when_same_quality_proper_should_be_called_first()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(20)
.WhereAll().Have(c => c.Quality = QualityTypes.DVD)
.And(c => c.Proper = false)
.WhereRandom(1).Has(c => c.Proper = true)
.Build();
Assert.Count(1, parseResults.Where(c => c.Proper));
var episode = Builder<Episode>.CreateNew().Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true);
mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true);
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.Is<EpisodeParseResult>(p => p.Proper)), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.Is<EpisodeParseResult>(p => p.Proper)), Times.Once());
}
[Test]
public void when_not_needed_should_check_the_rest()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew().Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4));
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
public void failed_IsNeeded_should_check_the_rest()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew().Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Throws(new Exception());
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4));
ExceptionVerification.ExcpectedErrors(4);
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
[Row(0)]
[Row(-1)]
[Row(-100)]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void target_id_less_than_0_throws_exception(int target)
{
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), target);
}
[Test]
public void should_search_all_providers()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew()
.With(c => c.Series = Builder<Series>.CreateNew().Build())
.With(c => c.SeasonNumber = 12)
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisode(episode.EpisodeId))
.Returns(episode);
var indexer1 = new Mock<IndexerBase>();
indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexer2 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexers = new List<IndexerBase> { indexer1.Object, indexer2.Object };
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(indexers);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), episode.EpisodeId);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(8));
ExceptionVerification.ExcpectedWarns(1);
indexer1.VerifyAll();
indexer2.VerifyAll();
}
[Test]
public void failed_indexer_should_not_break_job()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew()
.With(c => c.Series = Builder<Series>.CreateNew().Build())
.With(c => c.SeasonNumber = 12)
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisode(episode.EpisodeId))
.Returns(episode);
var indexer1 = new Mock<IndexerBase>();
indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexer2 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Throws(new Exception()).Verifiable();
var indexer3 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexers = new List<IndexerBase> { indexer1.Object, indexer2.Object, indexer3.Object };
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(indexers);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), episode.EpisodeId);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(8));
ExceptionVerification.ExcpectedWarns(1);
ExceptionVerification.ExcpectedErrors(1);
indexer1.VerifyAll();
indexer2.VerifyAll();
indexer3.VerifyAll();
}
[Test]
public void no_episode_found_should_return_with_error_logged()
{
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisode(It.IsAny<long>()))
.Returns<Episode>(null);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), 12);
//Assert
mocker.VerifyAllMocks();
ExceptionVerification.ExcpectedErrors(1);
}
}
}

View File

@ -27,17 +27,9 @@ internal static void Reset()
internal static void AssertNoError()
{
if (_logs.Count != 0)
{
string errors = GetLogsString(_logs);
var message = String.Format("{0} unexpected Fatal/Error/Warning were logged during execution.\n\r Use ExceptionVerification.Excpected methods if errors are excepted for this test.{1}{2}",
_logs.Count,
Environment.NewLine,
errors);
Assert.Fail(message);
}
ExcpectedFatals(0);
ExcpectedErrors(0);
ExcpectedWarns(0);
}
private static string GetLogsString(IEnumerable<LogEventInfo> logs)
@ -48,9 +40,9 @@ private static string GetLogsString(IEnumerable<LogEventInfo> logs)
string exception = "";
if (log.Exception != null)
{
exception = log.Exception.ToString();
exception = log.Exception.Message;
}
errors += Environment.NewLine + String.Format("[{0}] {1}: {2} {3}", log.Level, log.LoggerName, log.FormattedMessage, exception);
errors += Environment.NewLine + String.Format("[{0}] {1}: {2} [{3}]", log.Level, log.LoggerName, log.FormattedMessage, exception);
}
return errors;
}
@ -86,8 +78,14 @@ private static void Excpected(LogLevel level, int count)
if (levelLogs.Count != count)
{
var message = String.Format("{0} {1}(s) were expected but {2} were logged.\n\r{3}",
count, level, _logs.Count, GetLogsString(levelLogs));
count, level, levelLogs.Count, GetLogsString(levelLogs));
message =
"********************************************************************************************************************************\n\r"
+ message +
"\n\r********************************************************************************************************************************";
Assert.Fail(message);
}

View File

@ -20,10 +20,8 @@ namespace NzbDrone.Core.Test
public class ImportNewSeriesJobTest : TestBase
{
[Test]
public void series_specific_scan_should_scan_series()
public void import_new_series_succesfull()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.WhereAll().Have(s => s.LastInfoSync = null)
@ -37,21 +35,38 @@ public void series_specific_scan_should_scan_series()
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable())
.Callback(() => series.ToList().ForEach(c => c.LastInfoSync = DateTime.Now));//Set the last scan time on the collection
.Returns(series.AsQueryable());
mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId));
.Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastDiskSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[1].SeriesId));
.Setup(j => j.Start(notification, series[1].SeriesId))
.Callback(() => series[1].LastDiskSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId));
.Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastInfoSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId));
.Setup(j => j.Start(notification, series[1].SeriesId))
.Callback(() => series[1].LastInfoSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]);
mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[1].SeriesId)).Returns(series[1]);
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
//Act
mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0);
@ -61,81 +76,57 @@ public void series_specific_scan_should_scan_series()
}
[Test]
public void series_with_no_episodes_should_skip_scan()
[Timeout(3)]
public void failed_import_should_not_be_stuck_in_loop()
{
var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12)
.With(s => s.Episodes = new List<Episode>())
.Build();
var series = Builder<Series>.CreateListOfSize(2)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.WhereAll().Have(s => s.LastInfoSync = null)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.AndTheNext(1).Has(s => s.SeriesId = 15)
.Build();
var notification = new ProgressNotification("Test");
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(series.SeriesId))
.Returns(series);
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastInfoSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId))
.Throws(new InvalidOperationException())
.AtMostOnce();
mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastDiskSync = DateTime.Now)
.AtMostOnce();
mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]);
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
//Act
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId);
mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0);
//Assert
mocker.VerifyAllMocks();
ExceptionVerification.ExcpectedErrors(1);
}
[Test]
public void job_with_no_target_should_scan_all_series()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.AndTheNext(1).Has(s => s.SeriesId = 15)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
[Test]
public void job_with_no_target_should_scan_series_with_episodes()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.And(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.AndTheNext(1).Has(s => s.SeriesId = 15)
.And(s => s.Episodes = new List<Episode>())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
}
}

View File

@ -23,151 +23,6 @@ namespace NzbDrone.Core.Test
// ReSharper disable InconsistentNaming
public class IndexerProviderTest : TestBase
{
[Test]
[Row("nzbsorg.xml", 0)]
[Row("nzbsrus.xml", 6)]
[Row("newzbin.xml", 1)]
[Row("nzbmatrix.xml", 1)]
public void parse_feed_xml(string fileName, int warns)
{
var mocker = new AutoMoqer();
mocker.GetMock<HttpProvider>()
.Setup(h => h.DownloadStream(It.IsAny<String>(), It.IsAny<NetworkCredential>()))
.Returns(File.OpenRead(".\\Files\\Rss\\" + fileName));
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var mockIndexer = mocker.Resolve<MockIndexer>();
var parseResults = mockIndexer.FetchRss();
foreach (var episodeParseResult in parseResults)
{
var Uri = new Uri(episodeParseResult.NzbUrl);
Assert.DoesNotContain(Uri.PathAndQuery, "//");
}
Assert.IsNotEmpty(parseResults);
Assert.ForAll(parseResults, s => Assert.AreEqual(mockIndexer.Name, s.Indexer));
Assert.ForAll(parseResults, s => Assert.AreNotEqual("", s.NzbTitle));
Assert.ForAll(parseResults, s => Assert.AreNotEqual(null, s.NzbTitle));
ExceptionVerification.ExcpectedWarns(warns);
}
[Test]
public void newzbin()
{
var mocker = new AutoMoqer();
mocker.GetMock<HttpProvider>()
.Setup(h => h.DownloadStream(It.IsAny<String>(), It.IsAny<NetworkCredential>()))
.Returns(File.OpenRead(".\\Files\\Rss\\newzbin.xml"));
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var newzbinProvider = mocker.Resolve<Newzbin>();
var parseResults = newzbinProvider.FetchRss();
foreach (var episodeParseResult in parseResults)
{
var Uri = new Uri(episodeParseResult.NzbUrl);
Assert.DoesNotContain(Uri.PathAndQuery, "//");
}
Assert.IsNotEmpty(parseResults);
Assert.ForAll(parseResults, s => Assert.AreEqual(newzbinProvider.Name, s.Indexer));
Assert.ForAll(parseResults, s => Assert.AreNotEqual("", s.NzbTitle));
Assert.ForAll(parseResults, s => Assert.AreNotEqual(null, s.NzbTitle));
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
[Row("Adventure.Inc.S03E19.DVDRip.XviD-OSiTV", 3, 19, QualityTypes.DVD)]
public void custome_parser_partial_success(string title, int season, int episode, QualityTypes quality)
{
var mocker = new AutoMoqer();
const string summary = "My fake summary";
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var fakeRssItem = Builder<SyndicationItem>.CreateNew()
.With(c => c.Title = new TextSyndicationContent(title))
.With(c => c.Summary = new TextSyndicationContent(summary))
.Build();
var result = mocker.Resolve<CustomParserIndexer>().ParseFeed(fakeRssItem);
Assert.IsNotNull(result);
Assert.AreEqual(summary, result.EpisodeTitle);
Assert.AreEqual(season, result.SeasonNumber);
Assert.AreEqual(episode, result.EpisodeNumbers[0]);
Assert.AreEqual(quality, result.Quality);
}
[Test]
[Row("Adventure.Inc.DVDRip.XviD-OSiTV")]
public void custome_parser_full_parse(string title)
{
var mocker = new AutoMoqer();
const string summary = "My fake summary";
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var fakeRssItem = Builder<SyndicationItem>.CreateNew()
.With(c => c.Title = new TextSyndicationContent(title))
.With(c => c.Summary = new TextSyndicationContent(summary))
.Build();
var result = mocker.Resolve<CustomParserIndexer>().ParseFeed(fakeRssItem);
Assert.IsNotNull(result);
Assert.AreEqual(summary, result.EpisodeTitle);
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
public void downloadFeed()
{
var mocker = new AutoMoqer();
mocker.SetConstant(new HttpProvider());
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
mocker.Resolve<TestUrlIndexer>().FetchRss();
ExceptionVerification.IgnoreWarns();
}
[Test]
public void Init_indexer_test()
{
@ -178,49 +33,32 @@ public void Init_indexer_test()
//Act
var indexerProvider = mocker.Resolve<IndexerProvider>();
indexerProvider.InitializeIndexers(new List<IndexerBase> { mocker.Resolve<MockIndexer>() });
var indexers = indexerProvider.All();
var settings = indexerProvider.GetSettings(typeof(MockIndexer));
settings.Enable = true;
indexerProvider.SaveSettings(settings);
//Assert
Assert.Count(1, indexers);
Assert.Count(1, indexerProvider.GetAllISettings());
Assert.Count(1, indexerProvider.GetEnabledIndexers());
}
[Test]
public void unmapped_series_shouldnt_call_any_providers()
{
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(c => c.FindSeries(It.IsAny<String>()))
.Returns<Series>(null);
var indexer = mocker.Resolve<MockIndexer>();
//indexer.ProcessItem(new SyndicationItem { Title = new TextSyndicationContent("Adventure.Inc.S01E18.DVDRip.XviD-OSiTV") });
}
[Test]
public void nzbsorg_search_returns_valid_results()
public void Init_indexer_with_disabled_job()
{
var mocker = new AutoMoqer();
mocker.GetMock<ConfigProvider>()
.SetupGet(c => c.NzbsOrgUId)
.Returns("43516");
mocker.SetConstant(MockLib.GetEmptyRepository());
mocker.GetMock<ConfigProvider>()
.SetupGet(c => c.NzbsOrgHash)
.Returns("bc8edb4cc49d4ae440775adec5ac001f");
mocker.Resolve<HttpProvider>();
var result = mocker.Resolve<NzbsOrg>().FetchEpisode("Simpsons", 21, 23);
Assert.IsNotEmpty(result);
Assert.ForAll(result, r => r.CleanTitle == "simpsons");
Assert.ForAll(result, r => r.SeasonNumber == 21);
Assert.ForAll(result, r => r.EpisodeNumbers.Contains(23));
//Act
var indexerProvider = mocker.Resolve<IndexerProvider>();
indexerProvider.InitializeIndexers(new List<IndexerBase> { mocker.Resolve<MockIndexer>() });
var settings = indexerProvider.GetSettings(typeof(MockIndexer));
settings.Enable = false;
indexerProvider.SaveSettings(settings);
//Assert
Assert.Count(1, indexerProvider.GetAllISettings());
Assert.IsEmpty(indexerProvider.GetEnabledIndexers());
}
}

View File

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.ServiceModel.Syndication;
using System.Text;
using AutoMoq;
using FizzWare.NBuilder;
using Gallio.Framework;
using MbUnit.Framework;
using MbUnit.Framework.ContractVerifiers;
using Moq;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class IndexerTests : TestBase
{
[Test]
[Row("nzbsorg.xml", 0)]
[Row("nzbsrus.xml", 6)]
[Row("newzbin.xml", 1)]
[Row("nzbmatrix.xml", 1)]
public void parse_feed_xml(string fileName, int warns)
{
var mocker = new AutoMoqer();
mocker.GetMock<HttpProvider>()
.Setup(h => h.DownloadStream(It.IsAny<String>(), It.IsAny<NetworkCredential>()))
.Returns(File.OpenRead(".\\Files\\Rss\\" + fileName));
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var mockIndexer = mocker.Resolve<MockIndexer>();
var parseResults = mockIndexer.FetchRss();
foreach (var episodeParseResult in parseResults)
{
var Uri = new Uri(episodeParseResult.NzbUrl);
Assert.DoesNotContain(Uri.PathAndQuery, "//");
}
Assert.IsNotEmpty(parseResults);
Assert.ForAll(parseResults, s => Assert.AreEqual(mockIndexer.Name, s.Indexer));
Assert.ForAll(parseResults, s => Assert.AreNotEqual("", s.NzbTitle));
Assert.ForAll(parseResults, s => Assert.AreNotEqual(null, s.NzbTitle));
ExceptionVerification.ExcpectedWarns(warns);
}
[Test]
public void newzbin()
{
var mocker = new AutoMoqer();
mocker.GetMock<HttpProvider>()
.Setup(h => h.DownloadStream(It.IsAny<String>(), It.IsAny<NetworkCredential>()))
.Returns(File.OpenRead(".\\Files\\Rss\\newzbin.xml"));
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var newzbinProvider = mocker.Resolve<Newzbin>();
var parseResults = newzbinProvider.FetchRss();
foreach (var episodeParseResult in parseResults)
{
var Uri = new Uri(episodeParseResult.NzbUrl);
Assert.DoesNotContain(Uri.PathAndQuery, "//");
}
Assert.IsNotEmpty(parseResults);
Assert.ForAll(parseResults, s => Assert.AreEqual(newzbinProvider.Name, s.Indexer));
Assert.ForAll(parseResults, s => Assert.AreNotEqual("", s.NzbTitle));
Assert.ForAll(parseResults, s => Assert.AreNotEqual(null, s.NzbTitle));
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
[Row("Adventure.Inc.S03E19.DVDRip.XviD-OSiTV", 3, 19, QualityTypes.DVD)]
public void custome_parser_partial_success(string title, int season, int episode, QualityTypes quality)
{
var mocker = new AutoMoqer();
const string summary = "My fake summary";
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var fakeRssItem = Builder<SyndicationItem>.CreateNew()
.With(c => c.Title = new TextSyndicationContent(title))
.With(c => c.Summary = new TextSyndicationContent(summary))
.Build();
var result = mocker.Resolve<CustomParserIndexer>().ParseFeed(fakeRssItem);
Assert.IsNotNull(result);
Assert.AreEqual(summary, result.EpisodeTitle);
Assert.AreEqual(season, result.SeasonNumber);
Assert.AreEqual(episode, result.EpisodeNumbers[0]);
Assert.AreEqual(quality, result.Quality);
}
[Test]
[Row("Adventure.Inc.DVDRip.XviD-OSiTV")]
public void custome_parser_full_parse(string title)
{
var mocker = new AutoMoqer();
const string summary = "My fake summary";
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
var fakeRssItem = Builder<SyndicationItem>.CreateNew()
.With(c => c.Title = new TextSyndicationContent(title))
.With(c => c.Summary = new TextSyndicationContent(summary))
.Build();
var result = mocker.Resolve<CustomParserIndexer>().ParseFeed(fakeRssItem);
Assert.IsNotNull(result);
Assert.AreEqual(summary, result.EpisodeTitle);
ExceptionVerification.ExcpectedWarns(1);
}
[Test]
public void downloadFeed()
{
var mocker = new AutoMoqer();
mocker.SetConstant(new HttpProvider());
var fakeSettings = Builder<IndexerSetting>.CreateNew().Build();
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetSettings(It.IsAny<Type>()))
.Returns(fakeSettings);
mocker.Resolve<TestUrlIndexer>().FetchRss();
ExceptionVerification.IgnoreWarns();
}
[Test]
public void nzbsorg_search_returns_valid_results()
{
var mocker = new AutoMoqer();
mocker.GetMock<ConfigProvider>()
.SetupGet(c => c.NzbsOrgUId)
.Returns("43516");
mocker.GetMock<ConfigProvider>()
.SetupGet(c => c.NzbsOrgHash)
.Returns("bc8edb4cc49d4ae440775adec5ac001f");
mocker.Resolve<HttpProvider>();
var result = mocker.Resolve<NzbsOrg>().FetchEpisode("Simpsons", 21, 23);
Assert.IsNotEmpty(result);
Assert.ForAll(result, r => r.CleanTitle == "simpsons");
Assert.ForAll(result, r => r.SeasonNumber == 21);
Assert.ForAll(result, r => r.EpisodeNumbers.Contains(23));
}
}
}

View File

@ -114,13 +114,13 @@ public void no_concurent_jobs()
var timerProvider = mocker.Resolve<JobProvider>();
timerProvider.Initialize();
var firstRun = timerProvider.QueueJob(typeof(SlowJob),1);
var secondRun = timerProvider.QueueJob(typeof(SlowJob),2);
var third = timerProvider.QueueJob(typeof(SlowJob),3);
var firstRun = timerProvider.QueueJob(typeof(SlowJob), 1);
var secondRun = timerProvider.QueueJob(typeof(SlowJob), 2);
var third = timerProvider.QueueJob(typeof(SlowJob), 3);
Thread.Sleep(10000);
//Asserts are done in ExceptionVerification
}

View File

@ -86,9 +86,11 @@
</ItemGroup>
<ItemGroup>
<Compile Include="DownloadProviderTest.cs" />
<Compile Include="EpisodeSearchJobTest.cs" />
<Compile Include="EpisodeStatusTest.cs" />
<Compile Include="ImportNewSeriesJobTest.cs" />
<Compile Include="DiskScanJobTest.cs" />
<Compile Include="IndexerTests.cs" />
<Compile Include="InventoryProviderTest.cs" />
<Compile Include="Framework\AutoMoq\AutoMoqer.cs" />
<Compile Include="Framework\AutoMoq\AutoMoqerTest.cs" />

View File

@ -63,6 +63,9 @@ public void tvdbid_is_preserved([RandomNumbers(Minimum = 100, Maximum = 999, Cou
public void enteties_toString()
{
Console.WriteLine(new Episode().ToString());
Console.WriteLine(new Season().ToString());
Console.WriteLine(new Series().ToString());
Console.WriteLine(new EpisodeFile().ToString());
}
[Test]

View File

@ -53,12 +53,12 @@ public static StandardKernel NinjectKernel
private static void InitializeApp()
{
BindKernel();
LogConfiguration.Setup();
Migrations.Run();
ForceMigration(_kernel.Get<IRepository>());
SetupDefaultQualityProfiles(_kernel.Get<IRepository>()); //Setup the default QualityProfiles on start-up
BindIndexers();
@ -110,8 +110,6 @@ private static void BindIndexers()
_kernel.Bind<IndexerBase>().To<NzbMatrix>().InSingletonScope();
_kernel.Bind<IndexerBase>().To<NzbsRUs>().InSingletonScope();
_kernel.Bind<IndexerBase>().To<Newzbin>().InSingletonScope();
var indexers = _kernel.GetAll<IndexerBase>();
_kernel.Get<IndexerProvider>().InitializeIndexers(indexers.ToList());
}
private static void BindJobs()

View File

@ -96,7 +96,7 @@
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet>Properties\AnalysisRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
@ -264,6 +264,7 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Properties\AnalysisRules.ruleset" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Migrator.net\Migrator.Framework\Migrator.Framework.csproj">

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Copy of Microsoft Basic Correctness Rules" Description="These rules focus on logic errors and common mistakes made in the usage of framework APIs. Include this rule set to expand on the list of warnings reported by the minimum recommended rules." ToolsVersion="10.0">
<Include Path="minimumrecommendedrules.ruleset" Action="Default" />
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1008" Action="Warning" />
<Rule Id="CA1013" Action="Warning" />
<Rule Id="CA1301" Action="None" />
<Rule Id="CA1806" Action="Warning" />
<Rule Id="CA1816" Action="Warning" />
<Rule Id="CA1819" Action="Warning" />
<Rule Id="CA1820" Action="Warning" />
<Rule Id="CA1903" Action="Warning" />
<Rule Id="CA2004" Action="Warning" />
<Rule Id="CA2006" Action="Warning" />
<Rule Id="CA2101" Action="None" />
<Rule Id="CA2102" Action="Warning" />
<Rule Id="CA2105" Action="Warning" />
<Rule Id="CA2106" Action="Warning" />
<Rule Id="CA2115" Action="Warning" />
<Rule Id="CA2119" Action="Warning" />
<Rule Id="CA2120" Action="Warning" />
<Rule Id="CA2121" Action="Warning" />
<Rule Id="CA2122" Action="None" />
<Rule Id="CA2130" Action="Warning" />
<Rule Id="CA2205" Action="Warning" />
<Rule Id="CA2215" Action="Warning" />
<Rule Id="CA2221" Action="Warning" />
<Rule Id="CA2222" Action="Warning" />
<Rule Id="CA2223" Action="Warning" />
<Rule Id="CA2224" Action="Warning" />
<Rule Id="CA2226" Action="Warning" />
<Rule Id="CA2231" Action="Warning" />
<Rule Id="CA2239" Action="Warning" />
</Rules>
</RuleSet>

View File

@ -6,7 +6,6 @@
using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.Indexer
{
@ -24,6 +23,11 @@ protected IndexerBase(HttpProvider httpProvider, ConfigProvider configProvider)
_logger = LogManager.GetLogger(GetType().ToString());
}
public IndexerBase()
{
}
/// <summary>
/// Gets the name for the feed
/// </summary>
@ -35,15 +39,6 @@ protected IndexerBase(HttpProvider httpProvider, ConfigProvider configProvider)
protected abstract string[] Urls { get; }
/// <summary>
/// Gets the rss url for specific episode search
/// </summary>
/// <param name="seriesTitle">The series title.</param>
/// <param name="seasonNumber">The season number.</param>
/// <param name="episodeNumber">The episode number.</param>
/// <returns></returns>
protected abstract IList<String> GetSearchUrls(string seriesTitle, int seasonNumber, int episodeNumber);
/// <summary>
/// Gets the credential.
/// </summary>
@ -53,10 +48,37 @@ protected virtual NetworkCredential Credentials
}
/// <summary>
/// Gets the rss url for specific episode search
/// </summary>
/// <param name="seriesTitle">The series title.</param>
/// <param name="seasonNumber">The season number.</param>
/// <param name="episodeNumber">The episode number.</param>
/// <returns></returns>
protected abstract IList<String> GetSearchUrls(string seriesTitle, int seasonNumber, int episodeNumber);
/// <summary>
/// This method can be overwritten to provide indexer specific info parsing
/// </summary>
/// <param name="item">RSS item that needs to be parsed</param>
/// <param name="currentResult">Result of the built in parse function.</param>
/// <returns></returns>
protected virtual EpisodeParseResult CustomParser(SyndicationItem item, EpisodeParseResult currentResult)
{
return currentResult;
}
/// <summary>
/// Generates direct link to download an NZB
/// </summary>
/// <param name = "item">RSS Feed item to generate the link for</param>
/// <returns>Download link URL</returns>
protected abstract string NzbDownloadUrl(SyndicationItem item);
/// <summary>
/// Fetches RSS feed and process each news item.
/// </summary>
public IList<EpisodeParseResult> FetchRss()
public virtual IList<EpisodeParseResult> FetchRss()
{
_logger.Debug("Fetching feeds from " + Name);
@ -72,7 +94,7 @@ public IList<EpisodeParseResult> FetchRss()
}
public IList<EpisodeParseResult> FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber)
public virtual IList<EpisodeParseResult> FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber)
{
_logger.Debug("Searching {0} for {1}-S{2}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber);
@ -90,7 +112,7 @@ public IList<EpisodeParseResult> FetchEpisode(string seriesTitle, int seasonNumb
}
private IList<EpisodeParseResult> Fetch(string url)
private IEnumerable<EpisodeParseResult> Fetch(string url)
{
var result = new List<EpisodeParseResult>();
@ -140,23 +162,5 @@ public EpisodeParseResult ParseFeed(SyndicationItem item)
return CustomParser(item, episodeParseResult);
}
/// <summary>
/// This method can be overwritten to provide indexer specific info parsing
/// </summary>
/// <param name="item">RSS item that needs to be parsed</param>
/// <param name="currentResult">Result of the built in parse function.</param>
/// <returns></returns>
protected virtual EpisodeParseResult CustomParser(SyndicationItem item, EpisodeParseResult currentResult)
{
return currentResult;
}
/// <summary>
/// Generates direct link to download an NZB
/// </summary>
/// <param name = "item">RSS Feed item to generate the link for</param>
/// <returns>Download link URL</returns>
protected abstract string NzbDownloadUrl(SyndicationItem item);
}
}

View File

@ -13,6 +13,8 @@ public class IndexerProvider
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IRepository _repository;
private IList<IndexerBase> _indexers = new List<IndexerBase>();
public IndexerProvider(IRepository repository)
{
_repository = repository;
@ -23,7 +25,13 @@ public IndexerProvider()
}
public virtual List<IndexerSetting> All()
public virtual IList<IndexerBase> GetEnabledIndexers()
{
var all = GetAllISettings();
return _indexers.Where(i => all.Exists(c => c.IndexProviderType == i.GetType().ToString() && c.Enable)).ToList();
}
public virtual List<IndexerSetting> GetAllISettings()
{
return _repository.All<IndexerSetting>().ToList();
}
@ -47,23 +55,20 @@ public virtual IndexerSetting GetSettings(Type type)
return _repository.Single<IndexerSetting>(s => s.IndexProviderType == type.ToString());
}
public virtual IndexerSetting GetSettings(int id)
{
return _repository.Single<IndexerSetting>(s => s.Id == id);
}
public virtual void InitializeIndexers(IList<IndexerBase> indexers)
{
Logger.Info("Initializing indexers. Count {0}", indexers.Count);
var currentIndexers = All();
_indexers = indexers;
var currentIndexers = GetAllISettings();
foreach (var feedProvider in indexers)
{
IndexerBase indexerLocal = feedProvider;
if (!currentIndexers.Exists(c => c.IndexProviderType == indexerLocal.GetType().ToString()))
{
var settings = new IndexerSetting()
var settings = new IndexerSetting
{
Enable = false,
IndexProviderType = indexerLocal.GetType().ToString(),

View File

@ -12,20 +12,23 @@ public class InventoryProvider
private readonly SeasonProvider _seasonProvider;
private readonly EpisodeProvider _episodeProvider;
private readonly HistoryProvider _historyProvider;
private readonly SabProvider _sabProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public InventoryProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, EpisodeProvider episodeProvider, HistoryProvider historyProvider, SabProvider sabProvider)
public InventoryProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, EpisodeProvider episodeProvider, HistoryProvider historyProvider)
{
_seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
_episodeProvider = episodeProvider;
_historyProvider = historyProvider;
_sabProvider = sabProvider;
}
internal bool IsNeeded(EpisodeParseResult parseResult)
public InventoryProvider()
{
}
public virtual bool IsNeeded(EpisodeParseResult parseResult)
{
var series = _seriesProvider.FindSeries(parseResult.CleanTitle);

View File

@ -5,12 +5,12 @@
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.Jobs
{
public class EpisodeSearchJob : IJob
{
private readonly IEnumerable<IndexerBase> _indexers;
private readonly InventoryProvider _inventoryProvider;
private readonly DownloadProvider _downloadProvider;
private readonly IndexerProvider _indexerProvider;
@ -19,9 +19,8 @@ public class EpisodeSearchJob : IJob
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public EpisodeSearchJob(IEnumerable<IndexerBase> indexers, InventoryProvider inventoryProvider, DownloadProvider downloadProvider, IndexerProvider indexerProvider, EpisodeProvider episodeProvider)
public EpisodeSearchJob(InventoryProvider inventoryProvider, DownloadProvider downloadProvider, IndexerProvider indexerProvider, EpisodeProvider episodeProvider)
{
_indexers = indexers;
_inventoryProvider = inventoryProvider;
_downloadProvider = downloadProvider;
_indexerProvider = indexerProvider;
@ -40,27 +39,53 @@ public int DefaultInterval
public void Start(ProgressNotification notification, int targetId)
{
var reports = new List<EpisodeParseResult>();
if (targetId <= 0)
throw new ArgumentOutOfRangeException("targetId");
var episode = _episodeProvider.GetEpisode(targetId);
if (episode == null)
{
Logger.Error("Unbale to find an episode {0} in database", targetId);
return;
}
var indexers = _indexerProvider.GetEnabledIndexers();
var reports = new List<EpisodeParseResult>();
foreach (var indexer in _indexers.Where(i => _indexerProvider.GetSettings(i.GetType()).Enable))
foreach (var indexer in indexers)
{
try
{
notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name);
reports.AddRange(indexer.FetchRss());
IList<EpisodeParseResult> indexerResults = new List<EpisodeParseResult>();
if (episode.IsDailyEpisode)
{
//TODO:Add support for daily episodes
}
else
{
indexerResults = indexer.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber);
}
reports.AddRange(indexerResults);
}
catch (Exception e)
{
Logger.ErrorException("An error has occured while fetching items from " + indexer.Name, e);
Logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
}
}
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
notification.CurrentMessage = "Proccessing search results";
notification.CurrentMessage = "Processing search results";
foreach (var episodeParseResult in reports.OrderBy(c => c.Quality).ThenBy(c => c.Proper))
ProcessResults(notification, episode, reports);
}
public void ProcessResults(ProgressNotification notification, Episode episode, IEnumerable<EpisodeParseResult> reports)
{
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality).ThenByDescending(c => c.Proper))
{
try
{
@ -73,13 +98,11 @@ public void Start(ProgressNotification notification, int targetId)
}
catch (Exception e)
{
Logger.ErrorException("An error has occured while processing parse result items from " + episodeParseResult, e);
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
}
}
Logger.Warn("Unable to find {0} in any of indexers.", episode);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
@ -21,6 +22,8 @@ public class ImportNewSeriesJob : IJob
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private List<int> _attemptedSeries;
public ImportNewSeriesJob(SeriesProvider seriesProvider, SeasonProvider seasonProvider,
MediaFileProvider mediaFileProvider, UpdateInfoJob updateInfoJob, DiskScanJob diskScanJob)
{
@ -43,12 +46,13 @@ public int DefaultInterval
public void Start(ProgressNotification notification, int targetId)
{
_attemptedSeries = new List<int>();
ScanSeries(notification);
}
private void ScanSeries(ProgressNotification notification)
{
var syncList = _seriesProvider.GetAllSeries().Where(s => s.LastInfoSync == null).ToList();
var syncList = _seriesProvider.GetAllSeries().Where(s => s.LastInfoSync == null && !_attemptedSeries.Contains(s.SeriesId)).ToList();
if (syncList.Count == 0)
{
return;
@ -58,6 +62,7 @@ private void ScanSeries(ProgressNotification notification)
{
try
{
_attemptedSeries.Add(currentSeries.SeriesId);
notification.CurrentMessage = String.Format("Searching for '{0}'", new DirectoryInfo(currentSeries.Path).Name);
_updateInfoJob.Start(notification, currentSeries.SeriesId);

View File

@ -25,6 +25,14 @@ public class Episode
public Boolean Ignored { get; set; }
[SubSonicIgnore]
public Boolean IsDailyEpisode
{
get
{
return EpisodeNumber == 0;
}
}
/// <summary>
/// Gets or sets the grab date.
@ -72,10 +80,12 @@ public EpisodeStatusType Status
public override string ToString()
{
if (EpisodeNumber == 0)
return string.Format("{0} - {1}", Series.Title, AirDate.Date);
var seriesTitle = Series == null ? "[NULL]" : Series.Title;
return string.Format("{0} - S{1:00}E{2}", Series.Title, SeasonNumber, EpisodeNumber);
if (IsDailyEpisode)
return string.Format("{0} - {1}", seriesTitle, AirDate.Date);
return string.Format("{0} - S{1:00}E{2}", seriesTitle, SeasonNumber, EpisodeNumber);
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace NzbDrone.Web.Controllers
{
public class StreamController : Controller
{
//
// GET: /Stream/
public ActionResult Index()
{
return File(@"Z:\Clone High\Season 1\S01E02 - Episode Two- Election Blu-Galoo.avi", "video/divx");
//return File(@"Z:\30 Rock\Season 5\S05E04 - Live Show (East Coast Taping) - HD TV.mkv", "video/divx");
}
}
}

View File

@ -26,7 +26,7 @@ public ActionResult Jobs()
public ActionResult Indexers()
{
return View(_indexerProvider.All());
return View(_indexerProvider.GetAllISettings());
}

View File

@ -31,6 +31,7 @@
<MvcBuildViews>true</MvcBuildViews>
<EnableUpdateable>false</EnableUpdateable>
<ExcludeApp_Data>true</ExcludeApp_Data>
<CodeAnalysisRuleSet>BasicCorrectnessRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -223,6 +224,7 @@
<Compile Include="Controllers\SeriesController.cs" />
<Compile Include="Controllers\SettingsController.cs" />
<Compile Include="Controllers\SharedController.cs" />
<Compile Include="Controllers\StreamController.cs" />
<Compile Include="Controllers\SystemController.cs" />
<Compile Include="Controllers\UpcomingController.cs" />
<Compile Include="Global.asax.cs">

View File

@ -39,6 +39,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>true</UseVSHostingProcess>
<CodeAnalysisRuleSet>BasicCorrectnessRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>