1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-10-05 15:47:20 +02:00

Merge branch 'master' into backbone

Conflicts:
	.gitignore
This commit is contained in:
Mark McDowall 2012-12-23 00:46:23 -08:00
commit 0bfc6cfe71
57 changed files with 1891 additions and 121 deletions

159
.gitignore vendored
View File

@ -1,54 +1,127 @@
# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
[Bb]in/
[Oo]bj/
#ignore thumbnails created by windows # mstest test results
Thumbs.db TestResults
#Ignore files build by Visual Studio
*.obj ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user *.user
*.aps *.sln.docstates
*.pch
*.vspscc # Build results
[Dd]ebug/
[Rr]elease/
x64/
*_i.c *_i.c
*_p.c *_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk *.ilk
*.log *.meta
[Bb]in *.obj
[Dd]ebug*/ *.pch
[Rr]elease]*/ *.pdb
*.lib *.pgc
*.pgd
*.rsp
*.sbr *.sbr
*.nzb *.tlb
obj/ *.tli
_ReSharper*/ *.tlh
[Tt]est *.tmp
*.log
*.vspscc
*.vssscc
.builds
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
[Rr]esult[s] [Rr]esult[s]
[Nn]zbs
[Bb]uild/
[Ll]ogs/
[Aa]pp_Data/
packages/
/FakesAssemblies/
#NZBDrone specific
*.db
*Web.Publish.xml
NzbDrone.Web/NzbDrone.Web.Publish.xml
*.sdf *.sdf
[Bb]anners
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*
# Mindbench SASS cache
.sass-cache/
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Publish Web Output
*.Publish.xml
# NuGet Packages Directory
packages
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql
TestResults
[Tt]est[Rr]esult*
*.Cache
ClientBin
[Ss]tyle[Cc]op.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
# Git Files
*.orig *.orig
_rawPackage/
NzbDrone.zip # Tools
NzbDrone.sln.DotSettings.user*
config.xml
UpdateLogs/
NzbDrone.Web/MediaCover
NzbDrone.fpr
nzbdrone.log*txt
_rawPackage_service/
_NCrunch_* _NCrunch_*
_TeamCity* _TeamCity*
NCrunch_*
# NzbDrone
config.xml
nzbdrone.log*txt
NzbDrone.Web/MediaCover
UpdateLogs/

View File

@ -1,6 +1,7 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
using System; using System;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
@ -88,6 +89,7 @@ public Process StartDummyProcess()
public void ToString_on_new_processInfo() public void ToString_on_new_processInfo()
{ {
Console.WriteLine(new ProcessInfo().ToString()); Console.WriteLine(new ProcessInfo().ToString());
ExceptionVerification.MarkInconclusive(typeof(Win32Exception));
} }
} }

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Results>0</Results>

View File

@ -0,0 +1,420 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Results>
<show>
<showid>6753</showid>
<name>Top Gear</name>
<link>http://www.tvrage.com/Top_Gear</link>
<country>UK</country>
<started>Oct/20/2002</started>
<ended></ended>
<seasons>18</seasons>
<status>Returning Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre></genre>
<genre>Automobiles</genre>
<genre>Comedy</genre>
</genres>
<network country="UK">BBC TWO</network>
<airtime>20:00</airtime>
<airday>Sunday</airday>
</show>
<show>
<showid>19321</showid>
<name>Top Gear (1978)</name>
<link>http://www.tvrage.com/shows/id-19321</link>
<country>UK</country>
<started>Jul/13/1978</started>
<ended>Dec/17/2001</ended>
<seasons>24</seasons>
<status>Canceled/Ended</status>
<runtime>30</runtime>
<classification>Reality</classification>
<genres>
<genre>Automobiles</genre>
</genres>
<network country="UK">BBC TWO</network>
<airtime>12:00</airtime>
<airday>Sunday</airday>
<akas>
<aka country="UK">Top Gear Xtra</aka>
</akas>
</show>
<show>
<showid>20568</showid>
<name>Top Gear (US)</name>
<link>http://www.tvrage.com/Top_Gear_US</link>
<country>US</country>
<started>Nov/21/2010</started>
<ended></ended>
<seasons>3</seasons>
<status>Returning Series</status>
<runtime>60</runtime>
<classification>Documentary</classification>
<genres>
<genre>Automobiles</genre>
<genre>Comedy</genre>
</genres>
<network country="US">History Channel</network>
<airtime>21:00</airtime>
<airday>Tuesday</airday>
<akas>
<aka attr="Unofficial Working Title">Top Gear USA</aka>
</akas>
</show>
<show>
<showid>20324</showid>
<name>Top Gear Australia</name>
<link>http://www.tvrage.com/shows/id-20324</link>
<country>AU</country>
<started>Sep/29/2008</started>
<ended></ended>
<seasons>4</seasons>
<status>Returning Series</status>
<runtime>60</runtime>
<classification>Documentary</classification>
<genres>
<genre>Automobiles</genre>
<genre>Comedy</genre>
</genres>
<network country="AU">GEM</network>
<airtime>18:30</airtime>
<airday>Saturday</airday>
</show>
<show>
<showid>20569</showid>
<name>Top Gear Motorsport</name>
<link>http://www.tvrage.com/shows/id-20569</link>
<country>UK</country>
<started>Mar/24/1995</started>
<ended>1998</ended>
<seasons>3</seasons>
<status>Canceled/Ended</status>
<runtime>30</runtime>
<classification>Sports</classification>
<genres>
<genre>Educational</genre>
<genre>Family</genre>
<genre>How To/Do It Yourself</genre>
</genres>
<network country="UK">BBC TWO</network>
<airtime>12:00</airtime>
<airday>Wednesday</airday>
</show>
<show>
<showid>6249</showid>
<name>Top Secret Life of Edgar Briggs</name>
<link>http://www.tvrage.com/shows/id-6249</link>
<country>UK</country>
<started>Sep/15/1974</started>
<ended>Dec/20/1974</ended>
<seasons>1</seasons>
<status>Canceled/Ended</status>
<runtime>30</runtime>
<classification>Scripted</classification>
<genres>
<genre>Comedy</genre>
</genres>
<network country="UK">ITV</network>
<airtime>19:00</airtime>
<airday>Friday</airday>
</show>
<show>
<showid>25253</showid>
<name>Popstar Wesley: Op weg naar de Top</name>
<link>http://www.tvrage.com/shows/id-25253</link>
<country>NL</country>
<started>Feb/06/2010</started>
<ended>Feb/27/2010</ended>
<seasons>1</seasons>
<status>Canceled/Ended</status>
<runtime>15</runtime>
<classification>Reality</classification>
<genres>
<genre>How To/Do It Yourself</genre>
<genre>Music</genre>
<genre>Talent</genre>
</genres>
<network country="NL">SBS 6</network>
<airtime>23:15</airtime>
<airday>Saturday</airday>
</show>
<show>
<showid>19649</showid>
<name>Top Chef: Masters</name>
<link>http://www.tvrage.com/Top_Chef-Masters</link>
<country>US</country>
<started>Jun/10/2009</started>
<ended></ended>
<seasons>4</seasons>
<status>Returning Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Cooking/Food</genre>
<genre>Family</genre>
<genre>Talent</genre>
</genres>
<network country="US">Bravo</network>
<airtime>22:00</airtime>
<airday>Wednesday</airday>
</show>
<show>
<showid>26212</showid>
<name>Top Chef: Just Desserts</name>
<link>http://www.tvrage.com/Top_Chef-Just_Desserts</link>
<country>US</country>
<started>Sep/15/2010</started>
<ended></ended>
<seasons>2</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Celebrities</genre>
<genre>Cooking/Food</genre>
<genre>Educational</genre>
<genre>Family</genre>
<genre>How To/Do It Yourself</genre>
<genre>Talent</genre>
</genres>
<network country="US">Bravo</network>
<airtime>22:00</airtime>
<airday>Wednesday</airday>
</show>
<show>
<showid>11210</showid>
<name>Top Design</name>
<link>http://www.tvrage.com/shows/id-11210</link>
<country>US</country>
<started>Jan/31/2007</started>
<ended>Nov/05/2008</ended>
<seasons>2</seasons>
<status>Canceled/Ended</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Celebrities</genre>
<genre>Educational</genre>
<genre>Family</genre>
<genre>Housing/Building</genre>
<genre>How To/Do It Yourself</genre>
</genres>
<network country="US">Bravo</network>
<airtime>22:00</airtime>
<airday>Wednesday</airday>
<akas>
<aka attr="Working Title">Top Decorator</aka>
<aka attr="Working Title">Top Designer</aka>
</akas>
</show>
<show>
<showid>15390</showid>
<name>Air Gear</name>
<link>http://www.tvrage.com/shows/id-15390</link>
<country>AJ</country>
<started>Apr/04/2006</started>
<ended>Sep/26/2006</ended>
<seasons>1</seasons>
<status>Canceled/Ended</status>
<runtime>30</runtime>
<classification>Animation</classification>
<genres>
<genre>Anime</genre>
<genre>Adventure</genre>
<genre>Sci-Fi</genre>
<genre>Tech/Gaming</genre>
</genres>
<network country="JP">TV Tokyo</network>
<airtime>12:00</airtime>
<airday>Wednesday</airday>
</show>
<show>
<showid>30933</showid>
<name>Top Guns</name>
<link>http://www.tvrage.com/shows/id-30933</link>
<country>US</country>
<started>Feb/15/2012</started>
<ended></ended>
<seasons>1</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Action</genre>
<genre>Family</genre>
<genre>How To/Do It Yourself</genre>
<genre>Talent</genre>
</genres>
<network country="US">H2 TV</network>
<airtime>22:00</airtime>
<airday>Wednesday</airday>
</show>
<show>
<showid>28150</showid>
<name>Top Chef Canada</name>
<link>http://www.tvrage.com/shows/id-28150</link>
<country>CA</country>
<started>Apr/11/2011</started>
<ended></ended>
<seasons>2</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Cooking/Food</genre>
<genre>Family</genre>
<genre>Talent</genre>
</genres>
<network country="CA">Food Network Canada</network>
<airtime>21:00</airtime>
<airday>Monday</airday>
</show>
<show>
<showid>6386</showid>
<name>Top of the Pops Saturday</name>
<link>http://www.tvrage.com/shows/id-6386</link>
<country>UK</country>
<started>Sep/20/2003</started>
<ended>Mar/26/2005</ended>
<seasons>2</seasons>
<status>Canceled/Ended</status>
<runtime>60</runtime>
<classification>Variety</classification>
<genres>
<genre>Children</genre>
</genres>
<network country="UK">BBC One</network>
<airtime>23:00</airtime>
<airday>Saturday</airday>
</show>
<show>
<showid>29633</showid>
<name>Top Secret Recipe</name>
<link>http://www.tvrage.com/shows/id-29633</link>
<country>US</country>
<started>Oct/07/2011</started>
<ended></ended>
<seasons>1</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Cooking/Food</genre>
<genre>How To/Do It Yourself</genre>
</genres>
<network country="US">CMT</network>
<airtime>21:00</airtime>
<airday>Thursday</airday>
</show>
<show>
<showid>26650</showid>
<name>The Top 100: NFL's Greatest Players</name>
<link>http://www.tvrage.com/shows/id-26650</link>
<country>US</country>
<started>Sep/03/2010</started>
<ended>Nov/04/2010</ended>
<seasons>1</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Sports</classification>
<genres>
<genre>Sports</genre>
</genres>
<network country="US">NFL Network</network>
<airtime>21:00</airtime>
<airday>Thursday</airday>
</show>
<show>
<showid>7047</showid>
<name>Top of the Pops Reloaded</name>
<link>http://www.tvrage.com/shows/id-7047</link>
<country>UK</country>
<started>Sep/2005</started>
<ended>Mar/2006</ended>
<seasons>2</seasons>
<status>Canceled/Ended</status>
<runtime>45</runtime>
<classification>Variety</classification>
<genres>
<genre>Children</genre>
<genre>Music</genre>
<genre>Sketch/Improv</genre>
</genres>
<network country="UK">CBBC</network>
<airtime>11:00</airtime>
<airday>Saturday</airday>
</show>
<show>
<showid>19475</showid>
<name>Top Model Ghana</name>
<link>http://www.tvrage.com/shows/id-19475</link>
<country>GH</country>
<started>Aug/26/2006</started>
<ended>Oct/16/2006</ended>
<seasons>1</seasons>
<status>Canceled/Ended</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Celebrities</genre>
<genre>Family</genre>
<genre>Fashion/Make-up</genre>
<genre>Talent</genre>
<genre>Travel</genre>
</genres>
<network country="GH">GTV</network>
<airtime>21:00</airtime>
<airday>Monday</airday>
<akas>
<aka attr="Alternate title" country="US">Ghana's Next Top Model</aka>
<aka attr="Abbreviated title" country="GH">TMG</aka>
<aka attr="1st Season title" country="GH">Top Model Ghana, Cycle</aka>
</akas>
</show>
<show>
<showid>31823</showid>
<name>Top 100 Video Games of All Time</name>
<link>http://www.tvrage.com/shows/id-31823</link>
<country>US</country>
<started>Jun/11/2012</started>
<ended></ended>
<seasons>1</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Mini-Series</classification>
<genres>
<genre>Family</genre>
<genre>Teens</genre>
</genres>
<network country="US">G4</network>
<airtime>20:00</airtime>
<airday>Weekdays</airday>
</show>
<show>
<showid>25003</showid>
<name>Cantore Stories: On Top of the World</name>
<link>http://www.tvrage.com/Cantore_Stories-On_Top_of_the_World</link>
<country>US</country>
<started>Jan/24/2010</started>
<ended></ended>
<seasons>1</seasons>
<status>New Series</status>
<runtime>60</runtime>
<classification>Reality</classification>
<genres>
<genre>Adventure</genre>
<genre>Educational</genre>
<genre>Family</genre>
<genre>Travel</genre>
</genres>
<network country="US">The Weather Channel</network>
<airtime>22:00</airtime>
<airday>Sunday</airday>
<akas>
<aka attr="Short title" country="US">Cantore Stories</aka>
</akas>
</show>
</Results>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Results>
<show>
<showid>27518</showid>
<name>Suits</name>
<link>http://www.tvrage.com/Suits</link>
<country>US</country>
<started>Jun/23/2011</started>
<ended></ended>
<seasons>2</seasons>
<status>Returning Series</status>
<runtime>60</runtime>
<classification>Scripted</classification>
<genres>
<genre>Drama</genre>
<genre>Financial/Business</genre>
</genres>
<network country="US">USA</network>
<airtime>22:00</airtime>
<airday>Thursday</airday>
<akas>
<aka attr="Working title" country="US">A Legal Mind</aka>
</akas>
</show>
</Results>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Showinfo></Showinfo>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Showinfo>
<showid>29999</showid>
<showname>Anger Management</showname>
<showlink>http://tvrage.com/shows/id-29999</showlink>
<seasons>2</seasons>
<started>2012</started>
<startdate>Jun/28/2012</startdate>
<ended></ended>
<origin_country>US</origin_country>
<status>Returning Series</status>
<classification>Scripted</classification>
<genres>
<genre>Comedy</genre>
</genres>
<runtime>30</runtime>
<network country="US">FX</network>
<airtime>21:30</airtime>
<airday>Thursday</airday>
<timezone>GMT-5 -DST</timezone>
</Showinfo>

View File

@ -12,16 +12,12 @@
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test.HelperTests
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class SortHelperTest : CoreTest public class SortHelperTest : CoreTest
{ {
//American Gladiators
//Ancient Apocalypse
//There Will Be Brawl
[TestCase("The Office (US)", "Office (US)")] [TestCase("The Office (US)", "Office (US)")]
[TestCase("A Man in Anger", "Man in Anger")] [TestCase("A Man in Anger", "Man in Anger")]
[TestCase("An Idiot Abroad", "Idiot Abroad")] [TestCase("An Idiot Abroad", "Idiot Abroad")]
@ -32,7 +28,7 @@ public class SortHelperTest : CoreTest
[TestCase(null, "")] [TestCase(null, "")]
public void SkipArticles(string title, string expected) public void SkipArticles(string title, string expected)
{ {
var result = SortHelper.SkipArticles(title); var result = title.IgnoreArticles();
result.Should().Be(expected); result.Should().Be(expected);
} }
} }

View File

@ -0,0 +1,67 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using FluentAssertions;
using NUnit.Framework;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Exceptions;
namespace NzbDrone.Core.Test.HelperTests.XElementHelperTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class ParseDayOfWeekFixture : CoreTest
{
[Test]
public void should_return_null_if_xelement_is_null()
{
XElement test = null;
test.ConvertToDayOfWeek().Should().Be(null);
}
[Test]
public void should_return_null_if_value_is_null()
{
new XElement("airday", null).ConvertToDayOfWeek().Should().Be(null);
}
[Test]
public void should_return_null_if_value_is_empty()
{
new XElement("airday", "").ConvertToDayOfWeek().Should().Be(null);
}
[Test]
public void should_return_null_if_value_is_daily()
{
new XElement("airday", "Daily").ConvertToDayOfWeek().Should().Be(null);
}
[Test]
public void should_return_null_if_value_is_weekdays()
{
new XElement("airday", "Weekdays").ConvertToDayOfWeek().Should().Be(null);
}
[TestCase("Sunday", DayOfWeek.Sunday)]
[TestCase("Monday", DayOfWeek.Monday)]
[TestCase("Tuesday", DayOfWeek.Tuesday)]
[TestCase("Wednesday", DayOfWeek.Wednesday)]
[TestCase("Thursday", DayOfWeek.Thursday)]
[TestCase("Friday", DayOfWeek.Friday)]
[TestCase("Saturday", DayOfWeek.Saturday)]
public void should_return_dayOfWeek_when_it_is_valid(string value, DayOfWeek expected)
{
new XElement("airday", value).ConvertToDayOfWeek().Should().Be(expected);
}
}
}

View File

@ -0,0 +1,70 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HelperTests.XElementHelperTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class XElementHelperTest : CoreTest
{
[Test]
public void Int32_should_return_zero_when_xelement_is_null()
{
XElement test = null;
test.ConvertTo<Int32>().Should().Be(0);
}
[Test]
public void Int32_should_return_zero_when_value_is_null()
{
new XElement("test", null).ConvertTo<Int32>().Should().Be(0);
}
[Test]
public void Int32_should_return_value_when_value_is_an_int()
{
new XElement("test", 10).ConvertTo<Int32>().Should().Be(10);
}
[Test]
public void Nullable_Int32_should_return_null_when_xelement_is_null()
{
XElement test = null;
test.ConvertTo<Nullable<Int32>>().Should().Be(null);
}
[Test]
public void DateTime_should_return_zero_when_xelement_is_null()
{
XElement test = null;
test.ConvertTo<DateTime>().Should().Be(DateTime.MinValue);
}
[Test]
public void DateTime_should_return_zero_when_value_is_null()
{
new XElement("test", null).ConvertTo<DateTime>().Should().Be(DateTime.MinValue);
}
[Test]
public void DateTime_should_return_value_when_value_is_a_date()
{
var date = DateTime.Today;
new XElement("test", date.ToString()).ConvertTo<DateTime>().Should().Be(date);
}
}
}

View File

@ -27,8 +27,6 @@ public void series_specific_scan_should_scan_series()
.With(s => s.SeriesId = 12) .With(s => s.SeriesId = 12)
.Build(); .Build();
WithStrictMocker();
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(series.SeriesId)) .Setup(p => p.GetSeries(series.SeriesId))
.Returns(series); .Returns(series);
@ -54,8 +52,6 @@ public void job_with_no_target_should_scan_all_series()
.TheNext(1).With(s => s.SeriesId = 15) .TheNext(1).With(s => s.SeriesId = 15)
.Build(); .Build();
WithStrictMocker();
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries()) .Setup(p => p.GetAllSeries())
.Returns(series); .Returns(series);
@ -82,8 +78,6 @@ public void failed_scan_should_not_terminated_job()
.TheNext(1).With(s => s.SeriesId = 15) .TheNext(1).With(s => s.SeriesId = 15)
.Build(); .Build();
WithStrictMocker();
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries()) .Setup(p => p.GetAllSeries())
.Returns(series); .Returns(series);
@ -111,8 +105,6 @@ public void job_with_no_target_should_scan_series_with_episodes()
.TheNext(1).With(s => s.SeriesId = 15) .TheNext(1).With(s => s.SeriesId = 15)
.Build(); .Build();
WithStrictMocker();
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries()) .Setup(p => p.GetAllSeries())
.Returns(series); .Returns(series);

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.JobTests
{
[TestFixture]
public class RenameSeasonJobFixture : TestBase
{
private ProgressNotification _testNotification;
private Series _series;
private IList<EpisodeFile> _episodeFiles;
[SetUp]
public void Setup()
{
_testNotification = new ProgressNotification("TEST");
_series = Builder<Series>
.CreateNew()
.Build();
_episodeFiles = Builder<EpisodeFile>
.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 5)
.Build();
Mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(_series.SeriesId))
.Returns(_series);
Mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeasonFiles(_series.SeriesId, 5))
.Returns(_episodeFiles);
}
private void WithMovedFiles()
{
Mocker.GetMock<DiskScanProvider>()
.Setup(s => s.MoveEpisodeFile(It.IsAny<EpisodeFile>(), false))
.Returns(_episodeFiles.First());
}
[Test]
public void should_throw_if_seriesId_is_zero()
{
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<RenameSeasonJob>().Start(_testNotification, new { SeriesId = 0, SeasonNumber = 10 }));
}
[Test]
public void should_throw_if_seasonId_is_less_than_zero()
{
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<RenameSeasonJob>().Start(_testNotification, new { SeriesId = _series.SeriesId, SeasonNumber = -10 }));
}
[Test]
public void should_log_warning_if_no_episode_files_are_found()
{
Mocker.Resolve<RenameSeasonJob>().Start(_testNotification, new { SeriesId = _series.SeriesId, SeasonNumber = 10 });
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_return_if_no_episodes_are_moved()
{
Mocker.Resolve<RenameSeasonJob>().Start(_testNotification, new { SeriesId = _series.SeriesId, SeasonNumber = 5 });
Mocker.GetMock<MetadataProvider>().Verify(v => v.RemoveForEpisodeFiles(It.IsAny<List<EpisodeFile>>()), Times.Never());
}
[Test]
public void should_return_process_metadata_if_files_are_moved()
{
WithMovedFiles();
Mocker.Resolve<RenameSeasonJob>().Start(_testNotification, new { SeriesId = _series.SeriesId, SeasonNumber = 5 });
Mocker.GetMock<MetadataProvider>().Verify(v => v.RemoveForEpisodeFiles(It.IsAny<List<EpisodeFile>>()), Times.Once());
}
}
}

View File

@ -144,6 +144,15 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="HelperTests\XElementHelperTests\ConvertToTFixture.cs" />
<Compile Include="JobTests\RenameSeasonJobFixture.cs" />
<Compile Include="ProviderTests\SearchProviderTests\GetSeriesTitleFixture.cs" />
<Compile Include="ProviderTests\TvRageMappingProviderTests\FindMatchingTvRageSeriesFixture.cs" />
<Compile Include="ProviderTests\TvRageMappingProviderTests\ProcessResultsFixture.cs" />
<Compile Include="ProviderTests\TvRageProviderTests\GetSeriesFixture.cs" />
<Compile Include="HelperTests\XElementHelperTests\ConvertToDayOfWeekFixture.cs" />
<Compile Include="ProviderTests\TvRageProviderTests\GetUtcOffsetFixture.cs" />
<Compile Include="ProviderTests\TvRageProviderTests\SearchSeriesFixture.cs" />
<Compile Include="QualityTypesTest.cs" /> <Compile Include="QualityTypesTest.cs" />
<Compile Include="EpisodeParseResultTest.cs" /> <Compile Include="EpisodeParseResultTest.cs" />
<Compile Include="Integeration\ServiceIntegerationFixture.cs" /> <Compile Include="Integeration\ServiceIntegerationFixture.cs" />
@ -204,7 +213,7 @@
<Compile Include="ProviderTests\XemCommunicationProviderTests\GetSceneTvdbMappingsFixture.cs" /> <Compile Include="ProviderTests\XemCommunicationProviderTests\GetSceneTvdbMappingsFixture.cs" />
<Compile Include="ProviderTests\XemCommunicationProviderTests\GetXemSeriesIdsFixture.cs" /> <Compile Include="ProviderTests\XemCommunicationProviderTests\GetXemSeriesIdsFixture.cs" />
<Compile Include="Services\ParseErrorServiceFixture.cs" /> <Compile Include="Services\ParseErrorServiceFixture.cs" />
<Compile Include="SortHelperTest.cs" /> <Compile Include="HelperTests\SortHelperFixture.cs" />
<Compile Include="ProviderTests\EpisodeProviderTests\EpisodeProviderTest_DeleteInvalidEpisodes.cs" /> <Compile Include="ProviderTests\EpisodeProviderTests\EpisodeProviderTest_DeleteInvalidEpisodes.cs" />
<Compile Include="ProviderTests\DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" /> <Compile Include="ProviderTests\DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="ProviderTests\QualityTypeProviderTest.cs" /> <Compile Include="ProviderTests\QualityTypeProviderTest.cs" />
@ -333,6 +342,21 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<Content Include="Files\TvRage\SeriesInfo_empty.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\TvRage\SeriesInfo_one.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\TvRage\SearchResults_one.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\TvRage\SearchResults_many.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\TvRage\SearchResults_empty.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Xem\Ids.txt"> <Content Include="Files\Xem\Ids.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>

View File

@ -72,6 +72,10 @@ public class ParserTest : CoreTest
[TestCase("Top Gear - 07x03 - 2005.11.70", "Top Gear", 7, 3)] [TestCase("Top Gear - 07x03 - 2005.11.70", "Top Gear", 7, 3)]
[TestCase("Hatfields and McCoys 2012 Part 1 REPACK 720p HDTV x264 2HD", "Hatfields and McCoys 2012", 1, 1)] [TestCase("Hatfields and McCoys 2012 Part 1 REPACK 720p HDTV x264 2HD", "Hatfields and McCoys 2012", 1, 1)]
[TestCase("Glee.S04E09.Swan.Song.1080p.WEB-DL.DD5.1.H.264-ECI", "Glee", 4, 9)] [TestCase("Glee.S04E09.Swan.Song.1080p.WEB-DL.DD5.1.H.264-ECI", "Glee", 4, 9)]
[TestCase("S08E20 50-50 Carla [DVD]", "", 8, 20)]
[TestCase("Cheers S08E20 50-50 Carla [DVD]", "Cheers", 8, 20)]
[TestCase("S02E10 6-50 to SLC [SDTV]", "", 2, 10)]
[TestCase("Franklin & Bash S02E10 6-50 to SLC [SDTV]", "Franklin & Bash", 2, 10)]
public void ParseTitle_single(string postTitle, string title, int seasonNumber, int episodeNumber) public void ParseTitle_single(string postTitle, string title, int seasonNumber, int episodeNumber)
{ {
var result = Parser.ParseTitle(postTitle); var result = Parser.ParseTitle(postTitle);
@ -396,5 +400,12 @@ public void parse_header(string title, string expected)
{ {
Parser.ParseHeader(title).Should().Be(expected); Parser.ParseHeader(title).Should().Be(expected);
} }
[TestCase("password - \"bdc435cb-93c4-4902-97ea-ca00568c3887.337\" yEnc")]
public void should_not_parse_encypted_posts(string title)
{
Parser.ParseTitle(title).Should().BeNull();
ExceptionVerification.IgnoreWarns();
}
} }
} }

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{
public class GetSeriesTitleFixture : TestBase
{
private Series _series;
private const string SCENE_NAME = "Scandal";
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.With(s => s.Title = "Scandal (2012)")
.Build();
}
private void WithSceneName()
{
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetSceneName(_series.SeriesId))
.Returns("Scandal");
}
[Test]
public void should_return_scene_name_when_sceneName_is_available()
{
WithSceneName();
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(SCENE_NAME);
}
[Test]
public void should_return_seriesTitle_when_sceneName_is_not_available()
{
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(_series.Title);
}
[TestCase("Mike & Molly", "Mike and Molly")]
[TestCase("Franklin & Bash", "Franklin and Bash")]
[TestCase("Law & Order", "Law and Order")]
public void should_replace_ampersand_with_and_when_returning_title(string seriesTitle, string expectedTitle)
{
_series.Title = seriesTitle;
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(expectedTitle);
}
}
}

View File

@ -63,7 +63,7 @@ private void BuildIndexers(IList<EpisodeParseResult> parseResults)
.Returns(parseResults); .Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())) _episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults); .Returns(parseResults);
_episodeIndexer1.Setup(s => s.Name).Returns("Episode Indexer 1");
_episodeIndexer2 = new Mock<IndexerBase>(); _episodeIndexer2 = new Mock<IndexerBase>();
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())) _episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
@ -74,14 +74,17 @@ private void BuildIndexers(IList<EpisodeParseResult> parseResults)
.Returns(parseResults); .Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())) _episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults); .Returns(parseResults);
_episodeIndexer2.Setup(s => s.Name).Returns("Episode Indexer 2");
_brokenIndexer = new Mock<IndexerBase>(); _brokenIndexer = new Mock<IndexerBase>();
_brokenIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())) _brokenIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception()); .Throws(new Exception());
_brokenIndexer.Setup(s => s.Name).Returns("Broken Indexer");
_nullIndexer = new Mock<IndexerBase>(); _nullIndexer = new Mock<IndexerBase>();
_nullIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())) _nullIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns<List<EpisodeParseResult>>(null); .Returns<List<EpisodeParseResult>>(null);
_nullIndexer.Setup(s => s.Name).Returns("Null Indexer");
} }
private void WithTwoGoodOneBrokenIndexer() private void WithTwoGoodOneBrokenIndexer()

View File

@ -36,6 +36,7 @@ public void TearDown()
[TestCase("The Simpsons")] [TestCase("The Simpsons")]
[TestCase("Family Guy")] [TestCase("Family Guy")]
[TestCase("South Park")] [TestCase("South Park")]
[TestCase("Franklin & Bash")]
public void successful_search(string title) public void successful_search(string title)
{ {
var result = tvDbProvider.SearchSeries(title); var result = tvDbProvider.SearchSeries(title);

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Model.TvRage;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.TvRageMappingProviderTests
{
public class FindMatchingTvRageSeriesFixture : TestBase
{
private IList<TvRageSearchResult> _searchResults;
private Series _series;
private Episode _episode;
private TvRageSeries _tvRageSeries;
[SetUp]
public void Setup()
{
_searchResults = Builder<TvRageSearchResult>
.CreateListOfSize(5)
.Build();
_series = Builder<Series>
.CreateNew()
.With(s => s.TvRageId = 0)
.With(s => s.TvRageTitle = null)
.With(s => s.UtcOffset = 0)
.Build();
_episode = Builder<Episode>
.CreateNew()
.With(e => e.AirDate = DateTime.Today.AddDays(-365))
.Build();
_tvRageSeries = Builder<TvRageSeries>
.CreateNew()
.With(s => s.UtcOffset = -8)
.Build();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisode(_series.SeriesId, 1, 1))
.Returns(_episode);
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetCleanName(_series.SeriesId))
.Returns("");
Mocker.GetMock<TvRageProvider>()
.Setup(s => s.SearchSeries(_series.Title))
.Returns(_searchResults);
Mocker.GetMock<TvRageProvider>()
.Setup(s => s.GetSeries(_searchResults.First().ShowId))
.Returns(_tvRageSeries);
}
private void WithMatchingResult()
{
_series.CleanTitle = Parser.NormalizeTitle(_searchResults.First().Name);
}
[Test]
public void should_not_set_tvRage_info_when_result_is_null()
{
var result = Mocker.Resolve<TvRageMappingProvider>()
.FindMatchingTvRageSeries(_series);
result.TvRageId.Should().Be(0);
result.TvRageTitle.Should().Be(null);
result.UtcOffset.Should().Be(0);
}
[Test]
public void should_set_tvRage_info_when_result_is_returned()
{
WithMatchingResult();
var result = Mocker.Resolve<TvRageMappingProvider>()
.FindMatchingTvRageSeries(_series);
result.TvRageId.Should().Be(_searchResults.First().ShowId);
result.TvRageTitle.Should().Be(_searchResults.First().Name);
result.UtcOffset.Should().Be(_tvRageSeries.UtcOffset);
}
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Model.TvRage;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.TvRageMappingProviderTests
{
public class ProcessResultsFixture : TestBase
{
private IList<TvRageSearchResult> _searchResults;
private Series _series;
private Episode _episode;
[SetUp]
public void Setup()
{
_searchResults = Builder<TvRageSearchResult>
.CreateListOfSize(5)
.Build();
_series = Builder<Series>.CreateNew().Build();
_episode = Builder<Episode>
.CreateNew()
.With(e => e.AirDate = DateTime.Today.AddDays(-365))
.Build();
}
[Test]
public void should_return_null_if_no_match_is_found()
{
Mocker.Resolve<TvRageMappingProvider>()
.ProcessResults(_searchResults, _series, "nomatchhere", _episode)
.Should()
.BeNull();
}
[Test]
public void should_return_result_if_series_clean_name_matches()
{
_series.CleanTitle = Parser.NormalizeTitle(_searchResults.First().Name);
Mocker.Resolve<TvRageMappingProvider>()
.ProcessResults(_searchResults, _series, "nomatchhere", _episode)
.Should()
.Be(_searchResults.First());
}
[Test]
public void should_return_result_if_scene_clean_name_matches()
{
Mocker.Resolve<TvRageMappingProvider>()
.ProcessResults(_searchResults, _series, Parser.NormalizeTitle(_searchResults.First().Name), _episode)
.Should()
.Be(_searchResults.First());
}
[Test]
public void should_return_result_if_firstAired_matches()
{
_episode.AirDate = _searchResults.Last().Started;
Mocker.Resolve<TvRageMappingProvider>()
.ProcessResults(_searchResults, _series, "nomatchhere", _episode)
.Should()
.Be(_searchResults.Last());
}
}
}

View File

@ -0,0 +1,59 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Exceptions;
namespace NzbDrone.Core.Test.ProviderTests.TvRageProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class GetSeriesFixture : CoreTest
{
private const string showinfo = "http://services.tvrage.com/feeds/showinfo.php?key=NW4v0PSmQIoVmpbASLdD&sid=";
private void WithEmptyResults()
{
Mocker.GetMock<HttpProvider>()
.Setup(s => s.DownloadStream(It.Is<String>(u => u.StartsWith(showinfo)), null))
.Returns(new FileStream(@".\Files\TVRage\SeriesInfo_empty.xml", FileMode.Open, FileAccess.Read, FileShare.Read));
}
private void WithOneResult()
{
Mocker.GetMock<HttpProvider>()
.Setup(s => s.DownloadStream(It.Is<String>(u => u.StartsWith(showinfo)), null))
.Returns(new FileStream(@".\Files\TVRage\SeriesInfo_one.xml", FileMode.Open, FileAccess.Read, FileShare.Read));
}
[Test]
public void should_be_null_when_no_showinfo_is_returned()
{
WithEmptyResults();
Mocker.Resolve<TvRageProvider>().GetSeries(100).Should().BeNull();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_return_series_when_showinfo_is_valid()
{
WithOneResult();
var result = Mocker.Resolve<TvRageProvider>().GetSeries(29999);
result.ShowId.Should().Be(29999);
result.Name.Should().Be("Anger Management");
}
}
}

View File

@ -0,0 +1,50 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Exceptions;
namespace NzbDrone.Core.Test.ProviderTests.TvRageProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class GetUtcOffsetFixture : CoreTest
{
[Test]
public void should_return_zero_if_timeZone_is_empty()
{
Mocker.Resolve<TvRageProvider>().GetUtcOffset("").Should().Be(0);
}
[Test]
public void should_return_zero_if_cannot_be_coverted_to_int()
{
Mocker.Resolve<TvRageProvider>().GetUtcOffset("adfhadfhdjaf").Should().Be(0);
}
[TestCase("GMT-5", -5)]
[TestCase("GMT+0", 0)]
[TestCase("GMT+8", 8)]
public void should_return_offset_when_not_dst(string timezone, int expected)
{
Mocker.Resolve<TvRageProvider>().GetUtcOffset(timezone).Should().Be(expected);
}
[TestCase("GMT-5 +DST", -4)]
[TestCase("GMT+0 +DST", 1)]
[TestCase("GMT+8 +DST", 9)]
public void should_return_offset_plus_one_when_dst(string timezone, int expected)
{
Mocker.Resolve<TvRageProvider>().GetUtcOffset(timezone).Should().Be(expected);
}
}
}

View File

@ -0,0 +1,82 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using TvdbLib.Data;
using TvdbLib.Exceptions;
namespace NzbDrone.Core.Test.ProviderTests.TvRageProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class SearchSeriesFixture : CoreTest
{
private const string search = "http://services.tvrage.com/feeds/full_search.php?show=";
private void WithEmptyResults()
{
Mocker.GetMock<HttpProvider>()
.Setup(s => s.DownloadStream(It.Is<String>(u => u.StartsWith(search)), null))
.Returns(new FileStream(@".\Files\TVRage\SearchResults_empty.xml", FileMode.Open, FileAccess.Read, FileShare.Read));
}
private void WithManyResults()
{
Mocker.GetMock<HttpProvider>()
.Setup(s => s.DownloadStream(It.Is<String>(u => u.StartsWith(search)), null))
.Returns(new FileStream(@".\Files\TVRage\SearchResults_many.xml", FileMode.Open, FileAccess.Read, FileShare.Read));
}
private void WithOneResult()
{
Mocker.GetMock<HttpProvider>()
.Setup(s => s.DownloadStream(It.Is<String>(u => u.StartsWith(search)), null))
.Returns(new FileStream(@".\Files\TVRage\SearchResults_one.xml", FileMode.Open, FileAccess.Read, FileShare.Read));
}
[Test]
public void should_be_empty_when_no_results_are_found()
{
WithEmptyResults();
Mocker.Resolve<TvRageProvider>().SearchSeries("asdasdasdasdas").Should().BeEmpty();
}
[Test]
public void should_be_have_more_than_one_when_multiple_results_are_returned()
{
WithManyResults();
Mocker.Resolve<TvRageProvider>().SearchSeries("top+gear").Should().NotBeEmpty();
}
[Test]
public void should_have_one_when_only_one_result_is_found()
{
WithOneResult();
Mocker.Resolve<TvRageProvider>().SearchSeries("suits").Should().HaveCount(1);
}
[Test]
public void ended_should_not_have_a_value_when_series_has_not_ended()
{
WithOneResult();
Mocker.Resolve<TvRageProvider>().SearchSeries("suits").First().Ended.HasValue.Should().BeFalse();
}
[Test]
public void started_should_match_series()
{
WithOneResult();
Mocker.Resolve<TvRageProvider>().SearchSeries("suits").First().Started.Should().Be(new DateTime(2011, 6, 23));
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Data;
using Migrator.Framework;
using NzbDrone.Common;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20121218)]
public class Migration20121218 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
Database.AddColumn("Series", new Column("TvRageId", DbType.Int32, ColumnProperty.Null));
Database.AddColumn("Series", new Column("TvRageTitle", DbType.String, ColumnProperty.Null));
Database.AddColumn("Series", new Column("UtcOffset", DbType.Int32, ColumnProperty.Null));
}
}
}

View File

@ -112,6 +112,12 @@ public static string AddSpacesToEnum(this Enum enumValue)
private const Decimal ONE_GIGABYTE = ONE_MEGABYTE * 1024M; private const Decimal ONE_GIGABYTE = ONE_MEGABYTE * 1024M;
public static string ToBestFileSize(this long bytes, int precision = 0) public static string ToBestFileSize(this long bytes, int precision = 0)
{
var ulongBytes = (ulong)bytes;
return ulongBytes.ToBestFileSize(precision);
}
public static string ToBestFileSize(this ulong bytes, int precision = 0)
{ {
if (bytes == 0) if (bytes == 0)
return "0B"; return "0B";

View File

@ -5,9 +5,9 @@
namespace NzbDrone.Core.Helpers namespace NzbDrone.Core.Helpers
{ {
public class SortHelper public static class SortHelper
{ {
public static string SkipArticles(string input) public static string IgnoreArticles(this string input)
{ {
if (String.IsNullOrEmpty(input)) if (String.IsNullOrEmpty(input))
return String.Empty; return String.Empty;

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace NzbDrone.Core.Helpers
{
public static class XElementHelper
{
public static T ConvertTo<T>(this XElement element)
{
if (element == null)
return default(T);
if (String.IsNullOrEmpty(element.Value))
return default(T);
var converter = TypeDescriptor.GetConverter(typeof(T));
try
{
return (T)converter.ConvertFromString(element.Value);
}
catch
{
return default(T);
}
}
public static DayOfWeek? ConvertToDayOfWeek(this XElement element)
{
if (element == null)
return null;
if (String.IsNullOrWhiteSpace(element.Value))
return null;
try
{
return (DayOfWeek)Enum.Parse(typeof(DayOfWeek), element.Value);
}
catch (Exception)
{
}
return null;
}
}
}

View File

@ -15,13 +15,16 @@ public class DiskScanJob : IJob
{ {
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly DiskScanProvider _diskScanProvider; private readonly DiskScanProvider _diskScanProvider;
private readonly ConfigProvider _configProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject] [Inject]
public DiskScanJob(SeriesProvider seriesProvider, DiskScanProvider diskScanProvider) public DiskScanJob(SeriesProvider seriesProvider, DiskScanProvider diskScanProvider,
ConfigProvider configProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_diskScanProvider = diskScanProvider; _diskScanProvider = diskScanProvider;
_configProvider = configProvider;
} }
public DiskScanJob() public DiskScanJob()
@ -43,7 +46,11 @@ public virtual void Start(ProgressNotification notification, dynamic options)
IList<Series> seriesToScan; IList<Series> seriesToScan;
if (options == null || options.SeriesId == 0) if (options == null || options.SeriesId == 0)
{ {
seriesToScan = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList(); if (_configProvider.IgnoreArticlesWhenSortingSeries)
seriesToScan = _seriesProvider.GetAllSeries().OrderBy(o => o.Title.IgnoreArticles()).ToList();
else
seriesToScan = _seriesProvider.GetAllSeries().OrderBy(o => o.Title).ToList();
} }
else else
{ {

View File

@ -85,12 +85,20 @@ public void Start(ProgressNotification notification, dynamic options)
} }
} }
if(!oldEpisodeFiles.Any())
{
logger.Trace("No episodes were renamed for: {0} Season {1}, no changes were made", series.Title,
options.SeasonNumber);
notification.CurrentMessage = String.Format("Rename completed for: {0} Season {1}, no changes were made", series.Title, options.SeasonNumber);
return;
}
//Remove & Create Metadata for episode files //Remove & Create Metadata for episode files
//Todo: Add a metadata manager to avoid this hack
_metadataProvider.RemoveForEpisodeFiles(oldEpisodeFiles); _metadataProvider.RemoveForEpisodeFiles(oldEpisodeFiles);
_metadataProvider.CreateForEpisodeFiles(newEpisodeFiles); _metadataProvider.CreateForEpisodeFiles(newEpisodeFiles);
//Start AfterRename //Start AfterRename
var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, options.SeasonNumber); var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, options.SeasonNumber);
_externalNotificationProvider.AfterRename(message, series); _externalNotificationProvider.AfterRename(message, series);

View File

@ -6,6 +6,7 @@
using NzbDrone.Core.Helpers; using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs namespace NzbDrone.Core.Jobs
@ -15,15 +16,17 @@ public class UpdateInfoJob : IJob
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly EpisodeProvider _episodeProvider; private readonly EpisodeProvider _episodeProvider;
private readonly ReferenceDataProvider _referenceDataProvider; private readonly ReferenceDataProvider _referenceDataProvider;
private readonly ConfigProvider _configProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject] [Inject]
public UpdateInfoJob(SeriesProvider seriesProvider, EpisodeProvider episodeProvider, public UpdateInfoJob(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
ReferenceDataProvider referenceDataProvider) ReferenceDataProvider referenceDataProvider, ConfigProvider configProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_episodeProvider = episodeProvider; _episodeProvider = episodeProvider;
_referenceDataProvider = referenceDataProvider; _referenceDataProvider = referenceDataProvider;
_configProvider = configProvider;
} }
public UpdateInfoJob() public UpdateInfoJob()
@ -46,7 +49,11 @@ public virtual void Start(ProgressNotification notification, dynamic options)
IList<Series> seriesToUpdate; IList<Series> seriesToUpdate;
if (options == null || options.SeriesId == 0) if (options == null || options.SeriesId == 0)
{ {
seriesToUpdate = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList(); if (_configProvider.IgnoreArticlesWhenSortingSeries)
seriesToUpdate = _seriesProvider.GetAllSeries().OrderBy(o => o.Title.IgnoreArticles()).ToList();
else
seriesToUpdate = _seriesProvider.GetAllSeries().OrderBy(o => o.Title).ToList();
} }
else else
{ {

View File

@ -8,6 +8,7 @@ namespace NzbDrone.Core.Model
public class EpisodeParseResult public class EpisodeParseResult
{ {
public string SeriesTitle { get; set; } public string SeriesTitle { get; set; }
public string CleanTitle public string CleanTitle
{ {
get get

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.TvRage
{
public class TvRageEpisode
{
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string ProductionCode { get; set; }
public DateTime AirDate { get; set; }
public string Link { get; set; }
public string Title { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.TvRage
{
public class TvRageSearchResult
{
public int ShowId { get; set; }
public string Name { get; set; }
public string Link { get; set; }
public string Country { get; set; }
public DateTime Started { get; set; }
public DateTime? Ended { get; set; }
public int Seasons { get; set; }
public string Status { get; set; }
public int RunTime { get; set; }
public DateTime AirTime { get; set; }
public DayOfWeek? AirDay { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model.TvRage
{
public class TvRageSeries
{
public int ShowId { get; set; }
public string Name { get; set; }
public string Link { get; set; }
public int Seasons { get; set; }
public int Started { get; set; }
public DateTime StartDate { get; set; }
public DateTime Ended { get; set; }
public string OriginCountry { get; set; }
public string Status { get; set; }
public int RunTime { get; set; }
public string Network { get; set; }
public DateTime AirTime { get; set; }
public DayOfWeek? AirDay { get; set; }
public int UtcOffset { get; set; }
}
}

View File

@ -229,6 +229,7 @@
<Compile Include="Datastore\MigrationLogger.cs" /> <Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" /> <Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" /> <Compile Include="Datastore\CustomeMapper.cs" />
<Compile Include="Datastore\Migrations\Migration20121218.cs" />
<Compile Include="Datastore\Migrations\Migration20121209.cs" /> <Compile Include="Datastore\Migrations\Migration20121209.cs" />
<Compile Include="Datastore\Migrations\Migration20121202.cs" /> <Compile Include="Datastore\Migrations\Migration20121202.cs" />
<Compile Include="Datastore\Migrations\Migration20121122.cs" /> <Compile Include="Datastore\Migrations\Migration20121122.cs" />
@ -262,6 +263,7 @@
<Compile Include="Helpers\EpisodeSortingHelper.cs" /> <Compile Include="Helpers\EpisodeSortingHelper.cs" />
<Compile Include="Helpers\SortHelper.cs" /> <Compile Include="Helpers\SortHelper.cs" />
<Compile Include="Helpers\SabnzbdPriorityTypeConverter.cs" /> <Compile Include="Helpers\SabnzbdPriorityTypeConverter.cs" />
<Compile Include="Helpers\XElementHelper.cs" />
<Compile Include="Jobs\CleanupRecycleBinJob.cs" /> <Compile Include="Jobs\CleanupRecycleBinJob.cs" />
<Compile Include="Jobs\XemUpdateJob.cs" /> <Compile Include="Jobs\XemUpdateJob.cs" />
<Compile Include="Jobs\EmptyRecycleBinJob.cs" /> <Compile Include="Jobs\EmptyRecycleBinJob.cs" />
@ -292,6 +294,9 @@
<Compile Include="Model\Sabnzbd\SabQueueItem.cs" /> <Compile Include="Model\Sabnzbd\SabQueueItem.cs" />
<Compile Include="Model\Sabnzbd\SabVersionModel.cs" /> <Compile Include="Model\Sabnzbd\SabVersionModel.cs" />
<Compile Include="Model\StatsModel.cs" /> <Compile Include="Model\StatsModel.cs" />
<Compile Include="Model\TvRage\TvRageEpisode.cs" />
<Compile Include="Model\TvRage\TvRageSearchResult.cs" />
<Compile Include="Model\TvRage\TvRageSeries.cs" />
<Compile Include="Model\Twitter\TwitterAuthorizationModel.cs" /> <Compile Include="Model\Twitter\TwitterAuthorizationModel.cs" />
<Compile Include="Model\UpdatePackage.cs" /> <Compile Include="Model\UpdatePackage.cs" />
<Compile Include="Model\Xbmc\ActionType.cs" /> <Compile Include="Model\Xbmc\ActionType.cs" />
@ -346,6 +351,8 @@
<Compile Include="Jobs\RssSyncJob.cs" /> <Compile Include="Jobs\RssSyncJob.cs" />
<Compile Include="Jobs\UpdateInfoJob.cs" /> <Compile Include="Jobs\UpdateInfoJob.cs" />
<Compile Include="Providers\StatsProvider.cs" /> <Compile Include="Providers\StatsProvider.cs" />
<Compile Include="Providers\TvRageMappingProvider.cs" />
<Compile Include="Providers\TvRageProvider.cs" />
<Compile Include="Providers\XemCommunicationProvider.cs" /> <Compile Include="Providers\XemCommunicationProvider.cs" />
<Compile Include="Providers\XemProvider.cs" /> <Compile Include="Providers\XemProvider.cs" />
<Compile Include="Repository\MetadataDefinition.cs" /> <Compile Include="Repository\MetadataDefinition.cs" />

View File

@ -30,7 +30,7 @@ public static class Parser
RegexOptions.IgnoreCase | RegexOptions.Compiled), RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc) //Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc)
new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex])(?<episode>\d{2}(?!\d+)))+\W*)+\W?(?!\\)", new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled), RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc) //Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc)
@ -140,7 +140,8 @@ internal static EpisodeParseResult ParseTitle(string title)
} }
catch (Exception e) catch (Exception e)
{ {
Logger.ErrorException("An error has occurred while trying to parse " + title, e); if (!title.ToLower().Contains("password") && !title.ToLower().Contains("yenc"))
Logger.ErrorException("An error has occurred while trying to parse " + title, e);
} }
Logger.Trace("Unable to parse {0}", title); Logger.Trace("Unable to parse {0}", title);
@ -150,7 +151,7 @@ internal static EpisodeParseResult ParseTitle(string title)
private static EpisodeParseResult ParseMatchCollection(MatchCollection matchCollection) private static EpisodeParseResult ParseMatchCollection(MatchCollection matchCollection)
{ {
var seriesName = matchCollection[0].Groups["title"].Value; var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ');
int airyear; int airyear;
Int32.TryParse(matchCollection[0].Groups["airyear"].Value, out airyear); Int32.TryParse(matchCollection[0].Groups["airyear"].Value, out airyear);

View File

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

View File

@ -4,6 +4,7 @@
using Ninject; using Ninject;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using PetaPoco; using PetaPoco;
@ -25,8 +26,6 @@ public RootDirProvider(IDatabase database, SeriesProvider seriesProvider, DiskPr
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
} }
#region IRootDirProvider
public virtual List<RootDir> GetAll() public virtual List<RootDir> GetAll()
{ {
return _database.Fetch<RootDir>(); return _database.Fetch<RootDir>();
@ -51,7 +50,7 @@ public virtual void Remove(int rootDirId)
_database.Delete<RootDir>(rootDirId); _database.Delete<RootDir>(rootDirId);
} }
public List<String> GetUnmappedFolders(string path) public virtual List<String> GetUnmappedFolders(string path)
{ {
Logger.Debug("Generating list of unmapped folders"); Logger.Debug("Generating list of unmapped folders");
if (String.IsNullOrEmpty(path)) if (String.IsNullOrEmpty(path))
@ -77,26 +76,16 @@ public List<String> GetUnmappedFolders(string path)
return results; return results;
} }
public virtual string GetMostFreeRootDir() public virtual List<RootDir> AllWithFreeSpace()
{ {
ulong maxSize = 0;
var maxPath = String.Empty;
var rootDirs = GetAll(); var rootDirs = GetAll();
foreach (var rootDir in rootDirs) foreach (var rootDir in rootDirs)
{ {
rootDir.FreeSpace = _diskProvider.FreeDiskSpace(new DirectoryInfo(rootDir.Path)); rootDir.FreeSpace = _diskProvider.FreeDiskSpace(new DirectoryInfo(rootDir.Path));
if (rootDir.FreeSpace > maxSize)
{
maxPath = rootDir.Path;
maxSize = rootDir.FreeSpace;
}
} }
return maxPath; return rootDirs;
} }
#endregion
} }
} }

View File

@ -101,5 +101,15 @@ public virtual bool SubmitMapping(int id, string postTitle)
return false; return false;
} }
public virtual string GetCleanName(int seriesId)
{
var item = _database.FirstOrDefault<SceneMapping>("WHERE SeriesId = @0", seriesId);
if (item == null)
return null;
return item.CleanTitle;
}
} }
} }

View File

@ -570,8 +570,11 @@ public string GetSeriesTitle(Series series)
{ {
var title = _sceneMappingProvider.GetSceneName(series.SeriesId); var title = _sceneMappingProvider.GetSceneName(series.SeriesId);
if (String.IsNullOrWhiteSpace(title)) if(String.IsNullOrWhiteSpace(title))
{
title = series.Title; title = series.Title;
title = title.Replace("&", "and");
}
return title; return title;
} }

View File

@ -15,19 +15,24 @@ namespace NzbDrone.Core.Providers
{ {
public class SeriesProvider public class SeriesProvider
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ConfigProvider _configProvider; private readonly ConfigProvider _configProvider;
private readonly TvDbProvider _tvDbProvider; private readonly TvDbProvider _tvDbProvider;
private readonly IDatabase _database; private readonly IDatabase _database;
private readonly SceneMappingProvider _sceneNameMappingProvider; private readonly SceneMappingProvider _sceneNameMappingProvider;
private readonly BannerProvider _bannerProvider; private readonly BannerProvider _bannerProvider;
private readonly MetadataProvider _metadataProvider; private readonly MetadataProvider _metadataProvider;
private readonly TvRageMappingProvider _tvRageMappingProvider;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private static readonly Regex TimeRegex = new Regex(@"^(?<time>\d+:?\d*)\W*(?<meridiem>am|pm)?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex TimeRegex = new Regex(@"^(?<time>\d+:?\d*)\W*(?<meridiem>am|pm)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
[Inject] [Inject]
public SeriesProvider(IDatabase database, ConfigProvider configProviderProvider, public SeriesProvider(IDatabase database, ConfigProvider configProviderProvider,
TvDbProvider tvDbProviderProvider, SceneMappingProvider sceneNameMappingProvider, TvDbProvider tvDbProviderProvider, SceneMappingProvider sceneNameMappingProvider,
BannerProvider bannerProvider, MetadataProvider metadataProvider) BannerProvider bannerProvider, MetadataProvider metadataProvider,
TvRageMappingProvider tvRageMappingProvider)
{ {
_database = database; _database = database;
_configProvider = configProviderProvider; _configProvider = configProviderProvider;
@ -35,6 +40,7 @@ public SeriesProvider(IDatabase database, ConfigProvider configProviderProvider,
_sceneNameMappingProvider = sceneNameMappingProvider; _sceneNameMappingProvider = sceneNameMappingProvider;
_bannerProvider = bannerProvider; _bannerProvider = bannerProvider;
_metadataProvider = metadataProvider; _metadataProvider = metadataProvider;
_tvRageMappingProvider = tvRageMappingProvider;
} }
public SeriesProvider() public SeriesProvider()
@ -106,6 +112,17 @@ public virtual Series UpdateSeriesInfo(int seriesId)
series.BannerUrl = tvDbSeries.BannerPath; series.BannerUrl = tvDbSeries.BannerPath;
series.Network = tvDbSeries.Network; series.Network = tvDbSeries.Network;
try
{
if(series.TvRageId == 0)
series = _tvRageMappingProvider.FindMatchingTvRageSeries(series);
}
catch(Exception ex)
{
logger.ErrorException("Error getting TvRage information for series: " + series.Title, ex);
}
UpdateSeries(series); UpdateSeries(series);
_metadataProvider.CreateForSeries(series, tvDbSeries); _metadataProvider.CreateForSeries(series, tvDbSeries);
@ -114,7 +131,7 @@ public virtual Series UpdateSeriesInfo(int seriesId)
public virtual void AddSeries(string title, string path, int tvDbSeriesId, int qualityProfileId, DateTime? airedAfter) public virtual void AddSeries(string title, string path, int tvDbSeriesId, int qualityProfileId, DateTime? airedAfter)
{ {
Logger.Info("Adding Series [{0}] Path: [{1}]", tvDbSeriesId, path); logger.Info("Adding Series [{0}] Path: [{1}]", tvDbSeriesId, path);
if (tvDbSeriesId <=0) if (tvDbSeriesId <=0)
{ {
@ -175,33 +192,33 @@ public virtual void UpdateSeries(Series series)
public virtual void DeleteSeries(int seriesId) public virtual void DeleteSeries(int seriesId)
{ {
var series = GetSeries(seriesId); var series = GetSeries(seriesId);
Logger.Warn("Deleting Series [{0}]", series.Title); logger.Warn("Deleting Series [{0}]", series.Title);
using (var tran = _database.GetTransaction()) using (var tran = _database.GetTransaction())
{ {
//Delete History, Files, Episodes, Seasons then the Series //Delete History, Files, Episodes, Seasons then the Series
Logger.Debug("Deleting History Items from DB for Series: {0}", series.Title); logger.Debug("Deleting History Items from DB for Series: {0}", series.Title);
_database.Delete<History>("WHERE SeriesId=@0", seriesId); _database.Delete<History>("WHERE SeriesId=@0", seriesId);
Logger.Debug("Deleting EpisodeFiles from DB for Series: {0}", series.Title); logger.Debug("Deleting EpisodeFiles from DB for Series: {0}", series.Title);
_database.Delete<EpisodeFile>("WHERE SeriesId=@0", seriesId); _database.Delete<EpisodeFile>("WHERE SeriesId=@0", seriesId);
Logger.Debug("Deleting Seasons from DB for Series: {0}", series.Title); logger.Debug("Deleting Seasons from DB for Series: {0}", series.Title);
_database.Delete<Season>("WHERE SeriesId=@0", seriesId); _database.Delete<Season>("WHERE SeriesId=@0", seriesId);
Logger.Debug("Deleting Episodes from DB for Series: {0}", series.Title); logger.Debug("Deleting Episodes from DB for Series: {0}", series.Title);
_database.Delete<Episode>("WHERE SeriesId=@0", seriesId); _database.Delete<Episode>("WHERE SeriesId=@0", seriesId);
Logger.Debug("Deleting Series from DB {0}", series.Title); logger.Debug("Deleting Series from DB {0}", series.Title);
_database.Delete<Series>("WHERE SeriesId=@0", seriesId); _database.Delete<Series>("WHERE SeriesId=@0", seriesId);
Logger.Info("Successfully deleted Series [{0}]", series.Title); logger.Info("Successfully deleted Series [{0}]", series.Title);
tran.Complete(); tran.Complete();
} }
Logger.Trace("Beginning deletion of banner for SeriesID: ", seriesId); logger.Trace("Beginning deletion of banner for SeriesID: ", seriesId);
_bannerProvider.Delete(seriesId); _bannerProvider.Delete(seriesId);
} }

View File

@ -37,6 +37,12 @@ public virtual IList<TvdbSearchResult> SearchSeries(string title)
{ {
Logger.Debug("Searching TVDB for '{0}'", title); Logger.Debug("Searching TVDB for '{0}'", title);
if(title.Contains(" & "))
{
Logger.Debug("Removing ampersand before searching");
title = title.Replace(" & ", " ");
}
var result = _handler.SearchSeries(title); var result = _handler.SearchSeries(title);
Logger.Debug("Search for '{0}' returned {1} possible results", title, result.Count); Logger.Debug("Search for '{0}' returned {1} possible results", title, result.Count);

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using Ninject;
using NzbDrone.Core.Model.TvRage;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers
{
public class TvRageMappingProvider
{
private readonly SceneMappingProvider _sceneMappingProvider;
private readonly TvRageProvider _tvRageProvider;
private readonly EpisodeProvider _episodeProvider;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
[Inject]
public TvRageMappingProvider(SceneMappingProvider sceneMappingProvider,
TvRageProvider tvRageProvider, EpisodeProvider episodeProvider)
{
_sceneMappingProvider = sceneMappingProvider;
_tvRageProvider = tvRageProvider;
_episodeProvider = episodeProvider;
}
public TvRageMappingProvider()
{
}
public Series FindMatchingTvRageSeries(Series series)
{
var firstEpisode = _episodeProvider.GetEpisode(series.SeriesId, 1, 1);
var cleanName = _sceneMappingProvider.GetCleanName(series.SeriesId);
var results = _tvRageProvider.SearchSeries(series.Title);
var result = ProcessResults(results, series, cleanName, firstEpisode);
if (result != null)
{
logger.Trace("TV Rage: {0} matches TVDB: {1}", result.Name, series.Title);
series.TvRageId = result.ShowId;
series.TvRageTitle = result.Name;
series.UtcOffset = _tvRageProvider.GetSeries(result.ShowId).UtcOffset;
}
return series;
}
public TvRageSearchResult ProcessResults(IList<TvRageSearchResult> searchResults, Series series, string sceneCleanName, Episode firstEpisode)
{
foreach (var result in searchResults)
{
if (Parser.NormalizeTitle(result.Name).Equals(series.CleanTitle))
return result;
if (!String.IsNullOrWhiteSpace(sceneCleanName) && Parser.NormalizeTitle(result.Name).Equals(sceneCleanName))
return result;
if (firstEpisode.AirDate.HasValue && result.Started == firstEpisode.AirDate.Value)
return result;
}
return null;
}
}
}

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using NLog;
using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model.TvRage;
namespace NzbDrone.Core.Providers
{
public class TvRageProvider
{
private readonly HttpProvider _httpProvider;
private const string TVRAGE_APIKEY = "NW4v0PSmQIoVmpbASLdD";
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
[Inject]
public TvRageProvider(HttpProvider httpProvider)
{
_httpProvider = httpProvider;
}
public TvRageProvider()
{
}
public virtual IList<TvRageSearchResult> SearchSeries(string title)
{
var searchResults = new List<TvRageSearchResult>();
var xmlStream = _httpProvider.DownloadStream("http://services.tvrage.com/feeds/full_search.php?show=" + title, null);
var xml = XDocument.Load(xmlStream);
var shows = xml.Descendants("Results").Descendants("show");
foreach (var s in shows)
{
try
{
var show = new TvRageSearchResult();
show.ShowId = s.Element("showid").ConvertTo<Int32>();
show.Name = s.Element("name").Value;
show.Link = s.Element("link").Value;
show.Country = s.Element("country").Value;
show.Started = s.Element("started").ConvertTo<DateTime>();
show.Ended = s.Element("ended").ConvertTo<DateTime>();
if (show.Ended < new DateTime(1900, 1, 1))
show.Ended = null;
show.Seasons = s.Element("seasons").ConvertTo<Int32>();
show.Status = s.Element("status").Value;
show.RunTime = s.Element("seasons").ConvertTo<Int32>();
show.AirTime = s.Element("seasons").ConvertTo<DateTime>();
show.AirDay = s.Element("airday").ConvertToDayOfWeek();
searchResults.Add(show);
}
catch (Exception ex)
{
logger.DebugException("Failed to parse TvRage Search Result. Search Term : " + title, ex);
}
}
return searchResults;
}
public virtual TvRageSeries GetSeries(int id)
{
var url = string.Format("http://services.tvrage.com/feeds/showinfo.php?key={0}&sid={1}", TVRAGE_APIKEY, id);
var xmlStream = _httpProvider.DownloadStream(url, null);
var xml = XDocument.Load(xmlStream);
var s = xml.Descendants("Showinfo").First();
try
{
if(s.Element("showid") == null)
{
logger.Warn("TvRage did not return valid series info for id: {0}", id);
return null;
}
var show = new TvRageSeries();
show.ShowId = s.Element("showid").ConvertTo<Int32>();
show.Name = s.Element("showname").Value;
show.Link = s.Element("showlink").Value;
show.Seasons = s.Element("seasons").ConvertTo<Int32>();
show.Started = s.Element("started").ConvertTo<Int32>();
show.StartDate = s.Element("startdate").ConvertTo<DateTime>();
show.Ended = s.Element("ended").ConvertTo<DateTime>();
show.OriginCountry = s.Element("origin_country").Value;
show.Status = s.Element("status").Value;
show.RunTime = s.Element("runtime").ConvertTo<Int32>();
show.Network = s.Element("network").Value;
show.AirTime = s.Element("airtime").ConvertTo<DateTime>();
show.AirDay = s.Element("airday").ConvertToDayOfWeek();
show.UtcOffset = GetUtcOffset(s.Element("timezone").Value);
return show;
}
catch (Exception ex)
{
logger.DebugException("Failed to parse ShowInfo for ID: " + id, ex);
return null;
}
}
public virtual List<TvRageEpisode> GetEpisodes(int id)
{
var url = String.Format("http://services.tvrage.com/feeds/episode_list.php?key={0}&sid={1}", TVRAGE_APIKEY, id);
var xmlStream = _httpProvider.DownloadStream(url, null);
var xml = XDocument.Load(xmlStream);
var show = xml.Descendants("Show");
var seasons = show.Descendants("Season");
var episodes = new List<TvRageEpisode>();
foreach (var season in seasons)
{
var eps = season.Descendants("episode");
foreach (var e in eps)
{
try
{
var episode = new TvRageEpisode();
episode.EpisodeNumber = e.Element("epnum").ConvertTo<Int32>();
episode.SeasonNumber = e.Element("seasonnum").ConvertTo<Int32>();
episode.ProductionCode = e.Element("prodnum").Value;
episode.AirDate = e.Element("airdate").ConvertTo<DateTime>();
episode.Link = e.Element("link").Value;
episode.Title = e.Element("title").Value;
episodes.Add(episode);
}
catch (Exception ex)
{
logger.DebugException("Failed to parse TV Rage episode", ex);
}
}
}
return episodes;
}
internal int GetUtcOffset(string timeZone)
{
if (String.IsNullOrWhiteSpace(timeZone))
return 0;
var offsetString = timeZone.Substring(3, 2);
int offset;
if (!Int32.TryParse(offsetString, out offset))
return 0;
if (timeZone.IndexOf("+DST", StringComparison.CurrentCultureIgnoreCase) > 0)
offset++;
return offset;
}
}
}

View File

@ -52,6 +52,12 @@ public class Series
public bool UseSceneNumbering { get; set; } public bool UseSceneNumbering { get; set; }
public int TvRageId { get; set; }
public string TvRageTitle { get; set; }
public int UtcOffset { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this <see cref="Series"/> is hidden. /// Gets or sets a value indicating whether this <see cref="Series"/> is hidden.
/// </summary> /// </summary>

View File

@ -368,7 +368,7 @@
<WebProjectProperties> <WebProjectProperties>
<UseIIS>False</UseIIS> <UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort> <AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>32122</DevelopmentServerPort> <DevelopmentServerPort>25289</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath> <DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:62182/</IISUrl> <IISUrl>http://localhost:62182/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication> <NTLMAuthentication>False</NTLMAuthentication>

View File

@ -1,6 +1,7 @@
#menu #menu
{ {
height: 60px; height: 60px;
display: inline-block;
} }
#menu ul #menu ul
@ -9,6 +10,7 @@
padding: 5px 0px 5px 0px; padding: 5px 0px 5px 0px;
list-style: none; list-style: none;
line-height: normal; line-height: normal;
overflow: hidden;
} }
#menu li #menu li

View File

@ -211,19 +211,6 @@ button span, input[type="button"] span, input[type="submit"] span, input[type="r
cursor: pointer !important; cursor: pointer !important;
} }
/* Local Series Search */
#localSeriesLookup
{
width: 220px;
float: right;
margin-top: 7px;
margin-bottom: 0px;
border: 0px;
background: rgb(75, 75, 75);
color: rgb(169, 169, 169);
padding: 4px;
}
.ui-dialog-buttonset .ui-delete-button .ui-dialog-buttonset .ui-delete-button
{ {
background: url("jQueryUI/images/ui-bg_flat_30_b40404_40x100.png") repeat-x scroll 50% 50% #B40404; background: url("jQueryUI/images/ui-bg_flat_30_b40404_40x100.png") repeat-x scroll 50% 50% #B40404;
@ -261,4 +248,55 @@ button span, input[type="button"] span, input[type="submit"] span, input[type="r
/* Font-Awesome */ /* Font-Awesome */
i[class*="icon-"]:not(.gridAction):hover { i[class*="icon-"]:not(.gridAction):hover {
cursor: default; cursor: default;
}
/* Donate */
#donate a {
background-color: #065EFE;
color: #191919;
}
/* Right Menu */
#right-menu {
float: right;
display: inline-block;
height: 60px;
}
#right-menu ul {
list-style: none;
overflow: hidden;
}
#right-menu li
{
display: block;
float: left;
padding: 0px 0px 10px 15px;
}
#localSeriesLookup
{
width: 220px;
border: 0px;
background: rgb(75, 75, 75);
color: rgb(169, 169, 169);
padding: 4px;
}
.free-space {
display: inline-block;
margin-top: 2px;
padding-left: 5px;
padding-right: 5px;
height: 28px;
line-height: 28px;
background-color: #6e6e6e;
color: #d0d0d0;
/*color: #FFFFFF;*/
cursor: default;
}
.free-space span {
color: #191919;
} }

View File

@ -8,6 +8,7 @@
using NzbDrone.Core.Helpers; using NzbDrone.Core.Helpers;
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Web.Models; using NzbDrone.Web.Models;
namespace NzbDrone.Web.Controllers namespace NzbDrone.Web.Controllers
@ -16,11 +17,14 @@ public class HistoryController : Controller
{ {
private readonly HistoryProvider _historyProvider; private readonly HistoryProvider _historyProvider;
private readonly JobProvider _jobProvider; private readonly JobProvider _jobProvider;
private readonly ConfigProvider _configProvider;
public HistoryController(HistoryProvider historyProvider, JobProvider jobProvider) public HistoryController(HistoryProvider historyProvider, JobProvider jobProvider,
ConfigProvider configProvider)
{ {
_historyProvider = historyProvider; _historyProvider = historyProvider;
_jobProvider = jobProvider; _jobProvider = jobProvider;
_configProvider = configProvider;
} }
public ActionResult Index() public ActionResult Index()
@ -32,6 +36,7 @@ public ActionResult AjaxBinding(DataTablesPageRequest pageRequest)
{ {
var pageResult = _historyProvider.GetPagedItems(pageRequest); var pageResult = _historyProvider.GetPagedItems(pageRequest);
var totalItems = _historyProvider.Count(); var totalItems = _historyProvider.Count();
var ignoreArticles = _configProvider.IgnoreArticlesWhenSortingSeries;
var items = pageResult.Items.Select(h => new HistoryModel var items = pageResult.Items.Select(h => new HistoryModel
{ {
@ -41,7 +46,7 @@ public ActionResult AjaxBinding(DataTablesPageRequest pageRequest)
EpisodeTitle = h.EpisodeTitle, EpisodeTitle = h.EpisodeTitle,
EpisodeOverview = h.EpisodeOverview, EpisodeOverview = h.EpisodeOverview,
SeriesTitle = h.SeriesTitle, SeriesTitle = h.SeriesTitle,
SeriesTitleSorter = SortHelper.SkipArticles(h.SeriesTitle), SeriesTitleSorter = ignoreArticles ? h.SeriesTitle.IgnoreArticles() : h.SeriesTitle,
NzbTitle = h.NzbTitle, NzbTitle = h.NzbTitle,
Quality = h.Quality.ToString(), Quality = h.Quality.ToString(),
IsProper = h.IsProper, IsProper = h.IsProper,

View File

@ -8,6 +8,7 @@
using NzbDrone.Core; using NzbDrone.Core;
using NzbDrone.Core.Helpers; using NzbDrone.Core.Helpers;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Web.Models; using NzbDrone.Web.Models;
using ServiceStack.Text; using ServiceStack.Text;
@ -16,15 +17,18 @@ namespace NzbDrone.Web.Controllers
public class MissingController : Controller public class MissingController : Controller
{ {
private readonly EpisodeProvider _episodeProvider; private readonly EpisodeProvider _episodeProvider;
private readonly ConfigProvider _configProvider;
public MissingController(EpisodeProvider episodeProvider) public MissingController(EpisodeProvider episodeProvider, ConfigProvider configProvider)
{ {
_episodeProvider = episodeProvider; _episodeProvider = episodeProvider;
_configProvider = configProvider;
} }
public ActionResult Index() public ActionResult Index()
{ {
var missingEpisodes = _episodeProvider.EpisodesWithoutFiles(false); var missingEpisodes = _episodeProvider.EpisodesWithoutFiles(false);
var ignoreArticles = _configProvider.IgnoreArticlesWhenSortingSeries;
var missing = missingEpisodes.Select(e => new MissingEpisodeModel var missing = missingEpisodes.Select(e => new MissingEpisodeModel
{ {
@ -34,7 +38,7 @@ public ActionResult Index()
EpisodeTitle = e.Title, EpisodeTitle = e.Title,
Overview = e.Overview, Overview = e.Overview,
SeriesTitle = e.Series.Title, SeriesTitle = e.Series.Title,
SeriesTitleSorter = SortHelper.SkipArticles(e.Series.Title), SeriesTitleSorter = ignoreArticles ? e.Series.Title.IgnoreArticles() : e.Series.Title,
AirDateSorter = e.AirDate.Value.ToString("o", CultureInfo.InvariantCulture), AirDateSorter = e.AirDate.Value.ToString("o", CultureInfo.InvariantCulture),
AirDate = e.AirDate.Value.ToBestDateString() AirDate = e.AirDate.Value.ToBestDateString()
}); });

View File

@ -11,6 +11,7 @@
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
using NzbDrone.Web.Filters; using NzbDrone.Web.Filters;
@ -25,17 +26,19 @@ public class SeriesController : Controller
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly JobProvider _jobProvider; private readonly JobProvider _jobProvider;
private readonly SeasonProvider _seasonProvider; private readonly SeasonProvider _seasonProvider;
private readonly ConfigProvider _configProvider;
// //
// GET: /Series/ // GET: /Series/
public SeriesController(SeriesProvider seriesProvider, public SeriesController(SeriesProvider seriesProvider, QualityProvider qualityProvider,
QualityProvider qualityProvider, JobProvider jobProvider, JobProvider jobProvider, SeasonProvider seasonProvider,
SeasonProvider seasonProvider) ConfigProvider configProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_qualityProvider = qualityProvider; _qualityProvider = qualityProvider;
_jobProvider = jobProvider; _jobProvider = jobProvider;
_seasonProvider = seasonProvider; _seasonProvider = seasonProvider;
_configProvider = configProvider;
} }
public ActionResult Index() public ActionResult Index()
@ -177,7 +180,7 @@ public ActionResult Editor()
masterBacklogList.Insert(0, new KeyValuePair<int, string>(-10, "Select...")); masterBacklogList.Insert(0, new KeyValuePair<int, string>(-10, "Select..."));
ViewData["MasterBacklogSettingSelectList"] = new SelectList(masterBacklogList, "Key", "Value"); ViewData["MasterBacklogSettingSelectList"] = new SelectList(masterBacklogList, "Key", "Value");
var series = GetSeriesModels(_seriesProvider.GetAllSeries()).OrderBy(o => SortHelper.SkipArticles(o.Title)); var series = GetSeriesModels(_seriesProvider.GetAllSeries());
return View(series); return View(series);
} }
@ -206,11 +209,13 @@ public JsonResult Editor(List<SeriesModel> series)
private List<SeriesModel> GetSeriesModels(IList<Series> seriesInDb) private List<SeriesModel> GetSeriesModels(IList<Series> seriesInDb)
{ {
var ignoreArticles = _configProvider.IgnoreArticlesWhenSortingSeries;
var series = seriesInDb.Select(s => new SeriesModel var series = seriesInDb.Select(s => new SeriesModel
{ {
SeriesId = s.SeriesId, SeriesId = s.SeriesId,
Title = s.Title, Title = s.Title,
TitleSorter = SortHelper.SkipArticles(s.Title), TitleSorter = ignoreArticles? s.Title.IgnoreArticles() : s.Title,
AirsDayOfWeek = s.AirsDayOfWeek.ToString(), AirsDayOfWeek = s.AirsDayOfWeek.ToString(),
Monitored = s.Monitored, Monitored = s.Monitored,
Overview = s.Overview, Overview = s.Overview,

View File

@ -253,6 +253,7 @@ public ActionResult Misc()
model.EnableBacklogSearching = _configProvider.EnableBacklogSearching; model.EnableBacklogSearching = _configProvider.EnableBacklogSearching;
model.AutoIgnorePreviouslyDownloadedEpisodes = _configProvider.AutoIgnorePreviouslyDownloadedEpisodes; model.AutoIgnorePreviouslyDownloadedEpisodes = _configProvider.AutoIgnorePreviouslyDownloadedEpisodes;
model.AllowedReleaseGroups = _configProvider.AllowedReleaseGroups; model.AllowedReleaseGroups = _configProvider.AllowedReleaseGroups;
model.IgnoreArticlesWhenSortingSeries = _configProvider.IgnoreArticlesWhenSortingSeries;
return View(model); return View(model);
} }
@ -662,6 +663,7 @@ public JsonResult SaveMisc(MiscSettingsModel data)
_configProvider.EnableBacklogSearching = data.EnableBacklogSearching; _configProvider.EnableBacklogSearching = data.EnableBacklogSearching;
_configProvider.AutoIgnorePreviouslyDownloadedEpisodes = data.AutoIgnorePreviouslyDownloadedEpisodes; _configProvider.AutoIgnorePreviouslyDownloadedEpisodes = data.AutoIgnorePreviouslyDownloadedEpisodes;
_configProvider.AllowedReleaseGroups = data.AllowedReleaseGroups; _configProvider.AllowedReleaseGroups = data.AllowedReleaseGroups;
_configProvider.IgnoreArticlesWhenSortingSeries = data.IgnoreArticlesWhenSortingSeries;
return GetSuccessResult(); return GetSuccessResult();
} }

View File

@ -1,5 +1,6 @@
using System.Web.Mvc; using System.Web.Mvc;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Web.Models; using NzbDrone.Web.Models;
namespace NzbDrone.Web.Controllers namespace NzbDrone.Web.Controllers
@ -7,10 +8,12 @@ namespace NzbDrone.Web.Controllers
public class SharedController : Controller public class SharedController : Controller
{ {
private readonly EnvironmentProvider _environmentProvider; private readonly EnvironmentProvider _environmentProvider;
private readonly RootDirProvider _rootDirProvider;
public SharedController(EnvironmentProvider environmentProvider) public SharedController(EnvironmentProvider environmentProvider, RootDirProvider rootDirProvider)
{ {
_environmentProvider = environmentProvider; _environmentProvider = environmentProvider;
_rootDirProvider = rootDirProvider;
} }
public ActionResult Index() public ActionResult Index()
@ -24,5 +27,14 @@ public ActionResult Footer()
{ {
return PartialView(new FooterModel { BuildTime = _environmentProvider.BuildDateTime, Version = _environmentProvider.Version }); return PartialView(new FooterModel { BuildTime = _environmentProvider.BuildDateTime, Version = _environmentProvider.Version });
} }
[ChildActionOnly]
[OutputCache(Duration = 600)]
public ActionResult FreeSpace()
{
var rootDirs = _rootDirProvider.AllWithFreeSpace();
return PartialView(rootDirs);
}
} }
} }

View File

@ -20,5 +20,9 @@ public class MiscSettingsModel
[Description("Comma separated list of release groups to download episodes (leave empty for all groups)")] [Description("Comma separated list of release groups to download episodes (leave empty for all groups)")]
[DisplayFormat(ConvertEmptyStringToNull = false)] [DisplayFormat(ConvertEmptyStringToNull = false)]
public string AllowedReleaseGroups { get; set; } public string AllowedReleaseGroups { get; set; }
[DisplayName("Ignore Articles")]
[Description("Ignore articles when sorting by series title?")]
public bool IgnoreArticlesWhenSortingSeries { get; set; }
} }
} }

View File

@ -526,6 +526,7 @@
<Content Include="Views\System\Indexers.cshtml" /> <Content Include="Views\System\Indexers.cshtml" />
<Content Include="Views\System\Config.cshtml" /> <Content Include="Views\System\Config.cshtml" />
<Content Include="Views\Settings\_SettingsLayout.cshtml" /> <Content Include="Views\Settings\_SettingsLayout.cshtml" />
<Content Include="Views\Shared\FreeSpace.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="App_Data\" /> <Folder Include="App_Data\" />

View File

@ -27,6 +27,11 @@
</label> </label>
@Html.TextBoxFor(m => m.AllowedReleaseGroups, new { @class = "inputClass" }) @Html.TextBoxFor(m => m.AllowedReleaseGroups, new { @class = "inputClass" })
<label class="labelClass">@Html.LabelFor(m => m.IgnoreArticlesWhenSortingSeries)
<span class="small">@Html.DescriptionFor(m => m.IgnoreArticlesWhenSortingSeries)</span>
</label>
@Html.CheckBoxFor(m => m.IgnoreArticlesWhenSortingSeries, new { @class = "inputClass checkClass" })
<div style="overflow: hidden; height: 50px;"> <div style="overflow: hidden; height: 50px;">
</div> </div>

View File

@ -0,0 +1,15 @@
@using NzbDrone.Core
@model IEnumerable<NzbDrone.Core.Repository.RootDir>
@{
Layout = null;
}
@{
foreach(var rootDir in Model)
{
<div class="free-space" title="@rootDir.Path">
@rootDir.FreeSpace.ToBestFileSize(1) <span>Free</span>
</div>
}
}

View File

@ -30,9 +30,16 @@
@MvcHtmlString.Create(Html.CurrentControllerLink("Missing", "Index", "Missing")) @MvcHtmlString.Create(Html.CurrentControllerLink("Missing", "Index", "Missing"))
@MvcHtmlString.Create(Html.CurrentControllerLink("Settings", "Index", "Settings")) @MvcHtmlString.Create(Html.CurrentControllerLink("Settings", "Index", "Settings"))
@MvcHtmlString.Create(Html.CurrentControllerLink("Logs", "Index", "Log")) @MvcHtmlString.Create(Html.CurrentControllerLink("Logs", "Index", "Log"))
<li id="donate" title="Donate to support the development of NzbDrone"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KRTE52U3XJDSQ" target="_blank">Donate</a></li>
</ul> </ul>
<input id="localSeriesLookup" type="text" />
</div> </div>
<div id="right-menu">
<ul>
<li>@{ Html.RenderAction("FreeSpace", "Shared"); }</li>
<li><input id="localSeriesLookup" type="text" /></li>
</ul>
</div>
<div id="logo"> <div id="logo">
<span>@ViewBag.Title</span> <span>@ViewBag.Title</span>
</div> </div>