Merge branch 'thingi-provider' into develop
This commit is contained in:
commit
2fc8123d6b
|
@ -20,14 +20,14 @@ namespace Marr.Data.Converters
|
||||||
{
|
{
|
||||||
public class BooleanIntConverter : IConverter
|
public class BooleanIntConverter : IConverter
|
||||||
{
|
{
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
{
|
{
|
||||||
return DBNull.Value;
|
return DBNull.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int val = (int)dbValue;
|
int val = (int)context.DbValue;
|
||||||
|
|
||||||
if (val == 1)
|
if (val == 1)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,12 @@ namespace Marr.Data.Converters
|
||||||
throw new ConversionException(
|
throw new ConversionException(
|
||||||
string.Format(
|
string.Format(
|
||||||
"The BooleanCharConverter could not convert the value '{0}' to a boolean.",
|
"The BooleanCharConverter could not convert the value '{0}' to a boolean.",
|
||||||
dbValue));
|
context.DbValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -20,14 +20,14 @@ namespace Marr.Data.Converters
|
||||||
{
|
{
|
||||||
public class BooleanYNConverter : IConverter
|
public class BooleanYNConverter : IConverter
|
||||||
{
|
{
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
{
|
{
|
||||||
return DBNull.Value;
|
return DBNull.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
string val = dbValue.ToString();
|
string val = context.DbValue.ToString();
|
||||||
|
|
||||||
if (val == "Y")
|
if (val == "Y")
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,12 @@ namespace Marr.Data.Converters
|
||||||
throw new ConversionException(
|
throw new ConversionException(
|
||||||
string.Format(
|
string.Format(
|
||||||
"The BooleanYNConverter could not convert the value '{0}' to a boolean.",
|
"The BooleanYNConverter could not convert the value '{0}' to a boolean.",
|
||||||
dbValue));
|
context.DbValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext {ColumnMap = map, DbValue = dbValue});
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -30,10 +30,15 @@ namespace Marr.Data.Converters
|
||||||
get { return typeof(TDb); }
|
get { return typeof(TDb); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
TDb val = (TDb)context.DbValue;
|
||||||
|
return val.ToType(typeof(TClr), CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
{
|
{
|
||||||
TDb val = (TDb)dbValue;
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
return val.ToType(typeof(TClr), CultureInfo.InvariantCulture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Data;
|
||||||
|
using Marr.Data.Mapping;
|
||||||
|
|
||||||
|
namespace Marr.Data.Converters
|
||||||
|
{
|
||||||
|
public class ConverterContext
|
||||||
|
{
|
||||||
|
public ColumnMap ColumnMap { get; set; }
|
||||||
|
public object DbValue { get; set; }
|
||||||
|
public ColumnMapCollection MapCollection { get; set; }
|
||||||
|
public IDataRecord DataRecord { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,11 +20,16 @@ namespace Marr.Data.Converters
|
||||||
{
|
{
|
||||||
public class EnumIntConverter : IConverter
|
public class EnumIntConverter : IConverter
|
||||||
{
|
{
|
||||||
|
public object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
if (context.DbValue == null || context.DbValue == DBNull.Value)
|
||||||
|
return null;
|
||||||
|
return Enum.ToObject(context.ColumnMap.FieldType, (int)context.DbValue);
|
||||||
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
{
|
{
|
||||||
if (dbValue == null || dbValue == DBNull.Value)
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
return null;
|
|
||||||
return Enum.ToObject(map.FieldType, (int)dbValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -20,11 +20,16 @@ namespace Marr.Data.Converters
|
||||||
{
|
{
|
||||||
public class EnumStringConverter : IConverter
|
public class EnumStringConverter : IConverter
|
||||||
{
|
{
|
||||||
|
public object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
if (context.DbValue == null || context.DbValue == DBNull.Value)
|
||||||
|
return null;
|
||||||
|
return Enum.Parse(context.ColumnMap.FieldType, (string)context.DbValue);
|
||||||
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
{
|
{
|
||||||
if (dbValue == null || dbValue == DBNull.Value)
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
return null;
|
|
||||||
return Enum.Parse(map.FieldType, (string)dbValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -20,6 +20,9 @@ namespace Marr.Data.Converters
|
||||||
{
|
{
|
||||||
public interface IConverter
|
public interface IConverter
|
||||||
{
|
{
|
||||||
|
object FromDB(ConverterContext context);
|
||||||
|
|
||||||
|
[Obsolete("use FromDB(ConverterContext context) instead")]
|
||||||
object FromDB(ColumnMap map, object dbValue);
|
object FromDB(ColumnMap map, object dbValue);
|
||||||
object ToDB(object clrValue);
|
object ToDB(object clrValue);
|
||||||
Type DbType { get; }
|
Type DbType { get; }
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
using Marr.Data.Converters;
|
||||||
|
|
||||||
namespace Marr.Data.Mapping
|
namespace Marr.Data.Mapping
|
||||||
{
|
{
|
||||||
|
@ -53,7 +54,15 @@ namespace Marr.Data.Mapping
|
||||||
// Handle conversions
|
// Handle conversions
|
||||||
if (dataMap.Converter != null)
|
if (dataMap.Converter != null)
|
||||||
{
|
{
|
||||||
dbValue = dataMap.Converter.FromDB(dataMap, dbValue);
|
var convertContext = new ConverterContext
|
||||||
|
{
|
||||||
|
DbValue = dbValue,
|
||||||
|
ColumnMap = dataMap,
|
||||||
|
MapCollection = mappings,
|
||||||
|
DataRecord = reader
|
||||||
|
};
|
||||||
|
|
||||||
|
dbValue = dataMap.Converter.FromDB(convertContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbValue != DBNull.Value && dbValue != null)
|
if (dbValue != DBNull.Value && dbValue != null)
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
<Compile Include="Converters\BooleanYNConverter.cs" />
|
<Compile Include="Converters\BooleanYNConverter.cs" />
|
||||||
<Compile Include="Converters\CastConverter.cs" />
|
<Compile Include="Converters\CastConverter.cs" />
|
||||||
<Compile Include="Converters\ConversionException.cs" />
|
<Compile Include="Converters\ConversionException.cs" />
|
||||||
|
<Compile Include="Converters\ConverterContext.cs" />
|
||||||
<Compile Include="Converters\EnumIntConverter.cs" />
|
<Compile Include="Converters\EnumIntConverter.cs" />
|
||||||
<Compile Include="Converters\EnumStringConverter.cs" />
|
<Compile Include="Converters\EnumStringConverter.cs" />
|
||||||
<Compile Include="Converters\IConverter.cs" />
|
<Compile Include="Converters\IConverter.cs" />
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_field_for_every_property()
|
public void should_return_field_for_every_property()
|
||||||
{
|
{
|
||||||
var schema = SchemaBuilder.GenerateSchema(new TestModel());
|
var schema = SchemaBuilder.ToSchema(new TestModel());
|
||||||
schema.Should().HaveCount(2);
|
schema.Should().HaveCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
|
||||||
LastName = "Poop"
|
LastName = "Poop"
|
||||||
};
|
};
|
||||||
|
|
||||||
var schema = SchemaBuilder.GenerateSchema(model);
|
var schema = SchemaBuilder.ToSchema(model);
|
||||||
|
|
||||||
schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop");
|
schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop");
|
||||||
schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob");
|
schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob");
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace NzbDrone.Api.Test.MappingTests
|
||||||
[TestCase(typeof(Episode), typeof(EpisodeResource))]
|
[TestCase(typeof(Episode), typeof(EpisodeResource))]
|
||||||
[TestCase(typeof(RootFolder), typeof(RootFolderResource))]
|
[TestCase(typeof(RootFolder), typeof(RootFolderResource))]
|
||||||
[TestCase(typeof(NamingConfig), typeof(NamingConfigResource))]
|
[TestCase(typeof(NamingConfig), typeof(NamingConfigResource))]
|
||||||
[TestCase(typeof(Indexer), typeof(IndexerResource))]
|
[TestCase(typeof(IndexerDefinition), typeof(IndexerResource))]
|
||||||
[TestCase(typeof(ReleaseInfo), typeof(ReleaseResource))]
|
[TestCase(typeof(ReleaseInfo), typeof(ReleaseResource))]
|
||||||
[TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))]
|
[TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))]
|
||||||
[TestCase(typeof(DownloadDecision), typeof(ReleaseResource))]
|
[TestCase(typeof(DownloadDecision), typeof(ReleaseResource))]
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.EnsureThat;
|
||||||
using NzbDrone.Common.Reflection;
|
using NzbDrone.Common.Reflection;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
|
||||||
|
@ -8,8 +10,10 @@ namespace NzbDrone.Api.ClientSchema
|
||||||
{
|
{
|
||||||
public static class SchemaBuilder
|
public static class SchemaBuilder
|
||||||
{
|
{
|
||||||
public static List<Field> GenerateSchema(object model)
|
public static List<Field> ToSchema(object model)
|
||||||
{
|
{
|
||||||
|
Ensure.That(() => model).IsNotNull();
|
||||||
|
|
||||||
var properties = model.GetType().GetSimpleProperties();
|
var properties = model.GetType().GetSimpleProperties();
|
||||||
|
|
||||||
var result = new List<Field>(properties.Count);
|
var result = new List<Field>(properties.Count);
|
||||||
|
@ -50,6 +54,51 @@ namespace NzbDrone.Api.ClientSchema
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static object ReadFormSchema(List<Field> fields, Type targetType)
|
||||||
|
{
|
||||||
|
Ensure.That(() => targetType).IsNotNull();
|
||||||
|
|
||||||
|
var properties = targetType.GetSimpleProperties();
|
||||||
|
|
||||||
|
var target = Activator.CreateInstance(targetType);
|
||||||
|
|
||||||
|
foreach (var propertyInfo in properties)
|
||||||
|
{
|
||||||
|
var fieldAttribute = propertyInfo.GetAttribute<FieldDefinitionAttribute>(false);
|
||||||
|
|
||||||
|
if (fieldAttribute != null)
|
||||||
|
{
|
||||||
|
var field = fields.Find(f => f.Name == propertyInfo.Name);
|
||||||
|
|
||||||
|
if (propertyInfo.PropertyType == typeof(Int32))
|
||||||
|
{
|
||||||
|
var intValue = Convert.ToInt32(field.Value);
|
||||||
|
propertyInfo.SetValue(target, intValue, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (propertyInfo.PropertyType == typeof(Nullable<Int32>))
|
||||||
|
{
|
||||||
|
var intValue = field.Value.ToString().ParseInt32();
|
||||||
|
propertyInfo.SetValue(target, intValue, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(target, field.Value, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T ReadFormSchema<T>(List<Field> fields)
|
||||||
|
{
|
||||||
|
return (T)ReadFormSchema(fields, typeof (T));
|
||||||
|
}
|
||||||
|
|
||||||
private static List<SelectOption> GetSelectOptions(Type selectOptions)
|
private static List<SelectOption> GetSelectOptions(Type selectOptions)
|
||||||
{
|
{
|
||||||
var options = from Enum e in Enum.GetValues(selectOptions)
|
var options = from Enum e in Enum.GetValues(selectOptions)
|
||||||
|
|
|
@ -8,38 +8,6 @@ namespace NzbDrone.Api.ClientSchema
|
||||||
{
|
{
|
||||||
public static class SchemaDeserializer
|
public static class SchemaDeserializer
|
||||||
{
|
{
|
||||||
public static T DeserializeSchema<T>(T model, List<Field> fields)
|
|
||||||
{
|
|
||||||
var properties = model.GetType().GetSimpleProperties();
|
|
||||||
|
|
||||||
foreach (var propertyInfo in properties)
|
|
||||||
{
|
|
||||||
var fieldAttribute = propertyInfo.GetAttribute<FieldDefinitionAttribute>(false);
|
|
||||||
|
|
||||||
if (fieldAttribute != null)
|
|
||||||
{
|
|
||||||
var field = fields.Find(f => f.Name == propertyInfo.Name);
|
|
||||||
|
|
||||||
if (propertyInfo.PropertyType == typeof (Int32))
|
|
||||||
{
|
|
||||||
var intValue = Convert.ToInt32(field.Value);
|
|
||||||
propertyInfo.SetValue(model, intValue, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (propertyInfo.PropertyType == typeof(Nullable<Int32>))
|
|
||||||
{
|
|
||||||
var intValue = field.Value.ToString().ParseInt32();
|
|
||||||
propertyInfo.SetValue(model, intValue, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
propertyInfo.SetValue(model, field.Value, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Api.ClientSchema;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api
|
||||||
|
{
|
||||||
|
public class ProviderResource : RestResource
|
||||||
|
{
|
||||||
|
public Boolean Enable { get; set; }
|
||||||
|
public String Name { get; set; }
|
||||||
|
public List<Field> Fields { get; set; }
|
||||||
|
public String Implementation { get; set; }
|
||||||
|
public String ConfigContract { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,113 +1,12 @@
|
||||||
using System;
|
using NzbDrone.Core.Indexers;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NzbDrone.Api.ClientSchema;
|
|
||||||
using NzbDrone.Api.REST;
|
|
||||||
using NzbDrone.Core.Indexers;
|
|
||||||
using Omu.ValueInjecter;
|
|
||||||
using FluentValidation;
|
|
||||||
using NzbDrone.Api.Mapping;
|
|
||||||
|
|
||||||
namespace NzbDrone.Api.Indexers
|
namespace NzbDrone.Api.Indexers
|
||||||
{
|
{
|
||||||
public class IndexerModule : NzbDroneRestModule<IndexerResource>
|
public class IndexerModule : ProviderModuleBase<ProviderResource, IIndexer, IndexerDefinition>
|
||||||
{
|
{
|
||||||
private readonly IIndexerService _indexerService;
|
public IndexerModule(IndexerFactory indexerFactory)
|
||||||
|
: base(indexerFactory, "indexer")
|
||||||
public IndexerModule(IIndexerService indexerService)
|
|
||||||
{
|
{
|
||||||
_indexerService = indexerService;
|
|
||||||
GetResourceAll = GetAll;
|
|
||||||
GetResourceById = GetIndexer;
|
|
||||||
CreateResource = CreateIndexer;
|
|
||||||
UpdateResource = UpdateIndexer;
|
|
||||||
DeleteResource = DeleteIndexer;
|
|
||||||
|
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
|
||||||
SharedValidator.RuleFor(c => c.Implementation).NotEmpty();
|
|
||||||
|
|
||||||
PostValidator.RuleFor(c => c.Fields).NotEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IndexerResource GetIndexer(int id)
|
|
||||||
{
|
|
||||||
return _indexerService.Get(id).InjectTo<IndexerResource>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<IndexerResource> GetAll()
|
|
||||||
{
|
|
||||||
var indexers = _indexerService.All();
|
|
||||||
|
|
||||||
var result = new List<IndexerResource>(indexers.Count);
|
|
||||||
|
|
||||||
foreach (var indexer in indexers)
|
|
||||||
{
|
|
||||||
var indexerResource = new IndexerResource();
|
|
||||||
indexerResource.InjectFrom(indexer);
|
|
||||||
indexerResource.Fields = SchemaBuilder.GenerateSchema(indexer.Settings);
|
|
||||||
|
|
||||||
result.Add(indexerResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int CreateIndexer(IndexerResource indexerResource)
|
|
||||||
{
|
|
||||||
var indexer = GetIndexer(indexerResource);
|
|
||||||
indexer = _indexerService.Create(indexer);
|
|
||||||
return indexer.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateIndexer(IndexerResource indexerResource)
|
|
||||||
{
|
|
||||||
var indexer = _indexerService.Get(indexerResource.Id);
|
|
||||||
indexer.InjectFrom(indexerResource);
|
|
||||||
indexer.Settings = SchemaDeserializer.DeserializeSchema(indexer.Settings, indexerResource.Fields);
|
|
||||||
|
|
||||||
ValidateIndexer(indexer);
|
|
||||||
|
|
||||||
_indexerService.Update(indexer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void ValidateIndexer(Indexer indexer)
|
|
||||||
{
|
|
||||||
if (indexer.Enable)
|
|
||||||
{
|
|
||||||
var validationResult = indexer.Settings.Validate();
|
|
||||||
|
|
||||||
if (!validationResult.IsValid)
|
|
||||||
{
|
|
||||||
throw new ValidationException(validationResult.Errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Indexer GetIndexer(IndexerResource indexerResource)
|
|
||||||
{
|
|
||||||
var indexer = _indexerService.Schema()
|
|
||||||
.SingleOrDefault(i =>
|
|
||||||
i.Implementation.Equals(indexerResource.Implementation,
|
|
||||||
StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
|
|
||||||
if (indexer == null)
|
|
||||||
{
|
|
||||||
throw new BadRequestException("Invalid Indexer Implementation");
|
|
||||||
}
|
|
||||||
|
|
||||||
indexer.InjectFrom(indexerResource);
|
|
||||||
indexer.Settings = SchemaDeserializer.DeserializeSchema(indexer.Settings, indexerResource.Fields);
|
|
||||||
|
|
||||||
ValidateIndexer(indexer);
|
|
||||||
|
|
||||||
return indexer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteIndexer(int id)
|
|
||||||
{
|
|
||||||
_indexerService.Delete(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,5 +11,6 @@ namespace NzbDrone.Api.Indexers
|
||||||
public String Name { get; set; }
|
public String Name { get; set; }
|
||||||
public List<Field> Fields { get; set; }
|
public List<Field> Fields { get; set; }
|
||||||
public String Implementation { get; set; }
|
public String Implementation { get; set; }
|
||||||
|
public String ConfigContract { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NzbDrone.Api.ClientSchema;
|
using NzbDrone.Api.ClientSchema;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using Omu.ValueInjecter;
|
using Omu.ValueInjecter;
|
||||||
|
@ -7,26 +8,28 @@ namespace NzbDrone.Api.Indexers
|
||||||
{
|
{
|
||||||
public class IndexerSchemaModule : NzbDroneRestModule<IndexerResource>
|
public class IndexerSchemaModule : NzbDroneRestModule<IndexerResource>
|
||||||
{
|
{
|
||||||
private readonly IIndexerService _indexerService;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
|
|
||||||
public IndexerSchemaModule(IIndexerService indexerService)
|
public IndexerSchemaModule(IIndexerFactory indexerFactory)
|
||||||
: base("indexer/schema")
|
: base("indexer/schema")
|
||||||
{
|
{
|
||||||
_indexerService = indexerService;
|
_indexerFactory = indexerFactory;
|
||||||
GetResourceAll = GetSchema;
|
GetResourceAll = GetSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IndexerResource> GetSchema()
|
private List<IndexerResource> GetSchema()
|
||||||
{
|
{
|
||||||
var indexers = _indexerService.Schema();
|
|
||||||
|
|
||||||
var result = new List<IndexerResource>(indexers.Count);
|
var indexers = _indexerFactory.Templates().Where(c => c.Implementation =="Newznab");
|
||||||
|
|
||||||
|
|
||||||
|
var result = new List<IndexerResource>(indexers.Count());
|
||||||
|
|
||||||
foreach (var indexer in indexers)
|
foreach (var indexer in indexers)
|
||||||
{
|
{
|
||||||
var indexerResource = new IndexerResource();
|
var indexerResource = new IndexerResource();
|
||||||
indexerResource.InjectFrom(indexer);
|
indexerResource.InjectFrom(indexer);
|
||||||
indexerResource.Fields = SchemaBuilder.GenerateSchema(indexer.Settings);
|
indexerResource.Fields = SchemaBuilder.ToSchema(indexer.Settings);
|
||||||
|
|
||||||
result.Add(indexerResource);
|
result.Add(indexerResource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using NzbDrone.Api.ClientSchema;
|
using NzbDrone.Api.ClientSchema;
|
||||||
using NzbDrone.Api.Mapping;
|
using NzbDrone.Api.Mapping;
|
||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
using NzbDrone.Core.Notifications;
|
using NzbDrone.Core.Notifications;
|
||||||
using Omu.ValueInjecter;
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ namespace NzbDrone.Api.Notifications
|
||||||
{
|
{
|
||||||
var notificationResource = new NotificationResource();
|
var notificationResource = new NotificationResource();
|
||||||
notificationResource.InjectFrom(notification);
|
notificationResource.InjectFrom(notification);
|
||||||
notificationResource.Fields = SchemaBuilder.GenerateSchema(notification.Settings);
|
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
|
||||||
notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant());
|
notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant());
|
||||||
|
|
||||||
result.Add(notificationResource);
|
result.Add(notificationResource);
|
||||||
|
@ -79,7 +80,10 @@ namespace NzbDrone.Api.Notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.InjectFrom(notificationResource);
|
notification.InjectFrom(notificationResource);
|
||||||
notification.Settings = SchemaDeserializer.DeserializeSchema(notification.Settings, notificationResource.Fields);
|
|
||||||
|
//var configType = ReflectionExtensions.CoreAssembly.FindTypeByName(notification)
|
||||||
|
|
||||||
|
//notification.Settings = SchemaBuilder.ReadFormSchema(notification.Settings, notificationResource.Fields);
|
||||||
|
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace NzbDrone.Api.Notifications
|
||||||
{
|
{
|
||||||
var notificationResource = new NotificationResource();
|
var notificationResource = new NotificationResource();
|
||||||
notificationResource.InjectFrom(notification);
|
notificationResource.InjectFrom(notification);
|
||||||
notificationResource.Fields = SchemaBuilder.GenerateSchema(notification.Settings);
|
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
|
||||||
notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant());
|
notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant());
|
||||||
|
|
||||||
result.Add(notificationResource);
|
result.Add(notificationResource);
|
||||||
|
|
|
@ -109,6 +109,8 @@
|
||||||
<Compile Include="Frontend\StaticResourceModule.cs" />
|
<Compile Include="Frontend\StaticResourceModule.cs" />
|
||||||
<Compile Include="History\HistoryResource.cs" />
|
<Compile Include="History\HistoryResource.cs" />
|
||||||
<Compile Include="History\HistoryModule.cs" />
|
<Compile Include="History\HistoryModule.cs" />
|
||||||
|
<Compile Include="IndexerResource.cs" />
|
||||||
|
<Compile Include="ProviderModuleBase.cs" />
|
||||||
<Compile Include="Indexers\IndexerSchemaModule.cs" />
|
<Compile Include="Indexers\IndexerSchemaModule.cs" />
|
||||||
<Compile Include="Indexers\IndexerModule.cs" />
|
<Compile Include="Indexers\IndexerModule.cs" />
|
||||||
<Compile Include="Indexers\IndexerResource.cs" />
|
<Compile Include="Indexers\IndexerResource.cs" />
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentValidation;
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api.ClientSchema;
|
||||||
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Api.Indexers;
|
||||||
|
using NzbDrone.Api.Mapping;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api
|
||||||
|
{
|
||||||
|
public abstract class ProviderModuleBase<TProviderResource, TProvider, TProviderDefinition> : NzbDroneRestModule<TProviderResource>
|
||||||
|
where TProviderDefinition : ProviderDefinition, new()
|
||||||
|
where TProvider : IProvider
|
||||||
|
where TProviderResource : ProviderResource, new()
|
||||||
|
{
|
||||||
|
private readonly IProviderFactory<TProvider, TProviderDefinition> _providerFactory;
|
||||||
|
|
||||||
|
protected ProviderModuleBase(IProviderFactory<TProvider, TProviderDefinition> providerFactory, string resource)
|
||||||
|
: base(resource)
|
||||||
|
{
|
||||||
|
_providerFactory = providerFactory;
|
||||||
|
Get["templates"] = x => GetTemplates();
|
||||||
|
GetResourceAll = GetAll;
|
||||||
|
GetResourceById = GetProviderById;
|
||||||
|
CreateResource = CreateProvider;
|
||||||
|
UpdateResource = UpdateProvider;
|
||||||
|
DeleteResource = DeleteProvider;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||||
|
SharedValidator.RuleFor(c => c.Implementation).NotEmpty();
|
||||||
|
SharedValidator.RuleFor(c => c.ConfigContract).NotEmpty();
|
||||||
|
|
||||||
|
PostValidator.RuleFor(c => c.Fields).NotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TProviderResource GetProviderById(int id)
|
||||||
|
{
|
||||||
|
return _providerFactory.Get(id).InjectTo<TProviderResource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TProviderResource> GetAll()
|
||||||
|
{
|
||||||
|
var indexerDefinitions = _providerFactory.All();
|
||||||
|
|
||||||
|
var result = new List<TProviderResource>(indexerDefinitions.Count);
|
||||||
|
|
||||||
|
foreach (var definition in indexerDefinitions)
|
||||||
|
{
|
||||||
|
var indexerResource = new TProviderResource();
|
||||||
|
indexerResource.InjectFrom(definition);
|
||||||
|
indexerResource.Fields = SchemaBuilder.ToSchema(definition.Settings);
|
||||||
|
|
||||||
|
result.Add(indexerResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CreateProvider(TProviderResource indexerResource)
|
||||||
|
{
|
||||||
|
var indexer = GetDefinition(indexerResource);
|
||||||
|
indexer = _providerFactory.Create(indexer);
|
||||||
|
return indexer.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateProvider(TProviderResource indexerResource)
|
||||||
|
{
|
||||||
|
var indexer = GetDefinition(indexerResource);
|
||||||
|
|
||||||
|
ValidateIndexer(indexer);
|
||||||
|
|
||||||
|
_providerFactory.Update(indexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void ValidateIndexer(ProviderDefinition definition)
|
||||||
|
{
|
||||||
|
if (!definition.Enable) return;
|
||||||
|
|
||||||
|
var validationResult = definition.Settings.Validate();
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
{
|
||||||
|
throw new ValidationException(validationResult.Errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TProviderDefinition GetDefinition(TProviderResource indexerResource)
|
||||||
|
{
|
||||||
|
|
||||||
|
var definition = new TProviderDefinition();
|
||||||
|
|
||||||
|
definition.InjectFrom(indexerResource);
|
||||||
|
|
||||||
|
var configContract = ReflectionExtensions.CoreAssembly.FindTypeByName(definition.ConfigContract);
|
||||||
|
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFormSchema(indexerResource.Fields, configContract);
|
||||||
|
|
||||||
|
ValidateIndexer(definition);
|
||||||
|
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteProvider(int id)
|
||||||
|
{
|
||||||
|
_providerFactory.Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response GetTemplates()
|
||||||
|
{
|
||||||
|
|
||||||
|
var indexers = _providerFactory.Templates();
|
||||||
|
|
||||||
|
|
||||||
|
var result = new List<IndexerResource>(indexers.Count());
|
||||||
|
|
||||||
|
foreach (var indexer in indexers)
|
||||||
|
{
|
||||||
|
var indexerResource = new IndexerResource();
|
||||||
|
indexerResource.InjectFrom(indexer);
|
||||||
|
indexerResource.Fields = SchemaBuilder.ToSchema(indexer.Settings);
|
||||||
|
|
||||||
|
result.Add(indexerResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.AsResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ namespace NzbDrone.App.Test
|
||||||
{
|
{
|
||||||
var factory = MainAppContainerBuilder.BuildContainer(args).Resolve<IServiceFactory>();
|
var factory = MainAppContainerBuilder.BuildContainer(args).Resolve<IServiceFactory>();
|
||||||
|
|
||||||
factory.Build<IIndexerService>().Should().NotBeNull();
|
factory.Build<IIndexerFactory>().Should().NotBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace NzbDrone.Common.Reflection
|
||||||
{
|
{
|
||||||
public static class ReflectionExtensions
|
public static class ReflectionExtensions
|
||||||
{
|
{
|
||||||
|
public static readonly Assembly CoreAssembly = Assembly.Load("NzbDrone.Core");
|
||||||
|
|
||||||
public static List<PropertyInfo> GetSimpleProperties(this Type type)
|
public static List<PropertyInfo> GetSimpleProperties(this Type type)
|
||||||
{
|
{
|
||||||
var properties = type.GetProperties();
|
var properties = type.GetProperties();
|
||||||
|
@ -58,6 +60,11 @@ namespace NzbDrone.Common.Reflection
|
||||||
return (T)attribute;
|
return (T)attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Type FindTypeByName(this Assembly assembly, string name)
|
||||||
|
{
|
||||||
|
return assembly.GetTypes().SingleOrDefault(c => c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
public static bool HasAttribute<TAttribute>(this Type type)
|
public static bool HasAttribute<TAttribute>(this Type type)
|
||||||
{
|
{
|
||||||
return type.GetCustomAttributes(typeof(TAttribute), true).Any();
|
return type.GetCustomAttributes(typeof(TAttribute), true).Any();
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Marr.Data.Converters;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Datastore.Converters
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ProviderSettingConverterFixture : CoreTest<ProviderSettingConverter>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_return_null_config_if_config_is_null()
|
||||||
|
{
|
||||||
|
var result = Subject.FromDB(new ConverterContext()
|
||||||
|
{
|
||||||
|
DbValue = DBNull.Value
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
result.Should().Be(NullConfig.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(null)]
|
||||||
|
[TestCase("")]
|
||||||
|
public void should_return_null_config_if_config_is_empty(object dbValue)
|
||||||
|
{
|
||||||
|
var result = Subject.FromDB(new ConverterContext()
|
||||||
|
{
|
||||||
|
DbValue = dbValue
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
result.Should().Be(NullConfig.Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.IndexerTests
|
namespace NzbDrone.Core.Test.IndexerTests
|
||||||
{
|
{
|
||||||
public class IndexerServiceFixture : DbTest<IndexerService, IndexerDefinition>
|
public class IndexerServiceFixture : DbTest<IndexerFactory, IndexerDefinition>
|
||||||
{
|
{
|
||||||
private List<IIndexer> _indexers;
|
private List<IIndexer> _indexers;
|
||||||
|
|
||||||
|
@ -57,10 +57,8 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||||
var indexers = Subject.All().ToList();
|
var indexers = Subject.All().ToList();
|
||||||
indexers.Should().NotBeEmpty();
|
indexers.Should().NotBeEmpty();
|
||||||
indexers.Should().NotContain(c => c.Settings == null);
|
indexers.Should().NotContain(c => c.Settings == null);
|
||||||
indexers.Should().NotContain(c => c.Instance == null);
|
|
||||||
indexers.Should().NotContain(c => c.Name == null);
|
indexers.Should().NotContain(c => c.Name == null);
|
||||||
indexers.Select(c => c.Name).Should().OnlyHaveUniqueItems();
|
indexers.Select(c => c.Name).Should().OnlyHaveUniqueItems();
|
||||||
indexers.Select(c => c.Instance).Should().OnlyHaveUniqueItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +71,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||||
|
|
||||||
|
|
||||||
var existingIndexers = Builder<IndexerDefinition>.CreateNew().BuildNew();
|
var existingIndexers = Builder<IndexerDefinition>.CreateNew().BuildNew();
|
||||||
|
existingIndexers.ConfigContract = typeof (NewznabSettings).Name;
|
||||||
|
|
||||||
repo.Insert(existingIndexers);
|
repo.Insert(existingIndexers);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ using NzbDrone.Core.Indexers.Wombles;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Test.Common.Categories;
|
using NzbDrone.Test.Common.Categories;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -27,6 +28,12 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
|
||||||
{
|
{
|
||||||
var indexer = new Wombles();
|
var indexer = new Wombles();
|
||||||
|
|
||||||
|
indexer.Definition = new IndexerDefinition
|
||||||
|
{
|
||||||
|
Name = "Wombles",
|
||||||
|
Settings = NullConfig.Instance
|
||||||
|
};
|
||||||
|
|
||||||
var result = Subject.FetchRss(indexer);
|
var result = Subject.FetchRss(indexer);
|
||||||
|
|
||||||
ValidateResult(result, skipSize: true, skipInfo: true);
|
ValidateResult(result, skipSize: true, skipInfo: true);
|
||||||
|
@ -37,6 +44,11 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
|
||||||
public void extv_rss()
|
public void extv_rss()
|
||||||
{
|
{
|
||||||
var indexer = new Eztv();
|
var indexer = new Eztv();
|
||||||
|
indexer.Definition = new IndexerDefinition
|
||||||
|
{
|
||||||
|
Name = "Eztv",
|
||||||
|
Settings = NullConfig.Instance
|
||||||
|
};
|
||||||
|
|
||||||
var result = Subject.FetchRss(indexer);
|
var result = Subject.FetchRss(indexer);
|
||||||
|
|
||||||
|
@ -48,15 +60,15 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
|
||||||
public void nzbsorg_rss()
|
public void nzbsorg_rss()
|
||||||
{
|
{
|
||||||
var indexer = new Newznab();
|
var indexer = new Newznab();
|
||||||
indexer.Settings = new NewznabSettings
|
|
||||||
|
indexer.Definition = new IndexerDefinition();
|
||||||
|
indexer.Definition.Name = "nzbs.org";
|
||||||
|
indexer.Definition.Settings = new NewznabSettings
|
||||||
{
|
{
|
||||||
ApiKey = "64d61d3cfd4b75e51d01cbc7c6a78275",
|
ApiKey = "64d61d3cfd4b75e51d01cbc7c6a78275",
|
||||||
Url = "http://nzbs.org"
|
Url = "http://nzbs.org"
|
||||||
};
|
};
|
||||||
|
|
||||||
indexer.InstanceDefinition = new IndexerDefinition();
|
|
||||||
indexer.InstanceDefinition.Name = "nzbs.org";
|
|
||||||
|
|
||||||
var result = Subject.FetchRss(indexer);
|
var result = Subject.FetchRss(indexer);
|
||||||
|
|
||||||
ValidateResult(result);
|
ValidateResult(result);
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
<Compile Include="DataAugmentationFixture\Scene\SceneMappingProxyFixture.cs" />
|
<Compile Include="DataAugmentationFixture\Scene\SceneMappingProxyFixture.cs" />
|
||||||
<Compile Include="DataAugmentationFixture\Scene\SceneMappingServiceFixture.cs" />
|
<Compile Include="DataAugmentationFixture\Scene\SceneMappingServiceFixture.cs" />
|
||||||
<Compile Include="Datastore\BasicRepositoryFixture.cs" />
|
<Compile Include="Datastore\BasicRepositoryFixture.cs" />
|
||||||
|
<Compile Include="Datastore\Converters\ProviderSettingConverterFixture.cs" />
|
||||||
<Compile Include="Datastore\DatabaseRelationshipFixture.cs" />
|
<Compile Include="Datastore\DatabaseRelationshipFixture.cs" />
|
||||||
<Compile Include="Datastore\MappingExtentionFixture.cs" />
|
<Compile Include="Datastore\MappingExtentionFixture.cs" />
|
||||||
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
|
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
|
||||||
|
@ -181,6 +182,8 @@
|
||||||
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" />
|
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" />
|
||||||
<Compile Include="NotificationTests\PlexProviderTest.cs" />
|
<Compile Include="NotificationTests\PlexProviderTest.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedEpisodesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedEpisodesFixture.cs" />
|
||||||
|
<Compile Include="ThingiProviderTests\NullConfigFixture.cs" />
|
||||||
|
<Compile Include="ThingiProvider\ProviderBaseFixture.cs" />
|
||||||
<Compile Include="TvTests\RefreshEpisodeServiceFixture.cs" />
|
<Compile Include="TvTests\RefreshEpisodeServiceFixture.cs" />
|
||||||
<Compile Include="TvTests\EpisodeProviderTests\HandleEpisodeFileDeletedFixture.cs" />
|
<Compile Include="TvTests\EpisodeProviderTests\HandleEpisodeFileDeletedFixture.cs" />
|
||||||
<Compile Include="TvTests\EpisodeRepositoryTests\FindEpisodeFixture.cs" />
|
<Compile Include="TvTests\EpisodeRepositoryTests\FindEpisodeFixture.cs" />
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Indexers.Newznab;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ThingiProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ProviderRepositoryFixture : DbTest<IndexerRepository, IndexerDefinition>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_read_write_download_provider()
|
||||||
|
{
|
||||||
|
var model = Builder<IndexerDefinition>.CreateNew().BuildNew();
|
||||||
|
var newznabSettings = Builder<NewznabSettings>.CreateNew().Build();
|
||||||
|
model.Settings = newznabSettings;
|
||||||
|
Subject.Insert(model);
|
||||||
|
|
||||||
|
var storedProvider = Subject.Single();
|
||||||
|
|
||||||
|
storedProvider.Settings.Should().BeOfType<NewznabSettings>();
|
||||||
|
|
||||||
|
var storedSetting = (NewznabSettings)storedProvider.Settings;
|
||||||
|
|
||||||
|
storedSetting.ShouldHave().AllProperties().EqualTo(newznabSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ThingiProviderTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class NullConfigFixture : CoreTest<NullConfig>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_be_valid()
|
||||||
|
{
|
||||||
|
Subject.Validate().IsValid.Should().BeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,14 +6,14 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class BooleanIntConverter : IConverter
|
public class BooleanIntConverter : IConverter
|
||||||
{
|
{
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
{
|
{
|
||||||
return DBNull.Value;
|
return DBNull.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var val = (Int64)dbValue;
|
var val = (Int64)context.DbValue;
|
||||||
|
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
|
@ -22,10 +22,15 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
case 0:
|
case 0:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
throw new ConversionException(string.Format("The BooleanCharConverter could not convert the value '{0}' to a Boolean.", dbValue));
|
throw new ConversionException(string.Format("The BooleanCharConverter could not convert the value '{0}' to a Boolean.", context.DbValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
{
|
{
|
||||||
var val = (Nullable<bool>)clrValue;
|
var val = (Nullable<bool>)clrValue;
|
||||||
|
|
|
@ -7,22 +7,26 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class EmbeddedDocumentConverter : IConverter
|
public class EmbeddedDocumentConverter : IConverter
|
||||||
{
|
{
|
||||||
|
public virtual object FromDB(ConverterContext context)
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
{
|
{
|
||||||
return DBNull.Value;
|
return DBNull.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringValue = (string)dbValue;
|
var stringValue = (string)context.DbValue;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(stringValue))
|
if (string.IsNullOrWhiteSpace(stringValue))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Json.Deserialize(stringValue, map.FieldType);
|
return Json.Deserialize(stringValue, context.ColumnMap.FieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -14,16 +14,21 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (dbValue != null && dbValue != DBNull.Value)
|
if (context.DbValue != null && context.DbValue != DBNull.Value)
|
||||||
{
|
{
|
||||||
return Enum.ToObject(map.FieldType, (Int64)dbValue);
|
return Enum.ToObject(context.ColumnMap.FieldType, (Int64)context.DbValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
{
|
{
|
||||||
if (clrValue != null)
|
if (clrValue != null)
|
||||||
|
|
|
@ -6,6 +6,21 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class Int32Converter : IConverter
|
public class Int32Converter : IConverter
|
||||||
{
|
{
|
||||||
|
public object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
if (context.DbValue == DBNull.Value)
|
||||||
|
{
|
||||||
|
return DBNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.DbValue is Int32)
|
||||||
|
{
|
||||||
|
return context.DbValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToInt32(context.DbValue);
|
||||||
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (dbValue == DBNull.Value)
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using Marr.Data.Converters;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Converters
|
||||||
|
{
|
||||||
|
public class ProviderSettingConverter : EmbeddedDocumentConverter
|
||||||
|
{
|
||||||
|
public override object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
if (context.DbValue == DBNull.Value)
|
||||||
|
{
|
||||||
|
return NullConfig.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringValue = (string)context.DbValue;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(stringValue))
|
||||||
|
{
|
||||||
|
return NullConfig.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ordinal = context.DataRecord.GetOrdinal("ConfigContract");
|
||||||
|
var contract = context.DataRecord.GetString(ordinal);
|
||||||
|
|
||||||
|
|
||||||
|
var impType = typeof (IProviderConfig).Assembly.FindTypeByName(contract);
|
||||||
|
|
||||||
|
if (impType == null)
|
||||||
|
{
|
||||||
|
throw new ConfigContractNotFoundException(contract);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json.Deserialize(stringValue, impType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,18 +7,23 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class QualityIntConverter : IConverter
|
public class QualityIntConverter : IConverter
|
||||||
{
|
{
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (dbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
{
|
{
|
||||||
return Quality.Unknown;
|
return Quality.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
var val = Convert.ToInt32(dbValue);
|
var val = Convert.ToInt32(context.DbValue);
|
||||||
|
|
||||||
return (Quality)val;
|
return (Quality)val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
{
|
||||||
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
{
|
{
|
||||||
if(clrValue == null) return 0;
|
if(clrValue == null) return 0;
|
||||||
|
|
|
@ -6,9 +6,14 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class UtcConverter : IConverter
|
public class UtcConverter : IConverter
|
||||||
{
|
{
|
||||||
|
public object FromDB(ConverterContext context)
|
||||||
|
{
|
||||||
|
return context.DbValue;
|
||||||
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
{
|
{
|
||||||
return dbValue;
|
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
public object ToDB(object clrValue)
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(22)]
|
||||||
|
public class move_indexer_to_generic_provider : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("Indexers").AddColumn("ConfigContract").AsString().Nullable();
|
||||||
|
|
||||||
|
//Execute.WithConnection(ConvertSeasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConvertSeasons(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
using (IDbCommand allSeriesCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
allSeriesCmd.Transaction = tran;
|
||||||
|
allSeriesCmd.CommandText = @"SELECT Id FROM Series";
|
||||||
|
using (IDataReader allSeriesReader = allSeriesCmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (allSeriesReader.Read())
|
||||||
|
{
|
||||||
|
int seriesId = allSeriesReader.GetInt32(0);
|
||||||
|
var seasons = new List<dynamic>();
|
||||||
|
|
||||||
|
using (IDbCommand seasonsCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
seasonsCmd.Transaction = tran;
|
||||||
|
seasonsCmd.CommandText = String.Format(@"SELECT SeasonNumber, Monitored FROM Seasons WHERE SeriesId = {0}", seriesId);
|
||||||
|
|
||||||
|
using (IDataReader seasonReader = seasonsCmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (seasonReader.Read())
|
||||||
|
{
|
||||||
|
int seasonNumber = seasonReader.GetInt32(0);
|
||||||
|
bool monitored = seasonReader.GetBoolean(1);
|
||||||
|
|
||||||
|
if (seasonNumber == 0)
|
||||||
|
{
|
||||||
|
monitored = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seasons.Add(new { seasonNumber, monitored });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
var text = String.Format("UPDATE Series SET Seasons = '{0}' WHERE Id = {1}", seasons.ToJson(), seriesId);
|
||||||
|
|
||||||
|
updateCmd.Transaction = tran;
|
||||||
|
updateCmd.CommandText = text;
|
||||||
|
updateCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(23)]
|
||||||
|
public class add_config_contract_to_indexers : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Update.Table("Indexers").Set(new { ConfigContract = "NewznabSettings" }).Where(new { Implementation = "Newznab" });
|
||||||
|
Update.Table("Indexers").Set(new { ConfigContract = "OmgwtfnzbsSettings" }).Where(new { Implementation = "Omgwtfnzbs" });
|
||||||
|
Update.Table("Indexers").Set(new { ConfigContract = "NullConfig" }).Where(new { Implementation = "Wombles" });
|
||||||
|
Update.Table("Indexers").Set(new { ConfigContract = "NullConfig" }).Where(new { Implementation = "Eztv" });
|
||||||
|
|
||||||
|
Delete.FromTable("Indexers").IsNull("ConfigContract");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Marr.Data.Mapping;
|
using Marr.Data.Mapping;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.DataAugmentation.Scene;
|
using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
using NzbDrone.Core.Datastore.Converters;
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
|
@ -15,6 +16,7 @@ using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Core.RootFolders;
|
using NzbDrone.Core.RootFolders;
|
||||||
using NzbDrone.Core.SeriesStats;
|
using NzbDrone.Core.SeriesStats;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
namespace NzbDrone.Core.Datastore
|
||||||
|
@ -69,6 +71,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
private static void RegisterMappers()
|
private static void RegisterMappers()
|
||||||
{
|
{
|
||||||
RegisterEmbeddedConverter();
|
RegisterEmbeddedConverter();
|
||||||
|
RegisterProviderSettingConverter();
|
||||||
|
|
||||||
MapRepository.Instance.RegisterTypeConverter(typeof(Int32), new Int32Converter());
|
MapRepository.Instance.RegisterTypeConverter(typeof(Int32), new Int32Converter());
|
||||||
MapRepository.Instance.RegisterTypeConverter(typeof(DateTime), new UtcConverter());
|
MapRepository.Instance.RegisterTypeConverter(typeof(DateTime), new UtcConverter());
|
||||||
|
@ -78,10 +81,20 @@ namespace NzbDrone.Core.Datastore
|
||||||
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
|
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void RegisterProviderSettingConverter()
|
||||||
|
{
|
||||||
|
var settingTypes = typeof(IProviderConfig).Assembly.ImplementationsOf<IProviderConfig>();
|
||||||
|
|
||||||
|
var providerSettingConverter = new ProviderSettingConverter();
|
||||||
|
foreach (var embeddedType in settingTypes)
|
||||||
|
{
|
||||||
|
MapRepository.Instance.RegisterTypeConverter(embeddedType, providerSettingConverter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void RegisterEmbeddedConverter()
|
private static void RegisterEmbeddedConverter()
|
||||||
{
|
{
|
||||||
var embeddedTypes = typeof(IEmbeddedDocument).Assembly.GetTypes()
|
var embeddedTypes = typeof(IEmbeddedDocument).Assembly.ImplementationsOf<IEmbeddedDocument>();
|
||||||
.Where(c => c.GetInterfaces().Any(i => i == typeof(IEmbeddedDocument)));
|
|
||||||
|
|
||||||
|
|
||||||
var embeddedConvertor = new EmbeddedDocumentConverter();
|
var embeddedConvertor = new EmbeddedDocumentConverter();
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace NzbDrone.Core.IndexerSearch
|
||||||
|
|
||||||
public class NzbSearchService : ISearchForNzb
|
public class NzbSearchService : ISearchForNzb
|
||||||
{
|
{
|
||||||
private readonly IIndexerService _indexerService;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
private readonly IFetchFeedFromIndexers _feedFetcher;
|
private readonly IFetchFeedFromIndexers _feedFetcher;
|
||||||
private readonly ISceneMappingService _sceneMapping;
|
private readonly ISceneMappingService _sceneMapping;
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.IndexerSearch
|
||||||
private readonly IMakeDownloadDecision _makeDownloadDecision;
|
private readonly IMakeDownloadDecision _makeDownloadDecision;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public NzbSearchService(IIndexerService indexerService,
|
public NzbSearchService(IIndexerFactory indexerFactory,
|
||||||
IFetchFeedFromIndexers feedFetcher,
|
IFetchFeedFromIndexers feedFetcher,
|
||||||
ISceneMappingService sceneMapping,
|
ISceneMappingService sceneMapping,
|
||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
|
@ -40,7 +40,7 @@ namespace NzbDrone.Core.IndexerSearch
|
||||||
IMakeDownloadDecision makeDownloadDecision,
|
IMakeDownloadDecision makeDownloadDecision,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_indexerService = indexerService;
|
_indexerFactory = indexerFactory;
|
||||||
_feedFetcher = feedFetcher;
|
_feedFetcher = feedFetcher;
|
||||||
_sceneMapping = sceneMapping;
|
_sceneMapping = sceneMapping;
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
|
@ -132,7 +132,7 @@ namespace NzbDrone.Core.IndexerSearch
|
||||||
|
|
||||||
private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>> searchAction, SearchCriteriaBase criteriaBase)
|
private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>> searchAction, SearchCriteriaBase criteriaBase)
|
||||||
{
|
{
|
||||||
var indexers = _indexerService.GetAvailableIndexers().ToList();
|
var indexers = _indexerFactory.GetAvailableProviders().ToList();
|
||||||
var reports = new List<ReleaseInfo>();
|
var reports = new List<ReleaseInfo>();
|
||||||
|
|
||||||
_logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase);
|
_logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase);
|
||||||
|
|
|
@ -1,28 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Eztv
|
namespace NzbDrone.Core.Indexers.Eztv
|
||||||
{
|
{
|
||||||
public class Eztv : IndexerBase
|
public class Eztv : IndexerBase<NullConfig>
|
||||||
{
|
{
|
||||||
public override string Name
|
public override DownloadProtocol Protocol
|
||||||
{
|
|
||||||
get { return "Eztv"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IndexerKind Kind
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return IndexerKind.Torrent;
|
return DownloadProtocol.Torrent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool EnableByDefault
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IParseFeed Parser
|
public override IParseFeed Parser
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -35,10 +26,7 @@ namespace NzbDrone.Core.Indexers.Eztv
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new[]
|
yield return "http://www.ezrss.it/feed/";
|
||||||
{
|
|
||||||
"http://www.ezrss.it/feed/"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +43,7 @@ namespace NzbDrone.Core.Indexers.Eztv
|
||||||
|
|
||||||
public override IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date)
|
public override IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date)
|
||||||
{
|
{
|
||||||
//EZTV doesn't support searching based on actual epidose airdate. they only support release date.
|
//EZTV doesn't support searching based on actual episode airdate. they only support release date.
|
||||||
return new string[0];
|
return new string[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ namespace NzbDrone.Core.Indexers
|
||||||
|
|
||||||
public class FetchAndParseRssService : IFetchAndParseRss
|
public class FetchAndParseRssService : IFetchAndParseRss
|
||||||
{
|
{
|
||||||
private readonly IIndexerService _indexerService;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
private readonly IFetchFeedFromIndexers _feedFetcher;
|
private readonly IFetchFeedFromIndexers _feedFetcher;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public FetchAndParseRssService(IIndexerService indexerService, IFetchFeedFromIndexers feedFetcher, Logger logger)
|
public FetchAndParseRssService(IIndexerFactory indexerFactory, IFetchFeedFromIndexers feedFetcher, Logger logger)
|
||||||
{
|
{
|
||||||
_indexerService = indexerService;
|
_indexerFactory = indexerFactory;
|
||||||
_feedFetcher = feedFetcher;
|
_feedFetcher = feedFetcher;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
var result = new List<ReleaseInfo>();
|
var result = new List<ReleaseInfo>();
|
||||||
|
|
||||||
var indexers = _indexerService.GetAvailableIndexers().ToList();
|
var indexers = _indexerFactory.GetAvailableProviders().ToList();
|
||||||
|
|
||||||
if (!indexers.Any())
|
if (!indexers.Any())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,23 +1,15 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public interface IIndexer
|
public interface IIndexer : IProvider
|
||||||
{
|
{
|
||||||
string Name { get; }
|
IParseFeed Parser { get; }
|
||||||
|
DownloadProtocol Protocol { get; }
|
||||||
bool EnableByDefault { get; }
|
|
||||||
|
|
||||||
IEnumerable<IndexerDefinition> DefaultDefinitions { get; }
|
|
||||||
|
|
||||||
IndexerDefinition InstanceDefinition { get; set; }
|
|
||||||
|
|
||||||
IEnumerable<string> RecentFeed { get; }
|
IEnumerable<string> RecentFeed { get; }
|
||||||
|
|
||||||
IParseFeed Parser { get; }
|
|
||||||
IndexerKind Kind { get; }
|
|
||||||
|
|
||||||
IEnumerable<string> GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber);
|
IEnumerable<string> GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber);
|
||||||
IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date);
|
IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date);
|
||||||
IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset);
|
IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset);
|
||||||
|
|
|
@ -1,41 +1,62 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public abstract class IndexerBase : IIndexer
|
public abstract class IndexerBase<TSettings> : IIndexer where TSettings : IProviderConfig, new()
|
||||||
{
|
{
|
||||||
public abstract string Name { get; }
|
public Type ConfigContract
|
||||||
|
|
||||||
public abstract IndexerKind Kind { get; }
|
|
||||||
|
|
||||||
public virtual bool EnableByDefault { get { return true; } }
|
|
||||||
|
|
||||||
public IndexerDefinition InstanceDefinition { get; set; }
|
|
||||||
|
|
||||||
public virtual IEnumerable<IndexerDefinition> DefaultDefinitions
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
return typeof(TSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var config = (IProviderConfig)new TSettings();
|
||||||
|
|
||||||
yield return new IndexerDefinition
|
yield return new IndexerDefinition
|
||||||
{
|
{
|
||||||
Name = Name,
|
Name = GetType().Name,
|
||||||
Enable = EnableByDefault,
|
Enable = config.Validate().IsValid,
|
||||||
Implementation = GetType().Name,
|
Implementation = GetType().Name,
|
||||||
Settings = String.Empty
|
Settings = config
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProviderDefinition Definition { get; set; }
|
||||||
|
|
||||||
|
public abstract DownloadProtocol Protocol { get; }
|
||||||
|
|
||||||
|
protected TSettings Settings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (TSettings)Definition.Settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IParseFeed Parser { get; private set; }
|
public virtual IParseFeed Parser { get; private set; }
|
||||||
|
|
||||||
public abstract IEnumerable<string> RecentFeed { get; }
|
public abstract IEnumerable<string> RecentFeed { get; }
|
||||||
public abstract IEnumerable<string> GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber);
|
public abstract IEnumerable<string> GetEpisodeSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int episodeNumber);
|
||||||
public abstract IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date);
|
public abstract IEnumerable<string> GetDailyEpisodeSearchUrls(string seriesTitle, int tvRageId, DateTime date);
|
||||||
public abstract IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset);
|
public abstract IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int tvRageId, int seasonNumber, int offset);
|
||||||
|
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return GetType().Name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IndexerKind
|
public enum DownloadProtocol
|
||||||
{
|
{
|
||||||
Usenet,
|
Usenet,
|
||||||
Torrent
|
Torrent
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
using System;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Datastore;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public class IndexerDefinition : ModelBase
|
public class IndexerDefinition : ProviderDefinition
|
||||||
{
|
{
|
||||||
public Boolean Enable { get; set; }
|
|
||||||
public String Name { get; set; }
|
|
||||||
public String Settings { get; set; }
|
|
||||||
public String Implementation { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers
|
||||||
|
{
|
||||||
|
public interface IIndexerFactory : IProviderFactory<IIndexer, IndexerDefinition>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IndexerFactory : ProviderFactory<IIndexer, IndexerDefinition>, IIndexerFactory
|
||||||
|
{
|
||||||
|
private readonly IIndexerRepository _providerRepository;
|
||||||
|
private readonly IEnumerable<IIndexer> _providers;
|
||||||
|
|
||||||
|
public IndexerFactory(IIndexerRepository providerRepository, IEnumerable<IIndexer> providers, Logger logger)
|
||||||
|
: base(providerRepository, providers, logger)
|
||||||
|
{
|
||||||
|
_providerRepository = providerRepository;
|
||||||
|
_providers = providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InitializeProviders()
|
||||||
|
{
|
||||||
|
var definitions = _providers.Where(c => c.Protocol == DownloadProtocol.Usenet)
|
||||||
|
.SelectMany(indexer => indexer.DefaultDefinitions);
|
||||||
|
|
||||||
|
var currentProviders = All();
|
||||||
|
|
||||||
|
var newProviders = definitions.Where(def => currentProviders.All(c => c.Implementation != def.Implementation)).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
if (newProviders.Any())
|
||||||
|
{
|
||||||
|
_providerRepository.InsertMany(newProviders.Cast<IndexerDefinition>().ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,11 +33,11 @@ namespace NzbDrone.Core.Indexers
|
||||||
|
|
||||||
public virtual IList<ReleaseInfo> FetchRss(IIndexer indexer)
|
public virtual IList<ReleaseInfo> FetchRss(IIndexer indexer)
|
||||||
{
|
{
|
||||||
_logger.Debug("Fetching feeds from " + indexer.Name);
|
_logger.Debug("Fetching feeds from " + indexer);
|
||||||
|
|
||||||
var result = Fetch(indexer, indexer.RecentFeed);
|
var result = Fetch(indexer, indexer.RecentFeed);
|
||||||
|
|
||||||
_logger.Debug("Finished processing feeds from " + indexer.Name);
|
_logger.Debug("Finished processing feeds from " + indexer);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
|
|
||||||
var result = Fetch(indexer, searchCriteria, 0).DistinctBy(c => c.DownloadUrl).ToList();
|
var result = Fetch(indexer, searchCriteria, 0).DistinctBy(c => c.DownloadUrl).ToList();
|
||||||
|
|
||||||
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer.Name, searchCriteria, result.Count);
|
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
var result = Fetch(indexer, searchUrls);
|
var result = Fetch(indexer, searchUrls);
|
||||||
|
|
||||||
|
|
||||||
_logger.Info("{0} offset {1}. Found {2}", indexer.Name, searchCriteria, result.Count);
|
_logger.Info("{0} offset {1}. Found {2}", indexer, searchCriteria, result.Count);
|
||||||
|
|
||||||
if (result.Count > 90)
|
if (result.Count > 90)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
var result = Fetch(indexer, searchUrls);
|
var result = Fetch(indexer, searchUrls);
|
||||||
|
|
||||||
|
|
||||||
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer.Name, searchCriteria, result.Count);
|
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Series.TvRageId, searchCriteria.Airtime);
|
var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Series.TvRageId, searchCriteria.Airtime);
|
||||||
var result = Fetch(indexer, searchUrls);
|
var result = Fetch(indexer, searchUrls);
|
||||||
|
|
||||||
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer.Name, searchCriteria, result.Count);
|
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,17 +119,16 @@ namespace NzbDrone.Core.Indexers
|
||||||
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
|
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
|
||||||
webException.Message.Contains("timed out"))
|
webException.Message.Contains("timed out"))
|
||||||
{
|
{
|
||||||
_logger.Warn("{0} server is currently unavailable. {1} {2}", indexer.Name, url,
|
_logger.Warn("{0} server is currently unavailable. {1} {2}", indexer, url, webException.Message);
|
||||||
webException.Message);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Warn("{0} {1} {2}", indexer.Name, url, webException.Message);
|
_logger.Warn("{0} {1} {2}", indexer, url, webException.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ApiKeyException)
|
catch (ApiKeyException)
|
||||||
{
|
{
|
||||||
_logger.Warn("Invalid API Key for {0} {1}", indexer.Name, url);
|
_logger.Warn("Invalid API Key for {0} {1}", indexer, url);
|
||||||
}
|
}
|
||||||
catch (Exception feedEx)
|
catch (Exception feedEx)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +137,7 @@ namespace NzbDrone.Core.Indexers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.ForEach(c => c.Indexer = indexer.Name);
|
result.ForEach(c => c.Indexer = indexer.Definition.Name);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,20 @@
|
||||||
using System;
|
using NzbDrone.Core.Datastore;
|
||||||
using System.Linq;
|
|
||||||
using NzbDrone.Core.Datastore;
|
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public interface IIndexerRepository : IBasicRepository<IndexerDefinition>
|
public interface IIndexerRepository : IProviderRepository<IndexerDefinition>
|
||||||
{
|
{
|
||||||
IndexerDefinition Get(string name);
|
|
||||||
IndexerDefinition Find(string name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IndexerRepository : BasicRepository<IndexerDefinition>, IIndexerRepository
|
public class IndexerRepository : ProviderRepository<IndexerDefinition>, IIndexerRepository
|
||||||
{
|
{
|
||||||
public IndexerRepository(IDatabase database, IEventAggregator eventAggregator)
|
public IndexerRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||||
: base(database, eventAggregator)
|
: base(database, eventAggregator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexerDefinition Get(string name)
|
|
||||||
{
|
|
||||||
return Query.Single(i => i.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IndexerDefinition Find(string name)
|
|
||||||
{
|
|
||||||
return Query.SingleOrDefault(i => i.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Indexers.Newznab;
|
|
||||||
using NzbDrone.Core.Lifecycle;
|
|
||||||
using NzbDrone.Core.Messaging.Events;
|
|
||||||
using Omu.ValueInjecter;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
|
||||||
{
|
|
||||||
public class Indexer
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public bool Enable { get; set; }
|
|
||||||
public IIndexerSetting Settings { get; set; }
|
|
||||||
public IIndexer Instance { get; set; }
|
|
||||||
public string Implementation { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IIndexerService
|
|
||||||
{
|
|
||||||
List<Indexer> All();
|
|
||||||
List<IIndexer> GetAvailableIndexers();
|
|
||||||
Indexer Get(int id);
|
|
||||||
Indexer Get(string name);
|
|
||||||
List<Indexer> Schema();
|
|
||||||
Indexer Create(Indexer indexer);
|
|
||||||
Indexer Update(Indexer indexer);
|
|
||||||
void Delete(int id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IndexerService : IIndexerService, IHandle<ApplicationStartedEvent>
|
|
||||||
{
|
|
||||||
private readonly IIndexerRepository _indexerRepository;
|
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
|
||||||
private readonly INewznabTestService _newznabTestService;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
private readonly List<IIndexer> _indexers;
|
|
||||||
|
|
||||||
public IndexerService(IIndexerRepository indexerRepository,
|
|
||||||
IEnumerable<IIndexer> indexers,
|
|
||||||
IConfigFileProvider configFileProvider,
|
|
||||||
INewznabTestService newznabTestService,
|
|
||||||
Logger logger)
|
|
||||||
{
|
|
||||||
_indexerRepository = indexerRepository;
|
|
||||||
_configFileProvider = configFileProvider;
|
|
||||||
_newznabTestService = newznabTestService;
|
|
||||||
_logger = logger;
|
|
||||||
|
|
||||||
|
|
||||||
if (!configFileProvider.Torrent)
|
|
||||||
{
|
|
||||||
_indexers = indexers.Where(c => c.Kind != IndexerKind.Torrent).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_indexers = indexers.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Indexer> All()
|
|
||||||
{
|
|
||||||
return _indexerRepository.All().Select(ToIndexer).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<IIndexer> GetAvailableIndexers()
|
|
||||||
{
|
|
||||||
return All().Where(c => c.Enable && c.Settings.Validate().IsValid).Select(c => c.Instance).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Indexer Get(int id)
|
|
||||||
{
|
|
||||||
return ToIndexer(_indexerRepository.Get(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Indexer Get(string name)
|
|
||||||
{
|
|
||||||
return ToIndexer(_indexerRepository.Get(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Indexer> Schema()
|
|
||||||
{
|
|
||||||
var indexers = new List<Indexer>();
|
|
||||||
|
|
||||||
var newznab = new Indexer();
|
|
||||||
newznab.Instance = new Newznab.Newznab();
|
|
||||||
newznab.Id = 1;
|
|
||||||
newznab.Name = "Newznab";
|
|
||||||
newznab.Settings = new NewznabSettings();
|
|
||||||
newznab.Implementation = "Newznab";
|
|
||||||
|
|
||||||
indexers.Add(newznab);
|
|
||||||
|
|
||||||
return indexers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Indexer Create(Indexer indexer)
|
|
||||||
{
|
|
||||||
var definition = new IndexerDefinition
|
|
||||||
{
|
|
||||||
Name = indexer.Name,
|
|
||||||
Enable = indexer.Enable,
|
|
||||||
Implementation = indexer.Implementation,
|
|
||||||
Settings = indexer.Settings.ToJson()
|
|
||||||
};
|
|
||||||
|
|
||||||
var instance = ToIndexer(definition).Instance;
|
|
||||||
_newznabTestService.Test(instance);
|
|
||||||
|
|
||||||
definition = _indexerRepository.Insert(definition);
|
|
||||||
indexer.Id = definition.Id;
|
|
||||||
|
|
||||||
return indexer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Indexer Update(Indexer indexer)
|
|
||||||
{
|
|
||||||
var definition = _indexerRepository.Get(indexer.Id);
|
|
||||||
definition.InjectFrom(indexer);
|
|
||||||
definition.Settings = indexer.Settings.ToJson();
|
|
||||||
_indexerRepository.Update(definition);
|
|
||||||
|
|
||||||
return indexer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(int id)
|
|
||||||
{
|
|
||||||
_indexerRepository.Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Indexer ToIndexer(IndexerDefinition definition)
|
|
||||||
{
|
|
||||||
var indexer = new Indexer();
|
|
||||||
indexer.Id = definition.Id;
|
|
||||||
indexer.Enable = definition.Enable;
|
|
||||||
indexer.Instance = GetInstance(definition);
|
|
||||||
indexer.Name = definition.Name;
|
|
||||||
indexer.Implementation = definition.Implementation;
|
|
||||||
|
|
||||||
if (indexer.Instance.GetType().GetMethod("ImportSettingsFromJson") != null)
|
|
||||||
{
|
|
||||||
indexer.Settings = ((dynamic)indexer.Instance).ImportSettingsFromJson(definition.Settings);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
indexer.Settings = NullSetting.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IIndexer GetInstance(IndexerDefinition indexerDefinition)
|
|
||||||
{
|
|
||||||
var type = GetImplementation(indexerDefinition);
|
|
||||||
var instance = (IIndexer)Activator.CreateInstance(type);
|
|
||||||
instance.InstanceDefinition = indexerDefinition;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Type GetImplementation(IndexerDefinition indexerDefinition)
|
|
||||||
{
|
|
||||||
return _indexers.Select(c => c.GetType()).SingleOrDefault(c => c.Name.Equals(indexerDefinition.Implementation, StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Handle(ApplicationStartedEvent message)
|
|
||||||
{
|
|
||||||
_logger.Debug("Initializing indexers. Count {0}", _indexers.Count);
|
|
||||||
|
|
||||||
RemoveMissingImplementations();
|
|
||||||
|
|
||||||
var definitions = _indexers.SelectMany(indexer => indexer.DefaultDefinitions);
|
|
||||||
|
|
||||||
var currentIndexer = All();
|
|
||||||
|
|
||||||
var newIndexers = definitions.Where(def => currentIndexer.All(c => c.Implementation != def.Implementation)).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
if (newIndexers.Any())
|
|
||||||
{
|
|
||||||
_indexerRepository.InsertMany(newIndexers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveMissingImplementations()
|
|
||||||
{
|
|
||||||
var storedIndexers = _indexerRepository.All();
|
|
||||||
|
|
||||||
foreach (var indexerDefinition in storedIndexers.Where(i => GetImplementation(i) == null))
|
|
||||||
{
|
|
||||||
_logger.Debug("Removing Indexer {0} ", indexerDefinition.Name);
|
|
||||||
_indexerRepository.Delete(indexerDefinition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
|
||||||
{
|
|
||||||
public interface IProviderIndexerSetting
|
|
||||||
{
|
|
||||||
TSetting Get<TSetting>(IIndexer indexer) where TSetting : IIndexerSetting, new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IndexerSettingProvider : IProviderIndexerSetting
|
|
||||||
{
|
|
||||||
private readonly IIndexerRepository _indexerRepository;
|
|
||||||
|
|
||||||
public IndexerSettingProvider(IIndexerRepository indexerRepository)
|
|
||||||
{
|
|
||||||
_indexerRepository = indexerRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TSetting Get<TSetting>(IIndexer indexer) where TSetting : IIndexerSetting, new()
|
|
||||||
{
|
|
||||||
var indexerDef = _indexerRepository.Find(indexer.Name);
|
|
||||||
|
|
||||||
if (indexerDef == null || string.IsNullOrWhiteSpace(indexerDef.Settings))
|
|
||||||
{
|
|
||||||
return new TSetting();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json.Deserialize<TSetting>(indexerDef.Settings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,14 @@
|
||||||
using NzbDrone.Common.Messaging;
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public class IndexerSettingUpdatedEvent : IEvent
|
public class IndexerSettingUpdatedEvent : IEvent
|
||||||
{
|
{
|
||||||
public string IndexerName { get; private set; }
|
public string IndexerName { get; private set; }
|
||||||
public IIndexerSetting IndexerSetting { get; private set; }
|
public IProviderConfig IndexerSetting { get; private set; }
|
||||||
|
|
||||||
public IndexerSettingUpdatedEvent(string indexerName, IIndexerSetting indexerSetting)
|
public IndexerSettingUpdatedEvent(string indexerName, IProviderConfig indexerSetting)
|
||||||
{
|
{
|
||||||
IndexerName = indexerName;
|
IndexerName = indexerName;
|
||||||
IndexerSetting = indexerSetting;
|
IndexerSetting = indexerSetting;
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
|
||||||
{
|
|
||||||
public abstract class IndexerWithSetting<TSetting> : IndexerBase where TSetting : class, IIndexerSetting, new()
|
|
||||||
{
|
|
||||||
public TSetting Settings { get; set; }
|
|
||||||
|
|
||||||
public override bool EnableByDefault
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TSetting ImportSettingsFromJson(string json)
|
|
||||||
{
|
|
||||||
Settings = Json.Deserialize<TSetting>(json) ?? new TSetting();
|
|
||||||
|
|
||||||
return Settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,10 +2,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Newznab
|
namespace NzbDrone.Core.Indexers.Newznab
|
||||||
{
|
{
|
||||||
public class Newznab : IndexerWithSetting<NewznabSettings>
|
public class Newznab : IndexerBase<NewznabSettings>
|
||||||
{
|
{
|
||||||
public override IParseFeed Parser
|
public override IParseFeed Parser
|
||||||
{
|
{
|
||||||
|
@ -15,7 +16,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<IndexerDefinition> DefaultDefinitions
|
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -51,7 +52,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSettings(string url, List<int> categories)
|
private NewznabSettings GetSettings(string url, List<int> categories)
|
||||||
{
|
{
|
||||||
var settings = new NewznabSettings { Url = url };
|
var settings = new NewznabSettings { Url = url };
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
settings.Categories = categories;
|
settings.Categories = categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings.ToJson();
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<string> RecentFeed
|
public override IEnumerable<string> RecentFeed
|
||||||
|
@ -68,7 +69,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
//Todo: We should be able to update settings on start
|
//Todo: We should be able to update settings on start
|
||||||
if (Name.Equals("nzbs.org", StringComparison.InvariantCultureIgnoreCase))
|
if (Settings.Url.Contains("nzbs.org"))
|
||||||
{
|
{
|
||||||
Settings.Categories = new List<int> { 5000 };
|
Settings.Categories = new List<int> { 5000 };
|
||||||
}
|
}
|
||||||
|
@ -114,19 +115,11 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2}&offset={3}", url, NewsnabifyTitle(seriesTitle), seasonNumber, offset));
|
return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2}&offset={3}", url, NewsnabifyTitle(seriesTitle), seasonNumber, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Name
|
public override DownloadProtocol Protocol
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return InstanceDefinition.Name;
|
return DownloadProtocol.Usenet;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IndexerKind Kind
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return IndexerKind.Usenet;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Newznab
|
namespace NzbDrone.Core.Indexers.Newznab
|
||||||
|
@ -16,7 +17,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class NewznabSettings : IIndexerSetting
|
public class NewznabSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
private static readonly NewznabSettingsValidator Validator = new NewznabSettingsValidator();
|
private static readonly NewznabSettingsValidator Validator = new NewznabSettingsValidator();
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,13 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
||||||
{
|
{
|
||||||
public class Omgwtfnzbs : IndexerWithSetting<OmgwtfnzbsSettings>
|
public class Omgwtfnzbs : IndexerBase<OmgwtfnzbsSettings>
|
||||||
{
|
{
|
||||||
public override string Name
|
public override DownloadProtocol Protocol
|
||||||
{
|
|
||||||
get { return "omgwtfnzbs"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IndexerKind Kind
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return IndexerKind.Usenet;
|
return DownloadProtocol.Usenet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
||||||
{
|
{
|
||||||
|
@ -14,7 +15,7 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OmgwtfnzbsSettings : IIndexerSetting
|
public class OmgwtfnzbsSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
private static readonly OmgwtfnzbsSettingsValidator Validator = new OmgwtfnzbsSettingsValidator();
|
private static readonly OmgwtfnzbsSettingsValidator Validator = new OmgwtfnzbsSettingsValidator();
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Wombles
|
namespace NzbDrone.Core.Indexers.Wombles
|
||||||
{
|
{
|
||||||
public class Wombles : IndexerBase
|
public class Wombles : IndexerBase<NullConfig>
|
||||||
{
|
{
|
||||||
public override string Name
|
public override DownloadProtocol Protocol
|
||||||
{
|
|
||||||
get { return "WomblesIndex"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IndexerKind Kind
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return IndexerKind.Usenet;
|
return DownloadProtocol.Usenet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Email
|
namespace NzbDrone.Core.Notifications.Email
|
||||||
{
|
{
|
||||||
public class EmailSettings : INotifcationSettings
|
public class EmailSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
public EmailSettings()
|
public EmailSettings()
|
||||||
{
|
{
|
||||||
|
@ -38,5 +40,10 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
return !string.IsNullOrWhiteSpace(Server) && Port > 0 && !string.IsNullOrWhiteSpace(From) && !string.IsNullOrWhiteSpace(To);
|
return !string.IsNullOrWhiteSpace(Server) && Port > 0 && !string.IsNullOrWhiteSpace(From) && !string.IsNullOrWhiteSpace(To);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Growl
|
namespace NzbDrone.Core.Notifications.Growl
|
||||||
{
|
{
|
||||||
public class GrowlSettings : INotifcationSettings
|
public class GrowlSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
public GrowlSettings()
|
public GrowlSettings()
|
||||||
{
|
{
|
||||||
|
@ -26,5 +28,10 @@ namespace NzbDrone.Core.Notifications.Growl
|
||||||
return !string.IsNullOrWhiteSpace(Host) && !string.IsNullOrWhiteSpace(Password) && Port > 0;
|
return !string.IsNullOrWhiteSpace(Host) && !string.IsNullOrWhiteSpace(Password) && Port > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace NzbDrone.Core.Notifications
|
|
||||||
{
|
|
||||||
public interface INotifcationSettings
|
|
||||||
{
|
|
||||||
bool IsValid { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace NzbDrone.Core.Notifications
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications
|
||||||
{
|
{
|
||||||
public class Notification
|
public class Notification
|
||||||
{
|
{
|
||||||
|
@ -8,7 +10,7 @@
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
public bool OnGrab { get; set; }
|
public bool OnGrab { get; set; }
|
||||||
public bool OnDownload { get; set; }
|
public bool OnDownload { get; set; }
|
||||||
public INotifcationSettings Settings { get; set; }
|
public IProviderConfig Settings { get; set; }
|
||||||
public INotification Instance { get; set; }
|
public INotification Instance { get; set; }
|
||||||
public string Implementation { get; set; }
|
public string Implementation { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications
|
namespace NzbDrone.Core.Notifications
|
||||||
{
|
{
|
||||||
public abstract class NotificationBase<TSetting> : INotification where TSetting : class, INotifcationSettings, new()
|
public abstract class NotificationBase<TSetting> : INotification where TSetting : class, IProviderConfig, new()
|
||||||
{
|
{
|
||||||
public abstract string Name { get; }
|
public abstract string Name { get; }
|
||||||
public abstract string ImplementationName { get; }
|
public abstract string ImplementationName { get; }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications
|
namespace NzbDrone.Core.Notifications
|
||||||
{
|
{
|
||||||
|
@ -11,4 +12,11 @@ namespace NzbDrone.Core.Notifications
|
||||||
public String Settings { get; set; }
|
public String Settings { get; set; }
|
||||||
public String Implementation { get; set; }
|
public String Implementation { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class NotificationProviderModel : ProviderDefinition
|
||||||
|
{
|
||||||
|
public Boolean OnGrab { get; set; }
|
||||||
|
public Boolean OnDownload { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using Omu.ValueInjecter;
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
Notification Get(int id);
|
Notification Get(int id);
|
||||||
List<Notification> Schema();
|
List<Notification> Schema();
|
||||||
Notification Create(Notification notification);
|
Notification Create(Notification notification);
|
||||||
Notification Update(Notification notification);
|
void Update(Notification notification);
|
||||||
void Delete(int id);
|
void Delete(int id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
|
|
||||||
var instanceType = newNotification.Instance.GetType();
|
var instanceType = newNotification.Instance.GetType();
|
||||||
var baseGenArgs = instanceType.BaseType.GetGenericArguments();
|
var baseGenArgs = instanceType.BaseType.GetGenericArguments();
|
||||||
newNotification.Settings = (INotifcationSettings)Activator.CreateInstance(baseGenArgs[0]);
|
newNotification.Settings = (IProviderConfig)Activator.CreateInstance(baseGenArgs[0]);
|
||||||
newNotification.Implementation = type.Name;
|
newNotification.Implementation = type.Name;
|
||||||
|
|
||||||
notifications.Add(newNotification);
|
notifications.Add(newNotification);
|
||||||
|
@ -93,15 +94,13 @@ namespace NzbDrone.Core.Notifications
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Notification Update(Notification notification)
|
public void Update(Notification notification)
|
||||||
{
|
{
|
||||||
var definition = _notificationRepository.Get(notification.Id);
|
var definition = _notificationRepository.Get(notification.Id);
|
||||||
definition.InjectFrom(notification);
|
definition.InjectFrom(notification);
|
||||||
definition.Settings = notification.Settings.ToJson();
|
definition.Settings = notification.Settings.ToJson();
|
||||||
|
|
||||||
_notificationRepository.Update(definition);
|
_notificationRepository.Update(definition);
|
||||||
|
|
||||||
return notification;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete(int id)
|
public void Delete(int id)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications
|
namespace NzbDrone.Core.Notifications
|
||||||
{
|
{
|
||||||
public interface INotificationSettingsProvider
|
public interface INotificationSettingsProvider
|
||||||
{
|
{
|
||||||
TSetting Get<TSetting>(INotification indexer) where TSetting : INotifcationSettings, new();
|
TSetting Get<TSetting>(INotification indexer) where TSetting : IProviderConfig, new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NotificationSettingsProvider : INotificationSettingsProvider
|
public class NotificationSettingsProvider : INotificationSettingsProvider
|
||||||
|
@ -16,7 +17,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TSetting Get<TSetting>(INotification indexer) where TSetting : INotifcationSettings, new()
|
public TSetting Get<TSetting>(INotification indexer) where TSetting : IProviderConfig, new()
|
||||||
{
|
{
|
||||||
var indexerDef = _notificationRepository.Find(indexer.Name);
|
var indexerDef = _notificationRepository.Find(indexer.Name);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.NotifyMyAndroid
|
namespace NzbDrone.Core.Notifications.NotifyMyAndroid
|
||||||
{
|
{
|
||||||
public class NotifyMyAndroidSettings : INotifcationSettings
|
public class NotifyMyAndroidSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
[FieldDefinition(0, Label = "API Key", HelpLink = "http://www.notifymyandroid.com/")]
|
[FieldDefinition(0, Label = "API Key", HelpLink = "http://www.notifymyandroid.com/")]
|
||||||
public String ApiKey { get; set; }
|
public String ApiKey { get; set; }
|
||||||
|
@ -18,5 +20,10 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid
|
||||||
return !String.IsNullOrWhiteSpace(ApiKey) && Priority != null & Priority >= -1 && Priority <= 2;
|
return !String.IsNullOrWhiteSpace(ApiKey) && Priority != null & Priority >= -1 && Priority <= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Plex
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
{
|
{
|
||||||
public class PlexClientSettings : INotifcationSettings
|
public class PlexClientSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
public PlexClientSettings()
|
public PlexClientSettings()
|
||||||
{
|
{
|
||||||
|
@ -29,5 +31,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
return !string.IsNullOrWhiteSpace(Host);
|
return !string.IsNullOrWhiteSpace(Host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Plex
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
{
|
{
|
||||||
public class PlexServerSettings : INotifcationSettings
|
public class PlexServerSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
public PlexServerSettings()
|
public PlexServerSettings()
|
||||||
{
|
{
|
||||||
|
@ -26,5 +28,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
return !string.IsNullOrWhiteSpace(Host);
|
return !string.IsNullOrWhiteSpace(Host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Prowl
|
namespace NzbDrone.Core.Notifications.Prowl
|
||||||
{
|
{
|
||||||
public class ProwlSettings : INotifcationSettings
|
public class ProwlSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
[FieldDefinition(0, Label = "API Key", HelpLink = "https://www.prowlapp.com/api_settings.php")]
|
[FieldDefinition(0, Label = "API Key", HelpLink = "https://www.prowlapp.com/api_settings.php")]
|
||||||
public String ApiKey { get; set; }
|
public String ApiKey { get; set; }
|
||||||
|
@ -18,5 +20,10 @@ namespace NzbDrone.Core.Notifications.Prowl
|
||||||
return !string.IsNullOrWhiteSpace(ApiKey) && Priority != null & Priority >= -2 && Priority <= 2;
|
return !string.IsNullOrWhiteSpace(ApiKey) && Priority != null & Priority >= -2 && Priority <= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.PushBullet
|
namespace NzbDrone.Core.Notifications.PushBullet
|
||||||
{
|
{
|
||||||
public class PushBulletSettings : INotifcationSettings
|
public class PushBulletSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
[FieldDefinition(0, Label = "API Key", HelpLink = "https://www.pushbullet.com/")]
|
[FieldDefinition(0, Label = "API Key", HelpLink = "https://www.pushbullet.com/")]
|
||||||
public String ApiKey { get; set; }
|
public String ApiKey { get; set; }
|
||||||
|
@ -18,5 +20,10 @@ namespace NzbDrone.Core.Notifications.PushBullet
|
||||||
return !String.IsNullOrWhiteSpace(ApiKey) && DeviceId > 0;
|
return !String.IsNullOrWhiteSpace(ApiKey) && DeviceId > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Pushover
|
namespace NzbDrone.Core.Notifications.Pushover
|
||||||
{
|
{
|
||||||
public class PushoverSettings : INotifcationSettings
|
public class PushoverSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
[FieldDefinition(0, Label = "User Key", HelpLink = "https://pushover.net/")]
|
[FieldDefinition(0, Label = "User Key", HelpLink = "https://pushover.net/")]
|
||||||
public String UserKey { get; set; }
|
public String UserKey { get; set; }
|
||||||
|
@ -18,5 +20,10 @@ namespace NzbDrone.Core.Notifications.Pushover
|
||||||
return !string.IsNullOrWhiteSpace(UserKey) && Priority != null & Priority >= -1 && Priority <= 2;
|
return !string.IsNullOrWhiteSpace(UserKey) && Priority != null & Priority >= -1 && Priority <= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using FluentValidation.Results;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Xbmc
|
namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
{
|
{
|
||||||
public class XbmcSettings : INotifcationSettings
|
public class XbmcSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
public XbmcSettings()
|
public XbmcSettings()
|
||||||
{
|
{
|
||||||
|
@ -51,5 +53,10 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
return !string.IsNullOrWhiteSpace(Host) && Port > 0;
|
return !string.IsNullOrWhiteSpace(Host) && Port > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValidationResult Validate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,7 @@
|
||||||
<Compile Include="DataAugmentation\Xem\XemService.cs" />
|
<Compile Include="DataAugmentation\Xem\XemService.cs" />
|
||||||
<Compile Include="Datastore\ConnectionStringFactory.cs" />
|
<Compile Include="Datastore\ConnectionStringFactory.cs" />
|
||||||
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
||||||
|
<Compile Include="Datastore\Converters\ProviderSettingConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\QualityIntConverter.cs" />
|
<Compile Include="Datastore\Converters\QualityIntConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\Int32Converter.cs" />
|
<Compile Include="Datastore\Converters\Int32Converter.cs" />
|
||||||
<Compile Include="Datastore\Converters\EmbeddedDocumentConverter.cs" />
|
<Compile Include="Datastore\Converters\EmbeddedDocumentConverter.cs" />
|
||||||
|
@ -172,6 +173,8 @@
|
||||||
<Compile Include="Datastore\Migration\019_restore_unique_constraints.cs" />
|
<Compile Include="Datastore\Migration\019_restore_unique_constraints.cs" />
|
||||||
<Compile Include="Datastore\Migration\020_add_year_and_seasons_to_series.cs" />
|
<Compile Include="Datastore\Migration\020_add_year_and_seasons_to_series.cs" />
|
||||||
<Compile Include="Datastore\Migration\021_drop_seasons_table.cs" />
|
<Compile Include="Datastore\Migration\021_drop_seasons_table.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\022_move_notification_to_generic_provider.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\023_add_config_contract_to_indexers.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
||||||
|
@ -241,12 +244,10 @@
|
||||||
<Compile Include="Indexers\IIndexer.cs" />
|
<Compile Include="Indexers\IIndexer.cs" />
|
||||||
<Compile Include="Indexers\IndexerSettingUpdatedEvent.cs" />
|
<Compile Include="Indexers\IndexerSettingUpdatedEvent.cs" />
|
||||||
<Compile Include="Indexers\NewznabTestService.cs" />
|
<Compile Include="Indexers\NewznabTestService.cs" />
|
||||||
<Compile Include="Indexers\IndexerWithSetting.cs" />
|
|
||||||
<Compile Include="Indexers\IParseFeed.cs" />
|
<Compile Include="Indexers\IParseFeed.cs" />
|
||||||
<Compile Include="Indexers\Newznab\NewznabException.cs" />
|
<Compile Include="Indexers\Newznab\NewznabException.cs" />
|
||||||
<Compile Include="Indexers\Newznab\NewznabPreProcessor.cs" />
|
<Compile Include="Indexers\Newznab\NewznabPreProcessor.cs" />
|
||||||
<Compile Include="Indexers\Newznab\SizeParsingException.cs" />
|
<Compile Include="Indexers\Newznab\SizeParsingException.cs" />
|
||||||
<Compile Include="Indexers\NullSetting.cs" />
|
|
||||||
<Compile Include="Indexers\RssSyncCommand.cs" />
|
<Compile Include="Indexers\RssSyncCommand.cs" />
|
||||||
<Compile Include="Indexers\XElementExtensions.cs" />
|
<Compile Include="Indexers\XElementExtensions.cs" />
|
||||||
<Compile Include="Instrumentation\Commands\ClearLogCommand.cs" />
|
<Compile Include="Instrumentation\Commands\ClearLogCommand.cs" />
|
||||||
|
@ -343,13 +344,11 @@
|
||||||
<Compile Include="Indexers\IndexerBase.cs" />
|
<Compile Include="Indexers\IndexerBase.cs" />
|
||||||
<Compile Include="Indexers\IndexerDefinition.cs" />
|
<Compile Include="Indexers\IndexerDefinition.cs" />
|
||||||
<Compile Include="Indexers\IndexerRepository.cs" />
|
<Compile Include="Indexers\IndexerRepository.cs" />
|
||||||
<Compile Include="Indexers\IndexerSettingProvider.cs" />
|
|
||||||
<Compile Include="Indexers\Newznab\Newznab.cs" />
|
<Compile Include="Indexers\Newznab\Newznab.cs" />
|
||||||
<Compile Include="Indexers\Newznab\NewznabSettings.cs" />
|
<Compile Include="Indexers\Newznab\NewznabSettings.cs" />
|
||||||
<Compile Include="Indexers\Newznab\NewznabParser.cs" />
|
<Compile Include="Indexers\Newznab\NewznabParser.cs" />
|
||||||
<Compile Include="Indexers\Omgwtfnzbs\Omgwtfnzbs.cs" />
|
<Compile Include="Indexers\Omgwtfnzbs\Omgwtfnzbs.cs" />
|
||||||
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsParser.cs" />
|
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsParser.cs" />
|
||||||
<Compile Include="Indexers\IIndexerSetting.cs" />
|
|
||||||
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsSettings.cs" />
|
<Compile Include="Indexers\Omgwtfnzbs\OmgwtfnzbsSettings.cs" />
|
||||||
<Compile Include="Indexers\Wombles\Wombles.cs" />
|
<Compile Include="Indexers\Wombles\Wombles.cs" />
|
||||||
<Compile Include="Indexers\Wombles\WomblesParser.cs" />
|
<Compile Include="Indexers\Wombles\WomblesParser.cs" />
|
||||||
|
@ -371,7 +370,6 @@
|
||||||
<Compile Include="MetadataSource\Trakt\Images.cs" />
|
<Compile Include="MetadataSource\Trakt\Images.cs" />
|
||||||
<Compile Include="MetadataSource\Trakt\Season.cs" />
|
<Compile Include="MetadataSource\Trakt\Season.cs" />
|
||||||
<Compile Include="MetadataSource\Trakt\FullShow.cs" />
|
<Compile Include="MetadataSource\Trakt\FullShow.cs" />
|
||||||
<Compile Include="Notifications\INotifcationSettings.cs" />
|
|
||||||
<Compile Include="Notifications\Plex\TestPlexServerCommand.cs" />
|
<Compile Include="Notifications\Plex\TestPlexServerCommand.cs" />
|
||||||
<Compile Include="Notifications\Plex\PlexServer.cs" />
|
<Compile Include="Notifications\Plex\PlexServer.cs" />
|
||||||
<Compile Include="Notifications\Plex\PlexClientSettings.cs" />
|
<Compile Include="Notifications\Plex\PlexClientSettings.cs" />
|
||||||
|
@ -417,6 +415,8 @@
|
||||||
<Compile Include="Parser\Parser.cs" />
|
<Compile Include="Parser\Parser.cs" />
|
||||||
<Compile Include="Parser\ParsingService.cs" />
|
<Compile Include="Parser\ParsingService.cs" />
|
||||||
<Compile Include="Parser\QualityParser.cs" />
|
<Compile Include="Parser\QualityParser.cs" />
|
||||||
|
<Compile Include="ThingiProvider\ConfigContractNotFoundException.cs" />
|
||||||
|
<Compile Include="ThingiProvider\IProvider.cs" />
|
||||||
<Compile Include="Qualities\QualityProfileInUseException.cs" />
|
<Compile Include="Qualities\QualityProfileInUseException.cs" />
|
||||||
<Compile Include="Qualities\QualitySizeRepository.cs" />
|
<Compile Include="Qualities\QualitySizeRepository.cs" />
|
||||||
<Compile Include="Qualities\QualityProfileRepository.cs" />
|
<Compile Include="Qualities\QualityProfileRepository.cs" />
|
||||||
|
@ -427,6 +427,13 @@
|
||||||
<Compile Include="Rest\RestSharpExtensions.cs" />
|
<Compile Include="Rest\RestSharpExtensions.cs" />
|
||||||
<Compile Include="Rest\RestException.cs" />
|
<Compile Include="Rest\RestException.cs" />
|
||||||
<Compile Include="SeriesStats\SeriesStatisticsService.cs" />
|
<Compile Include="SeriesStats\SeriesStatisticsService.cs" />
|
||||||
|
<Compile Include="ThingiProvider\IProviderConfig.cs" />
|
||||||
|
<Compile Include="ThingiProvider\IProviderFactory.cs" />
|
||||||
|
<Compile Include="ThingiProvider\IProviderRepository.cs" />
|
||||||
|
<Compile Include="ThingiProvider\NullConfig.cs" />
|
||||||
|
<Compile Include="ThingiProvider\ProviderDefinition.cs" />
|
||||||
|
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
||||||
|
<Compile Include="ThingiProvider\ProviderFactory.cs" />
|
||||||
<Compile Include="Tv\EpisodeService.cs" />
|
<Compile Include="Tv\EpisodeService.cs" />
|
||||||
<Compile Include="Tv\Events\EpisodeInfoDeletedEvent.cs" />
|
<Compile Include="Tv\Events\EpisodeInfoDeletedEvent.cs" />
|
||||||
<Compile Include="Tv\Events\EpisodeInfoUpdatedEvent.cs" />
|
<Compile Include="Tv\Events\EpisodeInfoUpdatedEvent.cs" />
|
||||||
|
@ -505,7 +512,7 @@
|
||||||
<Compile Include="History\HistoryService.cs">
|
<Compile Include="History\HistoryService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Indexers\IndexerService.cs">
|
<Compile Include="Indexers\IndexerFactory.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Indexers\IndexerFetchService.cs">
|
<Compile Include="Indexers\IndexerFetchService.cs">
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
|
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
|
||||||
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
|
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
|
||||||
<DefaultTestTimeout>5000</DefaultTestTimeout>
|
<DefaultTestTimeout>5000</DefaultTestTimeout>
|
||||||
<UseBuildConfiguration>Debug</UseBuildConfiguration>
|
<UseBuildConfiguration>RELEASE</UseBuildConfiguration>
|
||||||
<UseBuildPlatform>x86</UseBuildPlatform>
|
<UseBuildPlatform>x86</UseBuildPlatform>
|
||||||
<ProxyProcessPath></ProxyProcessPath>
|
<ProxyProcessPath></ProxyProcessPath>
|
||||||
<UseCPUArchitecture>x86</UseCPUArchitecture>
|
<UseCPUArchitecture>x86</UseCPUArchitecture>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public class ConfigContractNotFoundException : NzbDroneException
|
||||||
|
{
|
||||||
|
public ConfigContractNotFoundException(string contract)
|
||||||
|
: base("Couldn't find config contract " + contract)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public interface IProvider
|
||||||
|
{
|
||||||
|
Type ConfigContract { get; }
|
||||||
|
|
||||||
|
IEnumerable<ProviderDefinition> DefaultDefinitions { get; }
|
||||||
|
ProviderDefinition Definition { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
{
|
{
|
||||||
public interface IIndexerSetting
|
public interface IProviderConfig
|
||||||
{
|
{
|
||||||
ValidationResult Validate();
|
ValidationResult Validate();
|
||||||
}
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public interface IProviderFactory<TProvider, TProviderDefinition>
|
||||||
|
where TProviderDefinition : ProviderDefinition, new()
|
||||||
|
where TProvider : IProvider
|
||||||
|
{
|
||||||
|
List<TProviderDefinition> All();
|
||||||
|
List<TProvider> GetAvailableProviders();
|
||||||
|
TProviderDefinition Get(int id);
|
||||||
|
TProviderDefinition Create(TProviderDefinition indexer);
|
||||||
|
void Update(TProviderDefinition indexer);
|
||||||
|
void Delete(int id);
|
||||||
|
List<TProviderDefinition> Templates();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public interface IProviderRepository<TProvider> : IBasicRepository<TProvider> where TProvider : ModelBase, new()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
{
|
{
|
||||||
public class NullSetting : IIndexerSetting
|
public class NullConfig : IProviderConfig
|
||||||
{
|
{
|
||||||
public static readonly NullSetting Instance = new NullSetting();
|
public static readonly NullConfig Instance = new NullConfig();
|
||||||
|
|
||||||
public ValidationResult Validate()
|
public ValidationResult Validate()
|
||||||
{
|
{
|
|
@ -0,0 +1,30 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public abstract class ProviderDefinition : ModelBase
|
||||||
|
{
|
||||||
|
private IProviderConfig _settings;
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Implementation { get; set; }
|
||||||
|
public bool Enable { get; set; }
|
||||||
|
|
||||||
|
public string ConfigContract { get; set; }
|
||||||
|
|
||||||
|
public IProviderConfig Settings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _settings;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_settings = value;
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
ConfigContract = value.GetType().Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Lifecycle;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public abstract class ProviderFactory<TProvider, TProviderDefinition> : IProviderFactory<TProvider, TProviderDefinition>, IHandle<ApplicationStartedEvent>
|
||||||
|
where TProviderDefinition : ProviderDefinition, new()
|
||||||
|
where TProvider : IProvider
|
||||||
|
{
|
||||||
|
private readonly IProviderRepository<TProviderDefinition> _providerRepository;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
private readonly List<TProvider> _providers;
|
||||||
|
|
||||||
|
protected ProviderFactory(IProviderRepository<TProviderDefinition> providerRepository, IEnumerable<TProvider> providers, Logger logger)
|
||||||
|
{
|
||||||
|
_providerRepository = providerRepository;
|
||||||
|
_providers = providers.ToList();
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TProviderDefinition> All()
|
||||||
|
{
|
||||||
|
return _providerRepository.All().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TProviderDefinition> Templates()
|
||||||
|
{
|
||||||
|
return _providers.Select(p => new TProviderDefinition()
|
||||||
|
{
|
||||||
|
ConfigContract = p.ConfigContract.Name,
|
||||||
|
Implementation = p.GetType().Name,
|
||||||
|
Settings = (IProviderConfig)Activator.CreateInstance(p.ConfigContract)
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TProvider> GetAvailableProviders()
|
||||||
|
{
|
||||||
|
return All().Where(c => c.Enable && c.Settings.Validate().IsValid)
|
||||||
|
.Select(GetInstance).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TProviderDefinition Get(int id)
|
||||||
|
{
|
||||||
|
return _providerRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TProviderDefinition Create(TProviderDefinition provider)
|
||||||
|
{
|
||||||
|
return _providerRepository.Insert(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(TProviderDefinition definition)
|
||||||
|
{
|
||||||
|
_providerRepository.Update(definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
_providerRepository.Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TProvider GetInstance(TProviderDefinition definition)
|
||||||
|
{
|
||||||
|
var type = GetImplementation(definition);
|
||||||
|
var instance = (TProvider)Activator.CreateInstance(type);
|
||||||
|
instance.Definition = definition;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type GetImplementation(TProviderDefinition definition)
|
||||||
|
{
|
||||||
|
return _providers.Select(c => c.GetType()).SingleOrDefault(c => c.Name.Equals(definition.Implementation, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(ApplicationStartedEvent message)
|
||||||
|
{
|
||||||
|
_logger.Debug("Initializing Providers. Count {0}", _providers.Count);
|
||||||
|
|
||||||
|
RemoveMissingImplementations();
|
||||||
|
|
||||||
|
InitializeProviders();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void InitializeProviders()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveMissingImplementations()
|
||||||
|
{
|
||||||
|
var storedProvider = _providerRepository.All();
|
||||||
|
|
||||||
|
foreach (var invalidDefinition in storedProvider.Where(def => GetImplementation(def) == null))
|
||||||
|
{
|
||||||
|
_logger.Debug("Removing {0} ", invalidDefinition.Name);
|
||||||
|
_providerRepository.Delete(invalidDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ThingiProvider
|
||||||
|
{
|
||||||
|
public class ProviderRepository<TProviderDefinition> : BasicRepository<TProviderDefinition>, IProviderRepository<TProviderDefinition>
|
||||||
|
where TProviderDefinition : ModelBase,
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
protected ProviderRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using FluentAssertions;
|
using System.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Integration.Test
|
namespace NzbDrone.Integration.Test
|
||||||
{
|
{
|
||||||
|
@ -13,6 +15,7 @@ namespace NzbDrone.Integration.Test
|
||||||
|
|
||||||
indexers.Should().NotBeEmpty();
|
indexers.Should().NotBeEmpty();
|
||||||
indexers.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name));
|
indexers.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name));
|
||||||
|
indexers.Where(c => c.ConfigContract == typeof(NullConfig).Name).Should().OnlyContain(c => c.Enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using FluentAssertions;
|
using System.Threading;
|
||||||
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Api.Indexers;
|
using NzbDrone.Api.Indexers;
|
||||||
|
|
||||||
|
@ -10,10 +11,13 @@ namespace NzbDrone.Integration.Test
|
||||||
[Test]
|
[Test]
|
||||||
public void should_only_have_unknown_series_releases()
|
public void should_only_have_unknown_series_releases()
|
||||||
{
|
{
|
||||||
|
|
||||||
var releases = Releases.All();
|
var releases = Releases.All();
|
||||||
|
var indexers = Indexers.All();
|
||||||
|
|
||||||
|
|
||||||
releases.Should().OnlyContain(c => c.Rejections.Contains("Unknown Series"));
|
releases.Should().OnlyContain(c => c.Rejections.Contains("Unknown Series"));
|
||||||
releases.Should().OnlyContain(c=>BeValidRelease(c));
|
releases.Should().OnlyContain(c => BeValidRelease(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio>
|
<FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio>
|
||||||
<FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec>
|
<FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec>
|
||||||
<FrameworkUtilisationTypeForMSTest>Disabled</FrameworkUtilisationTypeForMSTest>
|
<FrameworkUtilisationTypeForMSTest>Disabled</FrameworkUtilisationTypeForMSTest>
|
||||||
<EngineModes>Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk;Fast:DlN0cnVjdHVyYWxOb2RlBAAAABNEb2VzTm90SGF2ZUNhdGVnb3J5D0ludGVncmF0aW9uVGVzdBNEb2VzTm90SGF2ZUNhdGVnb3J5BkRiVGVzdApJc0ltcGFjdGVkE0RvZXNOb3RIYXZlQ2F0ZWdvcnkORGlza0FjY2Vzc1Rlc3QAAAAAAAAAAAAAAAA=</EngineModes>
|
<EngineModes>Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk;Fast:DlN0cnVjdHVyYWxOb2RlBQAAABNEb2VzTm90SGF2ZUNhdGVnb3J5D0ludGVncmF0aW9uVGVzdBNEb2VzTm90SGF2ZUNhdGVnb3J5BkRiVGVzdApJc0ltcGFjdGVkE0RvZXNOb3RIYXZlQ2F0ZWdvcnkORGlza0FjY2Vzc1Rlc3QISXNQaW5uZWQAAAAAAAAAAAAAAAABAAAA</EngineModes>
|
||||||
<MetricsExclusionList>
|
<MetricsExclusionList>
|
||||||
</MetricsExclusionList>
|
</MetricsExclusionList>
|
||||||
</SolutionConfiguration>
|
</SolutionConfiguration>
|
Loading…
Reference in New Issue