I have a feeling I'm breaking the world and bringing the apocalypse

It's quite hard to encapsulate something this large. This refactor
contains multiple attacks on the current architecture and is changing
things that were probably created quite a while back then. Luckily this
was done in increments so it mustn't be that impossible to recall what
has been done. I just need to relax my memory a little bit.

So the basic idea was quite simple. Let's distingush metas and normal
indexers a little bit more. Both of them were originating from
BaseIndexer, however very little of the functionality was actually
shared between them. Actually quite a few things made it even harder to
implement a different kind of indexer, especially for a newcomer for
both Jackett and C#.

Then in order to further reduce whatever was encapsulated in
any kind of, a couple things had to be changed. Like CardigannIndexer,
which probably had quite a mindshift change. IndexerManager and the
configuration management were also encapsulated and refactored, and now
I have a feeling that although the code could be improved, at least the
responsibilities of services and what they actually do is now clearer.

Anyhow, it would be safe to assume that I will not be able to go
step-by-step and define everything that has been changed. I'm sorry.
This commit is contained in:
chibidev 2017-07-10 22:58:44 +02:00 committed by kaso17
parent 35103206cf
commit 9e3076dde6
104 changed files with 1188 additions and 1102 deletions

View File

@ -94,8 +94,14 @@
<MonoDevelop>
<Properties>
<Policies>
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
<TextStylePolicy TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" FileWidth="80" TabsToSpaces="True" scope="text/x-csharp">
<inheritsSet />
<inheritsScope />
</TextStylePolicy>
<CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpacingAfterMethodDeclarationName="True" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="True" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="True" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" scope="text/x-csharp">
<inheritsSet />
<inheritsScope />
</CSharpFormattingPolicy>
</Policies>
</Properties>
</MonoDevelop>

View File

@ -66,9 +66,9 @@ Global
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.TextStylePolicy = $1
$1.inheritsSet = VisualStudio
$1.inheritsScope = text/plain
$1.scope = text/x-csharp
$1.TabsToSpaces = True
$1.EolMarker = Unix
$0.CSharpFormattingPolicy = $2
$2.IndentSwitchBody = True
$2.IndentBlocksInsideExpressions = True
@ -94,8 +94,13 @@ Global
$2.BeforeDelegateDeclarationParentheses = False
$2.NewParentheses = False
$2.SpacesBeforeBrackets = False
$2.inheritsSet = Mono
$2.inheritsScope = text/x-csharp
$2.scope = text/x-csharp
$2.IndentSwitchSection = True
$2.SpacingAfterMethodDeclarationName = False
$2.SpaceAfterMethodCallName = False
$2.SpaceBeforeOpenSquareBracket = False
$0.DotNetNamingPolicy = $3
$3.DirectoryNamespaceAssociation = PrefixedHierarchical
$0.StandardHeader = $4
EndGlobalSection
EndGlobal

View File

@ -205,7 +205,7 @@ namespace Jackett.Controllers
baseIndexer.ResetBaseConfig();
if (ex is ExceptionWithConfigData)
{
jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(null,false);
jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(null, false);
}
else
{
@ -431,7 +431,7 @@ namespace Jackett.Controllers
Engine.Server.Start();
})).Start();
}
if (saveDir != Engine.Server.Config.BlackholeDir)
{
if (!string.IsNullOrEmpty(saveDir))
@ -498,7 +498,7 @@ namespace Jackett.Controllers
var queryStr = value.Query;
if (queryStr != null)
{
{
var seasonMatch = Regex.Match(queryStr, @"S(\d{2,4})");
if (seasonMatch.Success)
{
@ -514,7 +514,7 @@ namespace Jackett.Controllers
}
queryStr = queryStr.Trim();
}
stringQuery.SearchTerm = queryStr;
stringQuery.Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category };
@ -556,9 +556,7 @@ namespace Jackett.Controllers
query = imdbQuery;
var searchResults = indexer.ResultsForQuery(query).Result;
searchResults = indexer.CleanLinks(searchResults);
cacheService.CacheRssResults(indexer, searchResults);
searchResults = indexer.FilterResults(query, searchResults);
foreach (var result in searchResults)
{

View File

@ -37,7 +37,7 @@ namespace Jackett.Controllers
var jsonReply = new JObject();
try
{
var indexer = indexerService.GetIndexer(indexerID);
var indexer = indexerService.GetWebIndexer(indexerID);
if (!indexer.IsConfigured)
{
logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName));
@ -48,8 +48,6 @@ namespace Jackett.Controllers
throw new Exception("Incorrect API key");
var remoteFile = new Uri(Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)), UriKind.RelativeOrAbsolute);
remoteFile = indexer.UncleanLink(remoteFile);
var downloadBytes = await indexer.Download(remoteFile);
if (string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir))

View File

@ -34,7 +34,7 @@ namespace Jackett.Controllers
{
try
{
var indexer = indexerService.GetIndexer(indexerID);
var indexer = indexerService.GetWebIndexer(indexerID);
if (!indexer.IsConfigured)
{
@ -48,20 +48,19 @@ namespace Jackett.Controllers
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
var target = new Uri(path, UriKind.RelativeOrAbsolute);
target = indexer.UncleanLink(target);
var downloadBytes = await indexer.Download(target);
// This will fix torrents where the keys are not sorted, and thereby not supported by Sonarr.
var torrentDictionary = BEncodedDictionary.DecodeTorrent(downloadBytes);
downloadBytes = torrentDictionary.Encode();
char[] invalidChars = System.IO.Path.GetInvalidFileNameChars();
for(int i=0;i<file.Count();i++)
if(invalidChars.Contains(file[i])) {
file = file.Remove(i, 1).Insert(i, " ");
}
char[] invalidChars = System.IO.Path.GetInvalidFileNameChars();
for (int i = 0; i < file.Count(); i++)
if (invalidChars.Contains(file[i]))
{
file = file.Remove(i, 1).Insert(i, " ");
}
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(downloadBytes);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent");

View File

@ -15,6 +15,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using Jackett.Indexers;
namespace Jackett.Controllers
{
@ -38,7 +39,7 @@ namespace Jackett.Controllers
};
torznabQuery.ExpandCatsToSubCats();
return torznabQuery.Categories;
return torznabQuery.Categories;
}
}
@ -55,7 +56,7 @@ namespace Jackett.Controllers
public async Task<HttpResponseMessage> Call(string indexerID, [FromUri]TorrentPotatoRequest request)
{
var indexer = indexerService.GetIndexer(indexerID);
var allowBadApiDueToDebug = false;
#if DEBUG
allowBadApiDueToDebug = Debugger.IsAttached;
@ -73,7 +74,8 @@ namespace Jackett.Controllers
return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured.");
}
if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i))){
if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i)))
{
logger.Warn(string.Format("Rejected a request to {0} which does not support searching for movies.", indexer.DisplayName));
return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer does not support movies.");
}
@ -92,7 +94,7 @@ namespace Jackett.Controllers
var torznabQuery = new TorznabQuery()
{
ApiKey = request.passkey,
ApiKey = request.passkey,
Categories = MOVIE_CATS,
SearchTerm = request.search,
ImdbID = request.imdbid,
@ -102,10 +104,7 @@ namespace Jackett.Controllers
IEnumerable<ReleaseInfo> releases = new List<ReleaseInfo>();
if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm))
{
releases = await indexer.ResultsForQuery(torznabQuery);
releases = indexer.CleanLinks(releases);
}
// Cache non query results
if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm))
@ -113,7 +112,6 @@ namespace Jackett.Controllers
cacheService.CacheRssResults(indexer, releases);
}
releases = indexer.FilterResults(torznabQuery, releases);
var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath());
var potatoResponse = new TorrentPotatoResponse();

View File

@ -14,6 +14,7 @@ using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Xml.Linq;
using Jackett.Indexers;
namespace Jackett.Controllers
{
@ -57,7 +58,7 @@ namespace Jackett.Controllers
{
var indexer = indexerService.GetIndexer(indexerID);
var torznabQuery = TorznabQuery.FromHttpQuery(HttpUtility.ParseQueryString(Request.RequestUri.Query));
if (string.Equals(torznabQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase))
{
return new HttpResponseMessage()
@ -113,7 +114,6 @@ namespace Jackett.Controllers
}
var releases = await indexer.ResultsForQuery(torznabQuery);
releases = indexer.CleanLinks(releases);
// Some trackers do not keep their clocks up to date and can be ~20 minutes out!
foreach (var release in releases.Where(r => r.PublishDate > DateTime.Now))
@ -122,26 +122,28 @@ namespace Jackett.Controllers
}
// Some trackers do not support multiple category filtering so filter the releases that match manually.
var filteredReleases = releases = indexer.FilterResults(torznabQuery, releases);
int? newItemCount = null;
// Cache non query results
if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm))
{
newItemCount = cacheService.GetNewItemCount(indexer, filteredReleases);
newItemCount = cacheService.GetNewItemCount(indexer, releases);
cacheService.CacheRssResults(indexer, releases);
}
// Log info
var logBuilder = new StringBuilder();
if (newItemCount != null) {
if (newItemCount != null)
{
logBuilder.AppendFormat(string.Format("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, indexer.DisplayName));
}
else {
else
{
logBuilder.AppendFormat(string.Format("Found {0} releases from {1}", releases.Count(), indexer.DisplayName));
}
if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) {
if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm))
{
logBuilder.AppendFormat(" for: {0}", torznabQuery.GetQueryString());
}

View File

@ -18,7 +18,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class SevenTor : BaseIndexer
public class SevenTor : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "ucp.php?mode=login"; } }
string SearchUrl { get { return SiteLink + "search.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public SevenTor(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public SevenTor(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "7tor",
description: null,
link: "https://7tor.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -22,7 +22,7 @@ namespace Jackett.Indexers
/// <summary>
/// Provider for Abnormal Private French Tracker
/// </summary>
public class Abnormal : BaseIndexer
public class Abnormal : BaseCachingWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
@ -43,13 +43,13 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Abnormal(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
public Abnormal(IIndexerConfigurationService configService, IWebClient w, Logger l, IProtectionService ps)
: base(
name: "Abnormal",
description: "General French Private Tracker",
link: "https://abnormal.ws/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,
@ -117,7 +117,8 @@ namespace Jackett.Indexers
// emulatedBrowserHeaders.Add("Accept-Encoding", "gzip, deflate");
// If we want to simulate a browser
if (ConfigData.Browser.Value) {
if (ConfigData.Browser.Value)
{
// Clean headers
emulatedBrowserHeaders.Clear();
@ -149,7 +150,8 @@ namespace Jackett.Indexers
};
// Do the login
var request = new Utils.Clients.WebRequest(){
var request = new Utils.Clients.WebRequest()
{
PostData = pairs,
Referer = LoginUrl,
Type = RequestType.POST,
@ -197,7 +199,7 @@ namespace Jackett.Indexers
int pageLinkCount = 0;
// Check cache first so we don't query the server (if search term used or not in dev mode)
if(!DevMode && !string.IsNullOrEmpty(searchTerm))
if (!DevMode && !string.IsNullOrEmpty(searchTerm))
{
lock (cache)
{
@ -230,14 +232,16 @@ namespace Jackett.Indexers
Boolean pagination = (fDom[".linkbox > a"].Length != 0);
// If pagination available
if (pagination) {
if (pagination)
{
// Calculate numbers of pages available for this search query (Based on number results and number of torrents on first page)
pageLinkCount = ParseUtil.CoerceInt(Regex.Match(fDom[".linkbox > a"].Last().Attr("href").ToString(), @"\d+").Value);
// Calculate average number of results (based on torrents rows lenght on first page)
nbResults = firstPageRows.Count() * pageLinkCount;
}
else {
else
{
// Check if we have a minimum of one result
if (firstPageRows.Length >= 1)
{
@ -528,13 +532,13 @@ namespace Jackett.Indexers
private void cleanCacheStorage(Boolean force = false)
{
// Check cleaning method
if(force)
if (force)
{
// Deleting Provider Storage folder and all files recursively
output("\nDeleting Provider Storage folder and all files recursively ...");
// Check if directory exist
if(System.IO.Directory.Exists(directory))
if (System.IO.Directory.Exists(directory))
{
// Delete storage directory of provider
System.IO.Directory.Delete(directory, true);
@ -555,17 +559,20 @@ namespace Jackett.Indexers
.Select(f => new System.IO.FileInfo(f))
.Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
.ToList()
.ForEach(f => {
.ForEach(f =>
{
output("Deleting cached file << " + f.Name + " >> ... done.");
f.Delete();
i++;
});
});
// Inform on what was cleaned during process
if(i > 0) {
if (i > 0)
{
output("-> Deleted " + i + " cached files during cleaning.");
}
else {
else
{
output("-> Nothing deleted during cleaning.");
}
}
@ -577,7 +584,7 @@ namespace Jackett.Indexers
private void latencyNow()
{
// Need latency ?
if(Latency)
if (Latency)
{
// Generate a random value in our range
var random = new Random(DateTime.Now.Millisecond);
@ -696,7 +703,7 @@ namespace Jackett.Indexers
private void output(string message, string level = "debug")
{
// Check if we are in dev mode
if(DevMode)
if (DevMode)
{
// Output message to console
Console.WriteLine(message);

View File

@ -18,7 +18,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public abstract class AvistazTracker : BaseIndexer
public abstract class AvistazTracker : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "auth/login"; } }
private string SearchUrl { get { return SiteLink + "torrents?in=1&type={0}&search={1}"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public AvistazTracker(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService, string name, string desc, string link)
public AvistazTracker(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService, string name, string desc, string link)
: base(name: name,
description: desc,
link: link,
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: indexerManager,
configService: configService,
client: webClient,
logger: logger,
p: protectionService,

View File

@ -17,7 +17,7 @@ using System.Web;
namespace Jackett.Indexers.Abstract
{
public abstract class GazelleTracker : BaseIndexer
public abstract class GazelleTracker : BaseWebIndexer
{
protected string LoginUrl { get { return SiteLink + "login.php"; } }
protected string APIUrl { get { return SiteLink + "ajax.php"; } }
@ -30,12 +30,12 @@ namespace Jackett.Indexers.Abstract
set { base.configData = value; }
}
public GazelleTracker(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService, string name, string desc, string link)
public GazelleTracker(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService, string name, string desc, string link)
: base(name: name,
description: desc,
link: link,
caps: new TorznabCapabilities(),
manager: indexerManager,
configService: configService,
client: webClient,
logger: logger,
p: protectionService,

View File

@ -19,19 +19,19 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class AlphaRatio : BaseIndexer
public class AlphaRatio : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "ajax.php?action=browse&order_by=time&order_way=desc&"; } }
private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } }
private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } }
public AlphaRatio(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
public AlphaRatio(IIndexerConfigurationService configService, IWebClient w, Logger l, IProtectionService ps)
: base(name: "AlphaRatio",
description: "Legendary",
link: "https://alpharatio.cc/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Linq;
namespace Jackett.Indexers
{
public class Andraste : BaseIndexer
public class Andraste : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string BrowseUrl { get { return SiteLink + "browse.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Andraste(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public Andraste(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Andraste",
description: "A German general tracker.",
link: "https://andraste.io/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -22,7 +22,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class AnimeBytes : BaseIndexer
public class AnimeBytes : BaseCachingWebIndexer
{
enum SearchType
{
@ -34,7 +34,7 @@ namespace Jackett.Indexers
private string SearchUrl { get { return SiteLink + "torrents.php?"; } }
private string MusicSearchUrl { get { return SiteLink + "torrents2.php?"; } }
public bool AllowRaws { get { return configData.IncludeRaw.Value; } }
public bool InsertSeason { get { return configData.InsertSeason!=null && configData.InsertSeason.Value; } }
public bool InsertSeason { get { return configData.InsertSeason != null && configData.InsertSeason.Value; } }
new ConfigurationDataAnimeBytes configData
{
@ -42,11 +42,11 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps)
public AnimeBytes(IIndexerConfigurationService configService, IWebClient client, Logger l, IProtectionService ps)
: base(name: "AnimeBytes",
link: "https://animebytes.tv/",
description: "Powered by Tentacles",
manager: i,
configService: configService,
client: client,
caps: new TorznabCapabilities(TorznabCatType.TVAnime,
TorznabCatType.Movies,
@ -67,7 +67,7 @@ namespace Jackett.Indexers
}
public override IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> input)
protected override IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> input)
{
// Prevent filtering
return input;
@ -128,21 +128,6 @@ namespace Jackett.Indexers
return IndexerConfigurationStatus.RequiresTesting;
}
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
if (jsonConfig is JObject)
{
configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
IsConfigured = true;
SaveConfig();
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
private string StripEpisodeNumber(string term)
{
// Tracer does not support searching with episode number so strip it if we have one
@ -155,7 +140,7 @@ namespace Jackett.Indexers
{
// The result list
var releases = new List<ReleaseInfo>();
if (ContainsMusicCategories(query.Categories))
{
foreach (var result in await GetResults(SearchType.Audio, query.SanitizedSearchTerm))
@ -210,7 +195,7 @@ namespace Jackett.Indexers
if (cachedResult != null)
return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray();
}
// Get the content from the tracker
var response = await RequestStringWithCookiesAndRetry(queryUrl);
if (response.IsRedirect)
@ -302,7 +287,7 @@ namespace Jackett.Indexers
releaseInfo = releaseInfo.Replace("Season ", "S");
releaseInfo = releaseInfo.Trim();
int test = 0;
if (InsertSeason && int.TryParse(releaseInfo, out test) && releaseInfo.Length<=3)
if (InsertSeason && int.TryParse(releaseInfo, out test) && releaseInfo.Length <= 3)
{
releaseInfo = "E0" + releaseInfo;
}

View File

@ -20,7 +20,7 @@ using System.Globalization;
namespace Jackett.Indexers
{
public class AnimeTorrents : BaseIndexer
public class AnimeTorrents : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "ajax/torrents_data.php"; } }
@ -32,12 +32,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public AnimeTorrents(IIndexerManagerService i, HttpWebClient c, Logger l, IProtectionService ps)
public AnimeTorrents(IIndexerConfigurationService configService, HttpWebClient c, Logger l, IProtectionService ps)
: base(name: "AnimeTorrents",
description: "Definitive source for anime and manga",
link: "https://animetorrents.me/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: c, // Forced HTTP client for custom headers
logger: l,
p: ps,

View File

@ -18,7 +18,7 @@ using Jackett.Utils.Clients;
namespace Jackett.Indexers
{
class ArcheTorrent : BaseIndexer
class ArcheTorrent : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "account-login.php"; } }
string BrowseUrl { get { return SiteLink + "torrents-search.php"; } }
@ -30,11 +30,11 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public ArcheTorrent(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public ArcheTorrent(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Arche Torrent",
description: "French Torrent Tracker",
link: "https://www.archetorrent.com/",
manager: indexerManager,
configService: configService,
logger: logger,
p: protectionService,
client: webClient,

View File

@ -20,11 +20,11 @@ namespace Jackett.Indexers
{
public class Avistaz : AvistazTracker
{
public Avistaz(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public Avistaz(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Avistaz",
desc: "Aka AsiaTorrents",
link: "https://avistaz.to/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -20,7 +20,7 @@ namespace Jackett.Indexers
{
// To comply with the rules for this tracker, only the acronym is used and no publicly displayed URLs to the site.
public class BB : BaseIndexer
public class BB : BaseWebIndexer
{
private string BaseUrl { get { return StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw=="); } }
private Uri BaseUri { get { return new Uri(BaseUrl); } }
@ -33,12 +33,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BB(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public BB(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "bB",
description: "bB",
link: "https://baconbits.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class BJShare : BaseIndexer
public class BJShare : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string BrowseUrl { get { return SiteLink + "torrents.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BJShare(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BJShare(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "BJ-Share",
description: "A brazilian tracker.",
link: "https://bj-share.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class BakaBT : BaseIndexer
public class BakaBT : BaseWebIndexer
{
public string SearchUrl { get { return SiteLink + "browse.php?only=0&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&reorder=1&q="; } }
public string LoginUrl { get { return SiteLink + "login.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BakaBT(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BakaBT(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "BakaBT",
description: "Anime Comunity",
link: "https://bakabt.me/",
caps: new TorznabCapabilities(TorznabCatType.TVAnime),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -10,7 +10,6 @@ using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
using AutoMapper;
using System.Threading;
using Jackett.Models.IndexerConfig;
using System.Text.RegularExpressions;
@ -18,25 +17,26 @@ namespace Jackett.Indexers
{
public abstract class BaseIndexer : IIndexer
{
public static string GetIndexerID(Type type)
{
return type.Name.ToLowerInvariant().StripNonAlphaNumeric();
}
public string SiteLink { get; protected set; }
public string DefaultSiteLink { get; protected set; }
public string[] AlternativeSiteLinks { get; protected set; } = new string[] { };
public string DisplayDescription { get; protected set; }
public string DisplayName { get; protected set; }
public string Language { get; protected set; }
public Encoding Encoding { get; protected set; }
public string Type { get; protected set; }
public virtual string ID { get { return GetIndexerID (GetType ()); } }
public virtual string ID { get { return GetIndexerID(GetType()); } }
public bool IsConfigured { get; protected set; }
public TorznabCapabilities TorznabCaps { get; protected set; }
public virtual bool IsConfigured { get; protected set; }
protected Logger logger;
protected IIndexerManagerService indexerService;
protected static List<CachedQueryResult> cache = new List<CachedQueryResult>();
protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0);
protected IWebClient webclient;
protected IIndexerConfigurationService configurationService;
protected IProtectionService protectionService;
protected readonly string downloadUrlBase = "";
protected ConfigurationData configData;
protected string CookieHeader
{
@ -56,14 +56,15 @@ namespace Jackett.Indexers
}
}
protected ConfigurationData configData;
private List<CategoryMapping> categoryMapping = new List<CategoryMapping>();
public abstract TorznabCapabilities TorznabCaps { get; protected set; }
// standard constructor used by most indexers
public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null, string downloadBase = null)
: this(manager, client, logger, p)
public BaseIndexer(string name, string link, string description, IIndexerConfigurationService configService, Logger logger, ConfigurationData configData, IProtectionService p)
{
this.logger = logger;
configurationService = configService;
protectionService = p;
if (!link.EndsWith("/", StringComparison.Ordinal))
throw new Exception("Site link must end with a slash.");
@ -71,111 +72,9 @@ namespace Jackett.Indexers
DisplayDescription = description;
SiteLink = link;
DefaultSiteLink = link;
this.downloadUrlBase = downloadBase;
this.configData = configData;
LoadValuesFromJson(null);
if (caps == null)
caps = TorznabUtil.CreateDefaultTorznabTVCaps();
TorznabCaps = caps;
}
// minimal constructor used by e.g. cardigann generic indexer
public BaseIndexer(IIndexerManagerService manager, IWebClient client, Logger logger, IProtectionService p)
{
this.logger = logger;
indexerService = manager;
webclient = client;
protectionService = p;
}
public IEnumerable<ReleaseInfo> CleanLinks(IEnumerable<ReleaseInfo> releases)
{
if (string.IsNullOrEmpty(downloadUrlBase))
return releases;
foreach (var release in releases)
{
if (release.Link.ToString().StartsWith(downloadUrlBase, StringComparison.Ordinal))
{
release.Link = new Uri(release.Link.ToString().Substring(downloadUrlBase.Length), UriKind.Relative);
}
}
return releases;
}
public virtual Uri UncleanLink(Uri link)
{
if (string.IsNullOrWhiteSpace(downloadUrlBase))
{
return link;
}
if (link.ToString().StartsWith(downloadUrlBase, StringComparison.Ordinal))
{
return link;
}
return new Uri(downloadUrlBase + link.ToString(), UriKind.RelativeOrAbsolute);
}
protected ICollection<int> MapTrackerCatToNewznab(string input)
{
var cats = new List<int>();
if (null != input)
{
var mapping = categoryMapping.Where(m => m.TrackerCategory != null && m.TrackerCategory.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault();
if (mapping != null)
{
cats.Add(mapping.NewzNabCategory);
}
// 1:1 category mapping
try
{
var trackerCategoryInt = int.Parse(input);
cats.Add(trackerCategoryInt + 100000);
}
catch (FormatException)
{
// input is not an integer, continue
}
}
return cats;
}
protected ICollection<int> MapTrackerCatDescToNewznab(string input)
{
var cats = new List<int>();
if (null != input)
{
var mapping = categoryMapping.Where(m => m.TrackerCategoryDesc != null && m.TrackerCategoryDesc.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault();
if (mapping != null)
{
cats.Add(mapping.NewzNabCategory);
if (mapping.TrackerCategory != null)
{
// 1:1 category mapping
try
{
var trackerCategoryInt = int.Parse(mapping.TrackerCategory);
cats.Add(trackerCategoryInt + 100000);
}
catch (FormatException)
{
// mapping.TrackerCategory is not an integer, continue
}
}
}
}
return cats;
}
public static string GetIndexerID(Type type)
{
return StringUtil.StripNonAlphaNumeric(type.Name.ToLowerInvariant());
if (configData != null)
LoadValuesFromJson(null);
}
public virtual Task<ConfigurationData> GetConfigurationForSetup()
@ -191,109 +90,9 @@ namespace Jackett.Indexers
public virtual void SaveConfig()
{
indexerService.SaveConfig(this as IIndexer, configData.ToJson(protectionService, forDisplay: false));
configurationService.Save(this as IIndexer, configData.ToJson(protectionService, forDisplay: false));
}
protected void OnParseError(string results, Exception ex)
{
var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), DisplayName);
var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5));
var fileContents = string.Format("{0}{1}{2}", ex, spacing, results);
logger.Error(fileName + fileContents);
throw ex;
}
protected void CleanCache()
{
foreach (var expired in cache.Where(i => DateTime.Now - i.Created > cacheTime).ToList())
{
cache.Remove(expired);
}
}
protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
var byteResult = new WebClientByteResult();
// Map to byte
Mapper.Map(response, byteResult);
await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies);
// Map to string
Mapper.Map(byteResult, response);
}
protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
// Follow up to 5 redirects
for (int i = 0; i < 5; i++)
{
if (!response.IsRedirect)
break;
await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies);
if (accumulateCookies)
{
CookieHeader = ResolveCookies((CookieHeader != null && CookieHeader != ""? CookieHeader + " " : "") + (overrideCookies != null && overrideCookies != "" ? overrideCookies + " " : "") + response.Cookies);
overrideCookies = response.Cookies = CookieHeader;
}
if (overrideCookies != null && response.Cookies == null)
{
response.Cookies = overrideCookies;
}
}
}
private String ResolveCookies(String incomingCookies = "")
{
var redirRequestCookies = (CookieHeader != null && CookieHeader != "" ? CookieHeader + " " : "") + incomingCookies;
System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\\,;\s]+)=([^=\\,;\s]*)");
Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>();
var matches = expression.Match(redirRequestCookies);
while (matches.Success)
{
if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value;
matches = matches.NextMatch();
}
return string.Join("; ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray());
}
// Update CookieHeader with new cookies and save the config if something changed (e.g. a new CloudFlare clearance cookie was issued)
protected void UpdateCookieHeader(string newCookies, string cookieOverride = null)
{
string newCookieHeader = ResolveCookies((cookieOverride != null && cookieOverride != "" ? cookieOverride + " " : "") + newCookies);
if (CookieHeader != newCookieHeader)
{
logger.Debug(string.Format("updating Cookies {0} => {1}", CookieHeader, newCookieHeader));
CookieHeader = newCookieHeader;
if (IsConfigured)
SaveConfig();
}
}
private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
if (incomingResponse.IsRedirect)
{
var redirRequestCookies = "";
if (accumulateCookies)
{
redirRequestCookies = ResolveCookies((CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null ? overrideCookies : ""));
} else
{
redirRequestCookies = (overrideCookies != null ? overrideCookies : "");
}
// Do redirect
var redirectedResponse = await webclient.GetBytes(new WebRequest()
{
Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo,
Referer = referrer,
Cookies = redirRequestCookies,
Encoding = Encoding
});
Mapper.Map(redirectedResponse, incomingResponse);
}
}
protected void LoadLegacyCookieConfig(JToken jsonConfig)
{
string legacyCookieHeader = (string)jsonConfig["cookie_header"];
@ -346,7 +145,7 @@ namespace Jackett.Indexers
SiteLink = configData.SiteLink.Value;
}
public virtual void LoadFromSavedConfiguration(JToken jsonConfig)
public void LoadFromSavedConfiguration(JToken jsonConfig)
{
if (jsonConfig is JArray)
{
@ -362,8 +161,100 @@ namespace Jackett.Indexers
}
}
public async virtual Task<byte[]> Download(Uri link) {
return await Download(link, RequestType.GET);
protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError)
{
if (isLoggedin)
{
CookieHeader = cookies;
IsConfigured = true;
SaveConfig();
}
else
{
await onError();
}
}
protected virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results)
{
if (query.Categories.Length == 0)
return results;
var filteredResults = results.Where(result =>
{
return result.Category.IsEmptyOrNull() || query.Categories.Intersect(result.Category).Any() || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category);
});
return filteredResults;
}
public bool CanHandleQuery(TorznabQuery query)
{
if (query == null)
return false;
var caps = TorznabCaps;
if (!caps.SearchAvailable && query.IsSearch)
return false;
if (!caps.TVSearchAvailable && query.IsTVSearch)
return false;
if (!caps.MovieSearchAvailable && query.IsMovieSearch)
return false;
if (!caps.SupportsTVRageSearch && query.IsTVRageSearch)
return false;
if (!caps.SupportsImdbSearch && query.IsImdbQuery)
return false;
if (query.HasSpecifiedCategories)
if (!caps.SupportsCategories(query.Categories))
return false;
return true;
}
public void Unconfigure()
{
IsConfigured = false;
}
public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson);
public virtual async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
{
var results = await PerformQuery(query);
results = FilterResults(query, results);
foreach (var result in results)
{
result.Origin = this;
}
return results;
}
protected abstract Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query);
}
public abstract class BaseWebIndexer : BaseIndexer, IWebIndexer
{
protected BaseWebIndexer(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, logger, configData, p)
{
this.webclient = client;
this.downloadUrlBase = downloadBase;
if (caps == null)
caps = TorznabUtil.CreateDefaultTorznabTVCaps();
TorznabCaps = caps;
}
// minimal constructor used by e.g. cardigann generic indexer
protected BaseWebIndexer(IIndexerConfigurationService configService, IWebClient client, Logger logger, IProtectionService p)
: base("", "/", "", configService, logger, null, p)
{
this.webclient = client;
}
public async virtual Task<byte[]> Download(Uri link)
{
var uncleanLink = UncleanLink(link);
return await Download(uncleanLink, RequestType.GET);
}
protected async Task<byte[]> Download(Uri link, RequestType method)
@ -379,7 +270,7 @@ namespace Jackett.Indexers
logger.Error("Failed download cookies: " + this.CookieHeader);
if (response.Content != null)
logger.Error("Failed download response:\n" + Encoding.UTF8.GetString(response.Content));
throw new Exception($"Remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => "+response.RedirectingTo : ""));
throw new Exception($"Remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => " + response.RedirectingTo : ""));
}
return response.Content;
@ -530,32 +421,90 @@ namespace Jackett.Indexers
{
response.Cookies = ResolveCookies(firstCallCookies + (accumulateCookies ? " " + response.Cookies : ""));
}
return response;
}
protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError)
protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
if (isLoggedin)
var byteResult = new WebClientByteResult();
// Map to byte
Mapper.Map(response, byteResult);
await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies);
// Map to string
Mapper.Map(byteResult, response);
}
protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
// Follow up to 5 redirects
for (int i = 0; i < 5; i++)
{
CookieHeader = cookies;
IsConfigured = true;
SaveConfig();
}
else
{
await onError();
if (!response.IsRedirect)
break;
await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies);
if (accumulateCookies)
{
CookieHeader = ResolveCookies((CookieHeader != null && CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null && overrideCookies != "" ? overrideCookies + " " : "") + response.Cookies);
overrideCookies = response.Cookies = CookieHeader;
}
if (overrideCookies != null && response.Cookies == null)
{
response.Cookies = overrideCookies;
}
}
}
public virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results)
private String ResolveCookies(String incomingCookies = "")
{
foreach (var result in results)
var redirRequestCookies = (CookieHeader != null && CookieHeader != "" ? CookieHeader + " " : "") + incomingCookies;
System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\\,;\s]+)=([^=\\,;\s]*)");
Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>();
var matches = expression.Match(redirRequestCookies);
while (matches.Success)
{
if (query.Categories.Length == 0 || result.Category == null || result.Category.Count() == 0 || query.Categories.Intersect(result.Category).Any() || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category))
if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value;
matches = matches.NextMatch();
}
return string.Join("; ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray());
}
// Update CookieHeader with new cookies and save the config if something changed (e.g. a new CloudFlare clearance cookie was issued)
protected void UpdateCookieHeader(string newCookies, string cookieOverride = null)
{
string newCookieHeader = ResolveCookies((cookieOverride != null && cookieOverride != "" ? cookieOverride + " " : "") + newCookies);
if (CookieHeader != newCookieHeader)
{
logger.Debug(string.Format("updating Cookies {0} => {1}", CookieHeader, newCookieHeader));
CookieHeader = newCookieHeader;
if (IsConfigured)
SaveConfig();
}
}
private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false)
{
if (incomingResponse.IsRedirect)
{
var redirRequestCookies = "";
if (accumulateCookies)
{
yield return result;
redirRequestCookies = ResolveCookies((CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null ? overrideCookies : ""));
}
else
{
redirRequestCookies = (overrideCookies != null ? overrideCookies : "");
}
// Do redirect
var redirectedResponse = await webclient.GetBytes(new WebRequest()
{
Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo,
Referer = referrer,
Cookies = redirRequestCookies,
Encoding = Encoding
});
Mapper.Map(redirectedResponse, incomingResponse);
}
}
@ -641,40 +590,130 @@ namespace Jackett.Indexers
return result.Distinct().ToList();
}
public bool CanHandleQuery(TorznabQuery query)
protected ICollection<int> MapTrackerCatToNewznab(string input)
{
if (query == null)
return false;
var caps = TorznabCaps;
if (!caps.SearchAvailable && query.IsSearch)
return false;
if (!caps.TVSearchAvailable && query.IsTVSearch)
return false;
if (!caps.MovieSearchAvailable && query.IsMovieSearch)
return false;
if (!caps.SupportsTVRageSearch && query.IsTVRageSearch)
return false;
if (!caps.SupportsImdbSearch && query.IsImdbQuery)
return false;
var cats = new List<int>();
if (null != input)
{
var mapping = categoryMapping.Where(m => m.TrackerCategory != null && m.TrackerCategory.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault();
if (mapping != null)
{
cats.Add(mapping.NewzNabCategory);
}
if (query.HasSpecifiedCategories)
if (!caps.SupportsCategories(query.Categories))
return false;
return true;
// 1:1 category mapping
try
{
var trackerCategoryInt = int.Parse(input);
cats.Add(trackerCategoryInt + 100000);
}
catch (FormatException)
{
// input is not an integer, continue
}
}
return cats;
}
public abstract Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson);
public virtual async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
protected ICollection<int> MapTrackerCatDescToNewznab(string input)
{
var results = await PerformQuery(query);
foreach (var result in results)
var cats = new List<int>();
if (null != input)
{
result.Origin = this;
var mapping = categoryMapping.Where(m => m.TrackerCategoryDesc != null && m.TrackerCategoryDesc.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault();
if (mapping != null)
{
cats.Add(mapping.NewzNabCategory);
if (mapping.TrackerCategory != null)
{
// 1:1 category mapping
try
{
var trackerCategoryInt = int.Parse(mapping.TrackerCategory);
cats.Add(trackerCategoryInt + 100000);
}
catch (FormatException)
{
// mapping.TrackerCategory is not an integer, continue
}
}
}
}
return cats;
}
private IEnumerable<ReleaseInfo> CleanLinks(IEnumerable<ReleaseInfo> releases)
{
if (string.IsNullOrEmpty(downloadUrlBase))
return releases;
foreach (var release in releases)
{
if (release.Link.ToString().StartsWith(downloadUrlBase, StringComparison.Ordinal))
{
release.Link = new Uri(release.Link.ToString().Substring(downloadUrlBase.Length), UriKind.Relative);
}
}
return releases;
}
public override async Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query)
{
var results = await base.ResultsForQuery(query);
results = CleanLinks(results);
return results;
}
protected abstract Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query);
protected virtual Uri UncleanLink(Uri link)
{
if (string.IsNullOrWhiteSpace(downloadUrlBase))
{
return link;
}
if (link.ToString().StartsWith(downloadUrlBase, StringComparison.Ordinal))
{
return link;
}
return new Uri(downloadUrlBase + link.ToString(), UriKind.RelativeOrAbsolute);
}
protected void OnParseError(string results, Exception ex)
{
var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), DisplayName);
var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5));
var fileContents = string.Format("{0}{1}{2}", ex, spacing, results);
logger.Error(fileName + fileContents);
throw ex;
}
public override TorznabCapabilities TorznabCaps { get; protected set; }
public Encoding Encoding { get; protected set; }
private List<CategoryMapping> categoryMapping = new List<CategoryMapping>();
protected IWebClient webclient;
protected readonly string downloadUrlBase = "";
}
public abstract class BaseCachingWebIndexer : BaseWebIndexer
{
protected BaseCachingWebIndexer(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 void CleanCache()
{
foreach (var expired in cache.Where(i => DateTime.Now - i.Created > cacheTime).ToList())
{
cache.Remove(expired);
}
}
protected static List<CachedQueryResult> cache = new List<CachedQueryResult>();
protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0);
}
}

View File

@ -15,7 +15,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class BestFriends : BaseIndexer
public class BestFriends : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BestFriends(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BestFriends(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Best Friends",
description: "A German general tracker.",
link: "http://bf.mine.nu/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class BeyondHD : BaseIndexer
public class BeyondHD : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php?searchin=title&incldead=0&"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BeyondHD(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public BeyondHD(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "BeyondHD",
description: "Without BeyondHD, your HDTV is just a TV",
link: "https://beyond-hd.me/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class BitCityReloaded : BaseIndexer
public class BitCityReloaded : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string BrowseUrl { get { return SiteLink + "uebersicht.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BitCityReloaded(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BitCityReloaded(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Bit-City Reloaded",
description: "A German general tracker.",
link: "https://bc-reloaded.net/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class BitHdtv : BaseIndexer
public class BitHdtv : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -32,12 +32,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BitHdtv(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public BitHdtv(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "BIT-HDTV",
description: "Home of high definition invites",
link: "https://www.bit-hdtv.com/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class BitMeTV : BaseIndexer
public class BitMeTV : BaseWebIndexer
{
//https is poorly implemented on BitMeTV. Site uses http to login, but then redirects to https for search
private string LoginUrl { get { return SiteLink + "login.php"; } }
@ -33,12 +33,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BitMeTV(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public BitMeTV(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "BitMeTV",
description: "TV Episode specialty tracker",
link: "http://www.bitmetv.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -20,7 +20,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class BitSoup : BaseIndexer
public class BitSoup : BaseWebIndexer
{
private string BrowseUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -33,12 +33,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BitSoup(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BitSoup(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "BitSoup",
description: "SoupieBits",
link: "https://www.bitsoup.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -20,7 +20,7 @@ using Newtonsoft.Json;
namespace Jackett.Indexers
{
public class BroadcastTheNet : BaseIndexer
public class BroadcastTheNet : BaseWebIndexer
{
string APIBASE = "https://api.broadcasthe.net";
@ -30,12 +30,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public BroadcastTheNet(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public BroadcastTheNet(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "BroadcastTheNet",
description: "Needs no description..",
link: "https://broadcasthe.net/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class BrokenStones : GazelleTracker
{
public BrokenStones(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public BrokenStones(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "BrokenStones",
desc: null,
link: "https://brokenstones.club/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -10,8 +10,6 @@ using System;
using Jackett.Models.IndexerConfig;
using System.Collections.Specialized;
using System.Text;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using static Jackett.Models.IndexerConfig.ConfigurationData;
using AngleSharp.Parser.Html;
using System.Text.RegularExpressions;
@ -22,11 +20,10 @@ using System.Linq;
namespace Jackett.Indexers
{
public class CardigannIndexer : BaseIndexer
public class CardigannIndexer : BaseWebIndexer
{
public string DefinitionString { get; protected set; }
protected IndexerDefinition Definition;
public override string ID { get { return (Definition != null ? Definition.Site : GetIndexerID (GetType ())); } }
public override string ID { get { return (Definition != null ? Definition.Site : GetIndexerID(GetType())); } }
protected WebClientStringResult landingResult;
protected IHtmlDocument landingResultDocument;
@ -37,228 +34,19 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
// A Dictionary allowing the same key multiple times
public class KeyValuePairList : List<KeyValuePair<string, selectorBlock>>, IDictionary<string, selectorBlock>
{
public selectorBlock this[string key]
{
get
{
throw new NotImplementedException();
}
set
{
base.Add(new KeyValuePair<string, selectorBlock>(key, value));
}
}
public ICollection<string> Keys
{
get
{
throw new NotImplementedException();
}
}
public ICollection<selectorBlock> Values
{
get
{
throw new NotImplementedException();
}
}
public void Add(string key, selectorBlock value)
{
base.Add(new KeyValuePair<string, selectorBlock>(key, value));
}
public bool ContainsKey(string key)
{
throw new NotImplementedException();
}
public bool Remove(string key)
{
throw new NotImplementedException();
}
public bool TryGetValue(string key, out selectorBlock value)
{
throw new NotImplementedException();
}
}
// Cardigann yaml classes
public class IndexerDefinition {
public string Site { get; set; }
public List<settingsField> Settings { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public string Language { get; set; }
public string Encoding { get; set; }
public List<string> Links { get; set; }
public List<string> Certificates { get; set; }
public capabilitiesBlock Caps { get; set; }
public loginBlock Login { get; set; }
public ratioBlock Ratio { get; set; }
public searchBlock Search { get; set; }
public downloadBlock Download { get; set; }
// IndexerDefinitionStats not needed/implemented
}
public class settingsField
{
public string Name { get; set; }
public string Type { get; set; }
public string Label { get; set; }
public string Default { get; set; }
public Dictionary<string, string> Options { get; set; }
}
public class CategorymappingBlock
{
public string id { get; set; }
public string cat { get; set; }
public string desc { get; set; }
}
public class capabilitiesBlock
{
public Dictionary<string, string> Categories { get; set; }
public List<CategorymappingBlock> Categorymappings { get; set; }
public Dictionary<string, List<string>> Modes { get; set; }
}
public class captchaBlock
{
public string Type { get; set; }
public string Image { get; set; }
public string Input { get; set; }
}
public class loginBlock
{
public string Path { get; set; }
public string Submitpath { get; set; }
public List<string> Cookies { get; set; }
public string Method { get; set; }
public string Form { get; set; }
public bool Selectors { get; set; } = false;
public Dictionary<string, string> Inputs { get; set; }
public Dictionary<string, selectorBlock> Selectorinputs { get; set; }
public Dictionary<string, selectorBlock> Getselectorinputs { get; set; }
public List<errorBlock> Error { get; set; }
public pageTestBlock Test { get; set; }
public captchaBlock Captcha { get; set; }
}
public class errorBlock
{
public string Path { get; set; }
public string Selector { get; set; }
public selectorBlock Message { get; set; }
}
public class selectorBlock
{
public string Selector { get; set; }
public bool Optional { get; set; } = false;
public string Text { get; set; }
public string Attribute { get; set; }
public string Remove { get; set; }
public List<filterBlock> Filters { get; set; }
public Dictionary<string, string> Case { get; set; }
}
public class filterBlock
{
public string Name { get; set; }
public dynamic Args { get; set; }
}
public class pageTestBlock
{
public string Path { get; set; }
public string Selector { get; set; }
}
public class ratioBlock : selectorBlock
{
public string Path { get; set; }
}
public class searchBlock
{
public string Path { get; set; }
public List<searchPathBlock> Paths { get; set; }
public Dictionary<string, List<string>> Headers { get; set; }
public List<filterBlock> Keywordsfilters { get; set; }
public Dictionary<string, string> Inputs { get; set; }
public List<errorBlock> Error { get; set; }
public rowsBlock Rows { get; set; }
public KeyValuePairList Fields { get; set; }
}
public class rowsBlock : selectorBlock
{
public int After { get; set; }
//public string Remove { get; set; } // already inherited
public selectorBlock Dateheaders { get; set; }
}
public class searchPathBlock : requestBlock
{
public List<string> Categories { get; set; }
public bool Inheritinputs { get; set; } = true;
}
public class requestBlock
{
public string Path { get; set; }
public string Method { get; set; }
public Dictionary<string, string> Inputs { get; set; }
}
public class downloadBlock
{
public string Selector { get; set; }
public string Method { get; set; }
public requestBlock Before { get; set; }
}
protected readonly string[] OptionalFileds = new string[] { "imdb", "rageid", "tvdbid", "banner" };
public CardigannIndexer(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
: base(manager: i,
public CardigannIndexer(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps, IndexerDefinition Definition)
: base(configService: configService,
client: wc,
logger: l,
p: ps)
{
}
public CardigannIndexer(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps, string DefinitionString)
: base(manager: i,
client: wc,
logger: l,
p: ps)
{
Init(DefinitionString);
}
protected void Init(string DefinitionString)
{
this.DefinitionString = DefinitionString;
var deserializer = new DeserializerBuilder()
.WithNamingConvention(new CamelCaseNamingConvention())
.IgnoreUnmatchedProperties()
.Build();
Definition = deserializer.Deserialize<IndexerDefinition>(DefinitionString);
this.Definition = Definition;
// Add default data if necessary
if (Definition.Settings == null)
{
{
Definition.Settings = new List<settingsField>();
Definition.Settings.Add(new settingsField { Name = "username", Label = "Username", Type = "text" });
Definition.Settings.Add(new settingsField { Name = "password", Label = "Password", Type = "password" });
@ -310,11 +98,11 @@ namespace Jackett.Indexers
switch (Setting.Type)
{
case "checkbox":
item = new BoolItem {Value = false};
item = new BoolItem { Value = false };
if (Setting.Default != null && Setting.Default == "true")
{
((BoolItem) item).Value = true;
((BoolItem)item).Value = true;
}
break;
case "password":
@ -337,13 +125,13 @@ namespace Jackett.Indexers
{
item = new StringItem { Value = Setting.Default }; ;
}
item.Name = Setting.Label;
configData.AddDynamic(Setting.Name, item);
}
if (Definition.Caps.Categories != null)
{
{
foreach (var Category in Definition.Caps.Categories)
{
var cat = TorznabCatType.GetCatByName(Category.Value);
@ -406,10 +194,10 @@ namespace Jackett.Indexers
value = ((SelectItem)item).Value;
}
else
{
{
value = ((StringItem)item).Value;
}
variables[".Config."+Setting.Name] = value;
variables[".Config." + Setting.Name] = value;
}
return variables;
}
@ -547,7 +335,7 @@ namespace Jackett.Indexers
}
return true; // no error
}
protected async Task<bool> DoLogin()
{
var Login = Definition.Login;
@ -581,7 +369,7 @@ namespace Jackett.Indexers
var CaptchaConfigItem = (RecaptchaItem)configData.GetDynamic("Captcha");
if (CaptchaConfigItem != null)
{
{
if (!string.IsNullOrWhiteSpace(CaptchaConfigItem.Cookie))
{
// for remote users just set the cookie and return
@ -594,7 +382,7 @@ namespace Jackett.Indexers
{
var CloudFlareQueryCollection = new NameValueCollection();
CloudFlareQueryCollection["id"] = CloudFlareCaptchaChallenge.GetAttribute("data-ray");
CloudFlareQueryCollection["g-recaptcha-response"] = CaptchaConfigItem.Value;
var ClearanceUrl = resolvePath("/cdn-cgi/l/chk_captcha?" + CloudFlareQueryCollection.GetQueryString());
@ -660,13 +448,13 @@ namespace Jackett.Indexers
pairs[name] = value;
}
foreach (var Input in Definition.Login.Inputs)
{
var value = applyGoTemplateText(Input.Value);
var input = Input.Key;
if (Login.Selectors)
{
{
var inputElement = landingResultDocument.QuerySelector(Input.Key);
if (inputElement == null)
throw new ExceptionWithConfigData(string.Format("Login failed: No input found using selector {0}", Input.Key), configData);
@ -716,7 +504,7 @@ namespace Jackett.Indexers
// automatically solve simpleCaptchas, if used
var simpleCaptchaPresent = landingResultDocument.QuerySelector("script[src*=\"simpleCaptcha\"]");
if(simpleCaptchaPresent != null)
if (simpleCaptchaPresent != null)
{
var captchaUrl = resolvePath("simpleCaptcha.php?numImages=1");
var simpleCaptchaResult = await RequestStringWithCookies(captchaUrl.ToString(), null, LoginUrl);
@ -736,7 +524,7 @@ namespace Jackett.Indexers
{
var input = Captcha.Input;
if (Login.Selectors)
{
{
var inputElement = landingResultDocument.QuerySelector(Captcha.Input);
if (inputElement == null)
throw new ExceptionWithConfigData(string.Format("Login failed: No captcha input found using {0}", Captcha.Input), configData);
@ -771,9 +559,11 @@ namespace Jackett.Indexers
bodyParts.Add("--" + boundary + "--");
headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
var body = string.Join("\r\n", bodyParts);
var body = string.Join("\r\n", bodyParts);
loginResult = await PostDataWithCookies(submitUrl.ToString(), pairs, configData.CookieHeader.Value, SiteLink, headers, body);
} else {
}
else
{
loginResult = await RequestLoginAndFollowRedirect(submitUrl.ToString(), pairs, configData.CookieHeader.Value, true, null, LoginUrl, true);
}
@ -903,7 +693,8 @@ namespace Jackett.Indexers
if (Captcha.Type == "image")
{
var captchaElement = landingResultDocument.QuerySelector(Captcha.Image);
if (captchaElement != null) {
if (captchaElement != null)
{
hasCaptcha = true;
var CaptchaUrl = resolvePath(captchaElement.GetAttribute("src"), LoginUrl);
@ -954,7 +745,7 @@ namespace Jackett.Indexers
if (Filters == null)
return Data;
foreach(filterBlock Filter in Filters)
foreach (filterBlock Filter in Filters)
{
switch (Filter.Name)
{
@ -974,7 +765,7 @@ namespace Jackett.Indexers
{
logger.Debug(ex.Message);
}
break;
break;
case "regexp":
var pattern = (string)Filter.Args;
var Regexp = new Regex(pattern);
@ -987,7 +778,7 @@ namespace Jackett.Indexers
regexpreplace_replacement = applyGoTemplateText(regexpreplace_replacement, variables);
Regex regexpreplace_regex = new Regex(regexpreplace_pattern);
Data = regexpreplace_regex.Replace(Data, regexpreplace_replacement);
break;
break;
case "split":
var sep = (string)Filter.Args[0];
var pos = (string)Filter.Args[1];
@ -1097,7 +888,7 @@ namespace Jackett.Indexers
if (Selector.Remove != null)
{
foreach(var i in selection.QuerySelectorAll(Selector.Remove))
foreach (var i in selection.QuerySelectorAll(Selector.Remove))
{
i.Remove();
}
@ -1105,7 +896,7 @@ namespace Jackett.Indexers
if (Selector.Case != null)
{
foreach(var Case in Selector.Case)
foreach (var Case in Selector.Case)
{
if (selection.Matches(Case.Key) || QuerySelector(selection, Case.Key) != null)
{
@ -1113,7 +904,7 @@ namespace Jackett.Indexers
break;
}
}
if(value == null)
if (value == null)
throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", Selector.Case), selection.ToHtmlPretty()));
}
else if (Selector.Attribute != null)
@ -1217,7 +1008,7 @@ namespace Jackett.Indexers
InputsList.Add(SearchPath.Inputs);
foreach (var Inputs in InputsList)
{
{
if (Inputs != null)
{
foreach (var Input in Inputs)
@ -1467,7 +1258,8 @@ namespace Jackett.Indexers
value = release.TVDBId.ToString();
break;
case "banner":
if(!string.IsNullOrWhiteSpace(value)) {
if (!string.IsNullOrWhiteSpace(value))
{
var bannerurl = resolvePath(value, searchUrlUri);
release.BannerUrl = bannerurl;
}
@ -1531,7 +1323,7 @@ namespace Jackett.Indexers
var PrevRow = Row.PreviousElementSibling;
string value = null;
if (PrevRow == null) // continue with parent
{
{
var Parent = Row.ParentElement;
if (Parent != null)
PrevRow = Parent.PreviousElementSibling;
@ -1557,7 +1349,7 @@ namespace Jackett.Indexers
PrevRow = Parent.PreviousElementSibling;
}
}
if (value == null && DateHeaders.Optional == false)
throw new Exception(string.Format("No date header row found for {0}", release.ToString()));
if (value != null)

View File

@ -20,11 +20,11 @@ namespace Jackett.Indexers
{
public class CinemaZ : AvistazTracker
{
public CinemaZ(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public CinemaZ(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "CinemaZ",
desc: "Part of the Avistaz network.",
link: "https://cinemaz.to/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -1,4 +1,4 @@
using CsQuery;
using CsQuery;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils.Clients;
@ -18,7 +18,7 @@ using Jackett.Utils;
namespace Jackett.Indexers
{
public class DanishBits : BaseIndexer
public class DanishBits : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public DanishBits(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public DanishBits(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "DanishBits",
description: "A danish closed torrent tracker",
link: "https://danishbits.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class Demonoid : BaseIndexer
public class Demonoid : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "account_handler.php"; } }
private string SearchUrl { get { return SiteLink + "files/?category={0}&subcategory=All&quality=All&seeded=2&to=1&query={1}&external=2"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Demonoid(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public Demonoid(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "Demonoid",
description: "Demonoid",
link: "https://www.demonoid.pw/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.IO;
namespace Jackett.Indexers
{
public class DigitalHive : BaseIndexer
public class DigitalHive : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "login.php?returnto=%2F"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public DigitalHive(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public DigitalHive(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "DigitalHive",
description: "DigitalHive is one of the oldest general trackers",
link: "https://www.digitalhive.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -18,7 +18,7 @@ using Jackett.Utils.Clients;
namespace Jackett.Indexers
{
class EliteTracker : BaseIndexer
class EliteTracker : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string BrowseUrl { get { return SiteLink + "browse.php"; } }
@ -29,11 +29,11 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public EliteTracker(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public EliteTracker(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Elite-Tracker",
description: "French Torrent Tracker",
link: "https://elite-tracker.net/",
manager: indexerManager,
configService: configService,
logger: logger,
p: protectionService,
client: webClient,

View File

@ -21,7 +21,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class FileList : BaseIndexer
public class FileList : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string BrowseUrl { get { return SiteLink + "browse.php"; } }
@ -32,12 +32,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public FileList(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "FileList",
description: "The best Romanian site.",
link: "http://filelist.ro/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -14,7 +14,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class FunFile : BaseIndexer
public class FunFile : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -25,12 +25,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public FunFile(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public FunFile(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "FunFile",
description: "A general tracker",
link: "https://www.funfile.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -20,7 +20,7 @@ using System.Threading;
namespace Jackett.Indexers
{
public class Fuzer : BaseIndexer
public class Fuzer : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "index.php?name=torrents&"; } }
private string LoginUrl { get { return SiteLink + "login.php"; } }
@ -32,11 +32,11 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Fuzer(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public Fuzer(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "Fuzer",
description: "Fuzer is a private torrent website with israeli torrents.",
link: "https://fuzer.me/",
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -22,7 +22,7 @@ namespace Jackett.Indexers
//
// Quick and dirty indexer for GFTracker.
//
public class GFTracker : BaseIndexer
public class GFTracker : BaseWebIndexer
{
private string StartPageUrl { get { return SiteLink + "login.php?returnto=%2F"; } }
private string LoginUrl { get { return SiteLink + "loginsite.php"; } }
@ -34,12 +34,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public GFTracker(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public GFTracker(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "GFTracker",
description: "Home of user happiness",
link: "https://www.thegft.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class GhostCity : BaseIndexer
public class GhostCity : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string BrowsePage { get { return SiteLink + "browse.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public GhostCity(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public GhostCity(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Ghost City",
description: "A German general tracker",
link: "http://ghostcity.dyndns.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
@ -18,7 +18,7 @@ using NLog;
namespace Jackett.Indexers
{
// ReSharper disable once InconsistentNaming
public class GimmePeers : BaseIndexer
public class GimmePeers : BaseWebIndexer
{
private string BrowseUrl => SiteLink + "browse.php";
private string LoginUrl => SiteLink + "takelogin.php";
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public GimmePeers(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public GimmePeers(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "GimmePeers",
description: "Formerly ILT",
link: "https://www.gimmepeers.com/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using AngleSharp.Parser.Html;
namespace Jackett.Indexers
{
public class HD4Free : BaseIndexer
public class HD4Free : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "ajax/initial_recall.php"; } }
private string LoginUrl { get { return SiteLink + "login.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public HD4Free(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public HD4Free(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "HD4Free",
description: "A HD trackers",
link: "https://hd4free.xyz/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class HDForever : GazelleTracker
{
public HDForever(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public HDForever(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "HD-Forever",
desc: null,
link: "https://hdf.world/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -11,11 +11,11 @@ namespace Jackett.Indexers
{
public class HDOnly : GazelleTracker
{
public HDOnly(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public HDOnly(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "HD-Only",
desc: null,
link: "https://hd-only.org/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -18,7 +18,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class HDSpace : BaseIndexer
public class HDSpace : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "index.php?page=login"; } }
private string SearchUrl { get { return SiteLink + "index.php?page=torrents&"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public HDSpace(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public HDSpace(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "HD-Space",
description: "Sharing The Universe",
link: "https://hd-space.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class HDTorrents : BaseIndexer
public class HDTorrents : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "torrents.php?"; } }
private string LoginUrl { get { return SiteLink + "login.php"; } }
@ -32,11 +32,11 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public HDTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public HDTorrents(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "HD-Torrents",
description: "HD-Torrents is a private torrent website with HD torrents and strict rules on their content.",
link: "https://hdts.ru/",// Of the accessible domains the .ru seems the most reliable. https://hdts.ru | https://hd-torrents.org | https://hd-torrents.net | https://hd-torrents.me
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -1,4 +1,4 @@
using Jackett.Models;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
@ -15,7 +15,7 @@ using System.Globalization;
namespace Jackett.Indexers
{
public class Hardbay : BaseIndexer
public class Hardbay : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } }
private string LoginUrl { get { return SiteLink + "api/v1/auth"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Hardbay(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public Hardbay(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "Hardbay",
description: null,
link: "https://hardbay.club/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class Hebits : BaseIndexer
public class Hebits : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string LoginPostUrl { get { return SiteLink + "takeloginAjax.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Hebits(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public Hebits(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "Hebits",
description: "The Israeli Tracker",
link: "https://hebits.net/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -1,4 +1,4 @@
using CsQuery;
using CsQuery;
using Jackett.Indexers;
using Jackett.Models;
using Jackett.Services;
@ -23,7 +23,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class Hounddawgs : BaseIndexer
public class Hounddawgs : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
@ -34,12 +34,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Hounddawgs(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public Hounddawgs(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "Hounddawgs",
description: "A danish closed torrent tracker",
link: "https://hounddawgs.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class HouseOfTorrents : BaseIndexer
public class HouseOfTorrents : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public HouseOfTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public HouseOfTorrents(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "House-of-Torrents",
description: "A general tracker",
link: "https://houseoftorrents.club/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -37,15 +37,15 @@ namespace Jackett.Indexers
void LoadFromSavedConfiguration(JToken jsonConfig);
void SaveConfig();
void Unconfigure();
Task<IEnumerable<ReleaseInfo>> ResultsForQuery(TorznabQuery query);
IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> input);
Task<byte[]> Download(Uri link);
IEnumerable<ReleaseInfo> CleanLinks(IEnumerable<ReleaseInfo> releases);
Uri UncleanLink(Uri link);
bool CanHandleQuery(TorznabQuery query);
}
public interface IWebIndexer : IIndexer
{
Task<byte[]> Download(Uri link);
}
}

View File

@ -19,7 +19,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class IPTorrents : BaseIndexer
public class IPTorrents : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string TakeLoginUrl { get { return SiteLink + "take_login.php"; } }
@ -32,12 +32,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public IPTorrents(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public IPTorrents(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "IPTorrents",
description: "Always a step ahead.",
link: "https://iptorrents.com/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -18,7 +18,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class ImmortalSeed : BaseIndexer
public class ImmortalSeed : BaseWebIndexer
{
private string BrowsePage { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -30,12 +30,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public ImmortalSeed(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public ImmortalSeed(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "ImmortalSeed",
description: "ImmortalSeed",
link: "http://immortalseed.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -1,9 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using CsQuery;
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Jackett.Services;
@ -13,10 +11,10 @@ using NLog;
namespace Jackett.Indexers.Meta
{
public abstract class BaseMetaIndexer : BaseIndexer
public abstract class BaseMetaIndexer : BaseWebIndexer
{
protected BaseMetaIndexer(string name, string description, IFallbackStrategyProvider fallbackStrategyProvider, IResultFilterProvider resultFilterProvider, IIndexerManagerService manager, IWebClient webClient, Logger logger, ConfigurationData configData, IProtectionService p, Func<IIndexer, bool> filter)
: base(name, "http://127.0.0.1/", description, manager, webClient, logger, configData, p, null, null)
protected BaseMetaIndexer(string name, string description, IFallbackStrategyProvider fallbackStrategyProvider, IResultFilterProvider resultFilterProvider, IIndexerConfigurationService configService, IWebClient webClient, Logger logger, ConfigurationData configData, IProtectionService p, Func<IIndexer, bool> filter)
: base(name, "http://127.0.0.1/", description, configService, webClient, logger, configData, p, null, null)
{
filterFunc = filter;
this.fallbackStrategyProvider = fallbackStrategyProvider;
@ -35,11 +33,12 @@ namespace Jackett.Indexers.Meta
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
IEnumerable<Task<IEnumerable<ReleaseInfo>>> supportedTasks = Indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
var indexers = validIndexers;
IEnumerable<Task<IEnumerable<ReleaseInfo>>> supportedTasks = indexers.Where(i => i.CanHandleQuery(query)).Select(i => i.ResultsForQuery(query)).ToList(); // explicit conversion to List to execute LINQ query
var fallbackStrategies = fallbackStrategyProvider.FallbackStrategiesForQuery(query);
var fallbackQueries = fallbackStrategies.Select(async f => await f.FallbackQueries()).SelectMany(t => t.Result);
var fallbackTasks = fallbackQueries.SelectMany(q => Indexers.Where(i => !i.CanHandleQuery(query) && i.CanHandleQuery(q)).Select(i => i.ResultsForQuery(q.Clone())));
var fallbackTasks = fallbackQueries.SelectMany(q => indexers.Where(i => !i.CanHandleQuery(query) && i.CanHandleQuery(q)).Select(i => i.ResultsForQuery(q.Clone())));
var tasks = supportedTasks.Concat(fallbackTasks.ToList()); // explicit conversion to List to execute LINQ query
var aggregateTask = Task.WhenAll(tasks);
@ -66,47 +65,36 @@ namespace Jackett.Indexers.Meta
return result;
}
public override Uri UncleanLink(Uri link)
public override TorznabCapabilities TorznabCaps
{
var indexer = GetOriginalIndexerForLink(link);
if (indexer != null)
return indexer.UncleanLink(link);
return base.UncleanLink(link);
get
{
return validIndexers.Select(i => i.TorznabCaps).Aggregate(new TorznabCapabilities(), TorznabCapabilities.Concat);
}
}
public override Task<byte[]> Download(Uri link)
public override bool IsConfigured
{
var indexer = GetOriginalIndexerForLink(link);
if (indexer != null)
return indexer.Download(link);
return base.Download(link);
get
{
return Indexers != null;
}
}
private IIndexer GetOriginalIndexerForLink(Uri link)
private IEnumerable<IIndexer> validIndexers
{
var prefix = string.Format("{0}://{1}", link.Scheme, link.Host);
var validIndexers = Indexers.Where(i => i.SiteLink.StartsWith(prefix, StringComparison.CurrentCulture));
if (validIndexers.Count() > 0)
return validIndexers.First();
get
{
if (Indexers == null)
return null;
return null;
return Indexers.Where(i => i.IsConfigured && filterFunc(i));
}
}
public IEnumerable<IIndexer> Indexers;
private Func<IIndexer, bool> filterFunc;
private IEnumerable<IIndexer> indexers;
public IEnumerable<IIndexer> Indexers {
get {
return indexers;
}
set {
indexers = value.Where(i => i.IsConfigured && filterFunc(i));
TorznabCaps = value.Select(i => i.TorznabCaps).Aggregate(new TorznabCapabilities(), TorznabCapabilities.Concat); ;
IsConfigured = true;
}
}
private IFallbackStrategyProvider fallbackStrategyProvider;
private IResultFilterProvider resultFilterProvider;
}

View File

@ -14,8 +14,8 @@ namespace Jackett.Indexers.Meta
{
class AggregateIndexer : BaseMetaIndexer
{
public AggregateIndexer(IFallbackStrategyProvider fallbackStrategyProvider, IResultFilterProvider resultFilterProvider, IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
: base("AggregateSearch", "This feed includes all configured trackers", fallbackStrategyProvider, resultFilterProvider, i, wc, l, new ConfigurationData(), ps, x => true)
public AggregateIndexer(IFallbackStrategyProvider fallbackStrategyProvider, IResultFilterProvider resultFilterProvider, IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base("AggregateSearch", "This feed includes all configured trackers", fallbackStrategyProvider, resultFilterProvider, configService, wc, l, new ConfigurationData(), ps, x => true)
{
}
}

View File

@ -19,7 +19,7 @@ using Jackett.Utils;
namespace Jackett.Indexers
{
public class MoreThanTV : BaseIndexer
public class MoreThanTV : BaseWebIndexer
{
private string LoginUrl => SiteLink + "login.php";
private string SearchUrl => SiteLink + "ajax.php?action=browse&searchstr=";
@ -28,13 +28,13 @@ namespace Jackett.Indexers
private ConfigurationDataBasicLogin ConfigData => (ConfigurationDataBasicLogin) configData;
public MoreThanTV(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
public MoreThanTV(IIndexerConfigurationService configService, IWebClient c, Logger l, IProtectionService ps)
: base(name: "MoreThanTV",
description: "ROMANIAN Private Torrent Tracker for TV / MOVIES, and the internal tracker for the release group DRACULA.",
link: "https://www.morethan.tv/",
caps: new TorznabCapabilities(TorznabCatType.TV,
TorznabCatType.Movies),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -21,7 +21,7 @@ using System.Globalization;
namespace Jackett.Indexers
{
public class Myanonamouse : BaseIndexer
public class Myanonamouse : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
private string SearchUrl { get { return SiteLink + "tor/js/loadSearch2.php"; } }
@ -32,7 +32,7 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Myanonamouse(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
public Myanonamouse(IIndexerConfigurationService configService, IWebClient c, Logger l, IProtectionService ps)
: base(name: "MyAnonamouse",
description: "Friendliness, Warmth and Sharing",
link: "https://www.myanonamouse.net/",
@ -42,7 +42,7 @@ namespace Jackett.Indexers
TorznabCatType.BooksEbook,
TorznabCatType.BooksMagazines,
TorznabCatType.BooksTechnical),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class NCore : BaseIndexer
public class NCore : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public NCore(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "nCore",
description: "A Hungarian private torrent site.",
link: "https://ncore.cc/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class NewRealWorld : BaseIndexer
public class NewRealWorld : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string BrowseUrl { get { return SiteLink + "browse.php"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public NewRealWorld(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public NewRealWorld(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "New Real World",
description: "A German general tracker.",
link: "http://nrw-tracker.eu/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -22,7 +22,7 @@ namespace Jackett.Indexers
/// <summary>s
/// Provider for Norbits Private Tracker
/// </summary>
public class Norbits : BaseIndexer
public class Norbits : BaseCachingWebIndexer
{
private string LoginUrl => SiteLink + "login.php";
private string LoginCheckUrl => SiteLink + "takelogin.php";
@ -39,13 +39,13 @@ namespace Jackett.Indexers
private CQ _fDom;
private ConfigurationDataNorbits ConfigData => (ConfigurationDataNorbits)configData;
public Norbits(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
public Norbits(IIndexerConfigurationService configService, IWebClient w, Logger l, IProtectionService ps)
: base(
name: "Norbits",
description: "Norbits",
link: "https://norbits.net/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,
@ -182,7 +182,7 @@ namespace Jackett.Indexers
var message = "Error during attempt !";
// Parse redirect header
var redirectTo = response.RedirectingTo;
// Oops, unable to login
Output("-> Login failed: " + message, "error");
throw new ExceptionWithConfigData("Login failed: " + message, configData);
@ -230,7 +230,7 @@ namespace Jackett.Indexers
var searchUrl = SearchUrl;
// Check login before performing a query
await CheckLogin();
await CheckLogin();
// Check cache first so we don't query the server (if search term used or not in dev mode)
if (!DevMode && !string.IsNullOrEmpty(exactSearchTerm))
@ -285,7 +285,7 @@ namespace Jackett.Indexers
else
{
// Check if no result
if(torrentRowList.Count == 0)
if (torrentRowList.Count == 0)
{
// No results found
Output("\nNo result found for your query, please try another search term ...\n", "info");
@ -314,7 +314,7 @@ namespace Jackett.Indexers
// Category
var categoryId = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last();
var categoryName = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("title");
var MainCat = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last();
var SubCat1 = "none";
var SubCat2 = "none";
@ -336,7 +336,7 @@ namespace Jackett.Indexers
// Seeders
var seeders = ParseUtil.CoerceInt(tRow.Find("td:eq(9)").Text());
Output("Seeders: " + seeders);
// Leechers
var leechers = ParseUtil.CoerceInt(tRow.Find("td:eq(10)").Text());
Output("Leechers: " + leechers);
@ -594,7 +594,8 @@ namespace Jackett.Indexers
.Select(f => new System.IO.FileInfo(f))
.Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
.ToList()
.ForEach(f => {
.ForEach(f =>
{
Output("Deleting cached file << " + f.Name + " >> ... done.");
f.Delete();
i++;
@ -605,7 +606,8 @@ namespace Jackett.Indexers
{
Output("-> Deleted " + i + " cached files during cleaning.");
}
else {
else
{
Output("-> Nothing deleted during cleaning.");
}
}

View File

@ -16,7 +16,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class PassThePopcorn : BaseIndexer
public class PassThePopcorn : BaseWebIndexer
{
private string LoginUrl { get { return "https://passthepopcorn.me/ajax.php?action=login"; } }
private string indexUrl { get { return "https://passthepopcorn.me/ajax.php?action=login"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public PassThePopcorn(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public PassThePopcorn(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "PassThePopcorn",
description: "PassThePopcorn",
link: "https://passthepopcorn.me/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
class PiXELHD : BaseIndexer
class PiXELHD : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string BrowseUrl { get { return SiteLink + "torrents.php"; } }
@ -32,12 +32,12 @@ namespace Jackett.Indexers
string input_username = null;
string input_password = null;
public PiXELHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public PiXELHD(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "PiXELHD",
description: null,
link: "https://pixelhd.me/",
caps: new TorznabCapabilities(),
manager: indexerManager,
configService: configService,
logger: logger,
p: protectionService,
client: webClient,

View File

@ -16,7 +16,7 @@ using System.Globalization;
namespace Jackett.Indexers
{
public class PirateTheNet : BaseIndexer
public class PirateTheNet : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "torrentsutils.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -30,12 +30,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public PirateTheNet(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public PirateTheNet(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "PirateTheNet",
description: "A movie tracker",
link: "http://piratethenet.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class Pretome : BaseIndexer
public class Pretome : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
private string LoginReferer { get { return SiteLink + "index.php?cat=1"; } }
@ -30,13 +30,13 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Pretome(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public Pretome(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "PreToMe",
description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
link: "https://pretome.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
client: wc,
manager: i,
configService: configService,
logger: l,
p: ps,
configData: new ConfigurationDataPinNumber())

View File

@ -18,11 +18,11 @@ namespace Jackett.Indexers
{
public class PrivateHD : AvistazTracker, IIndexer
{
public PrivateHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public PrivateHD(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "PrivateHD",
desc: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
link: "https://privatehd.to/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class Psytorrents : GazelleTracker
{
public Psytorrents(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public Psytorrents(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Psytorrents",
desc: null,
link: "https://psytorrents.info/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -16,7 +16,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class Rarbg : BaseIndexer
public class Rarbg : BaseWebIndexer
{
readonly static string defaultSiteLink = "https://torrentapi.org/";
@ -41,12 +41,12 @@ namespace Jackett.Indexers
private bool HasValidToken { get { return !string.IsNullOrEmpty(token) && lastTokenFetch > DateTime.Now - TOKEN_DURATION; } }
public Rarbg(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public Rarbg(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "RARBG",
description: null,
link: "https://rarbg.to/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class PassTheHeadphones : GazelleTracker
{
public PassTheHeadphones(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public PassTheHeadphones(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "Redacted",
desc: "A music tracker",
link: "https://redacted.ch/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -20,7 +20,7 @@ using System.Xml.Linq;
namespace Jackett.Indexers
{
public class RevolutionTT : BaseIndexer
public class RevolutionTT : BaseWebIndexer
{
private string LandingPageURL { get { return SiteLink + "login.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -36,12 +36,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public RevolutionTT(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public RevolutionTT(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "RevolutionTT",
description: "The Revolution has begun",
link: "https://revolutiontt.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Web;
namespace Jackett.Indexers
{
class SceneAccess : BaseIndexer
class SceneAccess : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login"; } }
private string SearchUrl { get { return SiteLink + "all?search={0}&method=2"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
public SceneAccess(IIndexerConfigurationService configService, IWebClient c, Logger l, IProtectionService ps)
: base(name: "SceneAccess",
description: "Your gateway to the scene",
link: "https://sceneaccess.eu/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class SceneFZ : BaseIndexer
public class SceneFZ : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public SceneFZ(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public SceneFZ(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "SceneFZ",
description: "Torrent tracker. Tracking over 50.000 torrent files.",
link: "http://scenefz.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class SceneTime : BaseIndexer
public class SceneTime : BaseWebIndexer
{
private string StartPageUrl { get { return SiteLink + "login.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public SceneTime(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public SceneTime(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "SceneTime",
description: "Always on time",
link: "https://www.scenetime.com/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -22,7 +22,7 @@ using System.Xml.XPath;
namespace Jackett.Indexers
{
public class Shazbat : BaseIndexer
public class Shazbat : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login"; } }
private string SearchUrl { get { return SiteLink + "search"; } }
@ -36,14 +36,14 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Shazbat(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps)
public Shazbat(IIndexerConfigurationService configService, IWebClient c, Logger l, IProtectionService ps)
: base(name: "Shazbat",
description: "Modern indexer",
link: "https://www.shazbat.tv/",
caps: new TorznabCapabilities(TorznabCatType.TV,
TorznabCatType.TVHD,
TorznabCatType.TVSD),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class ShowRSS : BaseIndexer
public class ShowRSS : BaseWebIndexer
{
private string SearchAllUrl { get { return SiteLink + "other/all.rss"; } }
@ -25,12 +25,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public ShowRSS(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "ShowRSS",
description: "showRSS is a service that allows you to keep track of your favorite TV shows",
link: "http://showrss.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -1,4 +1,4 @@
using CsQuery;
using CsQuery;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
@ -16,7 +16,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class SpeedCD : BaseIndexer
public class SpeedCD : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
private string SearchUrl { get { return SiteLink + "browse.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public SpeedCD(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public SpeedCD(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "Speed.cd",
description: "Your home now!",
link: "https://speed.cd/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Globalization;
namespace Jackett.Indexers
{
public class Superbits : BaseIndexer
public class Superbits : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } }
private string LoginUrl { get { return SiteLink + "api/v1/auth"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Superbits(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public Superbits(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "Superbits",
description: null,
link: "https://superbits.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -1,4 +1,4 @@
using Jackett.Models;
using Jackett.Models;
using Jackett.Services;
using Jackett.Utils;
using Jackett.Utils.Clients;
@ -15,7 +15,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class T411 : BaseIndexer
public class T411 : BaseWebIndexer
{
const string ApiUrl = "https://api.t411.al";
const string AuthUrl = ApiUrl + "/auth";
@ -32,12 +32,12 @@ namespace Jackett.Indexers
private Dictionary<int, List<int>> _mediaCategoryMapping = new Dictionary<int, List<int>>();
public T411(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public T411(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "T411",
description: "French Torrent Tracker",
link: "https://t411.al/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -21,7 +21,7 @@ using System.Xml.Linq;
namespace Jackett.Indexers
{
public class TVChaosUK : BaseIndexer
public class TVChaosUK : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string GetRSSKeyUrl { get { return SiteLink + "getrss.php"; } }
@ -36,12 +36,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TVChaosUK(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public TVChaosUK(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "TV Chaos",
description: "Total Chaos",
link: "https://www.tvchaosuk.com/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class TVVault : BaseIndexer
public class TVVault : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "login.php"; } }
string BrowseUrl { get { return SiteLink + "torrents.php"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TVVault(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public TVVault(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "TV-Vault",
description: "A TV tracker for old shows.",
link: "https://tv-vault.me/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class TehConnection : BaseIndexer
public class TehConnection : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string indexUrl { get { return SiteLink + "index.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TehConnection(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public TehConnection(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "TehConnection",
description: "Working towards providing a well-seeded archive of all available digital forms of cinema and film in their highest possible quality",
link: "https://tehconnection.eu/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class TorrentBytes : BaseIndexer
public class TorrentBytes : BaseWebIndexer
{
private string BrowseUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
@ -30,12 +30,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentBytes(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public TorrentBytes(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "TorrentBytes",
description: "A decade of torrentbytes",
link: "https://www.torrentbytes.net/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class TorrentDay : BaseIndexer
public class TorrentDay : BaseWebIndexer
{
private string StartPageUrl { get { return SiteLink + "login.php"; } }
private string LoginUrl { get { return SiteLink + "tak3login.php"; } }
@ -44,12 +44,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public TorrentDay(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "TorrentDay",
description: "TorrentDay",
link: "https://torrentday.it/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class TorrentHeaven : BaseIndexer
public class TorrentHeaven : BaseWebIndexer
{
string IndexUrl { get { return SiteLink + "index.php"; } }
string LoginCompleteUrl { get { return SiteLink + "index.php?strWebValue=account&strWebAction=login_complete&ancestry=verify"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentHeaven(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public TorrentHeaven(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "TorrentHeaven",
description: "A German general tracker.",
link: "https://torrentheaven.myfqdn.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,
@ -44,59 +44,53 @@ namespace Jackett.Indexers
Language = "de-de";
Type = "private";
AddCategoryMapping(1, TorznabCatType.PCGames); // GAMES/PC
AddCategoryMapping(3, TorznabCatType.Console); // GAMES/Sonstige
AddCategoryMapping(59, TorznabCatType.ConsolePS4); // GAMES/PlayStation
AddCategoryMapping(60, TorznabCatType.ConsolePSP); // GAMES/PSP
AddCategoryMapping(63, TorznabCatType.ConsoleWii); // GAMES/Wii
AddCategoryMapping(67, TorznabCatType.ConsoleXbox360); // GAMES/XBOX 360
AddCategoryMapping(68, TorznabCatType.PCPhoneOther); // GAMES/PDA / Handy
AddCategoryMapping(72, TorznabCatType.ConsoleNDS); // GAMES/NDS
AddCategoryMapping(1, TorznabCatType.PCGames); // GAMES/PC
AddCategoryMapping(3, TorznabCatType.Console); // GAMES/Sonstige
AddCategoryMapping(59, TorznabCatType.ConsolePS4); // GAMES/PlayStation
AddCategoryMapping(60, TorznabCatType.ConsolePSP); // GAMES/PSP
AddCategoryMapping(63, TorznabCatType.ConsoleWii); // GAMES/Wii
AddCategoryMapping(67, TorznabCatType.ConsoleXbox360); // GAMES/XBOX 360
AddCategoryMapping(68, TorznabCatType.PCPhoneOther); // GAMES/PDA / Handy
AddCategoryMapping(72, TorznabCatType.ConsoleNDS); // GAMES/NDS
AddCategoryMapping(7 , TorznabCatType.MoviesDVD); // MOVIES/DVD
AddCategoryMapping(8, TorznabCatType.MoviesSD); // MOVIES/SD
AddCategoryMapping(37, TorznabCatType.MoviesDVD); // MOVIES/DVD Spezial
AddCategoryMapping(41, TorznabCatType.MoviesForeign); // MOVIES/International
AddCategoryMapping(7, TorznabCatType.MoviesDVD); // MOVIES/DVD
AddCategoryMapping(8, TorznabCatType.MoviesSD); // MOVIES/SD
AddCategoryMapping(37, TorznabCatType.MoviesDVD); // MOVIES/DVD Spezial
AddCategoryMapping(41, TorznabCatType.MoviesForeign); // MOVIES/International
AddCategoryMapping(101, TorznabCatType.MoviesHD); // MOVIES/720p
AddCategoryMapping(102, TorznabCatType.MoviesHD); // MOVIES/1080p
AddCategoryMapping(103, TorznabCatType.MoviesHD); // MOVIES/AVCHD
AddCategoryMapping(104, TorznabCatType.MoviesBluRay); // MOVIES/Bluray
AddCategoryMapping(106, TorznabCatType.Movies3D); // MOVIES/3D
AddCategoryMapping(14, TorznabCatType.Audio); // AUDIO/Musik
AddCategoryMapping(15, TorznabCatType.AudioAudiobook); // AUDIO/Hörbücher
AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // AUDIO/Hörspiele
AddCategoryMapping(36, TorznabCatType.AudioLossless); // AUDIO/Flac
AddCategoryMapping(42, TorznabCatType.AudioOther); // AUDIO/Soundtracks
AddCategoryMapping(58, TorznabCatType.AudioVideo); // AUDIO/Musikvideos
AddCategoryMapping(14, TorznabCatType.Audio); // AUDIO/Musik
AddCategoryMapping(15, TorznabCatType.AudioAudiobook); // AUDIO/Hörbücher
AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // AUDIO/Hörspiele
AddCategoryMapping(36, TorznabCatType.AudioLossless); // AUDIO/Flac
AddCategoryMapping(42, TorznabCatType.AudioOther); // AUDIO/Soundtracks
AddCategoryMapping(58, TorznabCatType.AudioVideo); // AUDIO/Musikvideos
AddCategoryMapping(18, TorznabCatType.TVSD); // TV/Serien SD
AddCategoryMapping(19, TorznabCatType.TVHD); // TV/Serien HD 720p
AddCategoryMapping(20, TorznabCatType.TVHD); // TV/Serien HD 1080p
AddCategoryMapping(49, TorznabCatType.TVSD); // TV/Serien DVD
AddCategoryMapping(51, TorznabCatType.TVDocumentary); // TV/Doku SD
AddCategoryMapping(52, TorznabCatType.TVDocumentary); // TV/Doku HD
AddCategoryMapping(53, TorznabCatType.TV); // TV/Serien Complete Packs
AddCategoryMapping(54, TorznabCatType.TVSport); // TV/Sport
AddCategoryMapping(66, TorznabCatType.TVFOREIGN); // TV/International
AddCategoryMapping(22, TorznabCatType.Books); // MISC/EBooks
AddCategoryMapping(24, TorznabCatType.Other); // MISC/Sonstiges
AddCategoryMapping(25, TorznabCatType.Other); // MISC/Tonspuren
AddCategoryMapping(18, TorznabCatType.TVSD); // TV/Serien SD
AddCategoryMapping(19, TorznabCatType.TVHD); // TV/Serien HD 720p
AddCategoryMapping(20, TorznabCatType.TVHD); // TV/Serien HD 1080p
AddCategoryMapping(49, TorznabCatType.TVSD); // TV/Serien DVD
AddCategoryMapping(51, TorznabCatType.TVDocumentary); // TV/Doku SD
AddCategoryMapping(52, TorznabCatType.TVDocumentary); // TV/Doku HD
AddCategoryMapping(53, TorznabCatType.TV); // TV/Serien Complete Packs
AddCategoryMapping(54, TorznabCatType.TVSport); // TV/Sport
AddCategoryMapping(66, TorznabCatType.TVFOREIGN); // TV/International
AddCategoryMapping(22, TorznabCatType.Books); // MISC/EBooks
AddCategoryMapping(24, TorznabCatType.Other); // MISC/Sonstiges
AddCategoryMapping(25, TorznabCatType.Other); // MISC/Tonspuren
AddCategoryMapping(108, TorznabCatType.TVAnime); // MISC/Anime
AddCategoryMapping(28, TorznabCatType.PC); // APPLICATIONS/PC
AddCategoryMapping(29, TorznabCatType.PCPhoneOther); // APPLICATIONS/Mobile
AddCategoryMapping(30, TorznabCatType.PC); // APPLICATIONS/Sonstige
AddCategoryMapping(70, TorznabCatType.PC); // APPLICATIONS/Linux
AddCategoryMapping(71, TorznabCatType.PCMac); // APPLICATIONS/Mac
}
AddCategoryMapping(28, TorznabCatType.PC); // APPLICATIONS/PC
AddCategoryMapping(29, TorznabCatType.PCPhoneOther); // APPLICATIONS/Mobile
AddCategoryMapping(30, TorznabCatType.PC); // APPLICATIONS/Sonstige
AddCategoryMapping(70, TorznabCatType.PC); // APPLICATIONS/Linux
AddCategoryMapping(71, TorznabCatType.PCMac); // APPLICATIONS/Mac
public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false)
{
base.LoadValuesFromJson(jsonConfig, useProtectionService);
// add self signed cert to trusted certs
webclient.AddTrustedCertificate(new Uri(SiteLink).Host, certificateHash);
}
@ -105,7 +99,8 @@ namespace Jackett.Indexers
var loginPage = await RequestStringWithCookies(IndexUrl, string.Empty);
CQ dom = loginPage.Content;
CQ qCaptchaImg = dom.Find("td.tablea > img").First();
if(qCaptchaImg.Length == 1) {
if (qCaptchaImg.Length == 1)
{
var CaptchaUrl = SiteLink + qCaptchaImg.Attr("src");
var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies);
configData.CaptchaImage.Value = captchaImage.Content;
@ -121,7 +116,7 @@ namespace Jackett.Indexers
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
{
LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string>
{
{ "strWebAction", "login" },
@ -142,7 +137,7 @@ namespace Jackett.Indexers
{
CQ dom = result.Content;
var errorMessage = dom["table > tbody > tr > td[valign=top][width=100%]"].Html();
if(errorMessage.Length == 0)
if (errorMessage.Length == 0)
errorMessage = result.Content;
throw new ExceptionWithConfigData(errorMessage, configData);
}
@ -166,7 +161,7 @@ namespace Jackett.Indexers
TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments);
var releases = new List<ReleaseInfo>();
var searchString = query.GetQueryString();
var searchUrl = IndexUrl;
var queryCollection = new NameValueCollection();
@ -236,7 +231,7 @@ namespace Jackett.Indexers
else if (dateStrParts[0] == "Gestern")
dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStrParts[1]) - TimeSpan.FromDays(1);
else
dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStrParts[0]+ dateStrParts[1], "dd.MM.yyyyHH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStrParts[0] + dateStrParts[1], "dd.MM.yyyyHH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified);
DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz);
release.PublishDate = pubDateUtc.ToLocalTime();

View File

@ -18,7 +18,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class TorrentLeech : BaseIndexer
public class TorrentLeech : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "user/account/login/"; } }
private string SearchUrl { get { return SiteLink + "torrents/browse/index/"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentLeech(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps)
public TorrentLeech(IIndexerConfigurationService configService, Logger l, IWebClient wc, IProtectionService ps)
: base(name: "TorrentLeech",
description: "This is what happens when you seed",
link: "https://www.torrentleech.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class TorrentNetwork : BaseIndexer
public class TorrentNetwork : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "takelogin.php"; } }
string BrowseUrl { get { return SiteLink + "browse.php"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentNetwork(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public TorrentNetwork(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Torrent Network",
description: "A German general tracker.",
link: "https://tntracker.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -17,7 +17,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class TorrentSyndikat : BaseIndexer
public class TorrentSyndikat : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "eing2.php"; } }
@ -30,12 +30,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TorrentSyndikat(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public TorrentSyndikat(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "Torrent-Syndikat",
description: "A German general tracker",
link: "https://torrent-syndikat.org/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -18,7 +18,7 @@ using System.Web;
namespace Jackett.Indexers
{
public class Torrentech : BaseIndexer
public class Torrentech : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "index.php?act=Login&CODE=01&CookieDate=1"; } }
string IndexUrl { get { return SiteLink + "index.php"; } }
@ -29,12 +29,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Torrentech(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public Torrentech(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Torrentech",
description: null,
link: "https://www.torrentech.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -16,7 +16,7 @@ using System.Text.RegularExpressions;
namespace Jackett.Indexers
{
public class TransmitheNet : BaseIndexer
public class TransmitheNet : BaseWebIndexer
{
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php?action=basic&order_by=time&order_way=desc&search_type=0&taglist=&tags_type=0"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public TransmitheNet(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps)
public TransmitheNet(IIndexerConfigurationService configService, Logger l, IWebClient c, IProtectionService ps)
: base(name: "Nebulance",
description: " At Nebulance we will change the way you think about TV",
link: "https://nebulance.io/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: c,
logger: l,
p: ps,

View File

@ -19,7 +19,7 @@ using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class Trezzor : BaseIndexer
public class Trezzor : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "prihlasenie.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php?"; } }
@ -31,12 +31,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public Trezzor(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public Trezzor(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "Trezzor",
description: "SK/CZ Tracker.",
link: "https://tracker.czech-server.com/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -21,7 +21,7 @@ namespace Jackett.Indexers
/// <summary>
/// Provider for WiHD Private French Tracker
/// </summary>
public class WiHD : BaseIndexer
public class WiHD : BaseCachingWebIndexer
{
private string LoginUrl { get { return SiteLink + "login"; } }
private string LoginCheckUrl { get { return SiteLink + "login_check"; } }
@ -40,13 +40,13 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public WiHD(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
public WiHD(IIndexerConfigurationService configService, IWebClient w, Logger l, IProtectionService ps)
: base(
name: "WiHD",
description: "Your World in High Definition",
link: "http://world-in-hd.net/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,
@ -110,7 +110,8 @@ namespace Jackett.Indexers
// emulatedBrowserHeaders.Add("Accept-Encoding", "gzip, deflate");
// If we want to simulate a browser
if (ConfigData.Browser.Value) {
if (ConfigData.Browser.Value)
{
// Clean headers
emulatedBrowserHeaders.Clear();
@ -150,7 +151,8 @@ namespace Jackett.Indexers
};
// Do the login
var request = new Utils.Clients.WebRequest(){
var request = new Utils.Clients.WebRequest()
{
Cookies = loginPage.Cookies,
PostData = pairs,
Referer = LoginUrl,
@ -165,7 +167,7 @@ namespace Jackett.Indexers
var response = await RequestLoginAndFollowRedirect(LoginCheckUrl, pairs, loginPage.Cookies, true, null, null);
// Test if we are logged in
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout"), () =>
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout"), () =>
{
// Oops, unable to login
output("-> Login failed", "error");
@ -236,7 +238,8 @@ namespace Jackett.Indexers
// Calculate numbers of pages available for this search query (Based on number results and number of torrents on first page)
pageLinkCount = (int)Math.Ceiling((double)nbResults / firstPageRows.Length);
}
else {
else
{
// Check if we have a minimum of one result
if (firstPageRows.Length >= 1)
{
@ -416,7 +419,7 @@ namespace Jackett.Indexers
foreach (string category in categoriesList)
{
// If last, build !
if(categoriesList.Last() == category)
if (categoriesList.Last() == category)
{
// Adding previous categories to URL with latest category
parameters.Add(Uri.EscapeDataString("subcat[]"), category + categories);
@ -557,7 +560,8 @@ namespace Jackett.Indexers
.Select(f => new System.IO.FileInfo(f))
.Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
.ToList()
.ForEach(f => {
.ForEach(f =>
{
output("Deleting cached file << " + f.Name + " >> ... done.");
f.Delete();
i++;
@ -568,7 +572,8 @@ namespace Jackett.Indexers
{
output("-> Deleted " + i + " cached files during cleaning.");
}
else {
else
{
output("-> Nothing deleted during cleaning.");
}
}
@ -580,7 +585,7 @@ namespace Jackett.Indexers
private void latencyNow()
{
// Need latency ?
if(Latency)
if (Latency)
{
// Generate a random value in our range
var random = new Random(DateTime.Now.Millisecond);
@ -620,10 +625,10 @@ namespace Jackett.Indexers
private DateTime agoToDate(IList<string> clockList)
{
DateTime release = DateTime.Now;
foreach(var ago in clockList)
foreach (var ago in clockList)
{
// Check for years
if(ago.Contains("Années") || ago.Contains("Année"))
if (ago.Contains("Années") || ago.Contains("Année"))
{
// Number of years to remove
int years = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value);
@ -737,7 +742,7 @@ namespace Jackett.Indexers
if (dictionary.ContainsKey(media))
{
// Due to a bug on tracker side, check for a specific id/name as image is same for TV/Anime BR 3D
if(media == "565af82d1fd35761568b4592" && name == "Animations - Bluray 3D")
if (media == "565af82d1fd35761568b4592" && name == "Animations - Bluray 3D")
{
// If it's an Anime BR 3D
return "565af82d1fd35761568b45a6";
@ -763,7 +768,7 @@ namespace Jackett.Indexers
private void output(string message, string level = "debug")
{
// Check if we are in dev mode
if(DevMode)
if (DevMode)
{
// Output message to console
Console.WriteLine(message);
@ -777,7 +782,7 @@ namespace Jackett.Indexers
goto case "debug";
case "debug":
// Only if Debug Level Enabled on Jackett
if(Engine.Logger.IsDebugEnabled)
if (Engine.Logger.IsDebugEnabled)
{
logger.Debug(message);
}

View File

@ -19,7 +19,7 @@ using static Jackett.Models.IndexerConfig.ConfigurationData;
namespace Jackett.Indexers
{
public class XSpeeds : BaseIndexer
public class XSpeeds : BaseWebIndexer
{
string LandingUrl => SiteLink + "login.php";
string LoginUrl => SiteLink + "takelogin.php";
@ -35,12 +35,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public XSpeeds(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public XSpeeds(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "XSpeeds",
description: "XSpeeds",
link: "https://www.xspeeds.eu/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -20,7 +20,7 @@ namespace Jackett.Indexers
/// <summary>
/// Provider for Xthor Private French Tracker
/// </summary>
public class Xthor : BaseIndexer
public class Xthor : BaseCachingWebIndexer
{
private static string ApiEndpoint => "https://api.xthor.bz/";
private string TorrentCommentUrl => TorrentDescriptionUrl;
@ -31,13 +31,13 @@ namespace Jackett.Indexers
public Dictionary<string, string> EmulatedBrowserHeaders { get; } = new Dictionary<string, string>();
private ConfigurationDataXthor ConfigData => (ConfigurationDataXthor)configData;
public Xthor(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps)
public Xthor(IIndexerConfigurationService configService, IWebClient w, Logger l, IProtectionService ps)
: base(
name: "Xthor",
description: "General French Private Tracker",
link: "https://xthor.bz/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,
@ -115,9 +115,9 @@ namespace Jackett.Indexers
/// </summary>
/// <param name="configJson">Our params in Json</param>
/// <returns>Configuration state</returns>
#pragma warning disable 1998
#pragma warning disable 1998
public override async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson)
#pragma warning restore 1998
#pragma warning restore 1998
{
// Provider not yet configured
IsConfigured = false;
@ -159,7 +159,7 @@ namespace Jackett.Indexers
var searchTerm = query.GetQueryString();
// Check cache first so we don't query the server (if search term used or not in dev mode)
if(!DevMode && !string.IsNullOrEmpty(searchTerm))
if (!DevMode && !string.IsNullOrEmpty(searchTerm))
{
lock (cache)
{
@ -195,7 +195,8 @@ namespace Jackett.Indexers
{
// Mapping data
Category = MapTrackerCatToNewznab(torrent.category.ToString()),
Title = torrent.name, Seeders = torrent.seeders,
Title = torrent.name,
Seeders = torrent.seeders,
Peers = torrent.seeders + torrent.leechers,
MinimumRatio = 1,
MinimumSeedTime = 345600,
@ -453,13 +454,13 @@ namespace Jackett.Indexers
private void CleanCacheStorage(bool force = false)
{
// Check cleaning method
if(force)
if (force)
{
// Deleting Provider Storage folder and all files recursively
Output("\nDeleting Provider Storage folder and all files recursively ...");
// Check if directory exist
if(System.IO.Directory.Exists(Directory))
if (System.IO.Directory.Exists(Directory))
{
// Delete storage directory of provider
System.IO.Directory.Delete(Directory, true);
@ -480,17 +481,20 @@ namespace Jackett.Indexers
.Select(f => new System.IO.FileInfo(f))
.Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)))
.ToList()
.ForEach(f => {
.ForEach(f =>
{
Output("Deleting cached file << " + f.Name + " >> ... done.");
f.Delete();
i++;
});
});
// Inform on what was cleaned during process
if(i > 0) {
if (i > 0)
{
Output("-> Deleted " + i + " cached files during cleaning.");
}
else {
else
{
Output("-> Nothing deleted during cleaning.");
}
}
@ -504,7 +508,7 @@ namespace Jackett.Indexers
private void Output(string message, string level = "debug")
{
// Check if we are in dev mode
if(DevMode)
if (DevMode)
{
// Output message to console
Console.WriteLine(message);

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class CGPeers : GazelleTracker
{
public CGPeers(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public CGPeers(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "CGPeers",
desc: null,
link: "https://www.cgpeers.com/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -15,7 +15,7 @@ using System.Text;
namespace Jackett.Indexers
{
public class myAmity : BaseIndexer
public class myAmity : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "account-login.php"; } }
string BrowseUrl { get { return SiteLink + "torrents-search.php"; } }
@ -26,12 +26,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public myAmity(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public myAmity(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "myAmity",
description: "A German general tracker.",
link: "https://ttv2.myamity.info/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -8,11 +8,11 @@ namespace Jackett.Indexers
{
public class notwhatcd : GazelleTracker
{
public notwhatcd(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService)
public notwhatcd(IIndexerConfigurationService configService, IWebClient webClient, Logger logger, IProtectionService protectionService)
: base(name: "notwhat.cd",
desc: "A music tracker",
link: "https://notwhat.cd/",
indexerManager: indexerManager,
configService: configService,
logger: logger,
protectionService: protectionService,
webClient: webClient

View File

@ -14,7 +14,7 @@ using AngleSharp.Parser.Html;
namespace Jackett.Indexers
{
public class RuTracker : BaseIndexer
public class RuTracker : BaseWebIndexer
{
string LoginUrl { get { return SiteLink + "forum/login.php"; } }
string SearchUrl { get { return SiteLink + "forum/tracker.php"; } }
@ -28,12 +28,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public RuTracker(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps)
public RuTracker(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps)
: base(name: "RuTracker",
description: null,
link: "https://rutracker.org/",
caps: TorznabUtil.CreateDefaultTorznabTVCaps(),
manager: i,
configService: configService,
client: wc,
logger: l,
p: ps,

View File

@ -15,7 +15,7 @@ using System.Collections.Specialized;
namespace Jackett.Indexers
{
public class x264 : BaseIndexer
public class x264 : BaseWebIndexer
{
private string SearchUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "login.php"; } }
@ -27,12 +27,12 @@ namespace Jackett.Indexers
set { base.configData = value; }
}
public x264(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps)
public x264(IIndexerConfigurationService configService, Logger l, IWebClient w, IProtectionService ps)
: base(name: "x264",
description: "A movie/TV tracker",
link: "https://x264.me/",
caps: new TorznabCapabilities(),
manager: i,
configService: configService,
client: w,
logger: l,
p: ps,

View File

@ -377,6 +377,8 @@
<Compile Include="Indexers\Meta\ResultFilters.cs" />
<Compile Include="Services\ImdbResolver.cs" />
<Compile Include="Utils\Extensions.cs" />
<Compile Include="Services\IndexerConfigurationService.cs" />
<Compile Include="Models\IndexerDefinition.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
@ -573,8 +575,10 @@
<MonoDevelop>
<Properties>
<Policies>
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
<TextStylePolicy TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" FileWidth="80" TabsToSpaces="True" scope="text/plain">
<inheritsSet />
<inheritsScope />
</TextStylePolicy>
</Policies>
</Properties>
</MonoDevelop>

View File

@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
namespace Jackett.Models
{
// A Dictionary allowing the same key multiple times
public class KeyValuePairList : List<KeyValuePair<string, selectorBlock>>, IDictionary<string, selectorBlock>
{
public selectorBlock this[string key]
{
get
{
throw new NotImplementedException();
}
set
{
base.Add(new KeyValuePair<string, selectorBlock>(key, value));
}
}
public ICollection<string> Keys
{
get
{
throw new NotImplementedException();
}
}
public ICollection<selectorBlock> Values
{
get
{
throw new NotImplementedException();
}
}
public void Add(string key, selectorBlock value)
{
base.Add(new KeyValuePair<string, selectorBlock>(key, value));
}
public bool ContainsKey(string key)
{
throw new NotImplementedException();
}
public bool Remove(string key)
{
throw new NotImplementedException();
}
public bool TryGetValue(string key, out selectorBlock value)
{
throw new NotImplementedException();
}
}
// Cardigann yaml classes
public class IndexerDefinition
{
public string Site { get; set; }
public List<settingsField> Settings { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public string Language { get; set; }
public string Encoding { get; set; }
public List<string> Links { get; set; }
public List<string> Certificates { get; set; }
public capabilitiesBlock Caps { get; set; }
public loginBlock Login { get; set; }
public ratioBlock Ratio { get; set; }
public searchBlock Search { get; set; }
public downloadBlock Download { get; set; }
// IndexerDefinitionStats not needed/implemented
}
public class settingsField
{
public string Name { get; set; }
public string Type { get; set; }
public string Label { get; set; }
public string Default { get; set; }
public Dictionary<string, string> Options { get; set; }
}
public class CategorymappingBlock
{
public string id { get; set; }
public string cat { get; set; }
public string desc { get; set; }
}
public class capabilitiesBlock
{
public Dictionary<string, string> Categories { get; set; }
public List<CategorymappingBlock> Categorymappings { get; set; }
public Dictionary<string, List<string>> Modes { get; set; }
}
public class captchaBlock
{
public string Type { get; set; }
public string Image { get; set; }
public string Input { get; set; }
}
public class loginBlock
{
public string Path { get; set; }
public string Submitpath { get; set; }
public List<string> Cookies { get; set; }
public string Method { get; set; }
public string Form { get; set; }
public bool Selectors { get; set; } = false;
public Dictionary<string, string> Inputs { get; set; }
public Dictionary<string, selectorBlock> Selectorinputs { get; set; }
public Dictionary<string, selectorBlock> Getselectorinputs { get; set; }
public List<errorBlock> Error { get; set; }
public pageTestBlock Test { get; set; }
public captchaBlock Captcha { get; set; }
}
public class errorBlock
{
public string Path { get; set; }
public string Selector { get; set; }
public selectorBlock Message { get; set; }
}
public class selectorBlock
{
public string Selector { get; set; }
public bool Optional { get; set; } = false;
public string Text { get; set; }
public string Attribute { get; set; }
public string Remove { get; set; }
public List<filterBlock> Filters { get; set; }
public Dictionary<string, string> Case { get; set; }
}
public class filterBlock
{
public string Name { get; set; }
public dynamic Args { get; set; }
}
public class pageTestBlock
{
public string Path { get; set; }
public string Selector { get; set; }
}
public class ratioBlock : selectorBlock
{
public string Path { get; set; }
}
public class searchBlock
{
public string Path { get; set; }
public List<searchPathBlock> Paths { get; set; }
public Dictionary<string, List<string>> Headers { get; set; }
public List<filterBlock> Keywordsfilters { get; set; }
public Dictionary<string, string> Inputs { get; set; }
public List<errorBlock> Error { get; set; }
public rowsBlock Rows { get; set; }
public KeyValuePairList Fields { get; set; }
}
public class rowsBlock : selectorBlock
{
public int After { get; set; }
//public string Remove { get; set; } // already inherited
public selectorBlock Dateheaders { get; set; }
}
public class searchPathBlock : requestBlock
{
public List<string> Categories { get; set; }
public bool Inheritinputs { get; set; } = true;
}
public class requestBlock
{
public string Path { get; set; }
public string Method { get; set; }
public Dictionary<string, string> Inputs { get; set; }
}
public class downloadBlock
{
public string Selector { get; set; }
public string Method { get; set; }
public requestBlock Before { get; set; }
}
}

View File

@ -0,0 +1,154 @@
using System;
using System.IO;
using Jackett.Indexers;
using Newtonsoft.Json.Linq;
using NLog;
namespace Jackett.Services
{
public interface IIndexerConfigurationService
{
void Load(IIndexer indexer);
void Save(IIndexer indexer, JToken config);
void Delete(IIndexer indexer);
}
public class IndexerConfigurationService : IIndexerConfigurationService
{
//public override void LoadFromSavedConfiguration(JToken jsonConfig)
//{
// if (jsonConfig is JObject)
// {
// configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
// configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
// IsConfigured = true;
// SaveConfig();
// return;
// }
// base.LoadFromSavedConfiguration(jsonConfig);
//}
public IndexerConfigurationService(IConfigurationService configService, Logger logger)
{
this.configService = configService;
this.logger = logger;
}
public void Delete(IIndexer indexer)
{
var configFilePath = GetIndexerConfigFilePath(indexer);
File.Delete(configFilePath);
}
public void Load(IIndexer idx)
{
var configFilePath = GetIndexerConfigFilePath(idx);
if (File.Exists(configFilePath))
{
try
{
var fileStr = File.ReadAllText(configFilePath);
var jsonString = JToken.Parse(fileStr);
idx.LoadFromSavedConfiguration(jsonString);
}
catch (Exception ex)
{
logger.Error(ex, "Failed loading configuration for {0}, trying backup", idx.DisplayName);
var configFilePathBak = configFilePath + ".bak";
if (File.Exists(configFilePathBak))
{
try
{
var fileStrBak = File.ReadAllText(configFilePathBak);
var jsonStringBak = JToken.Parse(fileStrBak);
idx.LoadFromSavedConfiguration(jsonStringBak);
logger.Info("Successfully loaded backup config for {0}", idx.DisplayName);
idx.SaveConfig();
}
catch (Exception exbak)
{
logger.Error(exbak, "Failed loading backup configuration for {0}, you must reconfigure this indexer", idx.DisplayName);
}
}
else
{
logger.Error(ex, "Failed loading backup configuration for {0} (no backup available), you must reconfigure this indexer", idx.DisplayName);
}
}
}
}
public void Save(IIndexer indexer, JToken obj)
{
lock (configWriteLock)
{
var uID = Guid.NewGuid().ToString("N");
var configFilePath = GetIndexerConfigFilePath(indexer);
var configFilePathBak = configFilePath + ".bak";
var configFilePathTmp = configFilePath + "." + uID + ".tmp";
var content = obj.ToString();
logger.Debug(string.Format("Saving new config file: {0}", configFilePathTmp));
if (string.IsNullOrWhiteSpace(content))
{
throw new Exception(string.Format("New config content for {0} is empty, please report this bug.", indexer.ID));
}
if (content.Contains("\x00"))
{
throw new Exception(string.Format("New config content for {0} contains 0x00, please report this bug. Content: {1}", indexer.ID, content));
}
// make sure the config directory exists
if (!Directory.Exists(configService.GetIndexerConfigDir()))
Directory.CreateDirectory(configService.GetIndexerConfigDir());
// create new temporary config file
File.WriteAllText(configFilePathTmp, content);
var fileInfo = new FileInfo(configFilePathTmp);
if (fileInfo.Length == 0)
{
throw new Exception(string.Format("New config file {0} is empty, please report this bug.", configFilePathTmp));
}
// create backup file
File.Delete(configFilePathBak);
if (File.Exists(configFilePath))
{
try
{
File.Move(configFilePath, configFilePathBak);
}
catch (IOException ex)
{
logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePath, configFilePathBak, ex.ToString()));
}
}
// replace the actual config file
File.Delete(configFilePath);
try
{
File.Move(configFilePathTmp, configFilePath);
}
catch (IOException ex)
{
logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePathTmp, configFilePath, ex.ToString()));
}
}
}
private string GetIndexerConfigFilePath(IIndexer indexer)
{
return Path.Combine(configService.GetIndexerConfigDir(), indexer.ID + ".json");
}
private IConfigurationService configService;
private Logger logger;
private static readonly object configWriteLock = new object();
}
}

Some files were not shown because too many files have changed in this diff Show More