1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-04 10:02:40 +01:00

moved rootdir to eloquera

This commit is contained in:
kay.one 2013-02-03 20:18:59 -08:00
parent 0155de4d92
commit 9e4bb278ef
35 changed files with 398 additions and 565 deletions

View File

@ -3,17 +3,18 @@
using NzbDrone.Api.Extentions;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Api.RootFolders
{
public class RootDirModule : NzbDroneApiModule
{
private readonly RootDirProvider _rootDirProvider;
private readonly RootFolderService _rootFolderService;
public RootDirModule(RootDirProvider rootDirProvider)
public RootDirModule(RootFolderService rootFolderService)
: base("//rootdir")
{
_rootDirProvider = rootDirProvider;
_rootFolderService = rootFolderService;
Get["/"] = x => GetRootFolders();
Post["/"] = x => AddRootFolder();
@ -22,18 +23,18 @@ public RootDirModule(RootDirProvider rootDirProvider)
private Response AddRootFolder()
{
var dir = _rootDirProvider.Add(Request.Body.FromJson<RootDir>());
var dir = _rootFolderService.Add(Request.Body.FromJson<RootDir>());
return dir.AsResponse(HttpStatusCode.Created);
}
private Response GetRootFolders()
{
return _rootDirProvider.AllWithFreeSpace().AsResponse();
return _rootFolderService.All().AsResponse();
}
private Response DeleteRootFolder(int folderId)
{
_rootDirProvider.Remove(folderId);
_rootFolderService.Remove(folderId);
return new Response { StatusCode = HttpStatusCode.OK };
}
}

View File

@ -107,7 +107,15 @@ public virtual string StartUpPath
{
get
{
return new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
var path = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
if (path.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
StringComparison.InvariantCultureIgnoreCase))
{
path = Directory.GetCurrentDirectory();
}
return path;
}
}

View File

@ -7,6 +7,7 @@ public static class PathExtentions
{
private const string WEB_FOLDER = "NzbDrone.Web\\";
private const string APP_DATA = "App_Data\\";
private const string WEB_BIN = "bin\\";
public const string IIS_FOLDER = "IISExpress";
public const string IIS_EXE = "iisexpress.exe";
@ -70,6 +71,11 @@ public static string GetAppDataPath(this EnvironmentProvider environmentProvider
return Path.Combine(environmentProvider.GetWebRoot(), APP_DATA);
}
public static string GetWebBinPath(this EnvironmentProvider environmentProvider)
{
return Path.Combine(environmentProvider.GetWebRoot(), WEB_BIN);
}
public static string GetNlogConfigPath(this EnvironmentProvider environmentProvider)
{
return Path.Combine(environmentProvider.GetWebRoot(), LOG_CONFIG_FILE);

View File

@ -1,4 +1,5 @@
using System.Linq;
using Eloquera.Client;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
@ -82,6 +83,19 @@ public void new_objects_should_get_id()
Db.Insert(testSeries);
testSeries.Id.Should().NotBe(0);
}
[Test]
public void should_be_able_to_read_unknow_type()
{
Db.AsQueryable<UnKnowType>().ToList().Should().BeEmpty();
}
}
public class UnKnowType
{
[ID]
public string Id;
public string Field1 { get; set; }
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Test.Framework
@ -23,11 +24,11 @@ protected void WithObjectDb(bool memory = true)
{
if (memory)
{
_db = new EloqueraDbFactory().CreateMemoryDb();
_db = new EloqueraDbFactory(new EnvironmentProvider()).CreateMemoryDb();
}
else
{
_db = new EloqueraDbFactory().Create(Guid.NewGuid().ToString());
_db = new EloqueraDbFactory(new EnvironmentProvider()).Create();
}
Mocker.SetConstant(Db);

View File

@ -28,6 +28,32 @@ protected static void ThrowException()
}
public abstract class CoreTest<TSubject> : CoreTest
{
private TSubject _subject;
protected TSubject Subject
{
get
{
if (_subject == null)
{
_subject = Mocker.Resolve<TSubject>();
}
return _subject;
}
}
protected void InitiateSubject()
{
_subject = Mocker.Resolve<TSubject>();
}
}
public abstract class SqlCeTest : CoreTest
{

View File

@ -79,6 +79,7 @@
</Reference>
<Reference Include="Eloquera.Server">
<HintPath>..\packages\EloqueraDB.5.0.0\lib\net40\Eloquera.Server.exe</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FizzWare.NBuilder, Version=3.0.1.0, Culture=neutral, PublicKeyToken=5651b03e12e42c12, processorArchitecture=MSIL">
<HintPath>..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll</HintPath>

View File

@ -31,5 +31,6 @@
<RegularExpression>NzbDrone\.Core\.Test\.Integeration\.ServiceIntegerationFixture\..*</RegularExpression>
</RegexTestSelector>
</IgnoredTests>
<AdditionalFilesToInclude>..\NzbDrone.Core\bin\Debug\Eloquera.Server.exe</AdditionalFilesToInclude>
<HiddenWarnings>PostBuildEventDisabled</HiddenWarnings>
</ProjectConfiguration>

View File

@ -12,6 +12,7 @@
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq;
@ -38,7 +39,7 @@ public void should_return_one_drive_when_only_one_root_dir_exists()
.Setup(s => s.FreeDiskSpace(new DirectoryInfo(@"C:\")))
.Returns(123456);
var result = Mocker.Resolve<RootDirProvider>().FreeSpaceOnDrives();
var result = Mocker.Resolve<RootFolderService>().FreeSpaceOnDrives();
result.Should().HaveCount(1);
}
@ -59,7 +60,7 @@ public void should_return_one_drive_when_two_rootDirs_on_the_same_drive_exist()
.Setup(s => s.FreeDiskSpace(new DirectoryInfo(@"C:\")))
.Returns(123456);
var result = Mocker.Resolve<RootDirProvider>().FreeSpaceOnDrives();
var result = Mocker.Resolve<RootFolderService>().FreeSpaceOnDrives();
result.Should().HaveCount(1);
}
@ -84,7 +85,7 @@ public void should_return_two_drives_when_two_rootDirs_on_the_different_drive_ex
.Setup(s => s.FreeDiskSpace(It.IsAny<DirectoryInfo>()))
.Returns(123456);
var result = Mocker.Resolve<RootDirProvider>().FreeSpaceOnDrives();
var result = Mocker.Resolve<RootFolderService>().FreeSpaceOnDrives();
result.Should().HaveCount(2);
}
@ -104,7 +105,7 @@ public void should_skip_rootDir_if_not_found_on_disk()
.Setup(s => s.FreeDiskSpace(It.IsAny<DirectoryInfo>()))
.Throws(new DirectoryNotFoundException());
var result = Mocker.Resolve<RootDirProvider>().FreeSpaceOnDrives();
var result = Mocker.Resolve<RootFolderService>().FreeSpaceOnDrives();
result.Should().HaveCount(0);

View File

@ -1,6 +1,7 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -11,6 +12,7 @@
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.AutoMoq;
@ -18,7 +20,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RootDirProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class RootDirProviderFixture : SqlCeTest
public class RootDirProviderFixture : CoreTest<RootFolderService>
{
[SetUp]
public void Setup()
@ -35,32 +37,15 @@ private void WithNoneExistingFolder()
.Returns(false);
}
[Test]
public void GetRootDir_should_return_all_existing_roots()
{
WithRealDb();
Db.Insert(new RootDir { Path = @"C:\TV" });
Db.Insert(new RootDir { Path = @"C:\TV2" });
var result = Mocker.Resolve<RootDirProvider>().GetAll();
result.Should().HaveCount(2);
}
[TestCase("D:\\TV Shows\\")]
[TestCase("//server//folder")]
public void should_be_able_to_add_root_dir(string path)
{
WithRealDb();
var root = new RootDir { Path = path };
Subject.Add(root);
//Act
var rootDirProvider = Mocker.Resolve<RootDirProvider>();
rootDirProvider.Add(new RootDir { Path = path });
//Assert
var rootDirs = rootDirProvider.GetAll();
rootDirs.Should().HaveCount(1);
rootDirs.First().Path.Should().Be(path);
Mocker.GetMock<IRootFolderRepository>().Verify(c => c.Add(root), Times.Once());
}
[Test]
@ -68,34 +53,25 @@ public void should_throw_if_folder_being_added_doesnt_exist()
{
WithNoneExistingFolder();
var rootDirProvider = Mocker.Resolve<RootDirProvider>();
Assert.Throws<DirectoryNotFoundException>(() => rootDirProvider.Add(new RootDir { Path = "C:\\TEST" }));
Assert.Throws<DirectoryNotFoundException>(() => Subject.Add(new RootDir { Path = "C:\\TEST" }));
}
[Test]
public void should_be_able_to_remove_root_dir()
{
WithRealDb();
//Act
var rootDirProvider = Mocker.Resolve<RootDirProvider>();
rootDirProvider.Add(new RootDir { Path = @"C:\TV" });
rootDirProvider.Add(new RootDir { Path = @"C:\TV2" });
rootDirProvider.Remove(1);
//Assert
var rootDirs = rootDirProvider.GetAll();
rootDirs.Should().HaveCount(1);
Subject.Remove(1);
Mocker.GetMock<IRootFolderRepository>().Verify(c => c.Delete(1), Times.Once());
}
[Test]
public void None_existing_folder_returns_empty_list()
{
WithNoneExistingFolder();
Mocker.GetMock<IRootFolderRepository>().Setup(c => c.All()).Returns(new List<RootDir>());
const string path = "d:\\bad folder";
var result = Mocker.Resolve<RootDirProvider>().GetUnmappedFolders(path);
var result = Subject.GetUnmappedFolders(path);
result.Should().NotBeNull();
result.Should().BeEmpty();
@ -105,7 +81,7 @@ public void None_existing_folder_returns_empty_list()
[Test]
public void GetUnmappedFolders_throw_on_empty_folders()
{
Assert.Throws<ArgumentException>(() => Mocker.Resolve<RootDirProvider>().GetUnmappedFolders(""));
Assert.Throws<ArgumentException>(() => Mocker.Resolve<RootFolderService>().GetUnmappedFolders(""));
}
[TestCase("")]
@ -114,19 +90,17 @@ public void GetUnmappedFolders_throw_on_empty_folders()
public void invalid_folder_path_throws_on_add(string path)
{
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<RootDirProvider>().Add(new RootDir { Id = 0, Path = path })
Mocker.Resolve<RootFolderService>().Add(new RootDir { Id = 0, Path = path })
);
}
[Test]
public void adding_duplicated_root_folder_should_throw()
{
WithRealDb();
Mocker.GetMock<IRootFolderRepository>().Setup(c => c.All()).Returns(new List<RootDir> { new RootDir { Path = "C:\\TV" } });
//Act
var rootDirProvider = Mocker.Resolve<RootDirProvider>();
rootDirProvider.Add(new RootDir { Path = @"C:\TV" });
Assert.Throws<InvalidOperationException>(() => rootDirProvider.Add(new RootDir { Path = @"C:\TV" }));
Subject.Add(new RootDir { Path = @"C:\TV" });
Assert.Throws<InvalidOperationException>(() => Subject.Add(new RootDir { Path = @"C:\TV" }));
}
}
}

View File

@ -82,8 +82,7 @@ private static void InitDatabase(this ContainerBuilder container)
container.Register(c =>
{
var env = c.Resolve<EnvironmentProvider>();
return c.Resolve<EloqueraDbFactory>().Create(env.GetElqMainDbPath());
return c.Resolve<EloqueraDbFactory>().Create();
}).As<EloqueraDb>().SingleInstance();
container.RegisterType<DatabaseTarget>().WithParameter(ResolvedParameter.ForNamed<IDatabase>("DatabaseTarget"));

View File

@ -43,12 +43,12 @@ public IList<T> UpdateMany<T>(IEnumerable<T> objects)
}
public void Delete<T>(T obj)
public void Delete<T>(T obj) where T : new()
{
_db.Delete(obj);
}
public void DeleteMany<T>(IEnumerable<T> objects)
public void DeleteMany<T>(IEnumerable<T> objects) where T: new()
{
foreach (var o in objects)
{

View File

@ -2,27 +2,52 @@
using System.IO;
using System.Linq;
using Eloquera.Client;
using NzbDrone.Common;
namespace NzbDrone.Core.Datastore
{
public class EloqueraDbFactory
{
public EloqueraDb CreateMemoryDb()
private readonly EnvironmentProvider _environmentProvider;
private readonly string dllPath;
public EloqueraDbFactory(EnvironmentProvider environmentProvider)
{
return InternalCreate("server=(local);password=;options=inmemory;",Guid.NewGuid().ToString());
_environmentProvider = environmentProvider;
dllPath = _environmentProvider.GetWebBinPath();// this is the path where Eloquera dlls live.
}
public EloqueraDb Create(string dbPath)
public EloqueraDb CreateMemoryDb()
{
var file = new FileInfo(dbPath).Name;
return InternalCreate(string.Format("server=(local);database={0};usedatapath={1};password=;", file, dbPath),file);
return InternalCreate("server=(local);password=;options=inmemory;uselocalpath=" + dllPath, Guid.NewGuid().ToString());
}
public EloqueraDb Create(string dbPath = null)
{
if (dbPath == null)
{
dbPath = _environmentProvider.GetElqMainDbPath();
}
var file = new FileInfo(dbPath);
return InternalCreate(string.Format("server=(local);password=;usedatapath={0};uselocalpath={1}", file.Directory.FullName, dllPath), file.Name);
}
private EloqueraDb InternalCreate(string connectionString, string databaseName)
{
var db = new DB(connectionString);
db.CreateDatabase(databaseName);
db.OpenDatabase(databaseName);
try
{
db.OpenDatabase(databaseName);
}
catch (FileNotFoundException)
{
db.CreateDatabase(databaseName);
db.OpenDatabase(databaseName);
}
return new EloqueraDb(db);
}

View File

@ -0,0 +1,33 @@
using System.Collections.Generic;
using Migrator.Framework;
using NzbDrone.Core.Repository;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20130203)]
public class Migration20130203 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
var objectDb = GetObjectDb();
var rootFolderRepo = new RootFolderRepository(objectDb);
using (var dataReader = Database.ExecuteQuery("SELECT * from RootDirs"))
{
var dirs = new List<RootDir>();
while (dataReader.Read())
{
var rootFolder = new RootDir { Path = dataReader["Path"].ToString() };
dirs.Add(rootFolder);
}
objectDb.InsertMany(dirs);
}
//Database.RemoveTable("RootDirs");
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Data.SqlServerCe;
using System.Linq;
using Migrator.Framework;
using NzbDrone.Common;
@ -32,6 +33,14 @@ public override void Up()
}
}
protected EloqueraDb GetObjectDb()
{
var sqlCeConnection = new SqlCeConnection(Database.ConnectionString);
var eqPath = sqlCeConnection.Database.Replace(".sdf", ".eq");
return new EloqueraDbFactory(new EnvironmentProvider()).Create(eqPath);
}
public override void Down()
{

View File

@ -9,37 +9,37 @@ namespace NzbDrone.Core.Datastore
{
public class MigrationsHelper
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public static void Run(string connetionString, bool trace)
public static void Run(string connectionString, bool trace)
{
EnsureDatabase(connetionString);
EnsureDatabase(connectionString);
Logger.Trace("Preparing to run database migration");
logger.Trace("Preparing to run database migration");
try
{
Migrator.Migrator migrator;
if (trace)
{
migrator = new Migrator.Migrator("sqlserverce", connetionString, Assembly.GetAssembly(typeof(MigrationsHelper)), true, new MigrationLogger());
migrator = new Migrator.Migrator("sqlserverce", connectionString, Assembly.GetAssembly(typeof(MigrationsHelper)), true, new MigrationLogger());
}
else
{
migrator = new Migrator.Migrator("sqlserverce", connetionString, Assembly.GetAssembly(typeof(MigrationsHelper)));
migrator = new Migrator.Migrator("sqlserverce", connectionString, Assembly.GetAssembly(typeof(MigrationsHelper)));
}
migrator.MigrateToLastVersion();
Logger.Info("Database migration completed");
logger.Info("Database migration completed");
}
catch (Exception e)
{
Logger.FatalException("An error has occurred while migrating database", e);
logger.FatalException("An error has occurred while migrating database", e);
throw;
}
}

View File

@ -237,6 +237,7 @@
<Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" />
<Compile Include="Datastore\Migrations\Migration20130203.cs" />
<Compile Include="Datastore\Migrations\Migration20121226.cs" />
<Compile Include="Datastore\Migrations\Migration20121218.cs" />
<Compile Include="Datastore\Migrations\Migration20121209.cs" />
@ -536,7 +537,7 @@
<Compile Include="Providers\ReferenceDataProvider.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Providers\RootDirProvider.cs">
<Compile Include="RootFolders\RootFolderService.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Providers\SceneMappingProvider.cs">
@ -599,6 +600,7 @@
<Compile Include="Repository\Series.cs" />
<Compile Include="CentralDispatch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RootFolders\RootFolderRepository.cs" />
<Compile Include="Tvdb\Tvdb.cs" />
<Compile Include="Tvdb\Tvdb.Sync.cs" />
<Compile Include="Tvdb\TvdbActor.cs" />

View File

@ -3,9 +3,21 @@
namespace NzbDrone.Core.Repository
{
public interface IRootDir
{
int Id { get; set; }
string Path { get; set; }
[ResultColumn]
ulong FreeSpace { get; set; }
[Ignore]
List<string> UnmappedFolders { get; set; }
}
[TableName("RootDirs")]
[PrimaryKey("Id", autoIncrement = true)]
public class RootDir
public class RootDir : IRootDir
{
public virtual int Id { get; set; }

View File

@ -0,0 +1,46 @@
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Repository;
using System.Linq;
namespace NzbDrone.Core.RootFolders
{
public interface IRootFolderRepository
{
List<RootDir> All();
RootDir Get(int rootFolderId);
RootDir Add(RootDir rootFolder);
void Delete(int rootFolderId);
}
public class RootFolderRepository : IRootFolderRepository
{
private readonly EloqueraDb _db;
public RootFolderRepository(EloqueraDb db)
{
_db = db;
}
public List<RootDir> All()
{
return _db.AsQueryable<RootDir>().ToList();
}
public RootDir Get(int rootFolderId)
{
return _db.AsQueryable<RootDir>().Single(c => c.Id == rootFolderId);
}
public RootDir Add(RootDir rootFolder)
{
return _db.Insert(rootFolder);
}
public void Delete(int rootFolderId)
{
_db.Delete(Get(rootFolderId));
}
}
}

View File

@ -1,30 +1,40 @@
using System;
using System.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using PetaPoco;
namespace NzbDrone.Core.Providers
namespace NzbDrone.Core.RootFolders
{
public class RootDirProvider
public interface IRootFolderService
{
List<RootDir> All();
RootDir Add(RootDir rootDir);
void Remove(int rootDirId);
List<String> GetUnmappedFolders(string path);
Dictionary<string, ulong> FreeSpaceOnDrives();
}
public class RootFolderService : IRootFolderService
{
private readonly IDatabase _database;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IRootFolderRepository _rootFolderRepository;
private readonly DiskProvider _diskProvider;
private readonly SeriesProvider _seriesProvider;
public RootDirProvider(IDatabase database, SeriesProvider seriesProvider, DiskProvider diskProvider)
public RootFolderService(IRootFolderRepository rootFolderRepository, SeriesProvider seriesProvider, DiskProvider diskProvider)
{
_database = database;
_rootFolderRepository = rootFolderRepository;
_diskProvider = diskProvider;
_seriesProvider = seriesProvider;
}
public virtual List<RootDir> GetAll()
public virtual List<RootDir> All()
{
return _database.Fetch<RootDir>();
return _rootFolderRepository.All();
}
public virtual RootDir Add(RootDir rootDir)
@ -35,20 +45,19 @@ public virtual RootDir Add(RootDir rootDir)
if (!_diskProvider.FolderExists(rootDir.Path))
throw new DirectoryNotFoundException("Can't add root directory that doesn't exist.");
if (GetAll().Exists(r => DiskProvider.PathEquals(r.Path, rootDir.Path)))
if (All().Exists(r => DiskProvider.PathEquals(r.Path, rootDir.Path)))
throw new InvalidOperationException("Root directory already exist.");
var id = _database.Insert(rootDir);
rootDir.Id = Convert.ToInt32(id);
_rootFolderRepository.Add(rootDir);
rootDir.FreeSpace = _diskProvider.FreeDiskSpace(new DirectoryInfo(rootDir.Path));
rootDir.UnmappedFolders = GetUnmappedFolders(rootDir.Path);
return rootDir;
}
public virtual void Remove(int rootDirId)
{
_database.Delete<RootDir>(rootDirId);
_rootFolderRepository.Delete(rootDirId);
}
public virtual List<String> GetUnmappedFolders(string path)
@ -77,24 +86,12 @@ public virtual List<String> GetUnmappedFolders(string path)
return results;
}
public virtual List<RootDir> AllWithFreeSpace()
{
var rootDirs = GetAll();
foreach (var rootDir in rootDirs)
{
rootDir.FreeSpace = _diskProvider.FreeDiskSpace(new DirectoryInfo(rootDir.Path));
rootDir.UnmappedFolders = GetUnmappedFolders(rootDir.Path);
}
return rootDirs;
}
public virtual Dictionary<string, ulong> FreeSpaceOnDrives()
{
var freeSpace = new Dictionary<string, ulong>();
var rootDirs = GetAll();
var rootDirs = All();
foreach (var rootDir in rootDirs)
{

View File

@ -14,7 +14,7 @@
<RootNamespace>NzbDrone.Services.Api</RootNamespace>
<AssemblyName>NzbDrone.Services.Api</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<UseIISExpress>true</UseIISExpress>
<UseIISExpress>false</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
@ -150,9 +150,9 @@
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>0</DevelopmentServerPort>
<DevelopmentServerPort>1306</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:14615/</IISUrl>
<IISUrl>http://localhost/NzbDrone.Services.Api</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>

Binary file not shown.

View File

@ -1,188 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Jobs;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Web.Filters;
using NzbDrone.Web.Models;
using TvdbLib.Exceptions;
namespace NzbDrone.Web.Controllers
{
public class AddSeriesController : Controller
{
private readonly ConfigProvider _configProvider;
private readonly QualityProvider _qualityProvider;
private readonly RootDirProvider _rootFolderProvider;
private readonly SeriesProvider _seriesProvider;
private readonly JobProvider _jobProvider;
private readonly TvDbProvider _tvDbProvider;
private readonly DiskProvider _diskProvider;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public AddSeriesController(RootDirProvider rootFolderProvider,
ConfigProvider configProvider,
QualityProvider qualityProvider, TvDbProvider tvDbProvider,
SeriesProvider seriesProvider, JobProvider jobProvider,
DiskProvider diskProvider)
{
_rootFolderProvider = rootFolderProvider;
_configProvider = configProvider;
_qualityProvider = qualityProvider;
_tvDbProvider = tvDbProvider;
_seriesProvider = seriesProvider;
_jobProvider = jobProvider;
_diskProvider = diskProvider;
}
public ActionResult Index()
{
return View();
}
public ActionResult AddNew()
{
ViewData["RootDirs"] = _rootFolderProvider.GetAll().Select(c => c.Path).OrderBy(e => e).ToList();
var defaultQuality = _configProvider.DefaultQualityProfile;
var qualityProfiles = _qualityProvider.All();
ViewData["qualityProfiles"] = new SelectList(
qualityProfiles,
"QualityProfileId",
"Name",
defaultQuality);
return View();
}
public ActionResult ExistingSeries()
{
var result = new ExistingSeriesModel();
var unmappedList = new List<String>();
foreach (var folder in _rootFolderProvider.GetAll())
{
unmappedList.AddRange(_rootFolderProvider.GetUnmappedFolders(folder.Path));
}
result.ExistingSeries = new List<Tuple<string, string, int>>();
foreach (var folder in unmappedList)
{
var foldername = new DirectoryInfo(folder).Name;
try
{
var tvdbResult = _tvDbProvider.SearchSeries(foldername).FirstOrDefault();
var title = String.Empty;
var seriesId = 0;
if (tvdbResult != null)
{
title = tvdbResult.SeriesName;
seriesId = tvdbResult.id;
}
result.ExistingSeries.Add(new Tuple<string, string, int>(folder, title, seriesId));
}
catch (Exception ex)
{
logger.WarnException("Failed to connect to TheTVDB to search for: " + foldername, ex);
return View();
}
}
var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile);
result.Quality = new SelectList(_qualityProvider.All(), "QualityProfileId", "Name", defaultQuality);
return View(result);
}
[HttpPost]
[JsonErrorFilter]
public JsonResult AddNewSeries(string path, string seriesName, int seriesId, int qualityProfileId, string startDate)
{
if (string.IsNullOrWhiteSpace(path) || String.Equals(path, "null", StringComparison.InvariantCultureIgnoreCase))
return JsonNotificationResult.Error("Couldn't add " + seriesName, "You need a valid root folder");
path = Path.Combine(path, MediaFileProvider.CleanFilename(seriesName));
//Create the folder for the new series
//Use the created folder name when adding the series
path = _diskProvider.CreateDirectory(path);
return AddExistingSeries(path, seriesName, seriesId, qualityProfileId, startDate);
}
[HttpPost]
[JsonErrorFilter]
public JsonResult AddExistingSeries(string path, string seriesName, int seriesId, int qualityProfileId, string startDate)
{
if (seriesId == 0 || String.IsNullOrWhiteSpace(seriesName))
return JsonNotificationResult.Error("Add Existing series failed.", "Invalid Series information");
DateTime? date = null;
if (!String.IsNullOrWhiteSpace(startDate))
date = DateTime.Parse(startDate, null, DateTimeStyles.RoundtripKind);
_seriesProvider.AddSeries(seriesName, path, seriesId, qualityProfileId, date);
_jobProvider.QueueJob(typeof(ImportNewSeriesJob));
return JsonNotificationResult.Info(seriesName, "Was added successfully");
}
[HttpGet]
[JsonErrorFilter]
public JsonResult LookupSeries(string term)
{
return JsonNotificationResult.Info("Lookup Failed", "Unknown error while connecting to TheTVDB");
}
public ActionResult RootList()
{
IEnumerable<String> rootDir = _rootFolderProvider.GetAll().Select(c => c.Path).OrderBy(e => e);
return PartialView("RootList", rootDir);
}
public ActionResult RootDir()
{
return PartialView("RootDir");
}
[HttpPost]
[JsonErrorFilter]
public JsonResult SaveRootDir(string path)
{
if (String.IsNullOrWhiteSpace(path))
JsonNotificationResult.Error("Can't add root folder", "Path can not be empty");
_rootFolderProvider.Add(new RootDir { Path = path });
return JsonNotificationResult.Info("Root Folder saved", "Root folder saved successfully.");
}
[JsonErrorFilter]
public JsonResult DeleteRootDir(string path)
{
var id = _rootFolderProvider.GetAll().Where(c => c.Path == path).First().Id;
_rootFolderProvider.Remove(id);
return null;
}
}
}

View File

@ -1,6 +1,7 @@
using System.Web.Mvc;
using NzbDrone.Common;
using NzbDrone.Core.Providers;
using NzbDrone.Core.RootFolders;
using NzbDrone.Web.Models;
namespace NzbDrone.Web.Controllers
@ -8,12 +9,12 @@ namespace NzbDrone.Web.Controllers
public class SharedController : Controller
{
private readonly EnvironmentProvider _environmentProvider;
private readonly RootDirProvider _rootDirProvider;
private readonly RootFolderService _rootFolderService;
public SharedController(EnvironmentProvider environmentProvider, RootDirProvider rootDirProvider)
public SharedController(EnvironmentProvider environmentProvider, RootFolderService rootFolderService)
{
_environmentProvider = environmentProvider;
_rootDirProvider = rootDirProvider;
_rootFolderService = rootFolderService;
}
public ActionResult Index()
@ -32,7 +33,7 @@ public ActionResult Footer()
[OutputCache(Duration = 600)]
public ActionResult FreeSpace()
{
var rootDirs = _rootDirProvider.FreeSpaceOnDrives();
var rootDirs = _rootFolderService.FreeSpaceOnDrives();
return PartialView(rootDirs);
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<Eloquera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Cache IndexCacheSize="10000"
WriteThru="false"
IndexCleanerPeriod="100"
IndexCleanerBatchSize="100"
CleanerPeriod="100"
CleanerBatchSize="2000"
CommitSequenceMaxLength="2000"
ShallowReadThreshold="1000"
ShallowReadAhead="1000"
ReadAhead="20"
SaturationThreshold="10000"
MemoryFootPrint="60"/>
<MemoryManager Mode="1" />
<Server ServerPort="43962"
Trace="true"
InMemoryAllowed="true"
Secure="false"
AllowUsers=""
AllowGroups="Everyone"
SNMPAddress="net.tcp://localhost:8523/SNMP"
AutoRecovery="false"
NotificationsEnabled="false"
VarSectorSize="40"
IndexNodeSize="512"/>
<SmartRuntime Smart="true"
TypeUpdateAllowed="true"/>
<UserLogin Enabled="false"
PasswordHash="l+on1aCwDrcZ5bGlv+fyyIlYkbuFIOxZFlFwIGKlms0CCwoGn9TZvM0E3Uksjwx64+/yv8nsaUajWLz1kyKG7A==" />
</Eloquera>

View File

@ -17,7 +17,7 @@
<MvcBuildViews>true</MvcBuildViews>
<EnableUpdateable>false</EnableUpdateable>
<TargetFrameworkProfile />
<UseIISExpress>false</UseIISExpress>
<UseIISExpress>true</UseIISExpress>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
@ -26,6 +26,10 @@
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<JSLintSkip>\_backboneApp\JsLibraries\|\Scripts\</JSLintSkip>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -88,6 +92,17 @@
<Reference Include="Dynamic">
<HintPath>..\packages\DynamicQuery.1.0\lib\35\Dynamic.dll</HintPath>
</Reference>
<Reference Include="Eloquera.Client, Version=5.0.0.0, Culture=neutral, PublicKeyToken=170cadcdba67be6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\EloqueraDB.5.0.0\lib\net40\Eloquera.Client.dll</HintPath>
</Reference>
<Reference Include="Eloquera.Common, Version=5.0.0.0, Culture=neutral, PublicKeyToken=170cadcdba67be6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\EloqueraDB.5.0.0\lib\net40\Eloquera.Common.dll</HintPath>
</Reference>
<Reference Include="Eloquera.Server">
<HintPath>..\packages\EloqueraDB.5.0.0\lib\net40\Eloquera.Server.exe</HintPath>
</Reference>
<Reference Include="LowercaseRoutesMVC">
<HintPath>..\packages\LowercaseRoutesMVC.1.0.3\lib\LowercaseRoutesMVC.dll</HintPath>
</Reference>
@ -341,7 +356,6 @@
<Compile Include="Controllers\HealthController.cs" />
<Compile Include="Controllers\HistoryController.cs" />
<Compile Include="Controllers\LogController.cs" />
<Compile Include="Controllers\AddSeriesController.cs" />
<Compile Include="Controllers\MissingController.cs" />
<Compile Include="Controllers\NotificationController.cs" />
<Compile Include="Controllers\SeriesController.cs" />
@ -401,6 +415,7 @@
<Content Include="_backboneApp\Shared\NotificationView.js" />
<Content Include="_backboneApp\Shared\SpinnerTemplate.html" />
<Content Include="_backboneApp\Shared\SpinnerView.js" />
<Content Include="Eloquera.config" />
<None Include="_backboneApp\JsLibraries\jquery-1.8.2.intellisense.js" />
<Content Include="_backboneApp\JsLibraries\backbone.collectionbinder.js" />
<Content Include="_backboneApp\JsLibraries\backbone.debug.js" />
@ -606,8 +621,6 @@
<Content Include="Scripts\jquery.watermark.min.js" />
<Content Include="Scripts\underscore.js" />
<Content Include="Scripts\underscore.min.js" />
<Content Include="Views\AddSeries\Index.cshtml" />
<Content Include="Views\AddSeries\AddNew.cshtml" />
<Content Include="Web.config">
<SubType>Designer</SubType>
</Content>
@ -624,7 +637,6 @@
<Content Include="Views\Settings\Naming.cshtml" />
<Content Include="Views\Settings\Notifications.cshtml" />
<Content Include="Views\Settings\Quality.cshtml" />
<Content Include="Views\AddSeries\RootDir.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
<Content Include="Views\Shared\Footer.cshtml" />
<Content Include="Views\_ViewStart.cshtml" />
@ -666,15 +678,9 @@
<ItemGroup>
<Content Include="Views\Missing\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\AddSeries\ExistingSeries.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\System\PendingProcessing.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\AddSeries\RootList.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Settings\System.cshtml" />
</ItemGroup>

View File

@ -1,13 +0,0 @@
@using System.Collections
@{ Layout = null; }
<div>
<div>
<input id="newSeriesLookup" class="seriesLookup" type="text" style="width: 400px" />
@Html.Hidden("newSeriesId", 0, new { @class = "seriesId" })
</div>
@Html.DropDownList("newSeriesPath", new SelectList((IList)ViewData["RootDirs"]), new { style = "width: 406px; margin-left: 0px;" })
@Html.DropDownList("qualityList", (SelectList)ViewData["QualityProfiles"], new { @class = "qualitySelector" })
@Html.TextBox("newStartDate", "", new { type = "date", @class = "jQuery-datepicker start-date", placeholder = "Custom Start Date", title = "Only download episodes that aired after the specified date" })
<button id="saveNewSeries">
Add</button>
</div>

View File

@ -1,44 +0,0 @@
@using System.Collections
@using NzbDrone.Web.Models
@using System.Web.Mvc.Html
@model ExistingSeriesModel
@{
Layout = null;
}
@if (Model == null)
{
<h2 style="color: tomato">
Error searching TheTVDB, please try again later.
</h2>
}
else if (!Model.ExistingSeries.Any())
{
<h2 style="color: tomato">
No series available. Try adding a new Root Folder.
</h2>
}
else
{
@Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector masterQualitySelector" })
@Html.TextBox(Guid.NewGuid().ToString(), "", new { type="date", @class = "jQuery-datepicker start-date-master", placeholder = "Custom Start Date", title = "Only download episodes that aired after the specified date" })
foreach (var series in Model.ExistingSeries)
{
<div class="existingSeries">
<span class="seriesPathValue">
<label>@series.Item1</label>
</span>
<div class="existingSeriesContainer">
<input class="seriesLookup" type="text" style="width: 400px;" value="@series.Item2" placeholder="Series Title" />
@Html.Hidden("seriesId", series.Item3, new { @class = "seriesId" })
@Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector" })
@Html.TextBox(Guid.NewGuid().ToString(), "", new { type="date", @class = "jQuery-datepicker start-date", placeholder = "Custom Start Date", title = "Only download episodes that aired after the specified date" })
<button class="addExistingButton">
Add</button>
</div>
</div>
}
}

View File

@ -1,92 +0,0 @@
@using NzbDrone.Web.Helpers
@{ViewBag.Title = "Add Series";}
@section HeaderContent
{
<style>
.existingSeries
{
border-color: #f2f2f2;
border-width: 1px;
border-style: solid;
background-color: #f2f2f2;
margin: 0px 10px 10px 0px;
padding: 5px;
display: block;
}
.masterQualitySelector
{
left: 415px;
position: relative;
}
.start-date-master {
left: 430px;
position: relative;
}
.seriesPathValue
{
display: block;
}
.existingSeriesContainer
{
position: relative;
}
.ui-autocomplete.seriesLookupResults {
max-height: 180px;
overflow-y: auto;
/* prevent horizontal scrollbar */
overflow-x: hidden;
}
.tvDbLink {
float: right;
}
.tvDbLink:hover {
cursor: pointer;
text-decoration: underline;
}
input[type=date].start-date {
margin-left: 10px;
}
</style>
}
@{Html.RenderAction("RootDir");}
<div class="jquery-accordion jquery-accordion-collapse-all" id="addSeriesAccordion">
<h3>
<a href="#">Add New Series</a></h3>
<div id="addNewSeries">
@{ Html.RenderAction("AddNew", "AddSeries"); }
</div>
<h3>
<a href="#">Add Series Already on Disk</a></h3>
<div id="existingSeries">
<img src="../../Content/Images/ajax-loader.gif" />
@Ajax.RenderAction(
"ExistingSeries",
"AddSeries",
null,
new AjaxOptions { UpdateTargetId = "existingSeries", InsertionMode = InsertionMode.Replace }
)
</div>
</div>
@section Scripts
{
@Html.IncludeScript("NzbDrone/addSeries.js")
<script type="text/javascript">
$(document).on('click', '.tvDbLink', function (event) {
var url = $(this).attr('rel');
window.open(url, 'thetvdb');
event.preventDefault();
});
</script>
}

View File

@ -1,10 +0,0 @@
<h2>
Manage Root Folders
</h2>
<span>
<input id="rootDirInput" class="folderLookup" type="text" style="width: 400px" />
<button id="saveDir">
Add</button>
</span><span id="rootDirs">
@{Html.RenderAction("RootList");}
</span>

View File

@ -1,16 +0,0 @@
@model IEnumerable<String>
@if (!Model.Any())
{
<div class="actionButton delete">
<span>You have no root folders added.</span>
</div>
}
@foreach (var root in Model)
{
<div class="actionButton delete">
<div class="delete-root" data-path="@root">
<i class="icon-remove icon-large"></i>
</div>
<span>@root</span>
</div>
}

View File

@ -5,16 +5,16 @@
{
@Html.IncludeCss("Settings.css")
}
<style>
<style>
.progressbar {
position:relative;
width: 125px;
position: relative;
width: 125px;
height: 20px;
background-color: transparent;
border: 1px solid #065EFE;
margin: 2px;
}
.progressbar-text {
position: absolute;
display: block;
@ -27,33 +27,29 @@
border: 1px solid #065EFE;
}
.ui-progressbar-value .progressbar-text {
position: relative;
font-weight: normal;
color: white;
}
.ui-progressbar-value .progressbar-text {
position: relative;
font-weight: normal;
color: white;
}
/* Set the row height so it won't resize when the progress bar is created */
.seriesTable tr
{
.seriesTable tr {
height: 28px;
}
.commandsColumn, .statusColumn
{
.commandsColumn, .statusColumn {
text-align: center;
white-space: nowrap;
}
.ui-dialog-buttonpane .ui-dialog-buttonset .ui-delete-button
{
.ui-dialog-buttonpane .ui-dialog-buttonset .ui-delete-button {
margin-right: 445px;
}
</style>
@section ActionMenu{
<ul class="sub-menu">
<li>@Html.ActionLink("Add Series", "Index", "AddSeries", null, new { Title = "Add a new or existing series" })</li>
<li><a href="/v2#series/add">Add Series</a></li>
<li>@Ajax.ActionLink("Start RSS Sync", "RssSync", "Command", null, null, new { Title = "Check for newly released downloads" })</li>
<li>@Html.ActionLink("Series Editor", "Editor", "Series", null, new { Title = "Edit multiple series" })</li>
</ul>
@ -61,7 +57,7 @@
<table id="seriesGrid" class="dataTablesGrid hidden-grid">
<thead>
<tr>
<th style="width: 10px">Status</th>
<th style="width: auto">Title</th>
@ -70,7 +66,7 @@
<th style="width: 100px">Network</th>
<th style="width: 140px">Next Airing</th>
<th style="width: 100px">Episodes</th>
@*Commands Column*@
<th style="width: 80px"></th>
</tr>
@ -96,7 +92,7 @@
@Html.IncludeScript("NzbDrone/series.js")
<script type="text/javascript">
var pauseImage = '<i class="icon-pause grid-icon" title="Not Monitored"></i>';
var stopImage = '<i class="icon-stop grid-icon" title="Ended"></i>';
var playImage = '<i class="icon-play grid-icon" title="Continuing"></i>';
@ -115,56 +111,60 @@
"bInfo": false,
"bAutoWidth": false,
"bStateSave": true,
"iCookieDuration": 60 * 60 *24 * 365, //1 year
"iCookieDuration": 60 * 60 * 24 * 365, //1 year
"aoColumns": [
{ sWidth: '70px',
"sClass": "statusColumn",
"mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
var monitored = source["Monitored"];
var status = source["Status"];
if (!monitored) {
return pauseImage;
}
else {
if (status === "Ended"){
return stopImage;
}
else {
return playImage;
}
}
}
// 'sort' and 'type' both just use the raw data
return source["Status"];
{
sWidth: '70px',
"sClass": "statusColumn",
"mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
var monitored = source["Monitored"];
var status = source["Status"];
if (!monitored) {
return pauseImage;
}
else {
if (status === "Ended") {
return stopImage;
}
else {
return playImage;
}
}
}
// 'sort' and 'type' both just use the raw data
return source["Status"];
}
}, //Status
{ sWidth: 'auto', "mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
return "<a href='/series/details/" + source["SeriesId"] + "'>" + source["Title"] + "</a>";
}
// 'sort' and 'type' both just use the raw data
return source["TitleSorter"];
}
{
sWidth: 'auto', "mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
return "<a href='/series/details/" + source["SeriesId"] + "'>" + source["Title"] + "</a>";
}
// 'sort' and 'type' both just use the raw data
return source["TitleSorter"];
}
}, //Title
{ sWidth: '100px', "mDataProp": "SeasonsCount" }, //Seasons
{ sWidth: '100px', "mDataProp": "QualityProfileName", sClass: "qualityColumn" }, //Quality
{ sWidth: '120px', "mDataProp": "Network" }, //Network
{ sWidth: '120px', "mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
return source["NextAiring"];
}
// 'sort' and 'type' both just use the raw data
return source["NextAiringSorter"];
}
{
sWidth: '120px', "mDataProp": function (source, type, val) {
// 'display' and 'filter' use our fancy naming
if (type === 'display' || type === 'filter') {
return source["NextAiring"];
}
// 'sort' and 'type' both just use the raw data
return source["NextAiringSorter"];
}
}, //Next Airing
{ sWidth: '140px', "mDataProp": "Episodes", "bSortable": false, "fnRender": function (row) {
{
sWidth: '140px', "mDataProp": "Episodes", "bSortable": false, "fnRender": function (row) {
var progress = 100;
if (row.aData["EpisodeCount"] > 0)
progress = row.aData["EpisodeFileCount"] / row.aData["EpisodeCount"] * 100;
@ -188,16 +188,17 @@
"<i class='icon-remove deleteButton gridAction' title = 'Delete Series' data-series-id='" + row.aData["SeriesId"] + "' data-series-title='" + row.aData["Title"] + "'></i>";
}
}, //Commands
{ sWidth: '60px', "mDataProp": "Details", "bSortable": false, "bVisible": false, "fnRender": function (row) {
var result = "<b>Airs Day of Week: </b>" + row.aData["AirsDayOfWeek"] + "<br/>" +
"<b>Air Time: </b>" + row.aData["AirTime"] + "<br/>" +
"<b>Overview: </b>" + row.aData["Overview"] + "<br/>";
{
sWidth: '60px', "mDataProp": "Details", "bSortable": false, "bVisible": false, "fnRender": function (row) {
var result = "<b>Airs Day of Week: </b>" + row.aData["AirsDayOfWeek"] + "<br/>" +
"<b>Air Time: </b>" + row.aData["AirTime"] + "<br/>" +
"<b>Overview: </b>" + row.aData["Overview"] + "<br/>";
return result;
}
} //Details
],
],
"aaSorting": [[1, 'asc']],
"fnCreatedRow": function( nRow, aData, iDataIndex ) {
"fnCreatedRow": function (nRow, aData, iDataIndex) {
$(nRow).attr('data-series-id', aData["SeriesId"].toString());
},
"oLanguage": {
@ -205,25 +206,25 @@
}
});
});
//After we delete a series do this...
function afterDelete(seriesId) {
var row = $('[data-series-id="' + seriesId + '"]');
if ($(row).hasClass('details-opened')) {
var nextRow = $(row).next('tr');
if($(nextRow).children('.Details').length > 0) {
if ($(nextRow).children('.Details').length > 0) {
$(nextRow).hide();
}
}
$(row).hide();
}
//After we save do this...
function afterSave() {
updateStatus();
//Update Quality
var seriesId = $('#SeriesId').val();
var quality = $('#QualityProfileId :selected').text();

View File

@ -1,2 +1 @@

<div class="infoBox">It looks like you haven't added any series to NzbDrone. @Html.ActionLink("Click here to add one.", "Index", "AddSeries")</div>
<div class="infoBox">It looks like you haven't added any series to NzbDrone. <a href="/v2#series/add">Click here to add one.</a></div>

View File

@ -12,6 +12,7 @@
<package id="DataTables.Mvc.Core" version="0.1.0.85" />
<package id="DotlessClientOnly" version="1.3.1.0" targetFramework="net40" />
<package id="DynamicQuery" version="1.0" />
<package id="EloqueraDB" version="5.0.0" targetFramework="net40" />
<package id="FontAwesome" version="2.0.2" targetFramework="net40" />
<package id="jQuery" version="1.8.2" targetFramework="net40" />
<package id="jQuery.Ajax.Unobtrusive" version="2.0.20710.0" targetFramework="net40" />

View File

@ -1,7 +1,8 @@
<SolutionConfiguration>
<FileVersion>1</FileVersion>
<AutoEnableOnStartup>False</AutoEnableOnStartup>
<AutoEnableOnStartup>True</AutoEnableOnStartup>
<AllowParallelTestExecution>true</AllowParallelTestExecution>
<AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves>
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>
<FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio>
<FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec>