Remove Non-Music Indexers (#42)

Remove Non-Music Indexers
pull/49/head
Qstick 7 years ago committed by GitHub
parent 934bde7858
commit a5ac4ed37a

@ -1,57 +0,0 @@
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.BitMeTv;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using System;
using System.Linq;
using FluentAssertions;
namespace NzbDrone.Core.Test.IndexerTests.BitMeTvTests
{
[TestFixture]
public class BitMeTvFixture : CoreTest<BitMeTv>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "BitMeTV",
Settings = new BitMeTvSettings() { Cookie = "uid=123" }
};
}
[Test]
public void should_parse_recent_feed_from_BitMeTv()
{
var recentFeed = ReadAllText(@"Files/Indexers/BitMeTv/BitMeTv.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.Title.Should().Be("Total.Divas.S02E08.HDTV.x264-CRiMSON");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("http://www.bitmetv.org/download.php/12/Total.Divas.S02E08.HDTV.x264-CRiMSON.torrent");
torrentInfo.InfoUrl.Should().BeNullOrEmpty();
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/05/13 17:04:29"));
torrentInfo.Size.Should().Be(395009065);
torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null);
torrentInfo.Peers.Should().Be(null);
torrentInfo.Seeders.Should().Be(null);
}
}
}

@ -1,159 +0,0 @@
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.BroadcastheNet;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using System;
using System.Linq;
using FluentAssertions;
namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
{
[TestFixture]
public class BroadcastheNetFixture : CoreTest<BroadcastheNet>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "BroadcastheNet",
Settings = new BroadcastheNetSettings() { ApiKey = "abc", BaseUrl = "https://api.broadcasthe.net/" }
};
}
[Test]
public void should_parse_recent_feed_from_BroadcastheNet()
{
var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(2);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.Guid.Should().Be("BTN-123");
torrentInfo.Title.Should().Be("Jimmy.Kimmel.2014.09.15.Jane.Fonda.HDTV.x264-aAF");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("https://broadcasthe.net/torrents.php?action=download&id=123&authkey=123&torrent_pass=123");
torrentInfo.InfoUrl.Should().Be("https://broadcasthe.net/torrents.php?id=237457&torrentid=123");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/09/16 21:15:33"));
torrentInfo.Size.Should().Be(505099926);
torrentInfo.InfoHash.Should().Be("123");
torrentInfo.MagnetUrl.Should().BeNullOrEmpty();
torrentInfo.Peers.Should().Be(40+9);
torrentInfo.Seeders.Should().Be(40);
torrentInfo.Origin.Should().Be("Scene");
torrentInfo.Source.Should().Be("HDTV");
torrentInfo.Container.Should().Be("MP4");
torrentInfo.Codec.Should().Be("x264");
torrentInfo.Resolution.Should().Be("SD");
}
private void VerifyBackOff()
{
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Once());
}
[Test]
public void should_back_off_on_bad_request()
{
Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.BadRequest));
var results = Subject.FetchRecent();
results.Should().BeEmpty();
VerifyBackOff();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_back_off_and_report_api_key_invalid()
{
Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.Unauthorized));
var results = Subject.FetchRecent();
results.Should().BeEmpty();
VerifyBackOff();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_back_off_on_unknown_method()
{
Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.NotFound));
var results = Subject.FetchRecent();
results.Should().BeEmpty();
VerifyBackOff();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_back_off_api_limit_reached()
{
Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.ServiceUnavailable));
var results = Subject.FetchRecent();
results.Should().BeEmpty();
VerifyBackOff();
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_replace_https_http_as_needed()
{
var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json");
(Subject.Definition.Settings as BroadcastheNetSettings).BaseUrl = "http://api.broadcasthe.net/";
recentFeed = recentFeed.Replace("http:", "https:");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(2);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.DownloadUrl.Should().Be("http://broadcasthe.net/torrents.php?action=download&id=123&authkey=123&torrent_pass=123");
torrentInfo.InfoUrl.Should().Be("http://broadcasthe.net/torrents.php?id=237457&torrentid=123");
}
}
}

@ -1,77 +0,0 @@
using System;
using System.Linq;
using System.Text;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.HDBits;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
{
[TestFixture]
public class HDBitsFixture : CoreTest<HDBits>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "HdBits",
Settings = new HDBitsSettings() { ApiKey = "fakekey" }
};
}
[TestCase("Files/Indexers/HdBits/RecentFeedLongIDs.json")]
[TestCase("Files/Indexers/HdBits/RecentFeedStringIDs.json")]
public void should_parse_recent_feed_from_HDBits(string fileName)
{
var responseJson = ReadAllText(fileName);
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.POST)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), responseJson));
var torrents = Subject.FetchRecent();
torrents.Should().HaveCount(2);
torrents.First().Should().BeOfType<TorrentInfo>();
var first = torrents.First() as TorrentInfo;
first.Guid.Should().Be("HDBits-257142");
first.Title.Should().Be("Supernatural S10E17 1080p WEB-DL DD5.1 H.264-ECI");
first.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
first.DownloadUrl.Should().Be("https://hdbits.org/download.php?id=257142&passkey=fakekey");
first.InfoUrl.Should().Be("https://hdbits.org/details.php?id=257142");
first.PublishDate.Should().Be(DateTime.Parse("2015-04-04T20:30:46+0000").ToUniversalTime());
first.Size.Should().Be(1718009717);
first.InfoHash.Should().Be("EABC50AEF9F53CEDED84ADF14144D3368E586F3A");
first.MagnetUrl.Should().BeNullOrEmpty();
first.Peers.Should().Be(47);
first.Seeders.Should().Be(46);
}
[Test]
public void should_warn_on_wrong_passkey()
{
var responseJson = new { status = 5, message = "Invalid authentication credentials" }.ToJson();
Mocker.GetMock<IHttpClient>()
.Setup(v => v.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(),
Encoding.UTF8.GetBytes(responseJson)));
var torrents = Subject.FetchRecent();
torrents.Should().BeEmpty();
ExceptionVerification.ExpectedWarns(1);
}
}
}

@ -250,9 +250,6 @@
<Compile Include="IndexerSearchTests\NzbSearchServiceFixture.cs" />
<Compile Include="IndexerSearchTests\SearchDefinitionFixture.cs" />
<Compile Include="IndexerTests\BasicRssParserFixture.cs" />
<Compile Include="IndexerTests\BitMeTvTests\BitMeTvFixture.cs" />
<Compile Include="IndexerTests\BroadcastheNetTests\BroadcastheNetFixture.cs" />
<Compile Include="IndexerTests\HDBitsTests\HDBitsFixture.cs" />
<Compile Include="IndexerTests\IndexerServiceFixture.cs" />
<Compile Include="IndexerTests\IndexerStatusServiceFixture.cs" />
<Compile Include="IndexerTests\IntegrationTests\IndexerIntegrationTests.cs" />

@ -1,32 +0,0 @@
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NLog;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.BitMeTv
{
public class BitMeTv : HttpIndexerBase<BitMeTvSettings>
{
public override string Name => "BitMeTV";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsSearch => false;
public override int PageSize => 0;
public BitMeTv(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new BitMeTvRequestGenerator() { Settings = Settings };
}
public override IParseIndexerResponse GetParser()
{
return new TorrentRssParser() { ParseSizeInDescription = true };
}
}
}

@ -1,67 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.BitMeTv
{
public class BitMeTvRequestGenerator : IIndexerRequestGenerator
{
public BitMeTvSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRssRequests());
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private IEnumerable<IndexerRequest> GetRssRequests()
{
var request = new IndexerRequest(string.Format("{0}/rss.php?uid={1}&passkey={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.UserId, Settings.RssPasskey), HttpAccept.Html);
foreach (var cookie in HttpHeader.ParseCookies(Settings.Cookie))
{
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
}
yield return request;
}
}
}

@ -1,52 +0,0 @@
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.BitMeTv
{
public class BitMeTvSettingsValidator : AbstractValidator<BitMeTvSettings>
{
public BitMeTvSettingsValidator()
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.UserId).NotEmpty();
RuleFor(c => c.RssPasskey).NotEmpty();
RuleFor(c => c.Cookie).NotEmpty();
RuleFor(c => c.Cookie)
.Matches(@"pass=[0-9a-f]{32}", RegexOptions.IgnoreCase)
.WithMessage("Wrong pattern")
.AsWarning();
}
}
public class BitMeTvSettings : IProviderConfig
{
private static readonly BitMeTvSettingsValidator Validator = new BitMeTvSettingsValidator();
public BitMeTvSettings()
{
BaseUrl = "https://www.bitmetv.org";
}
[FieldDefinition(0, Label = "Website URL")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "UserId")]
public string UserId { get; set; }
[FieldDefinition(2, Label = "RSS Passkey")]
public string RssPasskey { get; set; }
[FieldDefinition(3, Label = "Cookie", HelpText = "BitMeTv uses a login cookie needed to access the rss, you'll have to retrieve it via a browser.")]
public string Cookie { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,45 +0,0 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNet : HttpIndexerBase<BroadcastheNetSettings>
{
public override string Name => "BroadcastheNet";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override int PageSize => 100;
public BroadcastheNet(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
var requestGenerator = new BroadcastheNetRequestGenerator() { Settings = Settings, PageSize = PageSize };
var releaseInfo = _indexerStatusService.GetLastRssSyncReleaseInfo(Definition.Id);
if (releaseInfo != null)
{
int torrentID;
if (int.TryParse(releaseInfo.Guid.Replace("BTN-", string.Empty), out torrentID))
{
requestGenerator.LastRecentTorrentID = torrentID;
}
}
return requestGenerator;
}
public override IParseIndexerResponse GetParser()
{
return new BroadcastheNetParser();
}
}
}

@ -1,95 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetParser : IParseIndexerResponse
{
private static readonly Regex RegexProtocol = new Regex("^https?:", RegexOptions.Compiled);
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var results = new List<ReleaseInfo>();
switch (indexerResponse.HttpResponse.StatusCode)
{
case HttpStatusCode.Unauthorized:
throw new ApiKeyException("API Key invalid or not authorized");
case HttpStatusCode.NotFound:
throw new IndexerException(indexerResponse, "Indexer API call returned NotFound, the Indexer API may have changed.");
case HttpStatusCode.ServiceUnavailable:
throw new RequestLimitReachedException("Cannot do more than 150 API requests per hour.");
default:
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
break;
}
if (indexerResponse.HttpResponse.Headers.ContentType != null && indexerResponse.HttpResponse.Headers.ContentType.Contains("text/html"))
{
throw new IndexerException(indexerResponse, "Indexer responded with html content. Site is likely blocked or unavailable.");
}
if (indexerResponse.Content == "Query execution was interrupted")
{
throw new IndexerException(indexerResponse, "Indexer API returned an internal server error");
}
JsonRpcResponse<BroadcastheNetTorrents> jsonResponse = new HttpResponse<JsonRpcResponse<BroadcastheNetTorrents>>(indexerResponse.HttpResponse).Resource;
if (jsonResponse.Error != null || jsonResponse.Result == null)
{
throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Error);
}
if (jsonResponse.Result.Results == 0)
{
return results;
}
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
foreach (var torrent in jsonResponse.Result.Torrents.Values)
{
var torrentInfo = new TorrentInfo();
torrentInfo.Guid = string.Format("BTN-{0}", torrent.TorrentID);
torrentInfo.Title = CleanReleaseName(torrent.ReleaseName);
torrentInfo.Size = torrent.Size;
torrentInfo.DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol);
torrentInfo.InfoUrl = string.Format("{0}//broadcasthe.net/torrents.php?id={1}&torrentid={2}", protocol, torrent.GroupID, torrent.TorrentID);
//torrentInfo.CommentUrl =
torrentInfo.PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().AddSeconds(torrent.Time);
//torrentInfo.MagnetUrl =
torrentInfo.InfoHash = torrent.InfoHash;
torrentInfo.Seeders = torrent.Seeders;
torrentInfo.Peers = torrent.Leechers + torrent.Seeders;
torrentInfo.Origin = torrent.Origin;
torrentInfo.Source = torrent.Source;
torrentInfo.Container = torrent.Container;
torrentInfo.Codec = torrent.Codec;
torrentInfo.Resolution = torrent.Resolution;
results.Add(torrentInfo);
}
return results;
}
private string CleanReleaseName(string releaseName)
{
releaseName = releaseName.Replace("\\", "");
return releaseName;
}
}
}

@ -1,203 +0,0 @@
using System.Linq;
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetRequestGenerator : IIndexerRequestGenerator
{
public int MaxPages { get; set; }
public int PageSize { get; set; }
public BroadcastheNetSettings Settings { get; set; }
public int? LastRecentTorrentID { get; set; }
public BroadcastheNetRequestGenerator()
{
MaxPages = 10;
PageSize = 100;
}
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
if (LastRecentTorrentID.HasValue)
{
pageableRequests.Add(GetPagedRequests(MaxPages, new BroadcastheNetTorrentQuery()
{
Id = ">=" + (LastRecentTorrentID.Value - 100)
}));
}
pageableRequests.AddTier(GetPagedRequests(MaxPages, new BroadcastheNetTorrentQuery()
{
Age = "<=86400"
}));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = new BroadcastheNetTorrentQuery();
if (AddSeriesSearchParameters(parameters, searchCriteria))
{
foreach (var episode in searchCriteria.Episodes)
{
parameters = parameters.Clone();
parameters.Category = "Episode";
parameters.Name = string.Format("S{0:00}%E{1:00}%", episode.SeasonNumber, episode.EpisodeNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct())
{
parameters = parameters.Clone();
parameters.Category = "Season";
parameters.Name = string.Format("Season {0}", seasonNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = new BroadcastheNetTorrentQuery();
if (AddSeriesSearchParameters(parameters, searchCriteria))
{
foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct())
{
parameters.Category = "Season";
parameters.Name = string.Format("Season {0}", seasonNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
parameters = parameters.Clone();
parameters.Category = "Episode";
parameters.Name = string.Format("S{0:00}E%", seasonNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = new BroadcastheNetTorrentQuery();
if (AddSeriesSearchParameters(parameters, searchCriteria))
{
parameters.Category = "Episode";
parameters.Name = string.Format("{0:yyyy}.{0:MM}.{0:dd}", searchCriteria.AirDate);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
pageableRequests.AddTier();
foreach (var episode in searchCriteria.Episodes)
{
parameters = parameters.Clone();
parameters.Category = "Episode";
parameters.Name = string.Format("S{0:00}E{1:00}", episode.SeasonNumber, episode.EpisodeNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = new BroadcastheNetTorrentQuery();
if (AddSeriesSearchParameters(parameters, searchCriteria))
{
foreach (var episode in searchCriteria.Episodes)
{
parameters = parameters.Clone();
parameters.Category = "Episode";
parameters.Name = string.Format("S{0:00}E{1:00}", episode.SeasonNumber, episode.EpisodeNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct())
{
parameters = parameters.Clone();
parameters.Category = "Season";
parameters.Name = string.Format("Season {0}", seasonNumber);
pageableRequests.Add(GetPagedRequests(MaxPages, parameters));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
private bool AddSeriesSearchParameters(BroadcastheNetTorrentQuery parameters, SearchCriteriaBase searchCriteria)
{
if (searchCriteria.Series.TvdbId != 0)
{
parameters.Tvdb = string.Format("{0}", searchCriteria.Series.TvdbId);
return true;
}
if (searchCriteria.Series.TvRageId != 0)
{
parameters.Tvrage = string.Format("{0}", searchCriteria.Series.TvRageId);
return true;
}
// BTN is very neatly managed, so it's unlikely they map tvrage/tvdb wrongly.
return false;
}
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, BroadcastheNetTorrentQuery parameters)
{
var builder = new JsonRpcRequestBuilder(Settings.BaseUrl)
.Call("getTorrents", Settings.ApiKey, parameters, PageSize, 0);
builder.SuppressHttpError = true;
for (var page = 0; page < maxPages; page++)
{
builder.JsonParameters[3] = page * PageSize;
yield return new IndexerRequest(builder.Build());
}
}
}
}

@ -1,37 +0,0 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetSettingsValidator : AbstractValidator<BroadcastheNetSettings>
{
public BroadcastheNetSettingsValidator()
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.ApiKey).NotEmpty();
}
}
public class BroadcastheNetSettings : IProviderConfig
{
private static readonly BroadcastheNetSettingsValidator Validator = new BroadcastheNetSettingsValidator();
public BroadcastheNetSettings()
{
BaseUrl = "http://api.broadcasthe.net/";
}
[FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key")]
public string ApiKey { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,31 +0,0 @@
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetTorrent
{
public string GroupName { get; set; }
public int GroupID { get; set; }
public int TorrentID { get; set; }
public int SeriesID { get; set; }
public string Series { get; set; }
public string SeriesBanner { get; set; }
public string SeriesPoster { get; set; }
public string YoutubeTrailer { get; set; }
public string Category { get; set; }
public int? Snatched { get; set; }
public int? Seeders { get; set; }
public int? Leechers { get; set; }
public string Source { get; set; }
public string Container { get; set; }
public string Codec { get; set; }
public string Resolution { get; set; }
public string Origin { get; set; }
public string ReleaseName { get; set; }
public long Size { get; set; }
public long Time { get; set; }
public int? TvdbID { get; set; }
public int? TvrageID { get; set; }
public string ImdbID { get; set; }
public string InfoHash { get; set; }
public string DownloadURL { get; set; }
}
}

@ -1,39 +0,0 @@
using Newtonsoft.Json;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetTorrentQuery
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Category { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Search { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Codec { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Container { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Source { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Resolution { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Origin { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Hash { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Tvdb { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Tvrage { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Age { get; set; }
public BroadcastheNetTorrentQuery Clone()
{
return MemberwiseClone() as BroadcastheNetTorrentQuery;
}
}
}

@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetTorrents
{
public Dictionary<int, BroadcastheNetTorrent> Torrents { get; set; }
public int Results { get; set; }
}
}

@ -1,30 +0,0 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.HDBits
{
public class HDBits : HttpIndexerBase<HDBitsSettings>
{
public override string Name => "HDBits";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override int PageSize => 30;
public HDBits(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{ }
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new HDBitsRequestGenerator() { Settings = Settings };
}
public override IParseIndexerResponse GetParser()
{
return new HDBitsParser(Settings);
}
}
}

@ -1,132 +0,0 @@
using System;
using Newtonsoft.Json;
namespace NzbDrone.Core.Indexers.HDBits
{
public class TorrentQuery
{
[JsonProperty(Required = Required.Always)]
public string Username { get; set; }
[JsonProperty(Required = Required.Always)]
public string Passkey { get; set; }
public string Hash { get; set; }
public string Search { get; set; }
public int[] Category { get; set; }
public int[] Codec { get; set; }
public int[] Medium { get; set; }
public int[] Origin { get; set; }
[JsonProperty(PropertyName = "imdb")]
public ImdbInfo ImdbInfo { get; set; }
[JsonProperty(PropertyName = "tvdb")]
public TvdbInfo TvdbInfo { get; set; }
[JsonProperty(PropertyName = "file_in_torrent")]
public string FileInTorrent { get; set; }
[JsonProperty(PropertyName = "snatched_only")]
public bool? SnatchedOnly { get; set; }
public int? Limit { get; set; }
public int? Page { get; set; }
public TorrentQuery Clone()
{
return MemberwiseClone() as TorrentQuery;
}
}
public class HDBitsResponse
{
[JsonProperty(Required = Required.Always)]
public StatusCode Status { get; set; }
public string Message { get; set; }
public object Data { get; set; }
}
public class TorrentQueryResponse
{
public string Id { get; set; }
public string Hash { get; set; }
public int Leechers { get; set; }
public int Seeders { get; set; }
public string Name { get; set; }
[JsonProperty(PropertyName = "times_completed")]
public uint TimesCompleted { get; set; }
public long Size { get; set; }
[JsonProperty(PropertyName = "utadded")]
public long UtAdded { get; set; }
public DateTime Added { get; set; }
public uint Comments { get; set; }
[JsonProperty(PropertyName = "numfiles")]
public uint NumFiles { get; set; }
[JsonProperty(PropertyName = "filename")]
public string FileName { get; set; }
[JsonProperty(PropertyName = "freeleech")]
public string FreeLeech { get; set; }
[JsonProperty(PropertyName = "type_category")]
public int TypeCategory { get; set; }
[JsonProperty(PropertyName = "type_codec")]
public int TypeCodec { get; set; }
[JsonProperty(PropertyName = "type_medium")]
public int TypeMedium { get; set; }
[JsonProperty(PropertyName = "type_origin")]
public int TypeOrigin { get; set; }
[JsonProperty(PropertyName = "imdb")]
public ImdbInfo ImdbInfo { get; set; }
[JsonProperty(PropertyName = "tvdb")]
public TvdbInfo TvdbInfo { get; set; }
}
public class ImdbInfo
{
public int? Id { get; set; }
public string EnglishTitle { get; set; }
public string OriginalTitle { get; set; }
public int? Year { get; set; }
public string[] Genres { get; set; }
public float? Rating { get; set; }
}
public class TvdbInfo
{
public int? Id { get; set; }
public int? Season { get; set; }
public int? Episode { get; set; }
}
public enum StatusCode
{
Success = 0,
Failure = 1,
SslRequired = 2,
JsonMalformed = 3,
AuthDataMissing = 4,
AuthFailed = 5,
MissingRequiredParameters = 6,
InvalidParameter = 7,
ImdbImportFail = 8,
ImdbTvNotAllowed = 9
}
}

@ -1,90 +0,0 @@
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.HDBits
{
public class HDBitsParser : IParseIndexerResponse
{
private readonly HDBitsSettings _settings;
public HDBitsParser(HDBitsSettings settings)
{
_settings = settings;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var torrentInfos = new List<ReleaseInfo>();
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse,
"Unexpected response status {0} code from API request",
indexerResponse.HttpResponse.StatusCode);
}
var jsonResponse = JsonConvert.DeserializeObject<HDBitsResponse>(indexerResponse.Content);
if (jsonResponse.Status != StatusCode.Success)
{
throw new IndexerException(indexerResponse,
"HDBits API request returned status code {0}: {1}",
jsonResponse.Status,
jsonResponse.Message ?? string.Empty);
}
var responseData = jsonResponse.Data as JArray;
if (responseData == null)
{
throw new IndexerException(indexerResponse,
"Indexer API call response missing result data");
}
var queryResults = responseData.ToObject<TorrentQueryResponse[]>();
foreach (var result in queryResults)
{
var id = result.Id;
torrentInfos.Add(new TorrentInfo()
{
Guid = string.Format("HDBits-{0}", id),
Title = result.Name,
Size = result.Size,
InfoHash = result.Hash,
DownloadUrl = GetDownloadUrl(id),
InfoUrl = GetInfoUrl(id),
Seeders = result.Seeders,
Peers = result.Leechers + result.Seeders,
PublishDate = result.Added.ToUniversalTime()
});
}
return torrentInfos.ToArray();
}
private string GetDownloadUrl(string torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/download.php")
.AddQueryParam("id", torrentId)
.AddQueryParam("passkey", _settings.ApiKey);
return url.FullUri;
}
private string GetInfoUrl(string torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/details.php")
.AddQueryParam("id", torrentId);
return url.FullUri;
}
}
}

@ -1,142 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.HDBits
{
public class HDBitsRequestGenerator : IIndexerRequestGenerator
{
public HDBitsSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRequest(new TorrentQuery()));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var queryBase = new TorrentQuery();
if (TryAddSearchParameters(queryBase, searchCriteria))
{
foreach (var episode in searchCriteria.Episodes)
{
var query = queryBase.Clone();
query.TvdbInfo.Season = episode.SeasonNumber;
query.TvdbInfo.Episode = episode.EpisodeNumber;
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria)
{
throw new System.NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var query = new TorrentQuery();
if (TryAddSearchParameters(query, searchCriteria))
{
query.Search = string.Format("{0:yyyy}-{0:MM}-{0:dd}", searchCriteria.AirDate);
pageableRequests.Add(GetRequest(query));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var queryBase = new TorrentQuery();
if (TryAddSearchParameters(queryBase, searchCriteria))
{
foreach (var seasonNumber in searchCriteria.Episodes.Select(e => e.SeasonNumber).Distinct())
{
var query = queryBase.Clone();
query.TvdbInfo.Season = seasonNumber;
pageableRequests.Add(GetRequest(query));
}
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var queryBase = new TorrentQuery();
if (TryAddSearchParameters(queryBase, searchCriteria))
{
foreach (var episode in searchCriteria.Episodes)
{
var query = queryBase.Clone();
query.TvdbInfo.Season = episode.SeasonNumber;
query.TvdbInfo.Episode = episode.EpisodeNumber;
pageableRequests.Add(GetRequest(query));
}
}
return pageableRequests;
}
private bool TryAddSearchParameters(TorrentQuery query, SearchCriteriaBase searchCriteria)
{
if (searchCriteria.Series.TvdbId != 0)
{
query.TvdbInfo = query.TvdbInfo ?? new TvdbInfo();
query.TvdbInfo.Id = searchCriteria.Series.TvdbId;
return true;
}
return false;
}
private IEnumerable<IndexerRequest> GetRequest(TorrentQuery query)
{
var request = new HttpRequestBuilder(Settings.BaseUrl)
.Resource("/api/torrents")
.Build();
request.Method = HttpMethod.POST;
const string appJson = "application/json";
request.Headers.Accept = appJson;
request.Headers.ContentType = appJson;
query.Username = Settings.Username;
query.Passkey = Settings.ApiKey;
request.SetContent(query.ToJson());
yield return new IndexerRequest(request);
}
}
}

@ -1,69 +0,0 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.HDBits
{
public class HDBitsSettingsValidator : AbstractValidator<HDBitsSettings>
{
public HDBitsSettingsValidator()
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.ApiKey).NotEmpty();
}
}
public class HDBitsSettings : IProviderConfig
{
private static readonly HDBitsSettingsValidator Validator = new HDBitsSettingsValidator();
public HDBitsSettings()
{
BaseUrl = "https://hdbits.org";
}
[FieldDefinition(0, Label = "Username")]
public string Username { get; set; }
[FieldDefinition(1, Label = "API Key")]
public string ApiKey { get; set; }
[FieldDefinition(2, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
public string BaseUrl { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
public enum HdBitsCategory
{
Movie = 1,
Tv = 2,
Documentary = 3,
Music = 4,
Sport = 5,
Audio = 6,
Xxx = 7,
MiscDemo = 8
}
public enum HdBitsCodec
{
H264 = 1,
Mpeg2 = 2,
Vc1 = 3,
Xvid = 4
}
public enum HdBitsMedium
{
Bluray = 1,
Encode = 3,
Capture = 4,
Remux = 5,
WebDl = 6
}
}

@ -616,16 +616,6 @@
<Compile Include="Indexers\Waffles\Waffles.cs" />
<Compile Include="Indexers\Waffles\WafflesRequestGenerator.cs" />
<Compile Include="Indexers\Waffles\WafflesSettings.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
<Compile Include="Indexers\BitMeTv\BitMeTvRequestGenerator.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetRequestGenerator.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNet.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetSettings.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetParser.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetTorrent.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetTorrentQuery.cs" />
<Compile Include="Indexers\BroadcastheNet\BroadcastheNetTorrents.cs" />
<Compile Include="Indexers\DownloadProtocol.cs" />
<Compile Include="Indexers\Exceptions\ApiKeyException.cs" />
<Compile Include="Indexers\Exceptions\IndexerException.cs" />
@ -636,11 +626,6 @@
<Compile Include="Indexers\Fanzub\FanzubRequestGenerator.cs" />
<Compile Include="Indexers\Fanzub\FanzubSettings.cs" />
<Compile Include="Indexers\FetchAndParseRssService.cs" />
<Compile Include="Indexers\HDBits\HDBits.cs" />
<Compile Include="Indexers\HDBits\HDBitsApi.cs" />
<Compile Include="Indexers\HDBits\HDBitsParser.cs" />
<Compile Include="Indexers\HDBits\HDBitsRequestGenerator.cs" />
<Compile Include="Indexers\HDBits\HDBitsSettings.cs" />
<Compile Include="Indexers\IIndexer.cs" />
<Compile Include="Indexers\IIndexerRequestGenerator.cs" />
<Compile Include="Indexers\IndexerBase.cs" />

Loading…
Cancel
Save