Abstracted & unified indexer config logic (logins are now saved), implemented indexer config migrations, fixed nCore implementation

This commit is contained in:
unknown
2015-08-03 15:38:45 -06:00
parent 5dc7ebaba5
commit 0a8d9d3447
54 changed files with 869 additions and 740 deletions

View File

@@ -246,22 +246,24 @@ function newConfigModal(title, config, caps) {
}
function getConfigModalJson(configForm) {
var configJson = {};
var configJson = [];
configForm.find(".config-setup-form").children().each(function (i, el) {
$el = $(el);
var type = $el.data("type");
var id = $el.data("id");
var itemEntry = { id: id };
switch (type) {
case "hiddendata":
configJson[id] = $el.find(".setup-item-hiddendata input").val();
itemEntry.value = $el.find(".setup-item-hiddendata input").val();
break;
case "inputstring":
configJson[id] = $el.find(".setup-item-inputstring input").val();
itemEntry.value = $el.find(".setup-item-inputstring input").val();
break;
case "inputbool":
configJson[id] = $el.find(".setup-item-inputbool input").is(":checked");
itemEntry.value = $el.find(".setup-item-inputbool input").is(":checked");
break;
}
configJson.push(itemEntry)
});
return configJson;
}

View File

@@ -23,7 +23,7 @@ namespace Jackett
public string Cookies { get; private set; }
public string Referer { get; private set; }
public HttpMethod Method { get; private set; }
public Dictionary<string, string> PostData { get; set; }
public IEnumerable<KeyValuePair<string, string>> PostData { get; set; }
public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null)
{
@@ -38,7 +38,7 @@ namespace Jackett
{
public List<string[]> HeaderList { get; private set; }
public byte[] Content { get; private set; }
public HttpStatusCode Status { get; private set;}
public HttpStatusCode Status { get; private set; }
public string Cookies { set; get; }
public CurlResponse(List<string[]> headers, byte[] content, HttpStatusCode s, string cookies)
@@ -57,7 +57,7 @@ namespace Jackett
return result;
}
public static async Task<CurlResponse> PostAsync(string url, Dictionary<string, string> formData, string cookies = null, string referer = null)
public static async Task<CurlResponse> PostAsync(string url, IEnumerable<KeyValuePair<string, string>> formData, string cookies = null, string referer = null)
{
var curlRequest = new CurlRequest(HttpMethod.Post, url, cookies, referer);
curlRequest.PostData = formData;
@@ -86,7 +86,7 @@ namespace Jackett
easy.BufferSize = 64 * 1024;
easy.UserAgent = BrowserUtil.ChromeUserAgent;
easy.FollowLocation = false;
easy.ConnectTimeout = 20;
easy.ConnectTimeout = 20;
easy.WriteFunction = (byte[] buf, int size, int nmemb, object data) =>
{
@@ -109,7 +109,7 @@ namespace Jackett
if (curlRequest.Method == HttpMethod.Post)
{
easy.Post = true;
var postString = new FormUrlEncodedContent(curlRequest.PostData).ReadAsStringAsync().Result;
var postString = StringUtil.PostDataFromDict(curlRequest.PostData);
easy.PostFields = postString;
easy.PostFieldSize = Encoding.UTF8.GetByteCount(postString);
}
@@ -125,7 +125,7 @@ namespace Jackett
easy.Perform();
if(easy.LastErrorCode != CurlCode.Ok)
if (easy.LastErrorCode != CurlCode.Ok)
{
var message = "Error " + easy.LastErrorCode.ToString() + " " + easy.LastErrorDescription;
if (null != OnErrorMessage)

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Jackett.Models.IndexerConfig;
namespace Jackett
{

View File

@@ -14,6 +14,7 @@ using Jackett.Utils;
using NLog;
using Jackett.Services;
using Jackett.Utils.Clients;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -31,16 +32,12 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
webclient = w;
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
@@ -54,13 +51,13 @@ namespace Jackett.Indexers
// Do the login
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink);
await ConfigureIfOK(response.Cookies, response.Content!=null && response.Content.Contains("logout.php?"), () =>
{
CQ dom = response.Content;
dom["#loginform > table"].Remove();
var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
});
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php?"), () =>
{
CQ dom = response.Content;
dom["#loginform > table"].Remove();
var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
});
}
void FillReleaseInfoFromJson(ReleaseInfo release, JObject r)

View File

@@ -25,7 +25,13 @@ namespace Jackett.Indexers
{
private string LoginUrl { get { return SiteLink + "user/login"; } }
private string SearchUrl { get { return SiteLink + "torrents.php?filter_cat[1]=1"; } }
public bool AllowRaws { get; private set; }
public bool AllowRaws { get { return configData.IncludeRaw.Value; } }
new ConfigurationDataAnimeBytes configData
{
get { return (ConfigurationDataAnimeBytes)base.configData; }
set { base.configData = value; }
}
public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l)
: base(name: "AnimeBytes",
@@ -34,19 +40,14 @@ namespace Jackett.Indexers
manager: i,
client: client,
caps: new TorznabCapabilities(TorznabCatType.Anime),
logger: l)
logger: l,
configData: new ConfigurationDataAnimeBytes())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLoginAnimeBytes());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLoginAnimeBytes();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
lock (cache)
{
@@ -59,18 +60,18 @@ namespace Jackett.Indexers
Url = LoginUrl
});
CQ loginPageDom =loginPage.Content;
CQ loginPageDom = loginPage.Content;
var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last();
// Build login form
var pairs = new Dictionary<string, string> {
{ "csrf_token", csrfToken.Attr("value") },
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "keeplogged_sent", "true" },
{ "keeplogged", "on" },
{ "login", "Log In!" }
};
};
// Do the login
var request = new Utils.Clients.WebRequest()
@@ -86,32 +87,26 @@ namespace Jackett.Indexers
// Follow the redirect
await FollowIfRedirect(response, request.Url, SearchUrl);
if (!(response.Content != null && response.Content.Contains("/user/logout")))
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () =>
{
// Their login page appears to be broken and just gives a 500 error.
throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", (ConfigurationData)config);
}
else
{
cookieHeader = response.Cookies;
AllowRaws = config.IncludeRaw.Value;
var configSaveData = new JObject();
configSaveData["cookies"] = cookieHeader;
configSaveData["raws"] = AllowRaws;
SaveConfig(configSaveData);
IsConfigured = true;
}
throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData);
});
}
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
// The old config used an array - just fail to load it
if (!(jsonConfig["cookies"] is JArray))
if (jsonConfig is JObject)
{
cookieHeader = (string)jsonConfig["cookies"];
AllowRaws = jsonConfig["raws"].Value<bool>();
configData.CookieHeader.Value = jsonConfig.Value<string>("cookies");
configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws");
SaveConfig();
IsConfigured = true;
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
@@ -257,7 +252,7 @@ namespace Jackett.Indexers
release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1);
var infoLink = links.Get(1);
release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href"));
release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href"));
release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name.
release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative);
@@ -337,7 +332,7 @@ namespace Jackett.Indexers
var response = await webclient.GetBytes(new Utils.Clients.WebRequest()
{
Url = SiteLink + link.ToString(),
Cookies = cookieHeader
Cookies = CookieHeader
});
return response.Content;

View File

@@ -13,6 +13,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -20,11 +21,17 @@ namespace Jackett.Indexers
public class BB : BaseIndexer, IIndexer
{
private string BaseUrl { get { return StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw=="); } }
private string BaseUrl { get { return StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw=="); } }
private Uri BaseUri { get { return new Uri(BaseUrl); } }
private string LoginUrl { get { return BaseUri + "login.php"; } }
private string SearchUrl { get { return BaseUri + "torrents.php?searchstr={0}&searchtags=&tags_type=0&order_by=s3&order_way=desc&disablegrouping=1&filter_cat%5B10%5D=1"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public BB(IIndexerManagerService i, Logger l, IWebClient w)
: base(name: "bB",
description: "bB",
@@ -32,22 +39,17 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "keeplogged", "1" },
{ "login", "Log In!" }
};
@@ -64,7 +66,7 @@ namespace Jackett.Indexers
messages.Add(child.Cq().Text().Trim());
}
var message = string.Join(" ", messages);
throw new ExceptionWithConfigData(message, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(message, configData);
});
}

View File

@@ -13,6 +13,7 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -21,6 +22,12 @@ namespace Jackett.Indexers
public string SearchUrl { get { return SiteLink + "browse.php?only=0&hentai=1&incomplete=1&lossless=1&hd=1&multiaudio=1&bonus=1&c1=1&reorder=1&q="; } }
public string LoginUrl { get { return SiteLink + "login.php"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public BakaBT(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "BakaBT",
description: "Anime Community",
@@ -28,19 +35,14 @@ namespace Jackett.Indexers
caps: new TorznabCapabilities(TorznabCatType.Anime),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var loginForm = await webclient.GetString(new Utils.Clients.WebRequest()
{
@@ -49,8 +51,8 @@ namespace Jackett.Indexers
});
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "returnto", "/index.php" }
};
@@ -61,7 +63,7 @@ namespace Jackett.Indexers
CQ dom = responseContent;
var messageEl = dom[".error"].First();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -11,6 +11,7 @@ using Jackett.Utils;
using Jackett.Utils.Clients;
using AutoMapper;
using System.Threading;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -28,11 +29,17 @@ namespace Jackett.Indexers
protected static List<CachedQueryResult> cache = new List<CachedQueryResult>();
protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0);
protected IWebClient webclient;
protected string cookieHeader = "";
protected string CookieHeader
{
get { return configData.CookieHeader.Value; }
set { configData.CookieHeader.Value = value; }
}
protected ConfigurationData configData;
private List<CategoryMapping> categoryMapping = new List<CategoryMapping>();
public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, TorznabCapabilities caps = null)
public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, ConfigurationData configData, TorznabCapabilities caps = null)
{
if (!link.EndsWith("/"))
throw new Exception("Site link must end with a slash.");
@@ -44,17 +51,21 @@ namespace Jackett.Indexers
indexerService = manager;
webclient = client;
this.configData = configData;
if (caps == null)
caps = TorznabCapsUtil.CreateDefaultTorznabTVCaps();
TorznabCaps = caps;
}
protected int MapTrackerCatToNewznab(string input)
{
if (null != input) {
if (null != input)
{
input = input.ToLowerInvariant();
var mapping = categoryMapping.Where(m => m.TrackerCategory == input).FirstOrDefault();
if(mapping!= null)
if (mapping != null)
{
return mapping.NewzNabCategory;
}
@@ -67,15 +78,20 @@ namespace Jackett.Indexers
return StringUtil.StripNonAlphaNumeric(type.Name.ToLowerInvariant());
}
public void ResetBaseConfig()
public virtual Task<ConfigurationData> GetConfigurationForSetup()
{
cookieHeader = string.Empty;
return Task.FromResult<ConfigurationData>(configData);
}
public virtual void ResetBaseConfig()
{
CookieHeader = string.Empty;
IsConfigured = false;
}
protected void SaveConfig(JToken config)
protected void SaveConfig()
{
indexerService.SaveConfig(this as IIndexer, config);
indexerService.SaveConfig(this as IIndexer, configData.ToJson(forDisplay: false));
}
protected void OnParseError(string results, Exception ex)
@@ -125,55 +141,57 @@ namespace Jackett.Indexers
{
Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo,
Referer = referrer,
Cookies = overrideCookies ?? cookieHeader
Cookies = overrideCookies ?? CookieHeader
});
Mapper.Map(redirectedResponse, incomingResponse);
}
}
protected void LoadCookieHeaderAndConfigure(JToken jsonConfig)
protected void LoadLegacyCookieConfig(JToken jsonConfig)
{
cookieHeader = (string)jsonConfig["cookie_header"];
if (!string.IsNullOrEmpty(cookieHeader))
string legacyCookieHeader = (string)jsonConfig["cookie_header"];
if (!string.IsNullOrEmpty(legacyCookieHeader))
{
IsConfigured = true;
CookieHeader = legacyCookieHeader;
}
else
{
// Legacy cookie key
var jcookes = jsonConfig["cookies"];
if (jcookes is JArray) {
var array = (JArray)jsonConfig["cookies"];
cookieHeader = string.Empty;
var jcookies = jsonConfig["cookies"];
if (jcookies is JArray)
{
var array = (JArray)jcookies;
legacyCookieHeader = string.Empty;
for (int i = 0; i < array.Count; i++)
{
if (i != 0)
cookieHeader += "; ";
cookieHeader += array[i];
legacyCookieHeader += "; ";
legacyCookieHeader += array[i];
}
CookieHeader = legacyCookieHeader;
}
else
cookieHeader = (string)jsonConfig["cookies"];
if (!string.IsNullOrEmpty(cookieHeader))
else if (jcookies != null)
{
IsConfigured = true;
CookieHeader = (string)jcookies;
}
}
}
protected void SaveCookieHeaderAndConfigure()
{
var configSaveData = new JObject();
configSaveData["cookie_header"] = cookieHeader;
SaveConfig(configSaveData);
IsConfigured = !string.IsNullOrEmpty(cookieHeader);
}
public virtual void LoadFromSavedConfiguration(JToken jsonConfig)
{
LoadCookieHeaderAndConfigure(jsonConfig);
if (jsonConfig is JArray)
{
configData.LoadValuesFromJson(jsonConfig);
IsConfigured = true;
}
// read and upgrade old settings file format
else if (jsonConfig is Object)
{
LoadLegacyCookieConfig(jsonConfig);
SaveConfig();
IsConfigured = true;
}
}
public async virtual Task<byte[]> Download(Uri link)
@@ -208,7 +226,7 @@ namespace Jackett.Indexers
{
Url = url,
Type = RequestType.GET,
Cookies = cookieHeader,
Cookies = CookieHeader,
Referer = referer
};
@@ -229,7 +247,7 @@ namespace Jackett.Indexers
catch (Exception e)
{
logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message));
lastException= e;
lastException = e;
}
await Task.Delay(500);
}
@@ -243,7 +261,7 @@ namespace Jackett.Indexers
{
Url = url,
Type = RequestType.GET,
Cookies = cookieOverride ?? cookieHeader
Cookies = cookieOverride ?? CookieHeader
};
if (cookieOverride != null)
@@ -251,26 +269,26 @@ namespace Jackett.Indexers
return await webclient.GetBytes(request);
}
protected async Task<WebClientStringResult> PostDataWithCookies(string url, Dictionary<string, string> data, string cookieOverride = null)
protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
{
var request = new Utils.Clients.WebRequest()
{
Url = url,
Type = RequestType.POST,
Cookies = cookieOverride ?? cookieHeader,
Cookies = cookieOverride ?? CookieHeader,
PostData = data
};
return await webclient.GetString(request);
}
protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, Dictionary<string, string> data, string cookieOverride = null)
protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null)
{
Exception lastException = null;
for (int i = 0; i < 3; i++)
{
try
{
return await PostDataWithCookies(url,data,cookieOverride);
return await PostDataWithCookies(url, data, cookieOverride);
}
catch (Exception e)
{
@@ -283,7 +301,7 @@ namespace Jackett.Indexers
throw lastException;
}
protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, Dictionary<string, string> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer =null)
protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, IEnumerable<KeyValuePair<string, string>> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer = null)
{
var request = new Utils.Clients.WebRequest()
{
@@ -313,8 +331,9 @@ namespace Jackett.Indexers
{
if (isLoggedin)
{
cookieHeader = cookies;
SaveCookieHeaderAndConfigure();
CookieHeader = cookies;
SaveConfig();
IsConfigured = true;
}
else
{
@@ -324,9 +343,9 @@ namespace Jackett.Indexers
public virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results)
{
foreach(var result in results)
foreach (var result in results)
{
if(query.Categories.Length == 0 || query.Categories.Contains(result.Category) || result.Category == 0 || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category))
if (query.Categories.Length == 0 || query.Categories.Contains(result.Category) || result.Category == 0 || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category))
{
yield return result;
}

View File

@@ -13,6 +13,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -21,6 +22,12 @@ namespace Jackett.Indexers
private string SearchUrl { get { return SiteLink + "browse.php?c40=1&c44=1&c48=1&c89=1&c46=1&c45=1&searchin=title&incldead=0&search={0}"; } }
private string DownloadUrl { get { return SiteLink + "download.php?torrent={0}"; } }
new ConfigurationDataCookie configData
{
get { return (ConfigurationDataCookie)base.configData; }
set { base.configData = value; }
}
public BeyondHD(IIndexerManagerService i, Logger l, IWebClient w)
: base(name: "BeyondHD",
description: "Without BeyondHD, your HDTV is just a TV",
@@ -28,31 +35,25 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataCookie())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataCookie());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataCookie();
config.LoadValuesFromJson(configJson);
cookieHeader = config.CookieHeader;
configData.LoadValuesFromJson(configJson);
var response = await webclient.GetString(new Utils.Clients.WebRequest()
{
Url = SiteLink,
Cookies = cookieHeader
Cookies = configData.Cookie.Value
});
await ConfigureIfOK(cookieHeader, response.Content.Contains("logout.php"), () =>
await ConfigureIfOK(CookieHeader, response.Content.Contains("logout.php"), () =>
{
CQ dom = response.Content;
throw new ExceptionWithConfigData("Invalid cookie header", (ConfigurationData)config);
throw new ExceptionWithConfigData("Invalid cookie header", configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string SearchUrl { get { return SiteLink + "torrents.php?cat=0&search="; } }
private string DownloadUrl { get { return SiteLink + "download.php?/{0}/dl.torrent"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public BitHdtv(IIndexerManagerService i, Logger l, IWebClient w)
: base(name: "BIT-HDTV",
description: "Home of high definition invites",
@@ -30,24 +37,19 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink);
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () =>
@@ -57,7 +59,7 @@ namespace Jackett.Indexers
messageEl.Children("a").Remove();
messageEl.Children("style").Remove();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -26,6 +26,12 @@ namespace Jackett.Indexers
private string CaptchaUrl { get { return SiteLink + "visual.php"; } }
private string SearchUrl { get { return SiteLink + "browse.php"; } }
new ConfigurationDataCaptchaLogin configData
{
get { return (ConfigurationDataCaptchaLogin)base.configData; }
set { base.configData = value; }
}
public BitMeTV(IIndexerManagerService i, Logger l, IWebClient c)
: base(name: "BitMeTV",
description: "TV Episode specialty tracker",
@@ -33,46 +39,45 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l)
logger: l,
configData: new ConfigurationDataCaptchaLogin())
{
}
public async Task<ConfigurationData> GetConfigurationForSetup()
public override async Task<ConfigurationData> GetConfigurationForSetup()
{
var response = await webclient.GetString(new Utils.Clients.WebRequest()
{
Url = LoginUrl
});
cookieHeader = response.Cookies;
CookieHeader = response.Cookies;
var captchaImage = await RequestBytesWithCookies(CaptchaUrl);
var config = new BmtvConfig();
config.CaptchaImage.Value = captchaImage.Content;
config.CaptchaCookie.Value = captchaImage.Cookies;
return (ConfigurationData)config;
configData.CaptchaImage.Value = captchaImage.Content;
configData.CaptchaCookie.Value = captchaImage.Cookies;
return configData;
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new BmtvConfig();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "secimage", config.CaptchaText.Value }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "secimage", configData.CaptchaText.Value }
};
var response = await RequestLoginAndFollowRedirect(LoginPost, pairs, config.CaptchaCookie.Value, true);
var response = await RequestLoginAndFollowRedirect(LoginPost, pairs, configData.CaptchaCookie.Value, true);
await ConfigureIfOK(response.Cookies, response.Content.Contains("/logout.php"), async () =>
{
CQ dom = response.Content;
var messageEl = dom["table tr > td.embedded > h2"].Last();
var errorMessage = messageEl.Text();
var captchaImage = await RequestBytesWithCookies(CaptchaUrl);
config.CaptchaImage.Value = captchaImage.Content;
config.CaptchaText.Value = "";
config.CaptchaCookie.Value = captchaImage.Cookies;
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
configData.CaptchaImage.Value = captchaImage.Content;
configData.CaptchaText.Value = "";
configData.CaptchaCookie.Value = captchaImage.Cookies;
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -8,9 +8,6 @@ using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
@@ -21,6 +18,12 @@ namespace Jackett.Indexers
private string MainUrl { get { return SiteLink + "?section=INDEX"; } }
private string SearchUrl { get { return SiteLink + "?section=TORRENTS&exact=1&name={0}&submit=GO"; } }
new ConfigurationDataCookie configData
{
get { return (ConfigurationDataCookie)base.configData; }
set { base.configData = value; }
}
public FrenchTorrentDb(IIndexerManagerService i, Logger l, IWebClient c)
: base(name: "FrenchTorrentDb",
description: "One the biggest French Torrent Tracker",
@@ -28,30 +31,24 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l)
logger: l,
configData: new ConfigurationDataCookie())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
public async Task ApplyConfiguration(JToken configJson)
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
}
public async Task ApplyConfiguration(Newtonsoft.Json.Linq.JToken configJson)
{
var config = new ConfigurationDataBasicLoginFrenchTorrentDb();
config.LoadValuesFromJson(configJson);
var cookies = "WebsiteID=" + config.Cookie.Value;
configData.LoadValuesFromJson(configJson);
var response = await webclient.GetString(new Utils.Clients.WebRequest()
{
Url = MainUrl,
Type = RequestType.GET,
Cookies = cookies
Cookies = configData.Cookie.Value
});
await ConfigureIfOK(cookies, response.Content.Contains("/?section=LOGOUT"), () =>
await ConfigureIfOK(configData.Cookie.Value, response.Content.Contains("/?section=LOGOUT"), () =>
{
throw new ExceptionWithConfigData("Failed to login", (ConfigurationData)config);
throw new ExceptionWithConfigData("Failed to login", configData);
});
}

View File

@@ -17,6 +17,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI.WebControls;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -26,6 +27,12 @@ namespace Jackett.Indexers
private string LoginPostUrl { get { return SiteLink + "login.php?action=makelogin"; } }
private string SearchUrl { get { return SiteLink + "browse.php"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public Freshon(IIndexerManagerService i, Logger l, IWebClient c)
: base(name: "FreshOnTV",
description: "Our goal is to provide the latest stuff in the TV show domain",
@@ -33,34 +40,29 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public async Task<ConfigurationData> GetConfigurationForSetup()
{
return await Task.FromResult< ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
// Get inital cookies
cookieHeader = string.Empty;
var response = await RequestLoginAndFollowRedirect(LoginPostUrl, pairs, cookieHeader, true, null, LoginUrl);
CookieHeader = string.Empty;
var response = await RequestLoginAndFollowRedirect(LoginPostUrl, pairs, CookieHeader, true, null, LoginUrl);
await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout.php"), () =>
{
CQ dom = response.Content;
var messageEl = dom[".error_text"];
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -13,6 +13,7 @@ using CsQuery;
using System.Web;
using System.Text.RegularExpressions;
using System.Globalization;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -21,6 +22,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "index.php?page=login"; } }
private string SearchUrl { get { return SiteLink + "index.php?page=torrents&active=0&options=0&category=21%3B22&search={0}"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public HDSpace(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "HD-Space",
description: "Sharing The Universe",
@@ -28,25 +35,20 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
var pairs = new Dictionary<string, string> {
{ "uid", config.Username.Value },
{ "pwd", config.Password.Value }
{ "uid", configData.Username.Value },
{ "pwd", configData.Password.Value }
};
// Send Post
@@ -58,7 +60,7 @@ namespace Jackett.Indexers
var remainingAttemptSpan = new Regex(string.Format(errorStr, "(.*?)")).Match(loginPage.Content).Groups[1].ToString();
var attempts = Regex.Replace(remainingAttemptSpan, "<.*?>", String.Empty);
var errorMessage = string.Format(errorStr, attempts);
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "login.php"; } }
private const int MAXPAGES = 3;
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public HDTorrents(IIndexerManagerService i, Logger l, IWebClient w)
: base(name: "HD-Torrents",
description: "HD-Torrents is a private torrent website with HD torrents and strict rules on their content.",
@@ -30,24 +37,19 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
var pairs = new Dictionary<string, string> {
{ "uid", incomingConfig.Username.Value },
{ "pwd", incomingConfig.Password.Value }
{ "uid", configData.Username.Value },
{ "pwd", configData.Password.Value }
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginUrl);
@@ -55,7 +57,7 @@ namespace Jackett.Indexers
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("If your browser doesn't have javascript enabled"), () =>
{
var errorMessage = "Couldn't login";
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -1,4 +1,5 @@
using Jackett.Models;
using Jackett.Models.IndexerConfig;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

View File

@@ -15,6 +15,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -22,6 +23,12 @@ namespace Jackett.Indexers
{
private string BrowseUrl { get { return SiteLink + "t"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public IPTorrents(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "IPTorrents",
description: "Always a step ahead.",
@@ -29,7 +36,8 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
AddCategoryMapping(72, TorznabCatType.Movies);
AddCategoryMapping(77, TorznabCatType.MoviesSD);
@@ -74,18 +82,12 @@ namespace Jackett.Indexers
AddCategoryMapping(94, TorznabCatType.Comic);
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value }
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var request = new Utils.Clients.WebRequest()
{
@@ -104,7 +106,7 @@ namespace Jackett.Indexers
CQ dom = response.Content;
var messageEl = dom["body > div"].First();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
private string QueryString { get { return "?do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public ImmortalSeed(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "ImmortalSeed",
description: "ImmortalSeed",
@@ -30,7 +37,8 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
AddCategoryMapping(32, TorznabCatType.Anime);
AddCategoryMapping(47, TorznabCatType.TVSD);
@@ -58,18 +66,12 @@ namespace Jackett.Indexers
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value }
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var request = new Utils.Clients.WebRequest()
{
@@ -88,7 +90,7 @@ namespace Jackett.Indexers
{
var tries = resultDom["#main tr:eq(1) td font"].First().Text();
var errorMessage = "Incorrect username or password! " + tries + " tries remaining.";
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -24,6 +25,12 @@ namespace Jackett.Indexers
private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } }
private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public MoreThanTV(IIndexerManagerService i, IWebClient c, Logger l)
: base(name: "MoreThanTV",
description: "ROMANIAN Private Torrent Tracker for TV / MOVIES, and the internal tracker for the release group DRACULA.",
@@ -31,25 +38,20 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "login", "Log in" },
{ "keeplogged", "1" }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "login", "Log in" },
{ "keeplogged", "1" }
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, SiteLink);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php?"), () =>
@@ -57,7 +59,7 @@ namespace Jackett.Indexers
CQ dom = result.Content;
dom["#loginform > table"].Remove();
var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " ");
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -21,6 +21,12 @@ namespace Jackett.Indexers
private string LoginReferer { get { return SiteLink + "index.php?cat=1"; } }
private string SearchUrl { get { return SiteLink + "browse.php?tags=&st=1&tf=all&cat%5B%5D=7&search={0}"; } }
new ConfigurationDataPinNumber configData
{
get { return (ConfigurationDataPinNumber)base.configData; }
set { base.configData = value; }
}
public Pretome(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "PreToMe",
description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
@@ -28,27 +34,22 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
client: wc,
manager: i,
logger: l)
logger: l,
configData: new ConfigurationDataPinNumber())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new PretomeConfiguration());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new PretomeConfiguration();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
var pairs = new Dictionary<string, string> {
{ "returnto", "%2F" },
{ "login_pin", config.Pin.Value },
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "login_pin", configData.Pin.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "login", "Login" }
};
@@ -56,16 +57,16 @@ namespace Jackett.Indexers
var result = await PostDataWithCookies(LoginUrl, pairs, loginPage.Cookies);
if (result.RedirectingTo == null)
{
throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that pretome emailed you?", (ConfigurationData)config);
throw new ExceptionWithConfigData("Login failed. Did you use the PIN number that pretome emailed you?", configData);
}
var loginCookies = result.Cookies;
// Get result from redirect
await FollowIfRedirect(result,LoginUrl,null, loginCookies);
await FollowIfRedirect(result, LoginUrl, null, loginCookies);
await ConfigureIfOK(loginCookies, result.Content != null && result.Content.Contains("logout.php"), () =>
{
cookieHeader = string.Empty;
throw new ExceptionWithConfigData("Failed", (ConfigurationData)config);
CookieHeader = string.Empty;
throw new ExceptionWithConfigData("Failed", configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Web;
using Jackett.Services;
using Jackett.Utils.Clients;
using System.Text.RegularExpressions;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -22,6 +23,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "auth/login"; } }
private string SearchUrl { get { return SiteLink + "torrents?in=1&type=2&search={0}"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "PrivateHD",
description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows",
@@ -29,20 +36,20 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString();
var pairs = new Dictionary<string, string> {
{ "_token", token },
{ "username_email", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value },
{ "username_email", configData.Username.Value },
{ "password", configData.Password.Value },
{ "remember", "on" }
};
@@ -52,15 +59,10 @@ namespace Jackett.Indexers
CQ dom = result.Content;
var messageEl = dom[".form-error"];
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();

View File

@@ -12,6 +12,7 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -20,6 +21,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "login"; } }
private string SearchUrl { get { return SiteLink + "{0}?method=1&c{1}=1&search={2}"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l)
: base(name: "SceneAccess",
description: "Your gateway to the scene",
@@ -27,23 +34,18 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: c,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "submit", "come on in" }
};
@@ -55,7 +57,7 @@ namespace Jackett.Indexers
CQ dom = result.Content;
var messageEl = dom["#login_box_desc"];
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string SearchUrl { get { return SiteLink + "browse_API.php"; } }
private string DownloadUrl { get { return SiteLink + "download.php/{0}/download.torrent"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public SceneTime(IIndexerManagerService i, Logger l, IWebClient w)
: base(name: "SceneTime",
description: "Always on time",
@@ -30,40 +37,35 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: w,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
{
CQ dom = result.Content;
var errorMessage = dom["td.text"].Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}
private Dictionary<string, string> GetSearchFormData(string searchString)
{
return new Dictionary<string, string> {
{ "c2", "1" }, { "c43", "1" }, { "c9", "1" }, { "c63", "1" }, { "c77", "1" }, { "c100", "1" }, { "c101", "1" },
{ "c2", "1" }, { "c43", "1" }, { "c9", "1" }, { "c63", "1" }, { "c77", "1" }, { "c100", "1" }, { "c101", "1" },
{ "cata", "yes" }, { "sec", "jax" },
{ "search", searchString}
};
};
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)

View File

@@ -14,57 +14,63 @@ using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class ShowRSS : BaseIndexer, IIndexer
{
private string searchAllUrl { get { return SiteLink + "feeds/all.rss"; } }
private string BaseUrl;
readonly static string defaultSiteLink = "http://showrss.info/";
private Uri BaseUri
{
get { return new Uri(configData.Url.Value); }
set { configData.Url.Value = value.ToString(); }
}
private string SearchAllUrl { get { return BaseUri + "feeds/all.rss"; } }
new ConfigurationDataUrl configData
{
get { return (ConfigurationDataUrl)base.configData; }
set { base.configData = value; }
}
public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "ShowRSS",
description: "showRSS is a service that allows you to keep track of your favorite TV shows",
link: "http://showrss.info/",
link: defaultSiteLink,
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataUrl(defaultSiteLink))
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
public async Task ApplyConfiguration(JToken configJson)
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
}
configData.LoadValuesFromJson(configJson);
var releases = await PerformQuery(new TorznabQuery());
public async Task ApplyConfiguration(Newtonsoft.Json.Linq.JToken configJson)
{
var config = new ConfigurationDataUrl(SiteLink);
config.LoadValuesFromJson(configJson);
var formattedUrl = config.GetFormattedHostUrl();
var releases = await PerformQuery(new TorznabQuery(), formattedUrl);
if (releases.Count() == 0)
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
{
throw new Exception("Could not find releases from this URL");
BaseUrl = formattedUrl;
var configSaveData = new JObject();
configSaveData["base_url"] = BaseUrl;
SaveConfig(configSaveData);
IsConfigured = true;
});
}
public override void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig)
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
BaseUrl = (string)jsonConfig["base_url"];
IsConfigured = true;
}
if (jsonConfig is JObject)
{
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
SaveConfig();
IsConfigured = true;
return;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
return await PerformQuery(query, BaseUrl);
base.LoadFromSavedConfiguration(jsonConfig);
}
public override Task<byte[]> Download(Uri link)
@@ -72,11 +78,11 @@ namespace Jackett.Indexers
throw new NotImplementedException();
}
async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
var episodeSearchUrl = string.Format(searchAllUrl);
var episodeSearchUrl = string.Format(SearchAllUrl);
var result = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
var xmlDoc = new XmlDocument();

View File

@@ -15,6 +15,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -26,6 +27,12 @@ namespace Jackett.Indexers
private string CommentsUrl { get { return SiteLink + "t/{0}"; } }
private string DownloadUrl { get { return SiteLink + "download.php?torrent={0}"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public SpeedCD(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "Speed.cd",
description: "Your home now!",
@@ -33,30 +40,25 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value },
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
{
CQ dom = result.Content;
var errorMessage = dom["h5"].First().Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -13,48 +13,65 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class Strike : BaseIndexer, IIndexer
{
private string DownloadUrl { get { return baseUri + "torrents/api/download/{0}.torrent"; } }
private string SearchUrl { get { return baseUri + "api/v2/torrents/search/?category=TV&phrase={0}"; } }
private string baseUrl = null;
private Uri baseUri { get { return new Uri(baseUrl); } }
readonly static string defaultSiteLink = "https://getstrike.net/";
private Uri BaseUri
{
get { return new Uri(configData.Url.Value); }
set { configData.Url.Value = value.ToString(); }
}
private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?category=TV&phrase={0}"; } }
private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } }
new ConfigurationDataUrl configData
{
get { return (ConfigurationDataUrl)base.configData; }
set { base.configData = value; }
}
public Strike(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "Strike",
description: "Torrent search engine",
link: "https://getstrike.net/",
link: defaultSiteLink,
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataUrl(defaultSiteLink))
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
public async Task ApplyConfiguration(JToken configJson)
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
}
public Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataUrl(SiteLink);
config.LoadValuesFromJson(configJson);
baseUrl = config.GetFormattedHostUrl();
var configSaveData = new JObject();
configSaveData["base_url"] = baseUrl;
SaveConfig(configSaveData);
IsConfigured = true;
return Task.FromResult(0);
configData.LoadValuesFromJson(configJson);
var releases = await PerformQuery(new TorznabQuery());
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
{
throw new Exception("Could not find releases from this URL");
});
}
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
baseUrl = (string)jsonConfig["base_url"];
IsConfigured = !string.IsNullOrEmpty(baseUrl);
if (jsonConfig is JObject)
{
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
SaveConfig();
IsConfigured = true;
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)

View File

@@ -14,6 +14,7 @@ using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -28,19 +29,21 @@ namespace Jackett.Indexers
HttpClientHandler handler;
HttpClient client;
string username = string.Empty;
string password = string.Empty;
string token = string.Empty;
DateTime lastTokenFetch = DateTime.MinValue;
new ConfigurationDataLoginTokin configData
{
get { return (ConfigurationDataLoginTokin)base.configData; }
set { base.configData = value; }
}
public T411(IIndexerManagerService i, Logger l,IWebClient wc)
public T411(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "T411",
description: "French Torrent Tracker",
link: "http://www.t411.io/",
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataLoginTokin())
{
CommentsUrl = SiteLink + "/torrents/{0}";
IsConfigured = false;
@@ -51,23 +54,17 @@ namespace Jackett.Indexers
client = new HttpClient(handler);
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
var config = new ConfigurationDataBasicLogin();
return Task.FromResult<ConfigurationData>(config);
}
async Task<string> GetAuthToken(bool forceFetch = false)
{
if (!forceFetch && lastTokenFetch > DateTime.Now - TimeSpan.FromHours(48))
if (!forceFetch && configData.LastTokenFetchDateTime > DateTime.Now - TimeSpan.FromHours(48))
{
return token;
return configData.ApiToken.Value;
}
var pairs = new Dictionary<string, string> {
{ "username", username },
{ "password", password }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var content = new FormUrlEncodedContent(pairs);
@@ -78,44 +75,45 @@ namespace Jackett.Indexers
{
throw new ApplicationException((string)jsonResponse["error"]);
}
token = (string)jsonResponse["token"];
lastTokenFetch = DateTime.Now;
return token;
configData.ApiToken.Value = (string)jsonResponse["token"];
configData.LastTokenFetchDateTime = DateTime.Now;
return configData.ApiToken.Value;
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
username = config.Username.Value;
password = config.Password.Value;
configData.LoadValuesFromJson(configJson);
Exception tokenFetchEx = null;
try
{
await GetAuthToken(true);
}
catch (Exception ex)
{
throw new ExceptionWithConfigData(ex.Message, (ConfigurationData)config);
tokenFetchEx = new ExceptionWithConfigData(ex.Message, configData);
}
var configSaveData = new JObject();
configSaveData["username"] = username;
configSaveData["password"] = password;
configSaveData["token"] = token;
configSaveData["last_token_fetch"] = lastTokenFetch;
SaveConfig(configSaveData);
IsConfigured = true;
await ConfigureIfOK(string.Empty, tokenFetchEx == null, () =>
{
throw tokenFetchEx;
});
}
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
username = (string)jsonConfig["username"];
password = (string)jsonConfig["password"];
token = (string)jsonConfig["token"];
lastTokenFetch = (DateTime)jsonConfig["last_token_fetch"];
IsConfigured = true;
if (jsonConfig is JObject)
{
configData.ApiToken.Value = jsonConfig.Value<string>("token"); ;
configData.Username.Value = jsonConfig.Value<string>("username");
configData.Password.Value = jsonConfig.Value<string>("password");
SaveConfig();
IsConfigured = true;
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)

View File

@@ -15,67 +15,71 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class ThePirateBay : BaseIndexer, IIndexer
{
private const string SearchUrl = "/search/{0}/0/99/208,205";
private string BaseUrl;
readonly static string defaultSiteLink = "https://thepiratebay.mn/";
private Uri BaseUri
{
get { return new Uri(configData.Url.Value); }
set { configData.Url.Value = value.ToString(); }
}
private string SearchUrl { get { return BaseUri + "search/{0}/0/99/208,205"; } }
new ConfigurationDataUrl configData
{
get { return (ConfigurationDataUrl)base.configData; }
set { base.configData = value; }
}
public ThePirateBay(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "The Pirate Bay",
description: "The worlds largest bittorrent indexer",
link: "https://thepiratebay.mn/",
link: defaultSiteLink,
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataUrl(defaultSiteLink))
{
BaseUrl = SiteLink.ToString();
IsConfigured = false;
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(BaseUrl));
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataUrl(SiteLink);
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var releases = await PerformQuery(new TorznabQuery());
var formattedUrl = config.GetFormattedHostUrl();
var releases = await PerformQuery(new TorznabQuery(), formattedUrl);
if (releases.Count() == 0)
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
{
throw new Exception("Could not find releases from this URL");
BaseUrl = formattedUrl;
var configSaveData = new JObject();
configSaveData["base_url"] = BaseUrl;
SaveConfig(configSaveData);
IsConfigured = true;
});
}
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
BaseUrl = (string)jsonConfig["base_url"];
IsConfigured = true;
if (jsonConfig is JObject)
{
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
SaveConfig();
IsConfigured = true;
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
return await PerformQuery(query, BaseUrl);
}
async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
{
var releases = new List<ReleaseInfo>();
var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
var queryStr = HttpUtility.UrlEncode(searchString);
var episodeSearchUrl = baseUrl + string.Format(SearchUrl, queryStr);
var episodeSearchUrl = string.Format(SearchUrl, queryStr);
var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty);
try
@@ -94,7 +98,7 @@ namespace Jackett.Indexers
release.MinimumSeedTime = 172800;
release.Title = qLink.Text().Trim();
release.Description = release.Title;
release.Comments = new Uri(baseUrl + "/" + qLink.Attr("href").TrimStart('/'));
release.Comments = new Uri(BaseUri + qLink.Attr("href").TrimStart('/'));
release.Guid = release.Comments;
var downloadCol = row.ChildElements.ElementAt(1).Cq().Children("a");

View File

@@ -15,6 +15,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string BrowseUrl { get { return SiteLink + "browse.php"; } }
private string LoginUrl { get { return SiteLink + "takelogin.php"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public TorrentBytes(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "TorrentBytes",
description: "A decade of torrentbytes",
@@ -30,7 +37,8 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
AddCategoryMapping(41, TorznabCatType.TV);
@@ -62,18 +70,12 @@ namespace Jackett.Indexers
AddCategoryMapping(24, TorznabCatType.XXXImg);
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDataBasicLogin();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", incomingConfig.Username.Value },
{ "password", incomingConfig.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "returnto", "/" },
{ "login", "Log in!" }
};
@@ -86,7 +88,7 @@ namespace Jackett.Indexers
CQ dom = result.Content;
var messageEl = dom["body > div"].First();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -23,6 +24,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "tak3login.php"; } }
private string SearchUrl { get { return SiteLink + "browse.php?search={0}&cata=yes&c2=1&c7=1&c14=1&c24=1&c26=1&c31=1&c32=1&c33=1"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "TorrentDay",
description: "TorrentDay",
@@ -30,27 +37,22 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var startMessage = await RequestStringWithCookies(StartPageUrl, string.Empty);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value }
};
{ "username", configData.Username.Value },
{ "password", configData.Password.Value }
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, LoginUrl);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
@@ -59,7 +61,7 @@ namespace Jackett.Indexers
var messageEl = dom["#login"];
messageEl.Children("form").Remove();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -22,6 +23,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "user/account/login/"; } }
private string SearchUrl { get { return SiteLink + "torrents/browse/index/query/{0}/categories/2%2C26%2C27%2C32/orderby/added?"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public TorrentLeech(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "TorrentLeech",
description: "This is what happens when you seed",
@@ -29,33 +36,28 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "remember_me", "on" },
{ "login", "submit" }
};
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true,null, LoginUrl);
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("/user/account/logout"), () =>
{
CQ dom = result.Content;
var messageEl = dom[".ui-state-error"].Last();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,6 +14,7 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
@@ -22,6 +23,12 @@ namespace Jackett.Indexers
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php?searchstr={0}&release_type=both&searchtags=&tags_type=0&order_by=s3&order_way=desc&torrent_preset=all&filter_cat%5B600%5D=1&filter_cat%5B620%5D=1&filter_cat%5B700%5D=1&filter_cat%5B981%5D=1&filter_cat%5B980%5D=1"; } }
new ConfigurationDataBasicLogin configData
{
get { return (ConfigurationDataBasicLogin)base.configData; }
set { base.configData = value; }
}
public TorrentShack(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "TorrentShack",
description: "TorrentShack",
@@ -29,26 +36,21 @@ namespace Jackett.Indexers
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
client: wc,
manager: i,
logger: l)
logger: l,
configData: new ConfigurationDataBasicLogin())
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataBasicLogin());
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataBasicLogin();
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var pairs = new Dictionary<string, string> {
{ "username", config.Username.Value },
{ "password", config.Password.Value },
{ "username", configData.Username.Value },
{ "password", configData.Password.Value },
{ "keeplogged", "1" },
{ "login", "Login" }
};
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () =>
@@ -57,7 +59,7 @@ namespace Jackett.Indexers
var messageEl = dom["#loginform"];
messageEl.Children("table").Remove();
var errorMessage = messageEl.Text().Trim();
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
throw new ExceptionWithConfigData(errorMessage, configData);
});
}

View File

@@ -14,48 +14,67 @@ using System.Web;
using System.Windows.Forms;
using System.Xml;
using System.Linq;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class Torrentz : BaseIndexer, IIndexer
{
private string SearchUrl { get { return SiteLink + "feed_verifiedP?f={0}"; } }
private string BaseUrl;
readonly static string defaultSiteLink = "https://torrentz.eu/";
private Uri BaseUri
{
get { return new Uri(configData.Url.Value); }
set { configData.Url.Value = value.ToString(); }
}
private string SearchUrl { get { return BaseUri + "feed_verifiedP?f={0}"; } }
new ConfigurationDataUrl configData
{
get { return (ConfigurationDataUrl)base.configData; }
set { base.configData = value; }
}
public Torrentz(IIndexerManagerService i, Logger l, IWebClient wc)
: base(name: "Torrentz",
description: "Torrentz is a meta-search engine and a Multisearch. This means we just search other search engines.",
link: "https://torrentz.eu/",
link: defaultSiteLink,
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client: wc,
logger: l)
logger: l,
configData: new ConfigurationDataUrl(defaultSiteLink))
{
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
return Task.FromResult<ConfigurationData>(new ConfigurationDataUrl(SiteLink));
}
public async Task ApplyConfiguration(JToken configJson)
{
var config = new ConfigurationDataUrl(SiteLink);
config.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
var releases = await PerformQuery(new TorznabQuery());
var formattedUrl = config.GetFormattedHostUrl();
IEnumerable<ReleaseInfo> releases = await PerformQuery(new TorznabQuery(), formattedUrl);
if (releases.Count() == 0)
await ConfigureIfOK(string.Empty, releases.Count() > 0, () =>
{
throw new Exception("Could not find releases from this URL");
BaseUrl = formattedUrl;
var configSaveData = new JObject();
configSaveData["base_url"] = BaseUrl;
SaveConfig(configSaveData);
IsConfigured = true;
});
}
async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, string baseUrl)
// Override to load legacy config format
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
if (jsonConfig is JObject)
{
BaseUri = new Uri(jsonConfig.Value<string>("base_url"));
SaveConfig();
IsConfigured = true;
return;
}
base.LoadFromSavedConfiguration(jsonConfig);
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
var releases = new List<ReleaseInfo>();
var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
@@ -106,18 +125,6 @@ namespace Jackett.Indexers
return releases;
}
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
BaseUrl = (string)jsonConfig["base_url"];
IsConfigured = true;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
return await PerformQuery(query, BaseUrl);
}
public override Task<byte[]> Download(Uri link)
{
throw new NotImplementedException();

View File

@@ -15,87 +15,114 @@ using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Jackett.Models.IndexerConfig;
namespace Jackett.Indexers
{
public class nCore : BaseIndexer, IIndexer
public class NCore : BaseIndexer, IIndexer
{
private string SearchUrl = "https://ncore.cc/torrents.php";
private static string LoginUrl = "https://ncore.cc/login.php";
private readonly string LoggedInUrl = "https://ncore.cc/index.php";
//private JToken configData = null;
private string LoginUrl { get { return SiteLink + "login.php"; } }
private string SearchUrl { get { return SiteLink + "torrents.php"; } }
private readonly string enSearch = "torrents.php?oldal=1&tipus=kivalasztottak_kozott&kivalasztott_tipus=xvidser,dvdser,hdser&mire={0}&miben=name";
private readonly string hunSearch = "torrents.php?oldal=1&tipus=kivalasztottak_kozott&kivalasztott_tipus=xvidser_hun,dvdser_hun,hdser_hun,mire={0}&miben=name";
private readonly string enHunSearch = "torrents.php?oldal=1&tipus=kivalasztottak_kozott&kivalasztott_tipus=xvidser_hun,xvidser,dvdser_hun,dvdser,hdser_hun,hdser&mire={0}&miben=name";
new ConfigurationDataNCore configData
{
get { return (ConfigurationDataNCore)base.configData; }
set { base.configData = value; }
}
private string SearchUrlEn { get { return SiteLink.ToString() + enSearch; } }
private string SearchUrlHun { get { return SiteLink.ToString() + hunSearch; } }
private string SearchUrlEnHun { get { return SiteLink.ToString() + enHunSearch; } }
public nCore(IIndexerManagerService i, IWebClient wc, Logger l)
public NCore(IIndexerManagerService i, IWebClient wc, Logger l)
: base(name: "nCore",
description: "A Hungarian private torrent site.",
link: "https://ncore.cc/",
caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(),
manager: i,
client:wc,
logger: l)
client: wc,
logger: l,
configData: new ConfigurationDataNCore())
{
SearchUrl = SearchUrlEnHun;
}
public Task<ConfigurationData> GetConfigurationForSetup()
{
//var config = configData == null ? new ConfigurationDatanCore() : new ConfigurationDatanCore(configData);
//return Task.FromResult<ConfigurationData>(config);
return Task.FromResult<ConfigurationData>(new ConfigurationDatanCore());
}
public async Task ApplyConfiguration(JToken configJson)
{
var incomingConfig = new ConfigurationDatanCore();
incomingConfig.LoadValuesFromJson(configJson);
configData.LoadValuesFromJson(configJson);
if (incomingConfig.Hungarian.Value == false && incomingConfig.English.Value == false)
throw new ExceptionWithConfigData("Please select atleast one language.", (ConfigurationData)incomingConfig);
if (configData.Hungarian.Value == false && configData.English.Value == false)
throw new ExceptionWithConfigData("Please select atleast one language.", configData);
var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty);
var pairs = new Dictionary<string, string> {
{ "nev", incomingConfig.Username.Value },
{ "pass", incomingConfig.Password.Value },
{ "ne_leptessen_ki", "on"}
};
{ "nev", configData.Username.Value },
{ "pass", configData.Password.Value },
{ "ne_leptessen_ki", "1"},
{ "set_lang", "en" },
{ "submitted", "1" },
{ "submit", "Access!" }
};
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, LoggedInUrl, LoggedInUrl);
ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("Felhasználó"), () =>
{
CQ dom = result.Content;
var messageEl = dom["#hibauzenet table tbody tr"];
var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1);
var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login.";
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)incomingConfig);
});
//var configSaveData = new JObject();
//configSaveData["config"] = incomingConfig.ToJson();
//SaveConfig(configSaveData);
var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink);
await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () =>
{
CQ dom = result.Content;
var messageEl = dom["#hibauzenet table tbody tr"];
var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1);
var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login.";
throw new ExceptionWithConfigData(errorMessage, configData);
});
}
List<KeyValuePair<string, string>> CreateKeyValueList(params string[][] keyValues)
{
var list = new List<KeyValuePair<string, string>>();
foreach (var d in keyValues)
{
list.Add(new KeyValuePair<string, string>(d[0], d[1]));
}
return list;
}
private IEnumerable<KeyValuePair<string, string>> GetSearchFormData(string searchString)
{
const string searchTypeKey = "kivalasztott_tipus[]";
var baseList = CreateKeyValueList(
new[] { "nyit_sorozat_resz", "true" },
new[] { "miben", "name" },
new[] { "tipus", "kivalasztottak_kozott" },
new[] { "submit.x", "1" },
new[] { "submit.y", "1" },
new[] { "submit", "Ok" },
new[] { "mire", searchString }
);
if (configData.English.Value)
{
baseList.AddRange(CreateKeyValueList(
new[] { searchTypeKey, "xvidser" },
new[] { searchTypeKey, "dvdser" },
new[] { searchTypeKey, "hdser" }
));
}
if (configData.Hungarian.Value)
{
baseList.AddRange(CreateKeyValueList(
new[] { searchTypeKey, "xvidser_hun" },
new[] { searchTypeKey, "dvdser_hun" },
new[] { searchTypeKey, "hdser_hun" }
));
}
return baseList;
}
public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{
List<ReleaseInfo> releases = new List<ReleaseInfo>();
var searchString = query.SanitizedSearchTerm + " " + query.GetEpisodeSearchString();
var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString));
var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(searchString));
var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl);
try
{
CQ dom = response.Content;
CQ dom = results.Content;
ReleaseInfo release;
var rows = dom[".box_torrent_all"].Find(".box_torrent");
@@ -129,36 +156,12 @@ namespace Jackett.Indexers
}
catch (Exception ex)
{
OnParseError(response.Content, ex);
OnParseError(results.Content, ex);
}
return releases.ToArray();
}
public override void LoadFromSavedConfiguration(JToken jsonConfig)
{
base.LoadFromSavedConfiguration(jsonConfig);
//if (jsonConfig["config"] != null)
//{
// string hun, eng;
// Dictionary<string, string>[] configDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>[]>(jsonConfig["config"].ToString());
// configDictionary[2].TryGetValue("value", out hun);
// configDictionary[3].TryGetValue("value", out eng);
// bool isHun = Boolean.Parse(hun);
// bool isEng = Boolean.Parse(eng);
// if (isHun && isEng)
// SearchUrl = SearchUrlEnHun;
// else if (isHun && !isEng)
// SearchUrl = SearchUrlHun;
// else if (!isHun && isEng)
// SearchUrl = SearchUrlEn;
// configData = jsonConfig["config"];
//}
}
}
}

View File

@@ -187,7 +187,7 @@
<Compile Include="Indexers\HDTorrents.cs" />
<Compile Include="Indexers\IIndexer.cs" />
<Compile Include="Indexers\ImmortalSeed.cs" />
<Compile Include="Indexers\nCore.cs" />
<Compile Include="Indexers\NCore.cs" />
<Compile Include="Indexers\TorrentBytes.cs" />
<Compile Include="Indexers\IPTorrents.cs" />
<Compile Include="Indexers\MoreThanTV.cs" />
@@ -206,11 +206,12 @@
<Compile Include="Indexers\Torrentz.cs" />
<Compile Include="Models\CachedResult.cs" />
<Compile Include="Models\CategoryMapping.cs" />
<Compile Include="Models\ConfigurationDatanCore.cs" />
<Compile Include="Models\IndexerConfig\BmtvConfig.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginAnimeBytes.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataBasicLoginFrenchTorrentDb.cs" />
<Compile Include="Models\IndexerConfig\PretomeConfiguration.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataLoginTokin.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataNCore.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataCaptchaLogin.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataAnimeBytes.cs" />
<Compile Include="Models\IndexerConfig\ISerializableConfig.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataPinNumber.cs" />
<Compile Include="Models\TorrentPotatoRequest.cs" />
<Compile Include="Models\TorrentPotatoResponse.cs" />
<Compile Include="Models\TorrentPotatoResponseItem.cs" />
@@ -233,10 +234,10 @@
<Compile Include="Utils\BrowserUtil.cs" />
<Compile Include="Models\CachedQueryResult.cs" />
<Compile Include="Models\ChannelInfo.cs" />
<Compile Include="Models\ConfigurationData.cs" />
<Compile Include="Models\ConfigurationDataBasicLogin.cs" />
<Compile Include="Models\ConfigurationDataCookie.cs" />
<Compile Include="Models\ConfigurationDataUrl.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationData.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataBasicLogin.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataCookie.cs" />
<Compile Include="Models\IndexerConfig\ConfigurationDataUrl.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="CookieContainerExtensions.cs" />
<Compile Include="Utils\Clients\WebRequest.cs" />

View File

@@ -3,10 +3,11 @@ using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models
namespace Jackett.Models.IndexerConfig
{
public abstract class ConfigurationData
{
@@ -19,6 +20,8 @@ namespace Jackett.Models
HiddenData
}
public HiddenItem CookieHeader { get; private set; } = new HiddenItem { Name = "CookieHeader" };
public ConfigurationData()
{
@@ -31,28 +34,31 @@ namespace Jackett.Models
public void LoadValuesFromJson(JToken json)
{
// todo: match up ids with items and fill values
IDictionary<string, JToken> dictionary = (JObject)json;
foreach (var item in GetItems())
var arr = (JArray)json;
foreach (var item in GetItems(forDisplay: false))
{
var arrItem = arr.FirstOrDefault(f => f.Value<string>("id") == item.ID);
if (arrItem == null)
continue;
switch (item.ItemType)
{
case ItemType.InputString:
((StringItem)item).Value = (string)dictionary[item.ID];
break;
case ItemType.InputBool:
((BoolItem)item).Value = (bool)dictionary[item.ID];
((StringItem)item).Value = arrItem.Value<string>("value");
break;
case ItemType.HiddenData:
((HiddenItem)item).Value = (string)dictionary[item.ID];
((HiddenItem)item).Value = arrItem.Value<string>("value");
break;
case ItemType.InputBool:
((BoolItem)item).Value = arrItem.Value<bool>("value");
break;
}
}
}
public JToken ToJson()
public JToken ToJson(bool forDisplay = true)
{
var items = GetItems();
var items = GetItems(forDisplay);
var jArray = new JArray();
foreach (var item in items)
{
@@ -80,6 +86,24 @@ namespace Jackett.Models
return jArray;
}
Item[] GetItems(bool forDisplay)
{
var properties = GetType()
.GetProperties()
.Where(p => p.CanRead)
.Where(p => p.PropertyType.IsSubclassOf(typeof(Item)))
.Select(p => (Item)p.GetValue(this));
if (!forDisplay)
{
properties = properties
.Where(p => p.ItemType == ItemType.HiddenData || p.ItemType == ItemType.InputBool || p.ItemType == ItemType.InputString)
.ToArray();
}
return properties.ToArray();
}
public class Item
{
public ItemType ItemType { get; set; }
@@ -89,7 +113,7 @@ namespace Jackett.Models
public class HiddenItem : StringItem
{
public HiddenItem(string value)
public HiddenItem(string value = "")
{
Value = value;
ItemType = ItemType.HiddenData;
@@ -132,7 +156,6 @@ namespace Jackett.Models
}
}
public abstract Item[] GetItems();
//public abstract Item[] GetItems();
}
}

View File

@@ -7,21 +7,16 @@ using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
class ConfigurationDataBasicLoginAnimeBytes : ConfigurationDataBasicLogin
class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin
{
public BoolItem IncludeRaw { get; private set; }
public DisplayItem DateWarning { get; private set; }
public ConfigurationDataBasicLoginAnimeBytes()
public ConfigurationDataAnimeBytes()
: base()
{
IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false };
DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" };
}
public override Item[] GetItems()
{
return new Item[] { Username, Password, IncludeRaw, DateWarning };
}
}
}

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models
namespace Jackett.Models.IndexerConfig
{
public class ConfigurationDataBasicLogin : ConfigurationData
{
@@ -18,9 +18,6 @@ namespace Jackett.Models
Password = new StringItem { Name = "Password" };
}
public override Item[] GetItems()
{
return new Item[] { Username, Password };
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
class ConfigurationDataBasicLoginFrenchTorrentDb : ConfigurationData
{
public StringItem Cookie { get; private set; }
public ConfigurationDataBasicLoginFrenchTorrentDb()
{
Cookie = new StringItem { Name = "Cookie" };
}
public override Item[] GetItems()
{
return new Item[] { Cookie };
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
class BmtvConfig : ConfigurationData
class ConfigurationDataCaptchaLogin : ConfigurationData
{
public StringItem Username { get; private set; }
@@ -18,7 +18,7 @@ namespace Jackett.Models.IndexerConfig
public HiddenItem CaptchaCookie { get; private set; }
public BmtvConfig()
public ConfigurationDataCaptchaLogin()
{
Username = new StringItem { Name = "Username" };
Password = new StringItem { Name = "Password" };
@@ -26,10 +26,5 @@ namespace Jackett.Models.IndexerConfig
CaptchaText = new StringItem { Name = "Captcha Text" };
CaptchaCookie = new HiddenItem("") { Name = "Captcha Cookie" };
}
public override Item[] GetItems()
{
return new Item[] { Username, Password, CaptchaImage, CaptchaText, CaptchaCookie };
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models
namespace Jackett.Models.IndexerConfig
{
public class ConfigurationDataCookie : ConfigurationData
@@ -17,7 +17,7 @@ namespace Jackett.Models
{
Cookie = new StringItem { Name = "Cookie" };
CookieHint = new DisplayItem(
"<ol><li>Login to BeyondHD in your browser <li>Open the developer console, go the network tab <li>Find 'cookie' in the request headers <li>Copy & paste it to here</ol>")
"<ol><li>Login to this tracker in your browser <li>Open the developer console, go the network tab <li>Find 'cookie' in the request headers <li>Copy & paste it to here</ol>")
{
Name = "CookieHint"
};
@@ -27,19 +27,6 @@ namespace Jackett.Models
Name = "CookieExample"
};
}
public override Item[] GetItems()
{
return new Item[] { Cookie, CookieHint, CookieExample };
}
public string CookieHeader
{
get
{
return Cookie.Value.Trim().TrimStart(new char[] { '"' }).TrimEnd(new char[] { '"' });
}
}
}
}

View File

@@ -0,0 +1,35 @@
using Jackett.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
public class ConfigurationDataLoginTokin : ConfigurationDataBasicLogin
{
public HiddenItem ApiToken { get; private set; }
public HiddenItem LastTokenFetchDate { get; private set; }
public DateTime LastTokenFetchDateTime
{
get
{
return DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(LastTokenFetchDate.Value));
}
set
{
LastTokenFetchDate.Value = DateTimeUtil.DateTimeToUnixTimestamp(value).ToString(CultureInfo.InvariantCulture);
}
}
public ConfigurationDataLoginTokin() : base()
{
ApiToken = new HiddenItem { Name = "ApiToken" };
LastTokenFetchDate = new HiddenItem { Name = "LastTokenFetchDate" };
LastTokenFetchDateTime = DateTime.MinValue;
}
}
}

View File

@@ -7,16 +7,16 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models
namespace Jackett.Models.IndexerConfig
{
public class ConfigurationDatanCore : ConfigurationData
public class ConfigurationDataNCore : ConfigurationData
{
public StringItem Username { get; private set; }
public StringItem Password { get; private set; }
public BoolItem Hungarian { get; set; }
public BoolItem English { get; set; }
public ConfigurationDatanCore()
public ConfigurationDataNCore()
{
Username = new StringItem { Name = "Username", Value = "" };
Password = new StringItem { Name = "Password", Value = "" };
@@ -24,9 +24,9 @@ namespace Jackett.Models
English = new BoolItem { Name = "English", Value = true };
}
public ConfigurationDatanCore(JToken json)
public ConfigurationDataNCore(JToken json)
{
ConfigurationDatanCore configData = new ConfigurationDatanCore();
ConfigurationDataNCore configData = new ConfigurationDataNCore();
dynamic configArray = JsonConvert.DeserializeObject(json.ToString());
foreach (var config in configArray)
@@ -52,11 +52,6 @@ namespace Jackett.Models
}
}
public override Item[] GetItems()
{
return new Item[] { Username, Password, Hungarian, English };
}
static string UppercaseFirst(string s)
{
if (string.IsNullOrEmpty(s))

View File

@@ -6,18 +6,13 @@ using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
class PretomeConfiguration : ConfigurationDataBasicLogin
class ConfigurationDataPinNumber : ConfigurationDataBasicLogin
{
public StringItem Pin { get; private set; }
public PretomeConfiguration() : base()
public ConfigurationDataPinNumber() : base()
{
Pin = new StringItem { Name = "Login Pin Number" };
}
public override Item[] GetItems()
{
return new Item[] { Pin, Username, Password };
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models
namespace Jackett.Models.IndexerConfig
{
public class ConfigurationDataUrl : ConfigurationData
{
@@ -19,16 +19,5 @@ namespace Jackett.Models
{
Url = new StringItem { Name = "Url", Value = defaultUrl };
}
public override Item[] GetItems()
{
return new Item[] { Url };
}
public string GetFormattedHostUrl()
{
var uri = new Uri(Url.Value);
return string.Format("{0}://{1}", uri.Scheme, uri.Host);
}
}
}

View File

@@ -0,0 +1,15 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Models.IndexerConfig
{
public interface ISerializableConfig
{
JObject Serialize();
ISerializableConfig Deserialize(JObject jobj);
}
}

View File

@@ -50,8 +50,16 @@ namespace Jackett.Services
var configFilePath = GetIndexerConfigFilePath(idx);
if (File.Exists(configFilePath))
{
var jsonString = JObject.Parse(File.ReadAllText(configFilePath));
idx.LoadFromSavedConfiguration(jsonString);
var fileStr = File.ReadAllText(configFilePath);
var jsonString = JToken.Parse(fileStr);
try
{
idx.LoadFromSavedConfiguration(jsonString);
}
catch (Exception ex)
{
logger.Error(ex, "Failed loading configuration for {0}, you must reconfigure this indexer", idx.DisplayName);
}
}
}
}

View File

@@ -97,7 +97,7 @@ namespace Jackett.Utils.Clients
var cookieBuilder = new StringBuilder();
foreach (var c in cookieHeaders)
{
cookieBuilder.AppendFormat("{0} ", c.Substring(0, c.IndexOf(';')+1));
cookieBuilder.AppendFormat("{0} ", c.Substring(0, c.IndexOf(';') + 1));
}
result.Cookies = cookieBuilder.ToString().TrimEnd();

View File

@@ -27,7 +27,7 @@ namespace Jackett.Utils.Clients
{
logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes(Url:{0})", request.Url));
var result = await Run(request);
logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes Returning {0} => {1} bytes", result.Status, (result.Content==null?"<NULL>":result.Content.Length.ToString())));
logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes Returning {0} => {1} bytes", result.Status, (result.Content == null ? "<NULL>" : result.Content.Length.ToString())));
return result;
}
@@ -35,20 +35,21 @@ namespace Jackett.Utils.Clients
{
logger.Debug(string.Format("UnixLibCurlWebClient:GetString(Url:{0})", request.Url));
var result = await Run(request);
logger.Debug(string.Format("UnixLibCurlWebClient:GetString Returning {0} => {1}", result.Status, (result.Content== null?"<NULL>": Encoding.UTF8.GetString(result.Content))));
logger.Debug(string.Format("UnixLibCurlWebClient:GetString Returning {0} => {1}", result.Status, (result.Content == null ? "<NULL>" : Encoding.UTF8.GetString(result.Content))));
return Mapper.Map<WebClientStringResult>(result);
}
public void Init()
{
try {
try
{
Engine.Logger.Info("LibCurl init " + Curl.GlobalInit(CurlInitFlag.All).ToString());
CurlHelper.OnErrorMessage += (msg) =>
{
Engine.Logger.Error(msg);
};
}
catch(Exception e)
catch (Exception e)
{
Engine.Logger.Warn("Libcurl failed to initalize. Did you install it?");
Engine.Logger.Warn("Debian: apt-get install libcurl4-openssl-dev");
@@ -59,7 +60,7 @@ namespace Jackett.Utils.Clients
var version = Curl.Version;
Engine.Logger.Info("LibCurl version " + version);
if (!Startup.DoSSLFix.HasValue && version.IndexOf("NSS")>-1)
if (!Startup.DoSSLFix.HasValue && version.IndexOf("NSS") > -1)
{
Engine.Logger.Info("NSS Detected SSL ECC workaround enabled.");
Startup.DoSSLFix = true;
@@ -75,9 +76,9 @@ namespace Jackett.Utils.Clients
}
else
{
if (request.PostData != null && request.PostData.Count > 0)
if (request.PostData != null && request.PostData.Count() > 0)
{
logger.Debug("UnixLibCurlWebClient: Posting " + new FormUrlEncodedContent(request.PostData).ReadAsStringAsync().Result);
logger.Debug("UnixLibCurlWebClient: Posting " + StringUtil.PostDataFromDict(request.PostData));
}
response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer);

View File

@@ -61,9 +61,9 @@ namespace Jackett.Utils.Clients
args.AppendFormat("--referer \"{0}\" ", request.Referer);
}
if (request.PostData != null && request.PostData.Count > 0)
if (request.PostData != null && request.PostData.Count() > 0)
{
var postString = new FormUrlEncodedContent(request.PostData).ReadAsStringAsync().Result;
var postString = StringUtil.PostDataFromDict(request.PostData);
args.AppendFormat("--data \"{0}\" ", postString);
}
@@ -80,7 +80,7 @@ namespace Jackett.Utils.Clients
string stdout = null;
await Task.Run(() =>
{
stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix?"curl":"curl.exe", args.ToString(), true);
stdout = processService.StartProcessAndGetOutput(System.Environment.OSVersion.Platform == PlatformID.Unix ? "curl" : "curl.exe", args.ToString(), true);
});
var outputData = File.ReadAllBytes(tempFile);
@@ -126,7 +126,7 @@ namespace Jackett.Utils.Clients
result.Content = new byte[outputData.Length - (headSplit + 3)];
var dest = 0;
for (int i= headSplit+4;i< outputData.Length; i++)
for (int i = headSplit + 4; i < outputData.Length; i++)
{
result.Content[dest] = outputData[i];
dest++;

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@@ -10,26 +11,27 @@ namespace Jackett.Utils.Clients
{
public WebRequest()
{
PostData = new Dictionary<string, string>();
PostData = new List<KeyValuePair<string, string>>();
Type = RequestType.GET;
}
public WebRequest(string url)
{
PostData = new Dictionary<string, string>();
PostData = new List<KeyValuePair<string, string>>();
Type = RequestType.GET;
Url = url;
}
public string Url { get; set; }
public Dictionary<string, string> PostData { get; set; }
public IEnumerable<KeyValuePair<string, string>> PostData { get; set; }
public string Cookies { get; set; }
public string Referer { get; set; }
public RequestType Type { get; set; }
public override bool Equals(System.Object obj)
{
if(obj is WebRequest)
if (obj is WebRequest)
{
var other = obj as WebRequest;
var postDataSame = PostData == null && other.PostData == null;
@@ -37,16 +39,16 @@ namespace Jackett.Utils.Clients
{
if (!(PostData == null || other.PostData == null))
{
var ok = PostData.Count == other.PostData.Count;
foreach(var i in PostData)
var ok = PostData.Count() == other.PostData.Count();
foreach (var i in PostData)
{
if (!other.PostData.ContainsKey(i.Key))
if (!other.PostData.Any(item => item.Key == i.Key))
{
ok = false;
break;
}
if(PostData[i.Key] != other.PostData[i.Key])
if (PostData.FirstOrDefault(item => item.Key == i.Key).Value != other.PostData.FirstOrDefault(item => item.Key == i.Key).Value)
{
ok = false;
break;
@@ -66,7 +68,8 @@ namespace Jackett.Utils.Clients
other.Type == Type &&
postDataSame;
} else
}
else
{
return false;
}

View File

@@ -15,6 +15,14 @@ namespace Jackett.Utils
return new DateTime(unixStart.Ticks + unixTimeStampInTicks);
}
public static double DateTimeToUnixTimestamp(DateTime dt)
{
var date = dt.ToUniversalTime();
var ticks = date.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
var ts = ticks / TimeSpan.TicksPerSecond;
return ts;
}
// ex: "2 hours 1 day"
public static DateTime FromTimeAgo(string str)
{

View File

@@ -9,6 +9,11 @@ namespace Jackett.Utils
{
public static class ParseUtil
{
public static double CoerceDouble(string str)
{
return double.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture);
}
public static float CoerceFloat(string str)
{
return float.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture);
@@ -25,6 +30,11 @@ namespace Jackett.Utils
}
public static bool TryCoerceDouble(string str, out double result)
{
return double.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result);
}
public static bool TryCoerceFloat(string str, out float result)
{
return float.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result);

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@@ -24,6 +25,11 @@ namespace Jackett.Utils
return Encoding.UTF8.GetString(Convert.FromBase64String(str));
}
public static string PostDataFromDict(IEnumerable<KeyValuePair<string, string>> dict)
{
return new FormUrlEncodedContent(dict).ReadAsStringAsync().Result;
}
public static string Hash(string input)
{
// Use input string to calculate MD5 hash
@@ -46,7 +52,8 @@ namespace Jackett.Utils
var properties = exception.GetType()
.GetProperties();
var fields = properties
.Select(property => new {
.Select(property => new
{
Name = property.Name,
Value = property.GetValue(exception, null)
})