Implementing Anime Tosho - introducing feed based indexers

This commit is contained in:
chibidev 2017-07-20 23:55:42 +02:00
parent 1ba1b91b8e
commit 929c12ccc6
6 changed files with 161 additions and 0 deletions

View File

@ -20,6 +20,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
### Supported Public Trackers
* Anidex
* Anime Tosho
* cpasbien
* EZTV
* Horrible Subs

View File

@ -0,0 +1,33 @@
using System;
using System.Text;
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Jackett.Services;
using Jackett.Utils.Clients;
using NLog;
namespace Jackett.Indexers.Newznab
{
public class AnimeTosho : BaseNewznabIndexer
{
public AnimeTosho(IIndexerConfigurationService configService, IWebClient client, Logger logger, IProtectionService p) : base("Anime Tosho", "https://animetosho.org/", "", configService, client, logger, new ConfigurationData(), p)
{
// TODO
// this might be downloaded and refreshed instead of hard-coding it
TorznabCaps = new TorznabCapabilities
{
SearchAvailable = true,
TVSearchAvailable = false,
MovieSearchAvailable = false,
SupportsImdbSearch = false,
SupportsTVRageSearch = false
};
Encoding = Encoding.UTF8;
Language = "en-en";
Type = "public";
}
protected override Uri FeedUri => new Uri("https://animetosho.org/feed/api");
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
using Newtonsoft.Json.Linq;
using NLog;
namespace Jackett.Indexers
{
public abstract class BaseFeedIndexer : BaseWebIndexer
{
protected abstract Uri FeedUri { get; }
protected BaseFeedIndexer(string name, string link, string description, IIndexerConfigurationService configService, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null, string downloadBase = null) : base(name, link, description, configService, client, logger, configData, p, caps, downloadBase)
{
}
public override Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
IsConfigured = true;
return Task.FromResult(IndexerConfigurationStatus.RequiresTesting);
}
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var requestUri = FeedUri.ToString();
if (!query.SanitizedSearchTerm.IsNullOrEmptyOrWhitespace())
requestUri = requestUri + "?q=" + query.SanitizedSearchTerm;
var request = new WebRequest
{
Url = requestUri,
Type = RequestType.GET
};
var result = await webclient.GetString(request);
var results = ParseFeedForResults(result.Content);
return results;
}
protected abstract IEnumerable<ReleaseInfo> ParseFeedForResults(string feedContent);
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
using NLog;
namespace Jackett.Indexers
{
public abstract class BaseNewznabIndexer : BaseFeedIndexer
{
protected BaseNewznabIndexer(string name, string link, string description, IIndexerConfigurationService configService, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null, string downloadBase = null) : base(name, link, description, configService, client, logger, configData, p, caps, downloadBase)
{
}
protected override IEnumerable<ReleaseInfo> ParseFeedForResults(string feedContent)
{
var doc = XDocument.Parse(feedContent);
var results = doc.Descendants("item").Select((XElement item) =>
{
var attributes = item.Descendants().Where(e => e.Name.LocalName == "attr");
var release = new ReleaseInfo
{
Title = item.FirstValue("title"),
Guid = item.FirstValue("guid").ToUri(),
Link = item.FirstValue("link").ToUri(),
Comments = item.FirstValue("comments").ToUri(),
PublishDate = item.FirstValue("pubDate").ToDateTime(),
Category = new List<int> { Int32.Parse(attributes.First(e => e.Attribute("name").Value == "category").Attribute("value").Value) },
Size = Int64.Parse(attributes.First(e => e.Attribute("name").Value == "size").Attribute("value").Value),
Files = Int64.Parse(attributes.First(e => e.Attribute("name").Value == "files").Attribute("value").Value),
Description = item.FirstValue("description"),
Seeders = Int32.Parse(attributes.First(e => e.Attribute("name").Value == "seeders").Attribute("value").Value),
Peers = Int32.Parse(attributes.First(e => e.Attribute("name").Value == "peers").Attribute("value").Value),
InfoHash = attributes.First(e => e.Attribute("name").Value == "infohash").Attribute("value").Value,
MagnetUri = attributes.First(e => e.Attribute("name").Value == "magneturl").Attribute("value").Value.ToUri(),
};
return release;
});
return results;
}
}
}

View File

@ -380,6 +380,9 @@
<Compile Include="Utils\JsonUtil.cs" />
<Compile Include="Services\IndexerConfigurationService.cs" />
<Compile Include="Models\IndexerDefinition.cs" />
<Compile Include="Indexers\Feeds\BaseNewznabIndexer.cs" />
<Compile Include="Indexers\Feeds\AnimeTosho.cs" />
<Compile Include="Indexers\Feeds\BaseFeedIndexer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
@ -564,6 +567,9 @@
</ItemGroup>
<ItemGroup />
<ItemGroup />
<ItemGroup>
<Folder Include="Indexers\Feeds\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Jackett.Utils
{
@ -50,6 +52,16 @@ namespace Jackett.Utils
{
return string.IsNullOrEmpty(str) || string.IsNullOrWhiteSpace(str);
}
public static DateTime ToDateTime(this string str)
{
return DateTime.Parse(str);
}
public static Uri ToUri(this string str)
{
return new Uri(str);
}
}
public static class CollectionExtension
@ -64,4 +76,17 @@ namespace Jackett.Utils
return obj == null || obj.IsEmpty();
}
}
public static class XElementExtension
{
public static XElement First(this XElement element, string name)
{
return element.Descendants(name).First();
}
public static string FirstValue(this XElement element, string name)
{
return element.First(name).Value;
}
}
}