1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-05 10:32:35 +01:00

Merge remote-tracking branch 'origin/metadata'

This commit is contained in:
Mark McDowall 2012-07-13 11:03:15 -07:00
commit 7c803c4691
43 changed files with 1348 additions and 91 deletions

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -200,6 +200,10 @@ public virtual string ReadAllText(string filePath)
return File.ReadAllText(filePath);
}
public virtual void WriteAllText(string filename, string contents)
{
File.WriteAllText(filename, contents);
}
public static bool PathEquals(string firstPath, string secondPath)
{

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -114,6 +114,8 @@
<Compile Include="ProviderTests\AnalyticsProviderTests\AnalyticsProviderFixture.cs" />
<Compile Include="ProviderTests\ConfigProviderTests\ConfigCachingFixture.cs" />
<Compile Include="ProviderTests\BannerProviderTest.cs" />
<Compile Include="ProviderTests\Metadata\Xbmc_ForEpisodeFile_Fixture.cs" />
<Compile Include="ProviderTests\Metadata\Xbmc_ForSeries_Fixture.cs" />
<Compile Include="ProviderTests\SearchHistoryProviderTest.cs" />
<Compile Include="ProviderTests\PlexProviderTest.cs" />
<Compile Include="ProviderTests\SeasonProviderTest.cs" />

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -212,7 +212,7 @@ public void move_should_not_move_file_if_source_and_destination_are_the_same_pat
var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, false);
//Assert
result.Should().BeFalse();
result.Should().BeNull();
}
[Test]
@ -368,7 +368,7 @@ public void MoveEpisodeFile_should_use_EpisodeFiles_quality()
var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, true);
//Assert
result.Should().BeTrue();
result.Should().NotBeNull();
Mocker.GetMock<ExternalNotificationProvider>()
.Verify(e => e.OnDownload("30 Rock - 1x01 - [WEBDL]", It.IsAny<Series>()), Times.Once());
}

View File

@ -172,7 +172,7 @@ public void RefreshEpisodeInfo_emptyRepo()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
//Act
@ -207,7 +207,7 @@ public void RefreshEpisodeInfo_should_set_older_than_1900_to_null()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -248,7 +248,7 @@ public void RefreshEpisodeInfo_should_set_older_than_1900_to_null_for_existing_e
Db.Insert(fakeEpisode);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeTvDbEpisodes);
//Act
@ -285,7 +285,7 @@ public void RefreshEpisodeInfo_ignore_episode_zero()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -324,7 +324,7 @@ public void RefreshEpisodeInfo_should_skip_future_episodes_with_no_title()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -362,7 +362,7 @@ public void RefreshEpisodeInfo_should_skip_older_than_1900_year_episodes_with_no
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -395,7 +395,7 @@ public void RefreshEpisodeInfo_should_add_future_episodes_with_title()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -428,7 +428,7 @@ public void RefreshEpisodeInfo_should_add_old_episodes_with_no_title()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
@ -463,7 +463,7 @@ public void RefreshEpisodeInfo_ignore_season_zero()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeEpisodes);
Mocker.GetMock<SeasonProvider>()
@ -493,7 +493,7 @@ public void new_episodes_only_calls_Insert()
var currentEpisodes = new List<Episode>();
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -528,7 +528,7 @@ public void existing_episodes_only_calls_Update()
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -565,7 +565,7 @@ public void should_try_to_get_existing_episode_using_tvdbid_first()
.Returns(fakeEpisodeList);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(fakeTvDbResult);
//Act
@ -602,7 +602,7 @@ public void should_try_to_get_existing_episode_using_tvdbid_first_then_season_ep
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<IDatabase>()
@ -634,7 +634,7 @@ public void existing_episodes_keep_their_episodeId_file_id()
}
Mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
var updatedEpisodes = new List<Episode>();
@ -695,7 +695,7 @@ public void RefreshEpisodeInfo_should_ignore_new_episode_for_ignored_season()
Db.Insert(fakeEpisode);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
Mocker.GetMock<SeasonProvider>()
@ -1407,7 +1407,7 @@ public void RefreshEpisodeInfo_should_ignore_episode_zero_except_if_season_one()
Db.Insert(fakeSeries);
Mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true))
.Setup(c => c.GetSeries(seriesId, true, false))
.Returns(tvdbSeries);
//Act

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
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.Providers.Core;
using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class Xbmc_ForEpisoddeFile_Fixture : CoreTest
{
private Series series;
private EpisodeFile episodeFile;
private TvdbSeries tvdbSeries;
[SetUp]
public void Setup()
{
WithTempAsAppPath();
series = Builder<Series>
.CreateNew()
.With(s => s.SeriesId == 79488)
.With(s => s.Title == "30 Rock")
.Build();
episodeFile = Builder<EpisodeFile>.CreateNew()
.With(f => f.SeriesId = 79488)
.With(f => f.SeasonNumber = 1)
.With(f => f.Path = @"C:\Test\30 Rock\Season 01\30 Rock - S01E01 - Pilot.avi")
.Build();
var tvdbEpisodes = Builder<TvdbEpisode>.CreateListOfSize(2)
.All()
.With(e => e.SeriesId = 79488)
.With(e => e.SeasonNumber = 1)
.With(e => e.Directors = new List<string>{ "Fake Director" })
.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.Season = 1)
.TheLast(2)
.With(b => b.Season = 2)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-1-1.jpg")
.TheNext(2)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-test.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-2-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.Build();
tvdbSeries = Builder<TvdbSeries>
.CreateNew()
.With(s => s.Id = 79488)
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.With(s => s.Episodes = tvdbEpisodes.ToList())
.Build();
tvdbSeries.Banners.AddRange(seasonBanners);
}
private void WithUseBanners()
{
Mocker.GetMock<ConfigProvider>().SetupGet(s => s.MetadataUseBanners).Returns(true);
}
private void WithSingleEpisodeFile()
{
var episode = Builder<Episode>.CreateNew()
.With(e => e.SeasonNumber = 1)
.With(e => e.SeriesId = 79488)
.With(e => e.EpisodeNumber = 1)
.Build();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodesByFileId(episodeFile.EpisodeFileId))
.Returns(new List<Episode> { episode });
}
private void WithMultiEpisodeFile()
{
var episodes = Builder<Episode>.CreateListOfSize(2)
.All()
.With(e => e.SeriesId = 79488)
.With(e => e.SeasonNumber = 1)
.Build();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodesByFileId(episodeFile.EpisodeFileId))
.Returns(episodes.ToList());
}
[Test]
public void should_not_blowup()
{
WithSingleEpisodeFile();
Mocker.Resolve<Xbmc>().CreateForEpisodeFile(episodeFile, tvdbSeries);
}
[Test]
public void should_call_diskprovider_writeAllText_once_for_single_episode()
{
WithSingleEpisodeFile();
Mocker.Resolve<Xbmc>().CreateForEpisodeFile(episodeFile, tvdbSeries);
Mocker.GetMock<DiskProvider>().Verify(v => v.WriteAllText(episodeFile.Path.Replace("avi", "nfo"), It.IsAny<string>()), Times.Once());
}
[Test]
public void should_call_diskprovider_writeAllText_once_for_multi_episode()
{
WithMultiEpisodeFile();
Mocker.Resolve<Xbmc>().CreateForEpisodeFile(episodeFile, tvdbSeries);
Mocker.GetMock<DiskProvider>().Verify(v => v.WriteAllText(episodeFile.Path.Replace("avi", "nfo"), It.IsAny<string>()), Times.Once());
}
[Test]
public void should_download_thumbnail_when_thumbnail_path_is_not_null()
{
WithSingleEpisodeFile();
Mocker.Resolve<Xbmc>().CreateForEpisodeFile(episodeFile, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.Episodes.First().BannerPath, episodeFile.Path.Replace("avi", "tbn")), Times.Once());
}
}
}

View File

@ -0,0 +1,165 @@
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.Providers.Core;
using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Test.ProviderTests.Metadata
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class Xbmc_ForSeries_Fixture : CoreTest
{
private Series series;
private TvdbSeries tvdbSeries;
[SetUp]
public void Setup()
{
WithTempAsAppPath();
series = Builder<Series>
.CreateNew()
.With(s => s.SeriesId == 79488)
.With(s => s.Title == "30 Rock")
.Build();
var seasonBanners = Builder<TvdbSeasonBanner>
.CreateListOfSize(4)
.TheFirst(2)
.With(b => b.Season = 1)
.TheLast(2)
.With(b => b.Season = 2)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-1-1.jpg")
.TheNext(2)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-test.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-2-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.Build();
tvdbSeries = Builder<TvdbSeries>
.CreateNew()
.With(s => s.Id = 79488)
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.Build();
tvdbSeries.Banners.AddRange(seasonBanners);
}
private void WithUseBanners()
{
Mocker.GetMock<ConfigProvider>().SetupGet(s => s.MetadataUseBanners).Returns(true);
}
private void WithSpecials()
{
var seasonBanners = Builder<TvdbSeasonBanner>
.CreateListOfSize(2)
.All()
.With(b => b.Season = 0)
.TheFirst(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.season)
.With(b => b.BannerPath = "seasons/79488-0-1.jpg")
.TheLast(1)
.With(b => b.BannerType = TvdbSeasonBanner.Type.seasonwide)
.With(b => b.BannerPath = "banners/seasons/79488-0-1.jpg")
.Build();
var seriesActors = Builder<TvdbActor>
.CreateListOfSize(5)
.Build();
tvdbSeries = Builder<TvdbSeries>
.CreateNew()
.With(s => s.Id = 79488)
.With(s => s.SeriesName = "30 Rock")
.With(s => s.TvdbActors = seriesActors.ToList())
.Build();
tvdbSeries.Banners.AddRange(seasonBanners);
}
[Test]
public void should_not_blowup()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
}
[Test]
public void should_call_diskprovider_writeAllText()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<DiskProvider>().Verify(v => v.WriteAllText(Path.Combine(series.Path, "tvshow.nfo"), It.IsAny<string>()), Times.Once());
}
[Test]
public void should_download_fanart()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
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.PosterPath, Path.Combine(series.Path, "folder.jpg")), Times.Once());
}
[Test]
public void should_download_banner_when_useBanners_is_true()
{
WithUseBanners();
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(tvdbSeries.BannerPath, Path.Combine(series.Path, "folder.jpg")), Times.Once());
}
[Test]
public void should_download_season_poster_when_useBanners_is_false()
{
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(It.Is<string>(s => !s.Contains("banners")), It.IsRegex(@"season\d{2}\.tbn")), Times.Exactly(2));
}
[Test]
public void should_download_season_banner_when_useBanners_is_true()
{
WithUseBanners();
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(It.Is<string>(s => s.Contains("banners")), It.IsRegex(@"season\d{2}\.tbn")), Times.Exactly(2));
}
[Test]
public void should_download_special_thumb_with_proper_name()
{
WithUseBanners();
WithSpecials();
Mocker.Resolve<Xbmc>().CreateForSeries(series, tvdbSeries);
Mocker.GetMock<BannerProvider>().Verify(v => v.Download(It.Is<string>(s => s.Contains("banners")), It.IsRegex(@"season-specials.tbn")), Times.Exactly(1));
}
}
}

View File

@ -210,7 +210,7 @@ public void when_no_file_are_imported_and_folder_size_isnt_small_enought_folder_
Mocker.GetMock<DiskProvider>().Setup(s => s.MoveDirectory(droppedFolder.FullName, taggedFolder));
Mocker.GetMock<DiskProvider>().Setup(s => s.GetDirectorySize(droppedFolder.FullName)).Returns(Constants.IgnoreFileSize + 10.Megabytes());
Mocker.GetMock<DiskScanProvider>().Setup(s => s.Scan(fakeSeries, droppedFolder.FullName)).Returns(fakeEpisodeFiles);
Mocker.GetMock<DiskScanProvider>().Setup(s => s.MoveEpisodeFile(It.IsAny<EpisodeFile>(), true)).Returns(true);
Mocker.GetMock<DiskScanProvider>().Setup(s => s.MoveEpisodeFile(It.IsAny<EpisodeFile>(), true)).Returns(new EpisodeFile());
Mocker.Resolve<PostDownloadProvider>().ProcessDownload(droppedFolder);
@ -281,9 +281,10 @@ public void when_files_are_imported_and_folder_is_small_enought_dir_should_be_de
Mocker.GetMock<SeriesProvider>().Setup(s => s.FindSeries("office")).Returns(fakeSeries);
Mocker.GetMock<DiskScanProvider>().Setup(s => s.CleanUpDropFolder(droppedFolder.FullName));
Mocker.GetMock<DiskScanProvider>().Setup(s => s.Scan(fakeSeries, droppedFolder.FullName)).Returns(fakeEpisodeFiles);
Mocker.GetMock<DiskScanProvider>().Setup(s => s.MoveEpisodeFile(It.IsAny<EpisodeFile>(), true)).Returns(true);
Mocker.GetMock<DiskScanProvider>().Setup(s => s.MoveEpisodeFile(It.IsAny<EpisodeFile>(), true)).Returns(new EpisodeFile());
Mocker.GetMock<DiskProvider>().Setup(s => s.GetDirectorySize(droppedFolder.FullName)).Returns(Constants.IgnoreFileSize - 1.Megabytes());
Mocker.GetMock<DiskProvider>().Setup(s => s.DeleteFolder(droppedFolder.FullName, true));
Mocker.GetMock<MetadataProvider>().Setup(s => s.CreateForEpisodeFiles(It.IsAny<List<EpisodeFile>>()));
//Act
Mocker.Resolve<PostDownloadProvider>().ProcessDownload(droppedFolder);

View File

@ -13,6 +13,7 @@
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository;
using PetaPoco;
using SignalR;
@ -20,6 +21,7 @@
using SignalR.Infrastructure;
using SignalR.Ninject;
using Connection = NzbDrone.Core.Datastore.Connection;
using Xbmc = NzbDrone.Core.Providers.ExternalNotification.Xbmc;
namespace NzbDrone.Core
{
@ -45,6 +47,7 @@ public CentralDispatch()
InitQuality();
InitExternalNotifications();
InitMetadataProviders();
InitIndexers();
InitJobs();
}
@ -161,6 +164,16 @@ private void InitExternalNotifications()
Kernel.Get<ExternalNotificationProvider>().InitializeNotifiers(notifiers.ToList());
}
private void InitMetadataProviders()
{
logger.Debug("Initializing Metadata Providers...");
Kernel.Bind<MetadataBase>().To<Providers.Metadata.Xbmc>().InSingletonScope();
var providers = Kernel.GetAll<MetadataBase>();
Kernel.Get<MetadataProvider>().Initialize(providers.ToList());
}
public void DedicateToHost()
{
try

View File

@ -0,0 +1,21 @@
using System.Data;
using Migrator.Framework;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20120707)]
public class Migration20120707 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
Database.AddTable("MetadataDefinitions", new[]
{
new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
new Column("Enable", DbType.Boolean, ColumnProperty.NotNull),
new Column("MetadataProviderType", DbType.String, ColumnProperty.NotNull),
new Column("Name", DbType.String, ColumnProperty.NotNull)
});
}
}
}

View File

@ -1,9 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System;
using NLog;
using Ninject;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs
{
@ -13,17 +15,20 @@ public class RenameSeasonJob : IJob
private readonly DiskScanProvider _diskScanProvider;
private readonly ExternalNotificationProvider _externalNotificationProvider;
private readonly SeriesProvider _seriesProvider;
private readonly MetadataProvider _metadataProvider;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
[Inject]
public RenameSeasonJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider,
ExternalNotificationProvider externalNotificationProvider, SeriesProvider seriesProvider)
ExternalNotificationProvider externalNotificationProvider, SeriesProvider seriesProvider,
MetadataProvider metadataProvider)
{
_mediaFileProvider = mediaFileProvider;
_diskScanProvider = diskScanProvider;
_externalNotificationProvider = externalNotificationProvider;
_seriesProvider = seriesProvider;
_metadataProvider = metadataProvider;
}
public string Name
@ -57,18 +62,32 @@ public void Start(ProgressNotification notification, int targetId, int secondary
return;
}
var newEpisodeFiles = new List<EpisodeFile>();
var oldEpisodeFiles = new List<EpisodeFile>();
foreach (var episodeFile in episodeFiles)
{
try
{
_diskScanProvider.MoveEpisodeFile(episodeFile);
}
catch (Exception exception)
var newFile = _diskScanProvider.MoveEpisodeFile(episodeFile);
if (newFile != null)
{
logger.WarnException("An error has occurred while renaming file", exception);
newEpisodeFiles.Add(newFile);
oldEpisodeFiles.Add(episodeFile);
}
}
catch (Exception e)
{
logger.WarnException("An error has occurred while renaming file", e);
}
}
//Remove & Create Metadata for episode files
_metadataProvider.RemoveForEpisodeFiles(oldEpisodeFiles);
_metadataProvider.CreateForEpisodeFiles(newEpisodeFiles);
//Start AfterRename
var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, secondaryTargetId);

View File

@ -1,9 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System;
using NLog;
using Ninject;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs
{
@ -13,17 +15,20 @@ public class RenameSeriesJob : IJob
private readonly DiskScanProvider _diskScanProvider;
private readonly ExternalNotificationProvider _externalNotificationProvider;
private readonly SeriesProvider _seriesProvider;
private readonly MetadataProvider _metadataProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject]
public RenameSeriesJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider,
ExternalNotificationProvider externalNotificationProvider, SeriesProvider seriesProvider)
ExternalNotificationProvider externalNotificationProvider, SeriesProvider seriesProvider,
MetadataProvider metadataProvider)
{
_mediaFileProvider = mediaFileProvider;
_diskScanProvider = diskScanProvider;
_externalNotificationProvider = externalNotificationProvider;
_seriesProvider = seriesProvider;
_metadataProvider = metadataProvider;
}
public string Name
@ -54,19 +59,32 @@ public void Start(ProgressNotification notification, int targetId, int secondary
return;
}
var newEpisodeFiles = new List<EpisodeFile>();
var oldEpisodeFiles = new List<EpisodeFile>();
foreach (var episodeFile in episodeFiles)
{
try
{
_diskScanProvider.MoveEpisodeFile(episodeFile);
var newFile = _diskScanProvider.MoveEpisodeFile(episodeFile);
if (newFile != null)
{
newEpisodeFiles.Add(newFile);
oldEpisodeFiles.Add(episodeFile);
}
}
catch(Exception e)
{
Logger.WarnException("An error has occurred while renaming file", e);
}
}
//Remove & Create Metadata for episode files
_metadataProvider.RemoveForEpisodeFiles(oldEpisodeFiles);
_metadataProvider.CreateForEpisodeFiles(newEpisodeFiles);
//Start AfterRename
var message = String.Format("Renamed: Series {0}", series.Title);

View File

@ -239,6 +239,7 @@
<Compile Include="Datastore\Migrations\Migration20110726.cs" />
<Compile Include="Datastore\Migrations\Migration20110707.cs" />
<Compile Include="Datastore\DbProviderFactory.cs" />
<Compile Include="Datastore\Migrations\Migration20120707.cs" />
<Compile Include="Datastore\Migrations\NzbDroneMigration.cs" />
<Compile Include="Datastore\Migrations\SchemaInfo.cs" />
<Compile Include="Datastore\PetaPoco\EpisodeSeasonRelator.cs" />
@ -285,6 +286,9 @@
<Compile Include="Providers\Indexer\NzbIndex.cs" />
<Compile Include="Providers\Indexer\FileSharingTalk.cs" />
<Compile Include="Providers\Indexer\Wombles.cs" />
<Compile Include="Providers\MetadataProvider.cs" />
<Compile Include="Providers\Metadata\MetadataBase.cs" />
<Compile Include="Providers\Metadata\Xbmc.cs" />
<Compile Include="Providers\SearchHistoryProvider.cs" />
<Compile Include="Providers\SeasonProvider.cs" />
<Compile Include="Jobs\RecentBacklogSearchJob.cs" />
@ -314,6 +318,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Providers\StatsProvider.cs" />
<Compile Include="Repository\MetadataDefinition.cs" />
<Compile Include="Repository\Search\SearchHistoryItem.cs" />
<Compile Include="Repository\Search\SearchHistory.cs" />
<Compile Include="Model\ReportRejectionType.cs" />

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -81,5 +81,22 @@ public virtual bool Delete(int seriesId)
}
return true;
}
public virtual void Download(string remotePath, string filename)
{
var url = BANNER_URL_PREFIX + remotePath;
try
{
_httpProvider.DownloadFile(url, filename);
logger.Trace("Successfully download banner from '{0}' to '{1}'", url, filename);
}
catch (Exception ex)
{
var message = String.Format("Failed to download Banner from '{0}' to '{1}'", url, filename);
logger.DebugException(message, ex);
throw;
}
}
}
}

View File

@ -501,6 +501,13 @@ public virtual string PlexPassword
set { SetValue("PlexPassword", value); }
}
public virtual Boolean MetadataUseBanners
{
get { return GetValueBoolean("MetadataUseBanners"); }
set { SetValue("MetadataUseBanners", value); }
}
private string GetValue(string key)
{
return GetValue(key, String.Empty);

View File

@ -168,7 +168,7 @@ public virtual EpisodeFile ImportFile(Series series, string filePath)
return episodeFile;
}
public virtual bool MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload = false)
public virtual EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload = false)
{
if (episodeFile == null)
throw new ArgumentNullException("episodeFile");
@ -182,7 +182,7 @@ public virtual bool MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload =
if (DiskProvider.PathEquals(episodeFile.Path, newFile.FullName))
{
Logger.Debug("Skipping file rename, source and destination are the same: {0}", episodeFile.Path);
return false;
return null;
}
_diskProvider.CreateDirectory(newFile.DirectoryName);
@ -213,7 +213,7 @@ public virtual bool MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload =
_externalNotificationProvider.OnRename(message, series);
}
return true;
return episodeFile;
}
/// <summary>

View File

@ -0,0 +1,65 @@
using System;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers.Metadata
{
public abstract class MetadataBase
{
protected readonly Logger _logger;
protected readonly ConfigProvider _configProvider;
protected readonly DiskProvider _diskProvider;
protected readonly BannerProvider _bannerProvider;
protected readonly EpisodeProvider _episodeProvider;
protected MetadataBase(ConfigProvider configProvider, DiskProvider diskProvider,
BannerProvider bannerProvider, EpisodeProvider episodeProvider)
{
_configProvider = configProvider;
_diskProvider = diskProvider;
_bannerProvider = bannerProvider;
_episodeProvider = episodeProvider;
_logger = LogManager.GetLogger(GetType().ToString());
}
/// <summary>
/// Gets the name for the metabase provider
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Creates metadata for a series
/// </summary>
/// <param name = "series">The series to create the metadata for</param>
/// <param name = "tvDbSeries">Series information from TheTvDb</param>
public abstract void CreateForSeries(Series series, TvdbSeries tvDbSeries);
/// <summary>
/// Creates metadata for the episode file
/// </summary>
/// <param name = "episodeFile">The episode file to create the metadata</param>
/// <param name = "tvDbSeries">Series information from TheTvDb</param>
public abstract void CreateForEpisodeFile(EpisodeFile episodeFile, TvdbSeries tvDbSeries);
/// <summary>
/// Removes metadata for a series
/// </summary>
/// <param name = "series">The series to create the metadata for</param>
public abstract void RemoveForSeries(Series series);
/// <summary>
/// Removes metadata for the episode file
/// </summary>
/// <param name = "episodeFile">The episode file to create the metadata</param>
public abstract void RemoveForEpisodeFile(EpisodeFile episodeFile);
public virtual string GetEpisodeGuideUrl(int seriesId)
{
return String.Format("http://www.thetvdb.com/api/{0}/series/{1}/all/en.zip", TvDbProvider.TVDB_APIKEY, seriesId);
}
}
}

View File

@ -0,0 +1,248 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Providers.Metadata
{
public class Xbmc : MetadataBase
{
protected readonly Logger _logger = LogManager.GetCurrentClassLogger();
public Xbmc(ConfigProvider configProvider, DiskProvider diskProvider, BannerProvider bannerProvider, EpisodeProvider episodeProvider)
: base(configProvider, diskProvider, bannerProvider, episodeProvider)
{
}
public override string Name
{
get { return "XBMC"; }
}
public override void CreateForSeries(Series series, TvdbSeries tvDbSeries)
{
//Create tvshow.nfo, fanart.jpg, folder.jpg and season##.tbn
var episodeGuideUrl = GetEpisodeGuideUrl(series.SeriesId);
_logger.Debug("Generating tvshow.nfo for: {0}", series.Title);
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
{
var tvShow = new XElement("tvshow");
tvShow.Add(new XElement("title", tvDbSeries.SeriesName));
tvShow.Add(new XElement("rating", tvDbSeries.Rating));
tvShow.Add(new XElement("plot", tvDbSeries.Overview));
tvShow.Add(new XElement("episodeguide", new XElement("url"), episodeGuideUrl));
tvShow.Add(new XElement("episodeguideurl", episodeGuideUrl));
tvShow.Add(new XElement("mpaa", tvDbSeries.ContentRating));
tvShow.Add(new XElement("genre", tvDbSeries.GenreString));
tvShow.Add(new XElement("premiered", tvDbSeries.FirstAired.ToString("yyyy-MM-dd")));
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", actor.ActorImage)
));
}
var doc = new XDocument(tvShow);
doc.Save(xw);
_logger.Debug("Saving tvshow.nfo for {0}", series.Title);
_diskProvider.WriteAllText(Path.Combine(series.Path, "tvshow.nfo"), doc.ToString());
}
_logger.Debug("Downloading fanart for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.FanartPath, Path.Combine(series.Path, "fanart.jpg"));
if (_configProvider.MetadataUseBanners)
{
_logger.Debug("Downloading series banner for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.BannerPath, Path.Combine(series.Path, "folder.jpg"));
_logger.Debug("Downloading Season banners for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.seasonwide);
}
else
{
_logger.Debug("Downloading series thumbnail for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.PosterPath, Path.Combine(series.Path, "folder.jpg"));
_logger.Debug("Downloading Season posters for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.season);
}
}
public override void CreateForEpisodeFile(EpisodeFile episodeFile, TvdbSeries tvDbSeries)
{
//Create filename.tbn and filename.nfo
var episodes = _episodeProvider.GetEpisodesByFileId(episodeFile.EpisodeFileId);
if (!episodes.Any())
{
_logger.Debug("No episodes where found for this episode file: {0}", episodeFile.EpisodeFileId);
return;
}
var episodeFileThumbnail = tvDbSeries.Episodes.FirstOrDefault(
e =>
e.SeasonNumber == episodeFile.SeasonNumber &&
e.EpisodeNumber == episodes.First().EpisodeNumber);
if (episodeFileThumbnail == null || String.IsNullOrWhiteSpace(episodeFileThumbnail.BannerPath))
{
_logger.Debug("No thumbnail is available for this episode");
return;
}
_logger.Debug("Downloading episode thumbnail for: {0}", episodeFile.EpisodeFileId);
_bannerProvider.Download(episodeFileThumbnail.BannerPath, episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".tbn"));
_logger.Debug("Generating filename.nfo for: {0}", episodeFile.EpisodeFileId);
var xmlResult = String.Empty;
foreach (var episode in episodes)
{
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
{
var doc = new XDocument();
var tvdbEpisode = tvDbSeries.Episodes.FirstOrDefault(
e =>
e.Id == episode.TvDbEpisodeId);
if (tvdbEpisode == null)
{
_logger.Debug("Looking up by TvDbEpisodeId failed, trying to match via season/episode number combination");
tvdbEpisode = tvDbSeries.Episodes.FirstOrDefault(
e =>
e.SeasonNumber == episode.SeasonNumber &&
e.EpisodeNumber == episode.EpisodeNumber);
}
if (tvdbEpisode == null)
{
_logger.Debug("Unable to find episode from TvDb - skipping");
return;
}
var details = new XElement("episodedetails");
details.Add(new XElement("title", tvdbEpisode.EpisodeName));
details.Add(new XElement("season", tvdbEpisode.SeasonNumber));
details.Add(new XElement("episode", tvdbEpisode.EpisodeNumber));
details.Add(new XElement("aired", tvdbEpisode.FirstAired));
details.Add(new XElement("plot", tvDbSeries.Overview));
details.Add(new XElement("displayseason"));
details.Add(new XElement("displayepisode"));
details.Add(new XElement("thumb", "http://www.thetvdb.com/banners/" + tvdbEpisode.BannerPath));
details.Add(new XElement("watched", "false"));
details.Add(new XElement("credits", tvdbEpisode.Writer.First()));
details.Add(new XElement("director", tvdbEpisode.Directors.First()));
details.Add(new XElement("rating", tvDbSeries.Rating));
foreach(var actor in tvdbEpisode.GuestStars)
{
if (!String.IsNullOrWhiteSpace(actor))
continue;
details.Add(new XElement("actor",
new XElement("name", actor)
));
}
foreach(var actor in tvDbSeries.TvdbActors)
{
details.Add(new XElement("actor",
new XElement("name", actor.Name),
new XElement("role", actor.Role),
new XElement("thumb", actor.ActorImage)
));
}
doc.Add(details);
doc.Save(xw);
xmlResult += doc.ToString();
}
}
var filename = episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".nfo");
_logger.Debug("Saving episodedetails to: {0}", filename);
_diskProvider.WriteAllText(filename, xmlResult);
}
public override void RemoveForSeries(Series series)
{
//Remove tvshow.nfo, fanart.jpg, folder.jpg and season##.tbn
_logger.Debug("Deleting series metadata for: ", series.Title);
_diskProvider.DeleteFile(Path.Combine(series.Path, "tvshow.nfo"));
_diskProvider.DeleteFile(Path.Combine(series.Path, "fanart.jpg"));
_diskProvider.DeleteFile(Path.Combine(series.Path, "fanart.jpg"));
foreach (var file in _diskProvider.GetFiles(series.Path, SearchOption.TopDirectoryOnly))
{
if (Path.GetExtension(file) != ".tbn")
continue;
if (!Path.GetFileName(file).StartsWith("season"))
continue;
_logger.Debug("Deleting season thumbnail: {0}", file);
_diskProvider.DeleteFile(file);
}
}
public override void RemoveForEpisodeFile(EpisodeFile episodeFile)
{
//Remove filename.tbn and filename.nfo
_logger.Debug("Deleting episode metadata for: {0}", episodeFile);
_diskProvider.DeleteFile(episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".nfo"));
_diskProvider.DeleteFile(episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".tbn"));
}
private void DownloadSeasonThumbnails(Series series, TvdbSeries tvDbSeries, TvdbSeasonBanner.Type bannerType)
{
var seasons = tvDbSeries.SeasonBanners.Where(s => s.BannerType == bannerType).Select(s => s.Season);
foreach (var season in seasons)
{
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)
{
_bannerProvider.Download(banner.BannerPath,
Path.Combine(series.Path, "season-specials.tbn"));
}
else
{
_bannerProvider.Download(banner.BannerPath,
Path.Combine(series.Path, String.Format("season{0:00}.tbn", season)));
}
}
}
}
}

View File

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers
{
public class MetadataProvider
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IDatabase _database;
private IEnumerable<MetadataBase> _metadataProviders;
private readonly TvDbProvider _tvDbProvider;
[Inject]
public MetadataProvider(IDatabase database, IEnumerable<MetadataBase> metadataProviders, TvDbProvider tvDbProvider)
{
_database = database;
_metadataProviders = metadataProviders;
_tvDbProvider = tvDbProvider;
}
public MetadataProvider()
{
}
public virtual List<MetadataDefinition> All()
{
return _database.Fetch<MetadataDefinition>();
}
public virtual void SaveSettings(MetadataDefinition settings)
{
if (settings.Id == 0)
{
Logger.Debug("Adding Metabase definition for {0}", settings.Name);
_database.Insert(settings);
}
else
{
Logger.Debug("Updating Metabase definition for {0}", settings.Name);
_database.Update(settings);
}
}
public virtual MetadataDefinition GetSettings(Type type)
{
return _database.SingleOrDefault<MetadataDefinition>("WHERE MetadataProviderType = @0", type.ToString());
}
public virtual IList<MetadataBase> GetEnabledMetabaseProviders()
{
var all = All();
return _metadataProviders.Where(i => all.Exists(c => c.MetadataProviderType == i.GetType().ToString() && c.Enable)).ToList();
}
public virtual void Initialize(IList<MetadataBase> metabaseProviders)
{
Logger.Debug("Initializing metabases. Count {0}", metabaseProviders.Count);
_metadataProviders = metabaseProviders;
var currentNotifiers = All();
foreach (var notificationProvider in metabaseProviders)
{
MetadataBase metadataProviderLocal = notificationProvider;
if (!currentNotifiers.Exists(c => c.MetadataProviderType == metadataProviderLocal.GetType().ToString()))
{
var settings = new MetadataDefinition
{
Enable = false,
MetadataProviderType = metadataProviderLocal.GetType().ToString(),
Name = metadataProviderLocal.Name
};
SaveSettings(settings);
}
}
}
public virtual void CreateForSeries(Series series)
{
var tvDbSeries = _tvDbProvider.GetSeries(series.SeriesId, false, true);
CreateForSeries(series, tvDbSeries);
}
public virtual void CreateForSeries(Series series, TvdbSeries tvDbSeries)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.CreateForSeries(series, tvDbSeries);
}
}
public virtual void CreateForEpisodeFile(EpisodeFile episodeFile)
{
var tvDbSeries = _tvDbProvider.GetSeries(episodeFile.SeriesId, true, true);
CreateForEpisodeFile(episodeFile, tvDbSeries);
}
public virtual void CreateForEpisodeFile(EpisodeFile episodeFile, TvdbSeries tvDbSeries)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.CreateForEpisodeFile(episodeFile, tvDbSeries);
}
}
public virtual void CreateForEpisodeFiles(List<EpisodeFile> episodeFiles)
{
var tvDbSeries = _tvDbProvider.GetSeries(episodeFiles.First().SeriesId, true, true);
foreach(var episodeFile in episodeFiles)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.CreateForEpisodeFile(episodeFile, tvDbSeries);
}
}
}
public virtual void RemoveForSeries(Series series)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.RemoveForSeries(series);
}
}
public virtual void RemoveForEpisodeFile(EpisodeFile episodeFile)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.RemoveForEpisodeFile(episodeFile);
}
}
public virtual void RemoveForEpisodeFiles(List<EpisodeFile> episodeFiles)
{
foreach (var episodeFile in episodeFiles)
{
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
provider.RemoveForEpisodeFile(episodeFile);
}
}
}
public virtual void RenameForEpisodeFile(EpisodeFile episodeFile)
{
}
}
}

View File

@ -16,14 +16,16 @@ public class PostDownloadProvider
private readonly DiskProvider _diskProvider;
private readonly DiskScanProvider _diskScanProvider;
private readonly SeriesProvider _seriesProvider;
private readonly MetadataProvider _metadataProvider;
[Inject]
public PostDownloadProvider(DiskProvider diskProvider, DiskScanProvider diskScanProvider,
SeriesProvider seriesProvider)
SeriesProvider seriesProvider, MetadataProvider metadataProvider)
{
_diskProvider = diskProvider;
_diskScanProvider = diskScanProvider;
_seriesProvider = seriesProvider;
_metadataProvider = metadataProvider;
}
public PostDownloadProvider()
@ -71,6 +73,9 @@ public virtual void ProcessDownload(DirectoryInfo subfolderInfo)
var importedFiles = _diskScanProvider.Scan(series, subfolderInfo.FullName);
importedFiles.ForEach(file => _diskScanProvider.MoveEpisodeFile(file, true));
//Create Metadata for all the episode files found
_metadataProvider.CreateForEpisodeFiles(importedFiles);
//Delete the folder only if folder is small enough
if (_diskProvider.GetDirectorySize(subfolderInfo.FullName) < Constants.IgnoreFileSize)
{

View File

@ -20,17 +20,19 @@ public class SeriesProvider
private readonly IDatabase _database;
private readonly SceneMappingProvider _sceneNameMappingProvider;
private readonly BannerProvider _bannerProvider;
private readonly MetadataProvider _metadataProvider;
private static readonly Regex TimeRegex = new Regex(@"^(?<time>\d+:?\d*)\W*(?<meridiem>am|pm)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public SeriesProvider(IDatabase database, ConfigProvider configProviderProvider,
TvDbProvider tvDbProviderProvider, SceneMappingProvider sceneNameMappingProvider,
BannerProvider bannerProvider)
BannerProvider bannerProvider, MetadataProvider metadataProvider)
{
_database = database;
_configProvider = configProviderProvider;
_tvDbProvider = tvDbProviderProvider;
_sceneNameMappingProvider = sceneNameMappingProvider;
_bannerProvider = bannerProvider;
_metadataProvider = metadataProvider;
}
public SeriesProvider()
@ -86,7 +88,7 @@ public virtual bool IsMonitored(long id)
public virtual Series UpdateSeriesInfo(int seriesId)
{
var tvDbSeries = _tvDbProvider.GetSeries(seriesId, false);
var tvDbSeries = _tvDbProvider.GetSeries(seriesId, false, true);
var series = GetSeries(seriesId);
series.SeriesId = tvDbSeries.Id;
@ -103,6 +105,8 @@ public virtual Series UpdateSeriesInfo(int seriesId)
series.Network = tvDbSeries.Network;
UpdateSeries(series);
_metadataProvider.CreateForSeries(series, tvDbSeries);
return series;
}

View File

@ -14,7 +14,7 @@ namespace NzbDrone.Core.Providers
public class TvDbProvider
{
private readonly EnvironmentProvider _environmentProvider;
private const string TVDB_APIKEY = "5D2D188E86E07F4F";
public const string TVDB_APIKEY = "5D2D188E86E07F4F";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly TvdbHandler _handler;
@ -44,13 +44,12 @@ public virtual IList<TvdbSearchResult> SearchSeries(string title)
}
}
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes)
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes, bool loadActors = false)
{
lock (_handler)
{
Logger.Debug("Fetching SeriesId'{0}' from tvdb", id);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, false, true, true);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, loadActors, true, true);
//Fix American Dad's scene gongshow
if (result != null && result.Id == 73141)
@ -86,6 +85,5 @@ public virtual TvdbSeries GetSeries(int id, bool loadEpisodes)
return result;
}
}
}
}

View File

@ -0,0 +1,17 @@
using PetaPoco;
namespace NzbDrone.Core.Repository
{
[TableName("MetadataDefinitions")]
[PrimaryKey("Id", autoIncrement = true)]
public class MetadataDefinition
{
public int Id { get; set; }
public bool Enable { get; set; }
public string MetadataProviderType { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -31,17 +31,19 @@ public class SettingsController : Controller
private readonly QualityTypeProvider _qualityTypeProvider;
private readonly ConfigFileProvider _configFileProvider;
private readonly NewznabProvider _newznabProvider;
private readonly MetadataProvider _metadataProvider;
public SettingsController(ConfigProvider configProvider, IndexerProvider indexerProvider,
QualityProvider qualityProvider, AutoConfigureProvider autoConfigureProvider,
SeriesProvider seriesProvider, ExternalNotificationProvider externalNotificationProvider,
QualityTypeProvider qualityTypeProvider,
ConfigFileProvider configFileProvider, NewznabProvider newznabProvider)
QualityTypeProvider qualityTypeProvider, ConfigFileProvider configFileProvider,
NewznabProvider newznabProvider, MetadataProvider metadataProvider)
{
_externalNotificationProvider = externalNotificationProvider;
_qualityTypeProvider = qualityTypeProvider;
_configFileProvider = configFileProvider;
_newznabProvider = newznabProvider;
_metadataProvider = metadataProvider;
_configProvider = configProvider;
_indexerProvider = indexerProvider;
_qualityProvider = qualityProvider;
@ -208,6 +210,10 @@ public ActionResult Naming()
model.NumberStyles = new SelectList(EpisodeSortingHelper.GetNumberStyles(), "Id", "Name");
model.MultiEpisodeStyles = new SelectList(EpisodeSortingHelper.GetMultiEpisodeStyles(), "Id", "Name");
//Metadata
model.MetadataXbmcEnabled = _metadataProvider.GetSettings(typeof(Core.Providers.Metadata.Xbmc)).Enable;
model.MetadataUseBanners = _configProvider.MetadataUseBanners;
return View(model);
}
@ -589,6 +595,14 @@ public JsonResult SaveNaming(EpisodeNamingModel data)
_configProvider.SortingNumberStyle = data.NumberStyle;
_configProvider.SortingMultiEpisodeStyle = data.MultiEpisodeStyle;
//Metadata
_configProvider.MetadataUseBanners = data.MetadataUseBanners;
//Xbmc
var xbmc = _metadataProvider.GetSettings(typeof(Core.Providers.Metadata.Xbmc));
xbmc.Enable = data.MetadataXbmcEnabled;
_metadataProvider.SaveSettings(xbmc);
return GetSuccessResult();
}

View File

@ -43,6 +43,14 @@ public class EpisodeNamingModel
[Description("How will multi-episode files be named?")]
public int MultiEpisodeStyle { get; set; }
[DisplayName("XBMC")]
[Description("Enable creating metadata for XBMC")]
public bool MetadataXbmcEnabled { get; set; }
[DisplayName("Use Banners")]
[Description("Use banners instead of posters?")]
public bool MetadataUseBanners { get; set; }
public SelectList SeparatorStyles { get; set; }
public SelectList NumberStyles { get; set; }
public SelectList MultiEpisodeStyles { get; set; }

View File

@ -543,6 +543,12 @@
<ItemGroup>
<Content Include="Views\System\Stats.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Settings\EpisodeNamingPartial.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Settings\MetadataPartial.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>

View File

@ -0,0 +1,53 @@
@using NzbDrone.Web.Helpers
@model NzbDrone.Web.Models.EpisodeNamingModel
@{
Layout = null;
}
<div class="settingsContainer">
@Html.ValidationSummary(true, "Unable to save your settings. Please correct the errors and try again.")
<label class="labelClass">@Html.LabelFor(m => m.SeriesName)
<span class="small">@Html.DescriptionFor(m => m.SeriesName)</span>
</label>
@Html.CheckBoxFor(m => m.SeriesName, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.EpisodeName)
<span class="small">@Html.DescriptionFor(m => m.EpisodeName)</span>
</label>
@Html.CheckBoxFor(m => m.EpisodeName, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.ReplaceSpaces)
<span class="small">@Html.DescriptionFor(m => m.ReplaceSpaces)</span>
</label>
@Html.CheckBoxFor(m => m.ReplaceSpaces, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.AppendQuality)
<span class="small">@Html.DescriptionFor(m => m.AppendQuality)</span>
</label>
@Html.CheckBoxFor(m => m.AppendQuality, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeasonFolders)
<span class="small">@Html.DescriptionFor(m => m.SeasonFolders)</span>
</label>
@Html.CheckBoxFor(m => m.SeasonFolders, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeasonFolderFormat)
<span class="small">@Html.DescriptionFor(m => m.SeasonFolderFormat)</span>
</label>
@Html.TextBoxFor(m => m.SeasonFolderFormat, new { @class = "inputClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeparatorStyle)
<span class="small">@Html.DescriptionFor(m => m.SeparatorStyle)</span>
</label>
@Html.DropDownListFor(m => m.SeparatorStyle, Model.SeparatorStyles, new { @class = "inputClass selectClass" })
<label class="labelClass">@Html.LabelFor(m => m.NumberStyle)
<span class="small">@Html.DescriptionFor(m => m.NumberStyle)</span>
</label>
@Html.DropDownListFor(m => m.NumberStyle, Model.NumberStyles, new { @class = "inputClass selectClass" })
<label class="labelClass">@Html.LabelFor(m => m.MultiEpisodeStyle)
<span class="small">@Html.DescriptionFor(m => m.MultiEpisodeStyle)</span>
</label>
@Html.DropDownListFor(m => m.MultiEpisodeStyle, Model.MultiEpisodeStyles, new { @class = "inputClass selectClass" })
</div>
<div id="examples">
<div id="singleEpisodeExample">
<b>Single Episode Example: </b><span class="result"></span>
</div>
<div id="multiEpisodeExample">
<b>Multi-Episode Example: </b><span class="result"></span>
</div>
</div>

View File

@ -0,0 +1,15 @@
@using NzbDrone.Web.Helpers
@model NzbDrone.Web.Models.EpisodeNamingModel
@{
Layout = null;
}
<label class="labelClass">@Html.LabelFor(m => m.MetadataXbmcEnabled)
<span class="small">@Html.DescriptionFor(m => m.MetadataXbmcEnabled)</span>
</label>
@Html.CheckBoxFor(m => m.MetadataXbmcEnabled, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.MetadataUseBanners)
<span class="small">@Html.DescriptionFor(m => m.MetadataUseBanners)</span>
</label>
@Html.CheckBoxFor(m => m.MetadataUseBanners, new { @class = "inputClass checkClass" })

View File

@ -20,51 +20,15 @@
<div id="stylized">
@using (Html.BeginForm("SaveNaming", "Settings", FormMethod.Post, new { id = "NamingForm", name = "NamingForm", @class = "settingsForm" }))
{
<div class="settingsContainer">
@Html.ValidationSummary(true, "Unable to save your settings. Please correct the errors and try again.")
<label class="labelClass">@Html.LabelFor(m => m.SeriesName)
<span class="small">@Html.DescriptionFor(m => m.SeriesName)</span>
</label>
@Html.CheckBoxFor(m => m.SeriesName, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.EpisodeName)
<span class="small">@Html.DescriptionFor(m => m.EpisodeName)</span>
</label>
@Html.CheckBoxFor(m => m.EpisodeName, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.ReplaceSpaces)
<span class="small">@Html.DescriptionFor(m => m.ReplaceSpaces)</span>
</label>
@Html.CheckBoxFor(m => m.ReplaceSpaces, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.AppendQuality)
<span class="small">@Html.DescriptionFor(m => m.AppendQuality)</span>
</label>
@Html.CheckBoxFor(m => m.AppendQuality, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeasonFolders)
<span class="small">@Html.DescriptionFor(m => m.SeasonFolders)</span>
</label>
@Html.CheckBoxFor(m => m.SeasonFolders, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeasonFolderFormat)
<span class="small">@Html.DescriptionFor(m => m.SeasonFolderFormat)</span>
</label>
@Html.TextBoxFor(m => m.SeasonFolderFormat, new { @class = "inputClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeparatorStyle)
<span class="small">@Html.DescriptionFor(m => m.SeparatorStyle)</span>
</label>
@Html.DropDownListFor(m => m.SeparatorStyle, Model.SeparatorStyles, new { @class = "inputClass selectClass" })
<label class="labelClass">@Html.LabelFor(m => m.NumberStyle)
<span class="small">@Html.DescriptionFor(m => m.NumberStyle)</span>
</label>
@Html.DropDownListFor(m => m.NumberStyle, Model.NumberStyles, new { @class = "inputClass selectClass" })
<label class="labelClass">@Html.LabelFor(m => m.MultiEpisodeStyle)
<span class="small">@Html.DescriptionFor(m => m.MultiEpisodeStyle)</span>
</label>
@Html.DropDownListFor(m => m.MultiEpisodeStyle, Model.MultiEpisodeStyles, new { @class = "inputClass selectClass" })
<div class="jquery-accordion">
<h3><a href="#">Episode Naming</a></h3>
<div id="episodeNamingContainer">
@{Html.RenderPartial("EpisodeNamingPartial", Model);}
</div>
<div id="examples">
<div id="singleEpisodeExample">
<b>Single Episode Example: </b><span class="result"></span>
</div>
<div id="multiEpisodeExample">
<b>Multi-Episode Example: </b><span class="result"></span>
<h3><a href="#">Metadata</a></h3>
<div id="metadataContainer">
@{Html.RenderPartial("MetaDataPartial", Model);}
</div>
</div>

View File

@ -1,10 +1,12 @@
<SolutionConfiguration>
<FileVersion>0</FileVersion>
<AutoEnableOnStartup>Default</AutoEnableOnStartup>
<FileVersion>1</FileVersion>
<AutoEnableOnStartup>True</AutoEnableOnStartup>
<AllowParallelTestExecution>false</AllowParallelTestExecution>
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>
<FrameworkUtilisationTypeForGallio>UseStaticAnalysis</FrameworkUtilisationTypeForGallio>
<FrameworkUtilisationTypeForMSpec>UseStaticAnalysis</FrameworkUtilisationTypeForMSpec>
<FrameworkUtilisationTypeForMSTest>UseStaticAnalysis</FrameworkUtilisationTypeForMSTest>
<EngineModes>Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk</EngineModes>
<MetricsExclusionList>
</MetricsExclusionList>
</SolutionConfiguration>

View File

@ -0,0 +1,19 @@
<ProjectConfiguration>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
</ProjectConfiguration>