Merge branch 'xem' into 'master'

Conflicts:
	NzbDrone.Common/DiskProvider.cs
	NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs
	NzbDrone.Core/Providers/DecisionEngine/CustomStartDateSpecification.cs
	NzbDrone.Core/Providers/DiskScanProvider.cs
	NzbDrone.Core/Providers/DownloadProvider.cs
pull/4/head
Mark McDowall 12 years ago
commit 5bbe310af5

Binary file not shown.

Binary file not shown.

@ -175,6 +175,18 @@ namespace NzbDrone.Common.Test
Console.WriteLine(new DirectoryInfo(@"C:\DRIVERS").LastWriteTimeUtc);
}
[Test]
public void IsChildOfPath_should_return_true_when_it_is_a_child()
{
Mocker.Resolve<DiskProvider>().IsChildOfPath(@"C:\Test\TV", @"C:\Test").Should().BeTrue();
}
[Test]
public void IsChildOfPath_should_return_false_when_it_is_not_a_child()
{
Mocker.Resolve<DiskProvider>().IsChildOfPath(@"C:\NOT_Test\TV", @"C:\Test").Should().BeFalse();
}
private void VerifyCopy()
{
BinFolder.Refresh();

@ -268,5 +268,12 @@ namespace NzbDrone.Common
return false;
}
public virtual bool IsChildOfPath(string child, string parent)
{
if (Path.GetFullPath(child).StartsWith(Path.GetFullPath(parent)))
return true;
return false;
}
}
}

@ -0,0 +1,7 @@
{
"result": "failure",
"data": [ ],
"message": "no show with the tvdb_id 79488 found"
}

@ -0,0 +1,10 @@
{
"result": "success",
"data": [
"73141",
"79886",
],
"message": ""
}

@ -0,0 +1,32 @@
{
"result": "success",
"data": [
{
"scene": {
"season": 1,
"episode": 1,
"absolute": 1
},
"tvdb": {
"season": 1,
"episode": 1,
"absolute": 1
}
},
{
"scene": {
"season": 1,
"episode": 2,
"absolute": 2
},
"tvdb": {
"season": 1,
"episode": 2,
"absolute": 2
}
}
],
"message": "full mapping for 73388 on tvdb. this was a cached version"
}

@ -0,0 +1,24 @@
{
"result": "success",
"data": {
"220571": [
"Is This a Zombie? Of the Dead",
"Kore wa Zombie Desuka?",
"Kore wa Zombie Desuka? Of the Dead",
"Kore wa Zombie Desuka Of the Dead",
"Kore wa Zombie Desu ka - Of the Dead",
"Kore wa Zombie Desu ka of the Dead"
],
"79151": [
"Fate Stay Night",
"Fate/Zero",
"Fate Zero",
"Fate/Zero (2012)",
"Fate Zero S2",
"Fate Zero"
]
},
"message": ""
}

@ -42,13 +42,15 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
.Callback(() => series[0].LastDiskSync = DateTime.Now);
Mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)))
.Callback(() => series[1].LastDiskSync = DateTime.Now);
Mocker.GetMock<BannerDownloadJob>()
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") >= 0)));
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") > 0)));
Mocker.GetMock<XemUpdateJob>()
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") > 0)));
Mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
@ -121,6 +123,9 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
Mocker.GetMock<XemUpdateJob>()
.Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)));
//Act
Mocker.Resolve<ImportNewSeriesJob>().Start(notification, null);

@ -129,13 +129,14 @@
<Reference Include="System.Transactions" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="TvdbLib, Version=0.8.8.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\TvdbLib.dll</HintPath>
</Reference>
<Reference Include="WebActivator, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WebActivator.1.5\lib\net40\WebActivator.dll</HintPath>
</Reference>
<Reference Include="XemLib">
<HintPath>..\Libraries\XemLib\XemLib.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="QualityTypesTest.cs" />
@ -156,6 +157,7 @@
<Compile Include="ProviderTests\DiskScanProviderTests\GetVideoFilesFixture.cs" />
<Compile Include="ProviderTests\DiskScanProviderTests\ScanFixture.cs" />
<Compile Include="ProviderTests\DownloadClientTests\PneumaticProviderFixture.cs" />
<Compile Include="ProviderTests\EpisodeProviderTests\GetEpisodeBySceneNumberFixture.cs" />
<Compile Include="ProviderTests\Metadata\Xbmc_ForEpisodeFile_Fixture.cs" />
<Compile Include="ProviderTests\Metadata\Xbmc_ForSeries_Fixture.cs" />
<Compile Include="ProviderTests\PostDownloadProviderTests\ProcessDropDirectoryFixture.cs" />
@ -194,9 +196,11 @@
<Compile Include="JobTests\AppUpdateJobFixture.cs" />
<Compile Include="ProviderTests\UpdateProviderTests\GetUpdateLogFixture.cs" />
<Compile Include="ProviderTests\UpdateProviderTests\GetAvilableUpdateFixture.cs" />
<Compile Include="ProviderTests\XemCommunicationProviderTests\GetSceneTvdbMappingsFixture.cs" />
<Compile Include="ProviderTests\XemCommunicationProviderTests\GetXemSeriesIdsFixture.cs" />
<Compile Include="Services\ParseErrorServiceFixture.cs" />
<Compile Include="SortHelperTest.cs" />
<Compile Include="ProviderTests\EpisodeProviderTest_DeleteInvalidEpisodes.cs" />
<Compile Include="ProviderTests\EpisodeProviderTests\EpisodeProviderTest_DeleteInvalidEpisodes.cs" />
<Compile Include="ProviderTests\DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="ProviderTests\QualityTypeProviderTest.cs" />
<Compile Include="ProviderTests\MisnamedProviderTest.cs" />
@ -206,7 +210,7 @@
<Compile Include="CentralDispatchFixture.cs" />
<Compile Include="ProviderTests\XbmcProviderTest.cs" />
<Compile Include="ProviderTests\DiskScanProviderTests\MoveEpisodeFileFixture.cs" />
<Compile Include="ProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
<Compile Include="ProviderTests\EpisodeProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
<Compile Include="ProviderTests\DiskScanProviderTests\ImportFileFixture.cs" />
<Compile Include="FluentTest.cs" />
<Compile Include="ProviderTests\LogProviderTests\LogProviderFixture.cs" />
@ -228,7 +232,7 @@
<Compile Include="ProviderTests\HistoryProviderTest.cs" />
<Compile Include="ProviderTests\MediaFileProviderTest.cs" />
<Compile Include="ProviderTests\ConfigProviderTests\ConfigProviderFixture.cs" />
<Compile Include="ProviderTests\EpisodeProviderTest.cs" />
<Compile Include="ProviderTests\EpisodeProviderTests\EpisodeProviderTest.cs" />
<Compile Include="Framework\TestDbHelper.cs" />
<Compile Include="ParserFixture\ParserTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -335,6 +339,18 @@
<SubType>Designer</SubType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="Files\Xem\Ids.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Xem\Failure.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Xem\Names.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Xem\Mappings.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="log.config">
<SubType>Designer</SubType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

@ -32,6 +32,9 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
{
_customStartDateSpecification = Mocker.Resolve<CustomStartDateSpecification>();
firstEpisode = new Episode { AirDate = DateTime.Today };
secondEpisode = new Episode { AirDate = DateTime.Today };
fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Monitored = true)
.With(c => c.CustomStartDate = null)
@ -43,6 +46,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Series = fakeSeries,
EpisodeNumbers = new List<int> { 3, 4 },
SeasonNumber = 12,
Episodes = new List<Episode> { firstEpisode, secondEpisode }
};
parseResultSingle = new EpisodeParseResult
@ -51,16 +55,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Series = fakeSeries,
EpisodeNumbers = new List<int> { 3 },
SeasonNumber = 12,
Episodes = new List<Episode> { firstEpisode }
};
firstEpisode = new Episode { AirDate = DateTime.Today };
secondEpisode = new Episode { AirDate = DateTime.Today };
var singleEpisodeList = new List<Episode> { firstEpisode };
var doubleEpisodeList = new List<Episode> { firstEpisode, secondEpisode };
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultSingle)).Returns(singleEpisodeList);
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultMulti)).Returns(doubleEpisodeList);
}
private void WithFirstEpisodeLastYear()

@ -31,6 +31,12 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Mocker.Resolve<QualityUpgradeSpecification>();
_upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>();
firstFile = new EpisodeFile { Quality = QualityTypes.Bluray1080p, Proper = true };
secondFile = new EpisodeFile { Quality = QualityTypes.Bluray1080p, Proper = true };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = null } };
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = secondFile }, new Episode { EpisodeFile = null } };
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.QualityProfile = new QualityProfile { Cutoff = QualityTypes.Bluray1080p })
.Build();
@ -41,6 +47,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Quality = new QualityModel(QualityTypes.DVD, true),
EpisodeNumbers = new List<int> { 3, 4 },
SeasonNumber = 12,
Episodes = doubleEpisodeList
};
parseResultSingle = new EpisodeParseResult
@ -49,17 +56,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Quality = new QualityModel(QualityTypes.DVD, true),
EpisodeNumbers = new List<int> { 3 },
SeasonNumber = 12,
Episodes = singleEpisodeList
};
firstFile = new EpisodeFile { Quality = QualityTypes.Bluray1080p, Proper = true };
secondFile = new EpisodeFile { Quality = QualityTypes.Bluray1080p, Proper = true };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = null } };
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = secondFile }, new Episode { EpisodeFile = null } };
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultSingle)).Returns(singleEpisodeList);
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultMulti)).Returns(doubleEpisodeList);
}
private void WithFirstFileUpgradable()
@ -73,9 +71,9 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
}
[Test]
public void should_return_false_if_single_episode_doesnt_exist_on_disk()
public void should_return_true_if_single_episode_doesnt_exist_on_disk()
{
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultSingle)).Returns(new List<Episode>());
parseResultSingle.Episodes = new List<Episode>();
_upgradeDisk.IsSatisfiedBy(parseResultSingle).Should().BeTrue();
}

@ -31,6 +31,13 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Mocker.Resolve<QualityUpgradeSpecification>();
_upgradeHistory = Mocker.Resolve<UpgradeHistorySpecification>();
var singleEpisodeList = new List<Episode> { new Episode { SeasonNumber = 12, EpisodeNumber = 3 } };
var doubleEpisodeList = new List<Episode> {
new Episode { SeasonNumber = 12, EpisodeNumber = 3 },
new Episode { SeasonNumber = 12, EpisodeNumber = 4 },
new Episode { SeasonNumber = 12, EpisodeNumber = 5 }
};
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.QualityProfile = new QualityProfile { Cutoff = QualityTypes.Bluray1080p })
.Build();
@ -41,6 +48,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Quality = new QualityModel(QualityTypes.DVD, true),
EpisodeNumbers = new List<int> { 3, 4 },
SeasonNumber = 12,
Episodes = doubleEpisodeList
};
parseResultSingle = new EpisodeParseResult
@ -49,21 +57,12 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
Quality = new QualityModel(QualityTypes.DVD, true),
EpisodeNumbers = new List<int> { 3 },
SeasonNumber = 12,
Episodes = singleEpisodeList
};
firstQuality = new QualityModel(QualityTypes.Bluray1080p, true);
secondQuality = new QualityModel(QualityTypes.Bluray1080p, true);
var singleEpisodeList = new List<Episode> { new Episode { SeasonNumber = 12, EpisodeNumber = 3 } };
var doubleEpisodeList = new List<Episode> {
new Episode { SeasonNumber = 12, EpisodeNumber = 3 },
new Episode { SeasonNumber = 12, EpisodeNumber = 4 },
new Episode { SeasonNumber = 12, EpisodeNumber = 5 }
};
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultSingle)).Returns(singleEpisodeList);
Mocker.GetMock<EpisodeProvider>().Setup(c => c.GetEpisodesByParseResult(parseResultMulti)).Returns(doubleEpisodeList);
Mocker.GetMock<HistoryProvider>().Setup(c => c.GetBestQualityInHistory(fakeSeries.SeriesId, 12, 3)).Returns(firstQuality);
Mocker.GetMock<HistoryProvider>().Setup(c => c.GetBestQualityInHistory(fakeSeries.SeriesId, 12, 4)).Returns(secondQuality);
Mocker.GetMock<HistoryProvider>().Setup(c => c.GetBestQualityInHistory(fakeSeries.SeriesId, 12, 5)).Returns<QualityModel>(null);

@ -175,6 +175,9 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
.Setup(p => p.Exists(It.IsAny<String>()))
.Returns(false);
Mocker.GetMock<DiskProvider>(MockBehavior.Strict)
.Setup(e => e.IsChildOfPath(fileName, fakeSeries.Path)).Returns(false);
Mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisodesByParseResult(It.IsAny<EpisodeParseResult>()))
.Returns(new List<Episode>());
@ -392,5 +395,47 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
Mocker.GetMock<EpisodeProvider>().Verify(p => p.UpdateEpisode(It.IsAny<Episode>()), Times.Never());
Mocker.GetMock<DiskProvider>().Verify(p => p.DeleteFile(It.IsAny<string>()), Times.Never());
}
[Test]
public void should_set_parseResult_SceneSource_if_not_in_series_Path()
{
var series = Builder<Series>
.CreateNew()
.With(s => s.Path == @"C:\Test\TV\30 Rock")
.Build();
const string path = @"C:\Test\Unsorted TV\30 Rock\30.rock.s01e01.pilot.mkv";
Mocker.GetMock<EpisodeProvider>().Setup(s => s.GetEpisodesByParseResult(It.IsAny<EpisodeParseResult>()))
.Returns(new List<Episode>());
Mocker.GetMock<DiskProvider>().Setup(s => s.IsChildOfPath(path, series.Path))
.Returns(false);
Mocker.Resolve<DiskScanProvider>().ImportFile(series, path);
Mocker.Verify<EpisodeProvider>(s => s.GetEpisodesByParseResult(It.Is<EpisodeParseResult>(p => p.SceneSource)), Times.Once());
}
[Test]
public void should_not_set_parseResult_SceneSource_if_in_series_Path()
{
var series = Builder<Series>
.CreateNew()
.With(s => s.Path == @"C:\Test\TV\30 Rock")
.Build();
const string path = @"C:\Test\TV\30 Rock\30.rock.s01e01.pilot.mkv";
Mocker.GetMock<EpisodeProvider>().Setup(s => s.GetEpisodesByParseResult(It.IsAny<EpisodeParseResult>()))
.Returns(new List<Episode>());
Mocker.GetMock<DiskProvider>().Setup(s => s.IsChildOfPath(path, series.Path))
.Returns(true);
Mocker.Resolve<DiskScanProvider>().ImportFile(series, path);
Mocker.Verify<EpisodeProvider>(s => s.GetEpisodesByParseResult(It.Is<EpisodeParseResult>(p => p.SceneSource == false)), Times.Once());
}
}
}

@ -52,6 +52,7 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, false))
.With(c => c.Series = Builder<Series>.CreateNew().Build())
.With(c => c.EpisodeNumbers = new List<int>{2})
.With(c => c.Episodes = episodes)
.Build();
}
@ -191,6 +192,15 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(c => c.Title = "My Series Name")
.Build();
var fakeEpisodes = new List<Episode>();
foreach(var episode in episodes)
fakeEpisodes.Add(Builder<Episode>
.CreateNew()
.With(e => e.EpisodeNumber = episode)
.With(e => e.Title = title)
.Build());
var parsResult = new EpisodeParseResult()
{
AirDate = DateTime.Now,
@ -198,7 +208,8 @@ namespace NzbDrone.Core.Test.ProviderTests
Quality = new QualityModel(quality, proper),
SeasonNumber = seasons,
Series = series,
EpisodeTitle = title
EpisodeTitle = title,
Episodes = fakeEpisodes
};
Mocker.Resolve<DownloadProvider>().GetDownloadTitle(parsResult).Should().Be(expected);
@ -234,16 +245,49 @@ namespace NzbDrone.Core.Test.ProviderTests
.With(c => c.Title = "My Series Name")
.Build();
var episode = Builder<Episode>.CreateNew()
.With(e => e.Title = "My Episode Title")
.Build();
var parsResult = new EpisodeParseResult
{
AirDate = new DateTime(2011, 12, 1),
Quality = new QualityModel(QualityTypes.Bluray720p, proper),
Series = series,
EpisodeTitle = "My Episode Title",
Episodes = new List<Episode>{ episode }
};
return Mocker.Resolve<DownloadProvider>().GetDownloadTitle(parsResult);
}
[Test]
public void should_not_repeat_the_same_episode_title()
{
var series = Builder<Series>.CreateNew()
.With(c => c.Title = "My Series Name")
.Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(2)
.All()
.With(e => e.SeasonNumber = 5)
.TheFirst(1)
.With(e => e.Title = "My Episode Title (1)")
.TheLast(1)
.With(e => e.Title = "My Episode Title (2)")
.Build();
var parsResult = new EpisodeParseResult
{
AirDate = DateTime.Now,
EpisodeNumbers = new List<int>{ 10, 11 },
Quality = new QualityModel(QualityTypes.HDTV, false),
SeasonNumber = 35,
Series = series,
Episodes = fakeEpisodes
};
Mocker.Resolve<DownloadProvider>().GetDownloadTitle(parsResult).Should().Be("My Series Name - 5x01-5x02 - My Episode Title [HDTV]");
}
}
}

@ -2,9 +2,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
@ -15,11 +13,10 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using XemLib.Data;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests
namespace NzbDrone.Core.Test.ProviderTests.EpisodeProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
@ -161,7 +158,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
@ -172,7 +169,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
//Act
@ -195,7 +192,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(10).
All()
.With(l => l.Language = "en").And(e => e.FirstAired = DateTime.Now)
.With(l => l.Language = new TvdbLanguage(0, "eng", "a")).And(e => e.FirstAired = DateTime.Now)
.TheFirst(7).With(e => e.FirstAired = new DateTime(1800, 1, 1))
.Build())
).With(c => c.Id = seriesId).Build();
@ -207,7 +204,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -236,7 +233,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(1)
.All()
.With(l => l.Language = "en").And(e => e.FirstAired = DateTime.Now)
.With(l => l.Language = new TvdbLanguage(0, "eng", "a")).And(e => e.FirstAired = DateTime.Now)
.TheFirst(1).With(e => e.FirstAired = new DateTime(1800, 1, 1))
.Build())
).With(c => c.Id = seriesId).Build();
@ -248,7 +245,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeEpisode);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeTvDbEpisodes);
//Act
@ -271,7 +268,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.TheFirst(1)
.With(e => e.EpisodeNumber = 0)
.With(e => e.SeasonNumber = 15)
@ -285,7 +282,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -324,7 +321,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -362,7 +359,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -395,7 +392,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -428,7 +425,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -451,7 +448,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.With(e => e.SeasonNumber = 0)
.Build())
).With(c => c.Id = seriesId).Build();
@ -463,7 +460,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
Mocker.GetMock<SeasonProvider>()
@ -493,7 +490,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var currentEpisodes = new List<Episode>();
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -528,7 +525,7 @@ namespace NzbDrone.Core.Test.ProviderTests
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -565,7 +562,7 @@ namespace NzbDrone.Core.Test.ProviderTests
.Returns(fakeEpisodeList);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeTvDbResult);
//Act
@ -602,7 +599,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -643,7 +640,7 @@ namespace NzbDrone.Core.Test.ProviderTests
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
var updatedEpisodes = new List<Episode>();
@ -692,7 +689,7 @@ namespace NzbDrone.Core.Test.ProviderTests
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
var updatedEpisodes = new List<Episode>();
@ -738,7 +735,7 @@ namespace NzbDrone.Core.Test.ProviderTests
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
var updatedEpisodes = new List<Episode>();
@ -777,7 +774,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.With(e => e.SeasonNumber = 5)
.TheFirst(1)
.With(e => e.EpisodeNumber = 1)
@ -796,7 +793,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeEpisode);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<SeasonProvider>()
@ -1487,7 +1484,7 @@ namespace NzbDrone.Core.Test.ProviderTests
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.With(e => e.EpisodeNumber = 0)
.TheFirst(1)
.With(e => e.SeasonNumber = 1)
@ -1509,7 +1506,7 @@ namespace NzbDrone.Core.Test.ProviderTests
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true, false, false))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
//Act

@ -2,17 +2,15 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using XemLib.Data;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests
namespace NzbDrone.Core.Test.ProviderTests.EpisodeProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
@ -27,7 +25,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var tvDbSeries = Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build();
@ -65,7 +63,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var tvDbSeries = Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build();
var fakeSeries = Builder<Series>.CreateNew()
@ -102,7 +100,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var tvDbSeries = Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build();
var fakeSeries = Builder<Series>.CreateNew()
@ -139,7 +137,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var tvDbSeries = Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build();
var fakeSeries = Builder<Series>.CreateNew()
@ -179,7 +177,7 @@ namespace NzbDrone.Core.Test.ProviderTests
var tvDbSeries = Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
All()
.With(l => l.Language = "en")
.With(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build();
var fakeSeries = Builder<Series>.CreateNew()

@ -5,17 +5,14 @@ using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
namespace NzbDrone.Core.Test.ProviderTests
namespace NzbDrone.Core.Test.ProviderTests.EpisodeProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming

@ -0,0 +1,77 @@
// ReSharper disable RedundantUsingDirective
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ProviderTests.EpisodeProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class GetEpisodeBySceneNumberFixture : CoreTest
{
private Series _series;
private Episode _episode;
[SetUp]
public void Setup()
{
WithRealDb();
_series = Builder<Series>
.CreateNew()
.Build();
Db.Insert(_series);
}
public void WithNullSceneNumbering()
{
_episode = Builder<Episode>
.CreateNew()
.With(e => e.SeriesId = _series.SeriesId)
.Build();
Db.Insert(_episode);
Db.Execute("UPDATE Episodes SET SceneSeasonNumber = NULL, SceneEpisodeNumber = NULL");
}
public void WithSceneNumbering()
{
_episode = Builder<Episode>
.CreateNew()
.With(e => e.SeriesId = _series.SeriesId)
.Build();
Db.Insert(_episode);
}
[Test]
public void should_return_null_if_no_episodes_in_db()
{
Mocker.Resolve<EpisodeProvider>().GetEpisodeBySceneNumbering(_series.SeriesId, 1, 1).Should().BeNull();
}
[Test]
public void should_return_null_if_no_matching_episode_is_found()
{
WithNullSceneNumbering();
Mocker.Resolve<EpisodeProvider>().GetEpisodeBySceneNumbering(_series.SeriesId, 1, 1).Should().BeNull();
}
[Test]
public void should_return_episode_if_matching_episode_is_found()
{
WithSceneNumbering();
var result = Mocker.Resolve<EpisodeProvider>()
.GetEpisodeBySceneNumbering(_series.SeriesId, _episode.SceneSeasonNumber, _episode.SceneEpisodeNumber);
result.EpisodeId.Should().Be(_episode.EpisodeId);
}
}
}

@ -699,5 +699,43 @@ namespace NzbDrone.Core.Test.ProviderTests.MediaFileProviderTests
//Assert
result.Should().Be("30 Rock - S06E06-E07 - Hello + World");
}
[Test]
public void should_have_two_episodeTitles_when_distinct_count_is_two()
{
//Setup
var fakeConfig = Mocker.GetMock<ConfigProvider>();
fakeConfig.SetupGet(c => c.SortingIncludeSeriesName).Returns(true);
fakeConfig.SetupGet(c => c.SortingIncludeEpisodeTitle).Returns(true);
fakeConfig.SetupGet(c => c.SortingAppendQuality).Returns(false);
fakeConfig.SetupGet(c => c.SortingSeparatorStyle).Returns(0);
fakeConfig.SetupGet(c => c.SortingNumberStyle).Returns(2);
fakeConfig.SetupGet(c => c.SortingReplaceSpaces).Returns(false);
fakeConfig.SetupGet(c => c.SortingMultiEpisodeStyle).Returns(3);
var episode = Builder<Episode>.CreateNew()
.With(e => e.Title = "Hello (3)")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 6)
.Build();
var episode2 = Builder<Episode>.CreateNew()
.With(e => e.Title = "Hello (2)")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 7)
.Build();
var episode3 = Builder<Episode>.CreateNew()
.With(e => e.Title = "World")
.With(e => e.SeasonNumber = 6)
.With(e => e.EpisodeNumber = 8)
.Build();
//Act
string result = Mocker.Resolve<MediaFileProvider>().GetNewFilename(new List<Episode> { episode, episode2, episode3 }, "30 Rock", QualityTypes.HDTV, false, new EpisodeFile());
//Assert
result.Should().Be("30 Rock - S06E06-E07-E08 - Hello + World");
}
}
}

@ -17,8 +17,8 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
using XemLib.Data;
using XemLib.Data.Banner;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
@ -52,30 +52,31 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
.With(e => e.SeriesId = 79488)
.With(e => e.SeasonNumber = 1)
.With(e => e.Directors = new List<string>{ "Fake Director" })
.With(e => e.Writers = new List<string>{ "Fake Writer" })
.With(e => e.Writer = new List<string>{ "Fake Writer" })
.With(e => e.GuestStars = new List<string> { "Guest Star 1", "Guest Star 2", "Guest Star 3", "" })
.Build();
var seasonBanners = Builder<TvdbSeasonBanner>
.CreateListOfSize(4)
.TheFirst(2)
.With(b => b.SeasonNumber = 1)
.With(b => b.Season = 1)
.TheLast(2)
.With(b => b.SeasonNumber = 2)
.With(b => b.Season = 2)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Poster)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-1-1.jpg")
.TheNext(2)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Banner)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-test.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Poster)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-2-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.All()
.With(a => a.ActorImage = Builder<TvdbActorBanner>.CreateNew().Build())
.Build();
tvdbSeries = Builder<TvdbSeries>
@ -84,10 +85,9 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.With(s => s.Episodes = tvdbEpisodes.ToList())
.With(s => s.Banners = new TvdbBanners())
.Build();
tvdbSeries.Banners.SeasonBanners.AddRange(seasonBanners);
tvdbSeries.Banners.AddRange(seasonBanners);
}
private void WithUseBanners()
@ -128,7 +128,7 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
private void WithNoWriters()
{
tvdbSeries.Episodes.ForEach(e => e.Writers = new List<string>());
tvdbSeries.Episodes.ForEach(e => e.Writer = new List<string>());
}
[Test]
@ -159,7 +159,7 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
WithSingleEpisodeFile();
Mocker.Resolve<Xbmc>().CreateForEpisodeFile(episodeFile, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Episodes.First().Banner, episodeFile.Path.Replace("avi", "tbn")), Times.Once());
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Episodes.First().BannerPath, episodeFile.Path.Replace("avi", "tbn")), Times.Once());
}
[Test]

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
@ -17,8 +16,8 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
using XemLib.Data;
using XemLib.Data.Banner;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
@ -43,23 +42,24 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
var seasonBanners = Builder<TvdbSeasonBanner>
.CreateListOfSize(4)
.TheFirst(2)
.With(b => b.SeasonNumber = 1)
.With(b => b.Season = 1)
.TheLast(2)
.With(b => b.SeasonNumber = 2)
.With(b => b.Season = 2)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Poster)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-1-1.jpg")
.TheNext(2)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Banner)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-test.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Poster)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-2-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.All()
.With(a => a.ActorImage = Builder<TvdbActorBanner>.CreateNew().Build())
.Build();
tvdbSeries = Builder<TvdbSeries>
@ -67,10 +67,9 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
.With(s => s.Id = 79488)
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.With(s => s.Banners = new TvdbBanners())
.Build();
tvdbSeries.Banners.SeasonBanners.AddRange(seasonBanners);
tvdbSeries.Banners.AddRange(seasonBanners);
}
private void WithUseBanners()
@ -83,18 +82,19 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
var seasonBanners = Builder<TvdbSeasonBanner>
.CreateListOfSize(2)
.All()
.With(b => b.SeasonNumber = 0)
.With(b => b.Season = 0)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Poster)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-0-1.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.Banner)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-0-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.All()
.With(a => a.ActorImage = Builder<TvdbActorBanner>.CreateNew().Build())
.Build();
tvdbSeries = Builder<TvdbSeries>
@ -102,11 +102,9 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
.With(s => s.Id = 79488)
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.With(s => s.Banners = new TvdbBanners())
.With(s => s.Genres = new List<String> { "Comedy" })
.Build();
tvdbSeries.Banners.SeasonBanners.AddRange(seasonBanners);
tvdbSeries.Banners.AddRange(seasonBanners);
}
[Test]
@ -126,14 +124,14 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
public void should_download_fanart()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Fanart, Path.Combine(series.Path, "fanart.jpg")), Times.Once());
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.FanartPath, Path.Combine(series.Path, "fanart.jpg")), Times.Once());
}
[Test]
public void should_download_poster_when_useBanners_is_false()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Poster, Path.Combine(series.Path, "folder.jpg")), Times.Once());
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.PosterPath, Path.Combine(series.Path, "folder.jpg")), Times.Once());
}
[Test]
@ -141,7 +139,7 @@ namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
WithUseBanners();
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Banner, Path.Combine(series.Path, "folder.jpg")), Times.Once());
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.BannerPath, Path.Combine(series.Path, "folder.jpg")), Times.Once());
}
[Test]

@ -18,6 +18,7 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
{

@ -18,6 +18,7 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
{

@ -18,6 +18,7 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
{

@ -18,6 +18,7 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
{

@ -185,7 +185,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void EpisodeSearch_should_skip_if_air_date_is_null()
public void EpisodeSearch_should_skip_if_air_date_is_null_and_is_a_daily_series()
{
//Setup
_series.IsDaily = true;

@ -16,6 +16,7 @@ using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test.ProviderTests
{

@ -10,8 +10,8 @@ using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using XemLib.Data;
using XemLib.Exceptions;
using TvdbLib.Data;
using TvdbLib.Exceptions;
namespace NzbDrone.Core.Test.ProviderTests
{
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.ProviderTests
[TearDown]
public void TearDown()
{
ExceptionVerification.MarkInconclusive(typeof(TheTvbdbUnavailableException));
ExceptionVerification.MarkInconclusive(typeof(TvdbNotAvailableException));
}
[TestCase("The Simpsons")]

@ -0,0 +1,77 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.XemCommunicationProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class GetSceneTvdbMappingsFixture : CoreTest
{
private void WithFailureJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Failure.txt"));
}
private void WithIdsJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Ids.txt"));
}
private void WithMappingsJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Mappings.txt"));
}
[Test]
public void should_throw_when_failure_is_found()
{
WithFailureJson();
Assert.Throws<Exception>(() => Mocker.Resolve<XemCommunicationProvider>().GetSceneTvdbMappings(12345));
}
[Test]
public void should_get_list_of_mappings()
{
WithMappingsJson();
Mocker.Resolve<XemCommunicationProvider>().GetSceneTvdbMappings(12345).Should().NotBeEmpty();
}
[Test]
public void should_have_two_mappings()
{
WithMappingsJson();
Mocker.Resolve<XemCommunicationProvider>().GetSceneTvdbMappings(12345).Should().HaveCount(2);
}
[Test]
public void should_have_expected_results()
{
WithMappingsJson();
var results = Mocker.Resolve<XemCommunicationProvider>().GetSceneTvdbMappings(12345);
var first = results.First();
first.Scene.Absolute.Should().Be(1);
first.Scene.Season.Should().Be(1);
first.Scene.Episode.Should().Be(1);
first.Tvdb.Absolute.Should().Be(1);
first.Tvdb.Season.Should().Be(1);
first.Tvdb.Episode.Should().Be(1);
}
}
}

@ -0,0 +1,63 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.XemCommunicationProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class GetXemSeriesIdsFixture : CoreTest
{
private void WithFailureJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Failure.txt"));
}
private void WithIdsJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Ids.txt"));
}
private void WithMappingsJson()
{
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString(It.IsAny<String>()))
.Returns(File.ReadAllText(@".\Files\Xem\Mappings.txt"));
}
[Test]
public void should_throw_when_failure_is_found()
{
WithFailureJson();
Assert.Throws<Exception>(() => Mocker.Resolve<XemCommunicationProvider>().GetXemSeriesIds());
}
[Test]
public void should_get_list_of_int()
{
WithIdsJson();
Mocker.Resolve<XemCommunicationProvider>().GetXemSeriesIds().Should().NotBeEmpty();
}
[Test]
public void should_have_two_ids()
{
WithIdsJson();
Mocker.Resolve<XemCommunicationProvider>().GetXemSeriesIds().Should().HaveCount(2);
}
}
}

@ -137,6 +137,7 @@ namespace NzbDrone.Core
Kernel.Bind<IJob>().To<RefreshEpisodeMetadata>().InSingletonScope();
Kernel.Bind<IJob>().To<CleanupRecycleBinJob>().InSingletonScope();
Kernel.Bind<IJob>().To<EmptyRecycleBinJob>().InSingletonScope();
Kernel.Bind<IJob>().To<XemUpdateJob>().InSingletonScope();
Kernel.Get<JobProvider>().Initialize();
Kernel.Get<WebTimer>().StartTimer(30);

@ -0,0 +1,20 @@
using System;
using System.Data;
using Migrator.Framework;
using NzbDrone.Common;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20121016)]
public class Migration20121016 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
Database.AddColumn("Episodes", new Column("SceneAbsoluteEpisodeNumber", DbType.Int32, ColumnProperty.Null));
Database.AddColumn("Episodes", new Column("SceneSeasonNumber", DbType.Int32, ColumnProperty.Null));
Database.AddColumn("Episodes", new Column("SceneEpisodeNumber", DbType.Int32, ColumnProperty.Null));
Database.AddColumn("Series", new Column("UseSceneNumbering", DbType.Boolean, ColumnProperty.Null));
}
}
}

@ -22,6 +22,7 @@ namespace NzbDrone.Core.Jobs
private readonly DiskScanJob _diskScanJob;
private readonly BannerDownloadJob _bannerDownloadJob;
private readonly SeasonProvider _seasonProvider;
private readonly XemUpdateJob _xemUpdateJob;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@ -30,7 +31,8 @@ namespace NzbDrone.Core.Jobs
[Inject]
public ImportNewSeriesJob(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
MediaFileProvider mediaFileProvider, UpdateInfoJob updateInfoJob,
DiskScanJob diskScanJob, BannerDownloadJob bannerDownloadJob,SeasonProvider seasonProvider)
DiskScanJob diskScanJob, BannerDownloadJob bannerDownloadJob,
SeasonProvider seasonProvider, XemUpdateJob xemUpdateJob)
{
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
@ -39,6 +41,7 @@ namespace NzbDrone.Core.Jobs
_diskScanJob = diskScanJob;
_bannerDownloadJob = bannerDownloadJob;
_seasonProvider = seasonProvider;
_xemUpdateJob = xemUpdateJob;
}
public string Name
@ -81,6 +84,9 @@ namespace NzbDrone.Core.Jobs
//Download the banner for the new series
_bannerDownloadJob.Start(notification, new { SeriesId = updatedSeries.SeriesId });
//Get Scene Numbering if applicable
_xemUpdateJob.Start(notification, new { SeriesId = updatedSeries.SeriesId });
notification.CurrentMessage = String.Format("{0} was successfully imported", updatedSeries.Title);
}

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using Ninject;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs
{
public class XemUpdateJob : IJob
{
private readonly XemProvider _xemProvider;
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
[Inject]
public XemUpdateJob(XemProvider xemProvider)
{
_xemProvider = xemProvider;
}
public XemUpdateJob()
{
}
public string Name
{
get { return "XEM Update"; }
}
public TimeSpan DefaultInterval
{
get { return TimeSpan.FromHours(12); }
}
public virtual void Start(ProgressNotification notification, dynamic options)
{
if (options == null || options.SeriesId == 0)
{
_logger.Trace("Starting XEM Update for all series");
_xemProvider.UpdateMappings();
}
else
{
_logger.Trace("Starting XEM Update for series: {0}", options.SeriesId);
_xemProvider.UpdateMappings(options.SeriesId);
}
_logger.Trace("XEM Update complete");
}
}
}

@ -46,6 +46,10 @@ namespace NzbDrone.Core.Model
public string ReleaseGroup { get; set; }
public bool SceneSource { get; set; }
public IList<Episode> Episodes { get; set; }
public override string ToString()
{

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.Xem
{
public class XemResult<T>
{
public string Result { get; set; }
public T Data { get; set; }
public string Message { get; set; }
}
}

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.Xem
{
public class XemSceneTvdbMapping
{
public XemValues Scene { get; set; }
public XemValues Tvdb { get; set; }
}
}

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.Xem
{
public class XemValues
{
public int Season { get; set; }
public int Episode { get; set; }
public int Absolute { get; set; }
}
}

@ -206,6 +206,10 @@
<Reference Include="System.Web.Extensions" />
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq" />
<Reference Include="TvdbLib, Version=0.8.8.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\TvdbLib.dll</HintPath>
</Reference>
<Reference Include="Twitterizer2, Version=2.4.0.26532, Culture=neutral, PublicKeyToken=69d1469eac671567, processorArchitecture=MSIL">
<HintPath>..\packages\twitterizer.2.4.0.26532\lib\net40\Twitterizer2.dll</HintPath>
</Reference>
@ -213,9 +217,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WebActivator.1.5\lib\net40\WebActivator.dll</HintPath>
</Reference>
<Reference Include="XemLib">
<HintPath>..\Libraries\XemLib\XemLib.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\NzbDrone.Common\Properties\SharedAssemblyInfo.cs">
@ -226,6 +227,7 @@
<Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" />
<Compile Include="Datastore\Migrations\Migration20121016.cs" />
<Compile Include="Datastore\Migrations\Migration20121012.cs" />
<Compile Include="Datastore\Migrations\Migration20120919.cs" />
<Compile Include="Datastore\Migrations\Migration20120918.cs" />
@ -256,6 +258,7 @@
<Compile Include="Helpers\SortHelper.cs" />
<Compile Include="Helpers\SabnzbdPriorityTypeConverter.cs" />
<Compile Include="Jobs\CleanupRecycleBinJob.cs" />
<Compile Include="Jobs\XemUpdateJob.cs" />
<Compile Include="Jobs\EmptyRecycleBinJob.cs" />
<Compile Include="Jobs\RefreshEpsiodeMetadata.cs" />
<Compile Include="Jobs\PastWeekBacklogSearchJob.cs" />
@ -291,6 +294,9 @@
<Compile Include="Model\Xbmc\TvShowResult.cs" />
<Compile Include="Model\Xbmc\ErrorResult.cs" />
<Compile Include="Model\Xbmc\IconType.cs" />
<Compile Include="Model\Xem\XemResult.cs" />
<Compile Include="Model\Xem\XemSceneTvdbMapping.cs" />
<Compile Include="Model\Xem\XemValues.cs" />
<Compile Include="Providers\BannerProvider.cs" />
<Compile Include="Providers\DecisionEngine\AllowedReleaseGroupSpecification.cs" />
<Compile Include="Providers\DecisionEngine\CustomStartDateSpecification.cs" />
@ -329,6 +335,8 @@
<Compile Include="Jobs\RssSyncJob.cs" />
<Compile Include="Jobs\UpdateInfoJob.cs" />
<Compile Include="Providers\StatsProvider.cs" />
<Compile Include="Providers\XemCommunicationProvider.cs" />
<Compile Include="Providers\XemProvider.cs" />
<Compile Include="Repository\MetadataDefinition.cs" />
<Compile Include="Repository\Quality\QualityTypes.cs" />
<Compile Include="Repository\Search\SearchHistoryItem.cs" />

@ -42,6 +42,7 @@ namespace NzbDrone.Core.Providers.DecisionEngine
}
var episodes = _episodeProvider.GetEpisodesByParseResult(subject);
subject.Episodes = episodes;
//return monitored if any of the episodes are monitored
if (episodes.Any(episode => !episode.Ignored))

@ -24,7 +24,7 @@ namespace NzbDrone.Core.Providers.DecisionEngine
public virtual bool IsSatisfiedBy(EpisodeParseResult subject)
{
foreach (var file in _episodeProvider.GetEpisodesByParseResult(subject).Select(c => c.EpisodeFile).Where(c => c != null))
foreach (var file in subject.Episodes.Select(c => c.EpisodeFile).Where(c => c != null))
{
logger.Trace("Comparing file quality with report. Existing file is {0} proper:{1}", file.Quality, file.Proper);
if (!_qualityUpgradeSpecification.IsSatisfiedBy(new QualityModel { Quality = file.Quality, Proper = file.Proper }, subject.Quality, subject.Series.QualityProfile.Cutoff))

@ -27,7 +27,7 @@ namespace NzbDrone.Core.Providers.DecisionEngine
public virtual bool IsSatisfiedBy(EpisodeParseResult subject)
{
foreach (var episode in _episodeProvider.GetEpisodesByParseResult(subject))
foreach (var episode in subject.Episodes)
{
var bestQualityInHistory = _historyProvider.GetBestQualityInHistory(subject.Series.SeriesId, episode.SeasonNumber, episode.EpisodeNumber);
if (bestQualityInHistory != null)

@ -122,6 +122,9 @@ namespace NzbDrone.Core.Providers
if (parseResult == null)
return null;
if (!_diskProvider.IsChildOfPath(filePath, series.Path))
parseResult.SceneSource = true;
parseResult.SeriesTitle = series.Title; //replaces the nasty path as title to help with logging
parseResult.Series = series;
@ -203,6 +206,7 @@ namespace NzbDrone.Core.Providers
var parseResult = Parser.ParsePath(episodeFile.Path);
parseResult.Series = series;
parseResult.Quality = new QualityModel{ Quality = episodeFile.Quality, Proper = episodeFile.Proper };
parseResult.Episodes = episodes;
var message = _downloadProvider.GetDownloadTitle(parseResult);

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
@ -48,13 +49,13 @@ namespace NzbDrone.Core.Providers
var provider = GetActiveDownloadClient();
bool success = provider.DownloadNzb(parseResult.NzbUrl, GetDownloadTitle(parseResult));
bool success = provider.DownloadNzb(parseResult.NzbUrl, downloadTitle);
if (success)
{
logger.Trace("Download added to Queue: {0}", downloadTitle);
foreach (var episode in _episodeProvider.GetEpisodesByParseResult(parseResult))
foreach (var episode in parseResult.Episodes)
{
var history = new History
{
@ -115,7 +116,7 @@ namespace NzbDrone.Core.Providers
if (parseResult.Series.IsDaily)
{
var dailyResult = String.Format("{0} - {1:yyyy-MM-dd} - {2} [{3}]", seriesTitle,
parseResult.AirDate, parseResult.EpisodeTitle, parseResult.Quality.Quality);
parseResult.AirDate, parseResult.Episodes.First().Title, parseResult.Quality.Quality);
if (parseResult.Quality.Proper)
dailyResult += " [Proper]";
@ -126,15 +127,25 @@ namespace NzbDrone.Core.Providers
//Show Name - 1x01-1x02 - Episode Name
//Show Name - 1x01 - Episode Name
var episodeString = new List<String>();
var episodeNames = new List<String>();
foreach (var episode in parseResult.EpisodeNumbers)
foreach (var episode in parseResult.Episodes)
{
episodeString.Add(String.Format("{0}x{1:00}", parseResult.SeasonNumber, episode));
episodeString.Add(String.Format("{0}x{1:00}", episode.SeasonNumber, episode.EpisodeNumber));
episodeNames.Add(Parser.CleanupEpisodeTitle(episode.Title));
}
var epNumberString = String.Join("-", episodeString);
string episodeName;
var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, parseResult.EpisodeTitle, parseResult.Quality.Quality);
if (episodeNames.Distinct().Count() == 1)
episodeName = episodeNames.First();
else
episodeName = String.Join(" + ", episodeNames.Distinct());
var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, episodeName, parseResult.Quality.Quality);
if (parseResult.Quality.Proper)
{

@ -7,7 +7,7 @@ using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Repository;
using PetaPoco;
using XemLib.Data;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers
{
@ -188,11 +188,20 @@ namespace NzbDrone.Core.Providers
foreach (var episodeNumber in parseResult.EpisodeNumbers)
{
var episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.SeasonNumber, episodeNumber);
if (episodeInfo == null && parseResult.AirDate != null)
Episode episodeInfo = null;
if (parseResult.SceneSource && parseResult.Series.UseSceneNumbering)
episodeInfo = GetEpisodeBySceneNumbering(parseResult.Series.SeriesId, parseResult.SeasonNumber, episodeNumber);
if (episodeInfo == null)
{
episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.AirDate.Value);
episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.SeasonNumber, episodeNumber);
if (episodeInfo == null && parseResult.AirDate != null)
{
episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.AirDate.Value);
}
}
//if still null we should add the temp episode
if (episodeInfo == null && autoAddNew)
{
@ -217,6 +226,16 @@ namespace NzbDrone.Core.Providers
{
result.Add(episodeInfo);
if (parseResult.Series.UseSceneNumbering)
{
logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}",
parseResult.Series.Title,
episodeInfo.SceneSeasonNumber,
episodeInfo.SceneEpisodeNumber,
episodeInfo.SeasonNumber,
episodeInfo.EpisodeNumber);
}
if (parseResult.EpisodeNumbers.Count == 1)
{
parseResult.EpisodeTitle = episodeInfo.Title.Trim();
@ -331,7 +350,7 @@ namespace NzbDrone.Core.Providers
episodeToUpdate.TvDbEpisodeId = episode.Id;
episodeToUpdate.EpisodeNumber = episode.EpisodeNumber;
episodeToUpdate.SeasonNumber = episode.SeasonNumber;
episodeToUpdate.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber;
episodeToUpdate.AbsoluteEpisodeNumber = episode.AbsoluteNumber;
episodeToUpdate.Title = episode.EpisodeName;
episodeToUpdate.Overview = episode.Overview.Truncate(3500);
@ -435,5 +454,26 @@ namespace NzbDrone.Core.Providers
logger.Trace("Updating PostDownloadStatus for all episodeIds in {0}", episodeIdString);
_database.Execute(episodeIdQuery);
}
public virtual void UpdateEpisodes(List<Episode> episodes)
{
_database.UpdateMany(episodes);
}
public virtual Episode GetEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
{
var episode = _database.Fetch<Episode, Series, EpisodeFile>(@"SELECT * FROM Episodes
INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId
LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId
WHERE Episodes.SeriesId = @0 AND Episodes.SceneSeasonNumber = @1 AND Episodes.SceneEpisodeNumber = @2", seriesId, seasonNumber, episodeNumber).SingleOrDefault();
if (episode == null)
return null;
if (episode.EpisodeFileId == 0)
episode.EpisodeFile = null;
return episode;
}
}
}

@ -247,6 +247,7 @@ namespace NzbDrone.Core.Providers.Indexer
{
episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PublishDate.Date).Days;
episodeParseResult.OriginalString = title;
episodeParseResult.SceneSource = true;
}
_logger.Trace("Parsed: {0} from: {1}", episodeParseResult, item.Title.Text);

@ -208,7 +208,7 @@ namespace NzbDrone.Core.Providers
result += separatorStyle.Pattern + episodeNames.First();
else
result += separatorStyle.Pattern + String.Join(" + ", episodeNames);
result += separatorStyle.Pattern + String.Join(" + ", episodeNames.Distinct());
}
if (_configProvider.SortingAppendQuality)

@ -4,7 +4,7 @@ using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using XemLib.Data;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers.Metadata
{

@ -8,8 +8,8 @@ using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using XemLib.Data;
using XemLib.Data.Banner;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Providers.Metadata
{
@ -48,16 +48,16 @@ namespace NzbDrone.Core.Providers.Metadata
tvShow.Add(new XElement("episodeguideurl", episodeGuideUrl));
tvShow.Add(new XElement("mpaa", tvDbSeries.ContentRating));
tvShow.Add(new XElement("id", tvDbSeries.Id));
tvShow.Add(new XElement("genre", tvDbSeries.Genres.FirstOrDefault()));
tvShow.Add(new XElement("genre", tvDbSeries.GenreString.Trim('|').Split('|')[0]));
tvShow.Add(new XElement("premiered", tvDbSeries.FirstAired.ToString("yyyy-MM-dd")));
tvShow.Add(new XElement("studio", tvDbSeries.Network));
tvShow.Add(new XElement("studio", tvDbSeries.Network));
foreach(var actor in tvDbSeries.TvdbActors)
{
tvShow.Add(new XElement("actor",
new XElement("name", actor.Name),
new XElement("role", actor.Role),
new XElement("thumb", "http://www.thetvdb.com/banners/" + actor.Image)
new XElement("thumb", "http://www.thetvdb.com/banners/" + actor.ActorImage.BannerPath)
));
}
@ -71,7 +71,7 @@ namespace NzbDrone.Core.Providers.Metadata
if (!_diskProvider.FileExists(Path.Combine(series.Path, "fanart.jpg")))
{
_logger.Debug("Downloading fanart for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.Fanart, Path.Combine(series.Path, "fanart.jpg"));
_bannerProvider.Download(tvDbSeries.FanartPath, Path.Combine(series.Path, "fanart.jpg"));
}
if (!_diskProvider.FileExists(Path.Combine(series.Path, "folder.jpg")))
@ -79,19 +79,19 @@ namespace NzbDrone.Core.Providers.Metadata
if(_configProvider.MetadataUseBanners)
{
_logger.Debug("Downloading series banner for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.Banner, Path.Combine(series.Path, "folder.jpg"));
_bannerProvider.Download(tvDbSeries.BannerPath, Path.Combine(series.Path, "folder.jpg"));
_logger.Debug("Downloading Season banners for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.Banner);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.seasonwide);
}
else
{
_logger.Debug("Downloading series thumbnail for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.Poster, Path.Combine(series.Path, "folder.jpg"));
_bannerProvider.Download(tvDbSeries.PosterPath, Path.Combine(series.Path, "folder.jpg"));
_logger.Debug("Downloading Season posters for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.Poster);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.season);
}
}
}
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Providers.Metadata
e.SeasonNumber == episodeFile.SeasonNumber &&
e.EpisodeNumber == episodes.First().EpisodeNumber);
if (episodeFileThumbnail == null || String.IsNullOrWhiteSpace(episodeFileThumbnail.Banner))
if (episodeFileThumbnail == null || String.IsNullOrWhiteSpace(episodeFileThumbnail.BannerPath))
{
_logger.Debug("No thumbnail is available for this episode");
return;
@ -121,7 +121,7 @@ namespace NzbDrone.Core.Providers.Metadata
if (!_diskProvider.FileExists(episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".tbn")))
{
_logger.Debug("Downloading episode thumbnail for: {0}", episodeFile.EpisodeFileId);
_bannerProvider.Download(episodeFileThumbnail.Banner,
_bannerProvider.Download(episodeFileThumbnail.BannerPath,
episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".tbn"));
}
@ -165,9 +165,9 @@ namespace NzbDrone.Core.Providers.Metadata
details.Add(new XElement("plot", tvdbEpisode.Overview));
details.Add(new XElement("displayseason"));
details.Add(new XElement("displayepisode"));
details.Add(new XElement("thumb", "http://www.thetvdb.com/banners/" + tvdbEpisode.Banner));
details.Add(new XElement("thumb", "http://www.thetvdb.com/banners/" + tvdbEpisode.BannerPath));
details.Add(new XElement("watched", "false"));
details.Add(new XElement("credits", tvdbEpisode.Writers.FirstOrDefault()));
details.Add(new XElement("credits", tvdbEpisode.Writer.FirstOrDefault()));
details.Add(new XElement("director", tvdbEpisode.Directors.FirstOrDefault()));
details.Add(new XElement("rating", tvdbEpisode.Rating));
@ -186,7 +186,7 @@ namespace NzbDrone.Core.Providers.Metadata
details.Add(new XElement("actor",
new XElement("name", actor.Name),
new XElement("role", actor.Role),
new XElement("thumb", "http://www.thetvdb.com/banners/" + actor.Image)
new XElement("thumb", "http://www.thetvdb.com/banners/" + actor.ActorImage.BannerPath)
));
}
@ -235,11 +235,11 @@ namespace NzbDrone.Core.Providers.Metadata
private void DownloadSeasonThumbnails(Series series, TvdbSeries tvDbSeries, TvdbSeasonBanner.Type bannerType)
{
var seasons = tvDbSeries.Banners.SeasonBanners.Where(s => s.BannerType == bannerType).Select(s => s.SeasonNumber);
var seasons = tvDbSeries.SeasonBanners.Where(s => s.BannerType == bannerType).Select(s => s.Season);
foreach (var season in seasons)
{
var banner = tvDbSeries.Banners.SeasonBanners.FirstOrDefault(b => b.BannerType == bannerType && b.SeasonNumber == season);
var banner = tvDbSeries.SeasonBanners.FirstOrDefault(b => b.BannerType == bannerType && b.Season == season);
_logger.Debug("Downloading banner for Season: {0} Series: {1}", season, series.Title);
if (season == 0)

@ -8,7 +8,7 @@ using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository;
using PetaPoco;
using XemLib.Data;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers
{
@ -92,7 +92,7 @@ namespace NzbDrone.Core.Providers
public virtual void CreateForSeries(Series series)
{
var tvDbSeries = _tvDbProvider.GetSeries(series.SeriesId, false, true, true);
var tvDbSeries = _tvDbProvider.GetSeries(series.SeriesId, false, true);
CreateForSeries(series, tvDbSeries);
}
@ -107,7 +107,7 @@ namespace NzbDrone.Core.Providers
public virtual void CreateForEpisodeFile(EpisodeFile episodeFile)
{
var tvDbSeries = _tvDbProvider.GetSeries(episodeFile.SeriesId, true, true, true);
var tvDbSeries = _tvDbProvider.GetSeries(episodeFile.SeriesId, true, true);
CreateForEpisodeFile(episodeFile, tvDbSeries);
}
@ -130,7 +130,7 @@ namespace NzbDrone.Core.Providers
Logger.Trace("Creating metadata for {0} files.", episodeFiles.Count);
var tvDbSeries = _tvDbProvider.GetSeries(episodeFiles.First().SeriesId, true, true, true);
var tvDbSeries = _tvDbProvider.GetSeries(episodeFiles.First().SeriesId, true, true);
foreach(var episodeFile in episodeFiles)
{

@ -112,6 +112,8 @@ namespace NzbDrone.Core.Providers
parseResult.NzbUrl = item.NzbUrl;
parseResult.Series = series;
parseResult.Indexer = item.Indexer;
parseResult.Episodes = _episodeProvider.GetEpisodesByParseResult(parseResult);
parseResult.SceneSource = true;
logger.Info("Forcing Download of: {0}", item.ReportTitle);
_downloadProvider.DownloadReport(parseResult);

@ -25,7 +25,7 @@ namespace NzbDrone.Core.Providers
private readonly AllowedDownloadSpecification _allowedDownloadSpecification;
private readonly SearchHistoryProvider _searchHistoryProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
[Inject]
public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider,
@ -60,7 +60,7 @@ namespace NzbDrone.Core.Providers
if (series == null)
{
Logger.Error("Unable to find an series {0} in database", seriesId);
_logger.Error("Unable to find an series {0} in database", seriesId);
return new List<int>();
}
@ -72,17 +72,17 @@ namespace NzbDrone.Core.Providers
var reports = PerformSearch(notification, series, seasonNumber);
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
if (reports.Count == 0)
return new List<int>();
Logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber);
_logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber);
var episodeNumbers = _episodeProvider.GetEpisodeNumbersBySeason(seriesId, seasonNumber);
if (episodeNumbers == null || episodeNumbers.Count == 0)
{
Logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber);
_logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber);
return new List<int>();
}
@ -111,7 +111,7 @@ namespace NzbDrone.Core.Providers
if (series == null)
{
Logger.Error("Unable to find an series {0} in database", seriesId);
_logger.Error("Unable to find an series {0} in database", seriesId);
return new List<int>();
}
@ -122,7 +122,7 @@ namespace NzbDrone.Core.Providers
notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber);
var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber);
var reports = PerformSearch(notification, series, seasonNumber, episodes);
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
if (reports.Count == 0)
return new List<int>();
@ -140,14 +140,14 @@ namespace NzbDrone.Core.Providers
if (episode == null)
{
Logger.Error("Unable to find an episode {0} in database", episodeId);
_logger.Error("Unable to find an episode {0} in database", episodeId);
return false;
}
//Check to see if an upgrade is possible before attempting
if (!_upgradePossibleSpecification.IsSatisfiedBy(episode))
{
Logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
_logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
notification.CurrentMessage = String.Format("Skipping search for {0}, the file you have is already at cutoff", episode);
return false;
}
@ -156,7 +156,7 @@ namespace NzbDrone.Core.Providers
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
{
Logger.Warn("AirDate is not Valid for: {0}", episode);
_logger.Warn("AirDate is not Valid for: {0}", episode);
notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode);
return false;
}
@ -169,7 +169,7 @@ namespace NzbDrone.Core.Providers
var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List<Episode> { episode });
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
_logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
notification.CurrentMessage = "Processing search results";
if (episode.Series.IsDaily)
@ -181,6 +181,34 @@ namespace NzbDrone.Core.Providers
return true;
}
else if (episode.Series.UseSceneNumbering)
{
searchResult.EpisodeId = episodeId;
var seasonNumber = episode.SceneSeasonNumber;
var episodeNumber = episode.SceneEpisodeNumber;
if (seasonNumber == 0 || episodeNumber == 0)
{
seasonNumber = episode.SeasonNumber;
episodeNumber = episode.EpisodeNumber;
}
searchResult.SearchHistoryItems = ProcessSearchResults(
notification,
reports,
searchResult,
episode.Series,
seasonNumber,
episodeNumber
);
_searchHistoryProvider.Add(searchResult);
if (searchResult.SearchHistoryItems.Any(r => r.Success))
return true;
}
else
{
searchResult.EpisodeId = episodeId;
@ -188,10 +216,10 @@ namespace NzbDrone.Core.Providers
_searchHistoryProvider.Add(searchResult);
if (searchResult.SearchHistoryItems.Any(r => r.Success))
return true;
return true;
}
Logger.Warn("Unable to find {0} in any of indexers.", episode);
_logger.Warn("Unable to find {0} in any of indexers.", episode);
if (reports.Any())
{
@ -228,7 +256,12 @@ namespace NzbDrone.Core.Providers
//Treat as single episode
else if (episodes.Count == 1)
{
if (!series.IsDaily)
//Use SceneNumbering - Only if SceneSN and SceneEN are greater than zero
if (series.UseSceneNumbering && episodes.First().SceneSeasonNumber > 0 && episodes.First().SceneEpisodeNumber > 0)
reports.AddRange(indexer.FetchEpisode(title, episodes.First().SceneSeasonNumber, episodes.First().SceneEpisodeNumber));
//Standard
else if (!series.IsDaily)
reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodes.First().EpisodeNumber));
//Daily Episode
@ -250,7 +283,7 @@ namespace NzbDrone.Core.Providers
catch (Exception e)
{
Logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
_logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
}
});
@ -268,7 +301,7 @@ namespace NzbDrone.Core.Providers
{
try
{
Logger.Trace("Analysing report " + episodeParseResult);
_logger.Trace("Analysing report " + episodeParseResult);
var item = new SearchHistoryItem
{
@ -290,7 +323,7 @@ namespace NzbDrone.Core.Providers
//If series is null or doesn't match the series we're looking for return
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
{
Logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
_logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
item.SearchError = ReportRejectionType.WrongSeries;
continue;
}
@ -298,7 +331,7 @@ namespace NzbDrone.Core.Providers
//If SeasonNumber doesn't match or episode is not in the in the list in the parse result, skip the report.
if (episodeParseResult.SeasonNumber != seasonNumber)
{
Logger.Trace("Season number does not match searched season number, skipping.");
_logger.Trace("Season number does not match searched season number, skipping.");
item.SearchError = ReportRejectionType.WrongSeason;
continue;
}
@ -306,7 +339,7 @@ namespace NzbDrone.Core.Providers
//If the EpisodeNumber was passed in and it is not contained in the parseResult, skip the report.
if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value))
{
Logger.Trace("Searched episode number is not contained in post, skipping.");
_logger.Trace("Searched episode number is not contained in post, skipping.");
item.SearchError = ReportRejectionType.WrongEpisode;
continue;
}
@ -314,15 +347,17 @@ namespace NzbDrone.Core.Providers
//Make sure we haven't already downloaded a report with this episodenumber, if we have, skip the report.
if (searchResult.Successes.Intersect(episodeParseResult.EpisodeNumbers).Any())
{
Logger.Trace("Episode has already been downloaded in this search, skipping.");
_logger.Trace("Episode has already been downloaded in this search, skipping.");
item.SearchError = ReportRejectionType.Skipped;
continue;
}
episodeParseResult.Episodes = _episodeProvider.GetEpisodesByParseResult(episodeParseResult);
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
if (item.SearchError == ReportRejectionType.None)
{
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
_logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
try
{
if (_downloadProvider.DownloadReport(episodeParseResult))
@ -340,7 +375,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
_logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
item.SearchError = ReportRejectionType.DownloadClientFailure;
}
@ -348,7 +383,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
_logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
}
}
@ -384,7 +419,7 @@ namespace NzbDrone.Core.Providers
continue;
}
Logger.Trace("Analysing report " + episodeParseResult);
_logger.Trace("Analysing report " + episodeParseResult);
//Get the matching series
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
@ -403,10 +438,12 @@ namespace NzbDrone.Core.Providers
continue;
}
episodeParseResult.Episodes = _episodeProvider.GetEpisodesByParseResult(episodeParseResult);
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
if (item.SearchError == ReportRejectionType.None)
{
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
_logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
try
{
if (_downloadProvider.DownloadReport(episodeParseResult))
@ -425,7 +462,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
_logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
item.SearchError = ReportRejectionType.DownloadClientFailure;
}
@ -433,7 +470,7 @@ namespace NzbDrone.Core.Providers
}
catch (Exception e)
{
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
_logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
}
}

@ -97,11 +97,11 @@ namespace NzbDrone.Core.Providers
series.AirsDayOfWeek = tvDbSeries.AirsDayOfWeek;
series.Overview = tvDbSeries.Overview;
series.Status = tvDbSeries.Status;
series.Language = tvDbSeries.Language != null ? tvDbSeries.Language : string.Empty;
series.Language = tvDbSeries.Language != null ? tvDbSeries.Language.Abbriviation : string.Empty;
series.CleanTitle = Parser.NormalizeTitle(tvDbSeries.SeriesName);
series.LastInfoSync = DateTime.Now;
series.Runtime = (int)tvDbSeries.Runtime;
series.BannerUrl = tvDbSeries.Banner;
series.BannerUrl = tvDbSeries.BannerPath;
series.Network = tvDbSeries.Network;
UpdateSeries(series);

@ -5,8 +5,9 @@ using System.Text.RegularExpressions;
using NLog;
using Ninject;
using NzbDrone.Common;
using XemLib;
using XemLib.Data;
using TvdbLib;
using TvdbLib.Cache;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers
{
@ -16,13 +17,13 @@ namespace NzbDrone.Core.Providers
public const string TVDB_APIKEY = "5D2D188E86E07F4F";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly XemClient _xemClient;
private readonly TvdbHandler _handler;
[Inject]
public TvDbProvider(EnvironmentProvider environmentProvider)
{
_environmentProvider = environmentProvider;
_xemClient = new XemClient(TVDB_APIKEY);
_handler = new TvdbHandler(new XmlCacheProvider(_environmentProvider.GetCacheFolder()), TVDB_APIKEY);
}
public TvDbProvider()
@ -32,27 +33,33 @@ namespace NzbDrone.Core.Providers
public virtual IList<TvdbSearchResult> SearchSeries(string title)
{
Logger.Debug("Searching TVDB for '{0}'", title);
lock (_handler)
{
Logger.Debug("Searching TVDB for '{0}'", title);
var result = _xemClient.SearchSeries(title);
var result = _handler.SearchSeries(title);
Logger.Debug("Search for '{0}' returned {1} possible results", title, result.Count);
return result;
Logger.Debug("Search for '{0}' returned {1} possible results", title, result.Count);
return result;
}
}
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes, bool loadActors = false, bool loadBanners = false)
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes, bool loadActors = false)
{
Logger.Debug("Fetching SeriesId'{0}' from tvdb", id);
var result = _xemClient.GetSeries(id, loadEpisodes, loadActors, true, TvdbLanguage.Default);
lock (_handler)
{
Logger.Debug("Fetching SeriesId'{0}' from tvdb", id);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, loadActors, true, true);
//Remove duplicated episodes
var episodes = result.Episodes.OrderByDescending(e => e.FirstAired).ThenByDescending(e => e.EpisodeName)
.GroupBy(e => e.SeriesId.ToString("000000") + e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))
.Select(e => e.First());
//Remove duplicated episodes
var episodes = result.Episodes.OrderByDescending(e => e.FirstAired).ThenByDescending(e => e.EpisodeName)
.GroupBy(e => e.SeriesId.ToString("000000") + e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))
.Select(e => e.First());
result.Episodes = episodes.ToList();
result.Episodes = episodes.ToList();
return result;
return result;
}
}
}
}

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Model.Xem;
namespace NzbDrone.Core.Providers
{
public class XemCommunicationProvider
{
private readonly HttpProvider _httpProvider;
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private const string XEM_BASE_URL = "http://thexem.de/map/";
[Inject]
public XemCommunicationProvider(HttpProvider httpProvider)
{
_httpProvider = httpProvider;
}
public XemCommunicationProvider()
{
}
public virtual List<Int32> GetXemSeriesIds(string origin = "tvdb")
{
_logger.Trace("Fetching Series IDs from: {0}", origin);
var url = String.Format("{0}havemap?origin={1}", XEM_BASE_URL, origin);
var response =_httpProvider.DownloadString(url);
CheckForFailureResult(response);
var result = JsonConvert.DeserializeObject<XemResult<List<Int32>>>(response);
return result.Data.ToList();
}
public virtual List<XemSceneTvdbMapping> GetSceneTvdbMappings(int id)
{
_logger.Trace("Fetching Mappings for: {0}", id);
var url = String.Format("{0}all?id={1}&origin=tvdb", XEM_BASE_URL, id);
var response = _httpProvider.DownloadString(url);
CheckForFailureResult(response);
var result = JsonConvert.DeserializeObject<List<XemSceneTvdbMapping>>(JObject.Parse(response).SelectToken("data").ToString());
return result;
}
public virtual void CheckForFailureResult(string response)
{
var result = JsonConvert.DeserializeObject<XemResult<dynamic>>(response);
if (result != null && result.Result.Equals("failure", StringComparison.InvariantCultureIgnoreCase))
throw new Exception("Error response received from Xem: " + result.Message);
}
}
}

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using Ninject;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers
{
public class XemProvider
{
private readonly SeriesProvider _seriesProvider;
private readonly EpisodeProvider _episodeProvider;
private readonly XemCommunicationProvider _xemCommunicationProvider;
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
[Inject]
public XemProvider(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
XemCommunicationProvider xemCommunicationProvider)
{
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
_xemCommunicationProvider = xemCommunicationProvider;
}
public XemProvider()
{
}
public virtual void UpdateMappings()
{
_logger.Trace("Starting scene numbering update");
try
{
var ids = _xemCommunicationProvider.GetXemSeriesIds();
var series = _seriesProvider.GetAllSeries();
var wantedSeries = series.Where(s => ids.Contains(s.SeriesId)).ToList();
foreach(var ser in wantedSeries)
{
PerformUpdate(ser);
}
_logger.Trace("Completed scene numbering update");
}
catch(Exception ex)
{
_logger.WarnException("Error updating Scene Mappings", ex);
throw;
}
}
public virtual void UpdateMappings(int seriesId)
{
var series = _seriesProvider.GetSeries(seriesId);
if (series == null)
{
_logger.Trace("Series could not be found: {0}", seriesId);
return;
}
PerformUpdate(series);
}
public virtual void PerformUpdate(Series series)
{
_logger.Trace("Updating scene numbering mapping for: {0}", series.Title);
try
{
var episodesToUpdate = new List<Episode>();
var mappings = _xemCommunicationProvider.GetSceneTvdbMappings(series.SeriesId);
if (mappings == null)
{
_logger.Trace("Mappings for: {0} are null, skipping", series.Title);
return;
}
var episodes = _episodeProvider.GetEpisodeBySeries(series.SeriesId);
foreach (var mapping in mappings)
{
_logger.Trace("Setting scene numbering mappings for {0} S{1:00}E{2:00}", series.Title, mapping.Tvdb.Season, mapping.Tvdb.Episode);
var episode = episodes.SingleOrDefault(e => e.SeasonNumber == mapping.Tvdb.Season && e.EpisodeNumber == mapping.Tvdb.Episode);
if (episode == null)
{
_logger.Trace("Information hasn't been added to TheTVDB yet, skipping.");
continue;
}
episode.AbsoluteEpisodeNumber = mapping.Scene.Absolute;
episode.SceneSeasonNumber = mapping.Scene.Season;
episode.SceneEpisodeNumber = mapping.Scene.Episode;
episodesToUpdate.Add(episode);
}
_logger.Trace("Committing scene numbering mappings to database for: {0}", series.Title);
_episodeProvider.UpdateEpisodes(episodesToUpdate);
_logger.Trace("Setting UseSceneMapping for {0}", series.Title);
series.UseSceneNumbering = true;
_seriesProvider.UpdateSeries(series);
}
catch (Exception ex)
{
_logger.WarnException("Error updating scene numbering mappings for: " + series, ex);
}
}
}
}

@ -22,6 +22,9 @@ namespace NzbDrone.Core.Repository
public Boolean Ignored { get; set; }
public PostDownloadStatusType PostDownloadStatus { get; set; }
public int AbsoluteEpisodeNumber { get; set; }
public int SceneAbsoluteEpisodeNumber { get; set; }
public int SceneSeasonNumber { get; set; }
public int SceneEpisodeNumber { get; set; }
/// <summary>
/// Gets or sets the grab date.

@ -50,6 +50,8 @@ namespace NzbDrone.Core.Repository
public DateTime? CustomStartDate { get; set; }
public bool UseSceneNumbering { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Series"/> is hidden.
/// </summary>

@ -12,7 +12,7 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Web.Filters;
using NzbDrone.Web.Models;
using XemLib.Exceptions;
using TvdbLib.Exceptions;
namespace NzbDrone.Web.Controllers
{
@ -156,14 +156,14 @@ namespace NzbDrone.Web.Controllers
DisplayedTitle = r.FirstAired.Year > 1900 && !r.SeriesName.EndsWith("(" + r.FirstAired.Year + ")")
? string.Format("{0} ({1})", r.SeriesName, r.FirstAired.Year)
: r.SeriesName,
Banner = r.Banner,
Banner = r.Banner.BannerPath,
Url = String.Format("http://www.thetvdb.com/?tab=series&id={0}", r.Id)
}).ToList();
return Json(tvDbResults, JsonRequestBehavior.AllowGet);
}
catch (TheTvbdbUnavailableException ex)
catch(TvdbNotAvailableException ex)
{
logger.WarnException("Unable to lookup series on TheTVDB", ex);
return JsonNotificationResult.Info("Lookup Failed", "TheTVDB is not available at this time.");

@ -141,13 +141,13 @@
<Private>True</Private>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="WebActivator, Version=1.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="TvdbLib, Version=0.8.8.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\WebActivator.1.5.1\lib\net40\WebActivator.dll</HintPath>
<HintPath>..\Libraries\TvdbLib.dll</HintPath>
</Reference>
<Reference Include="XemLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="WebActivator, Version=1.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\XemLib\XemLib.dll</HintPath>
<HintPath>..\packages\WebActivator.1.5.1\lib\net40\WebActivator.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

Loading…
Cancel
Save