diff --git a/src/Jackett/Content/custom.js b/src/Jackett/Content/custom.js index 5aca89c2b..11c832a92 100644 --- a/src/Jackett/Content/custom.js +++ b/src/Jackett/Content/custom.js @@ -137,7 +137,7 @@ function displayIndexers(items) { for (var i = 0; i < items.length; i++) { var item = items[i]; item.torznab_host = resolveUrl("/torznab/" + item.id); - item.potato_host = resolveUrl("/potato/" + item.id); + item.potato_host = resolveUrl("/potato/" + item.id); if (item.configured) $('#indexers').append(indexerTemplate(item)); else @@ -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; } diff --git a/src/Jackett/CurlHelper.cs b/src/Jackett/CurlHelper.cs index 99d066fa3..18de4aed1 100644 --- a/src/Jackett/CurlHelper.cs +++ b/src/Jackett/CurlHelper.cs @@ -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 PostData { get; set; } + public IEnumerable> PostData { get; set; } public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null) { @@ -38,7 +38,7 @@ namespace Jackett { public List 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 headers, byte[] content, HttpStatusCode s, string cookies) @@ -55,9 +55,9 @@ namespace Jackett var curlRequest = new CurlRequest(HttpMethod.Get, url, cookies, referer); var result = await PerformCurlAsync(curlRequest); return result; - } + } - public static async Task PostAsync(string url, Dictionary formData, string cookies = null, string referer = null) + public static async Task PostAsync(string url, IEnumerable> 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) diff --git a/src/Jackett/ExceptionWithConfigData.cs b/src/Jackett/ExceptionWithConfigData.cs index 9c4c7125e..e987eb81a 100644 --- a/src/Jackett/ExceptionWithConfigData.cs +++ b/src/Jackett/ExceptionWithConfigData.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; namespace Jackett { diff --git a/src/Jackett/Indexers/AlphaRatio.cs b/src/Jackett/Indexers/AlphaRatio.cs index dd4e7f16a..4be8a70d7 100644 --- a/src/Jackett/Indexers/AlphaRatio.cs +++ b/src/Jackett/Indexers/AlphaRatio.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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) diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs index b8ae9758b..e9822e95d 100644 --- a/src/Jackett/Indexers/AnimeBytes.cs +++ b/src/Jackett/Indexers/AnimeBytes.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { { "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(); + configData.CookieHeader.Value = jsonConfig.Value("cookies"); + configData.IncludeRaw.Value = jsonConfig.Value("raws"); + SaveConfig(); IsConfigured = true; + return; } + + base.LoadFromSavedConfiguration(jsonConfig); } public async Task> 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; diff --git a/src/Jackett/Indexers/BB.cs b/src/Jackett/Indexers/BB.cs index 7ba01fcf2..8dc1293e8 100644 --- a/src/Jackett/Indexers/BB.cs +++ b/src/Jackett/Indexers/BB.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/BakaBT.cs b/src/Jackett/Indexers/BakaBT.cs index 5680e1748..0416014a5 100644 --- a/src/Jackett/Indexers/BakaBT.cs +++ b/src/Jackett/Indexers/BakaBT.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { - { "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); }); } @@ -88,7 +90,7 @@ namespace Jackett.Indexers foreach (var row in rows) { - + var qRow = row.Cq(); var qTitleLink = qRow.Find("a.title").First(); var title = qTitleLink.Text().Trim(); diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs index f88d9928f..ede51bec1 100644 --- a/src/Jackett/Indexers/BaseIndexer.cs +++ b/src/Jackett/Indexers/BaseIndexer.cs @@ -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 cache = new List(); 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 = new List(); - 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 GetConfigurationForSetup() { - cookieHeader = string.Empty; + return Task.FromResult(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 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 PostDataWithCookies(string url, Dictionary data, string cookieOverride = null) + protected async Task PostDataWithCookies(string url, IEnumerable> 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 PostDataWithCookiesAndRetry(string url, Dictionary data, string cookieOverride = null) + protected async Task PostDataWithCookiesAndRetry(string url, IEnumerable> 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 RequestLoginAndFollowRedirect(string url, Dictionary data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer =null) + protected async Task RequestLoginAndFollowRedirect(string url, IEnumerable> 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 FilterResults(TorznabQuery query, IEnumerable 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; } diff --git a/src/Jackett/Indexers/BeyondHD.cs b/src/Jackett/Indexers/BeyondHD.cs index cab8600b9..9c885fd97 100644 --- a/src/Jackett/Indexers/BeyondHD.cs +++ b/src/Jackett/Indexers/BeyondHD.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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); }); } diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs index 1dd1e165f..5f6b32a85 100644 --- a/src/Jackett/Indexers/BitHdtv.cs +++ b/src/Jackett/Indexers/BitHdtv.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs index e8b7cc123..47180b9fb 100644 --- a/src/Jackett/Indexers/BitMeTV.cs +++ b/src/Jackett/Indexers/BitMeTV.cs @@ -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 GetConfigurationForSetup() + public override async Task 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 { - { "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); }); } diff --git a/src/Jackett/Indexers/FrenchTorrentDb.cs b/src/Jackett/Indexers/FrenchTorrentDb.cs index bfd7854d2..85c631fb9 100644 --- a/src/Jackett/Indexers/FrenchTorrentDb.cs +++ b/src/Jackett/Indexers/FrenchTorrentDb.cs @@ -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 GetConfigurationForSetup() + public async Task ApplyConfiguration(JToken configJson) { - return Task.FromResult(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); }); } diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs index 169a7d7e3..fcf01f75d 100644 --- a/src/Jackett/Indexers/Freshon.cs +++ b/src/Jackett/Indexers/Freshon.cs @@ -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 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 { - { "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); }); } diff --git a/src/Jackett/Indexers/HDSpace.cs b/src/Jackett/Indexers/HDSpace.cs index d266a079b..3c5e6aaad 100644 --- a/src/Jackett/Indexers/HDSpace.cs +++ b/src/Jackett/Indexers/HDSpace.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { - { "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); }); } diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs index d8e3d5158..1a4a9073b 100644 --- a/src/Jackett/Indexers/HDTorrents.cs +++ b/src/Jackett/Indexers/HDTorrents.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { - { "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); }); } diff --git a/src/Jackett/Indexers/IIndexer.cs b/src/Jackett/Indexers/IIndexer.cs index c768591eb..662dd8ebe 100644 --- a/src/Jackett/Indexers/IIndexer.cs +++ b/src/Jackett/Indexers/IIndexer.cs @@ -1,4 +1,5 @@ using Jackett.Models; +using Jackett.Models.IndexerConfig; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index 975c7a74e..289cd2dee 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } @@ -130,7 +132,7 @@ namespace Jackett.Indexers { searchUrl += "?" + queryCollection.GetQueryString(); } - + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); var results = response.Content; diff --git a/src/Jackett/Indexers/ImmortalSeed.cs b/src/Jackett/Indexers/ImmortalSeed.cs index 7bd11569e..078e44264 100644 --- a/src/Jackett/Indexers/ImmortalSeed.cs +++ b/src/Jackett/Indexers/ImmortalSeed.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } @@ -153,6 +155,6 @@ namespace Jackett.Indexers return releases; } - + } } diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs index 8d4d74a8c..c1a59a1b9 100644 --- a/src/Jackett/Indexers/MoreThanTV.cs +++ b/src/Jackett/Indexers/MoreThanTV.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/Pretome.cs b/src/Jackett/Indexers/Pretome.cs index 2b4575561..92cbf4282 100644 --- a/src/Jackett/Indexers/Pretome.cs +++ b/src/Jackett/Indexers/Pretome.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { { "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); }); } @@ -98,7 +99,7 @@ namespace Jackett.Indexers release.Comments = new Uri(SiteLink + qLink.Attr("href")); release.Guid = release.Comments; - + var qDownload = row.ChildElements.ElementAt(2).Cq().Find("a").First(); release.Link = new Uri(SiteLink + qDownload.Attr("href")); diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs index 23a79a399..d7fe3f4f4 100644 --- a/src/Jackett/Indexers/PrivateHD.cs +++ b/src/Jackett/Indexers/PrivateHD.cs @@ -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 { { "_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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task> PerformQuery(TorznabQuery query) { var releases = new List(); diff --git a/src/Jackett/Indexers/SceneAccess.cs b/src/Jackett/Indexers/SceneAccess.cs index 6add4bd21..b73901192 100644 --- a/src/Jackett/Indexers/SceneAccess.cs +++ b/src/Jackett/Indexers/SceneAccess.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/SceneTime.cs b/src/Jackett/Indexers/SceneTime.cs index 0144dfc3a..2de2accf1 100644 --- a/src/Jackett/Indexers/SceneTime.cs +++ b/src/Jackett/Indexers/SceneTime.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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 GetSearchFormData(string searchString) { return new Dictionary { - { "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> PerformQuery(TorznabQuery query) diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs index c6fffcf7c..730ee62cb 100644 --- a/src/Jackett/Indexers/ShowRSS.cs +++ b/src/Jackett/Indexers/ShowRSS.cs @@ -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 GetConfigurationForSetup() + public async Task ApplyConfiguration(JToken configJson) { - return Task.FromResult(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("base_url")); + SaveConfig(); + IsConfigured = true; + return; + } - public async Task> PerformQuery(TorznabQuery query) - { - return await PerformQuery(query, BaseUrl); + base.LoadFromSavedConfiguration(jsonConfig); } public override Task Download(Uri link) @@ -72,11 +78,11 @@ namespace Jackett.Indexers throw new NotImplementedException(); } - async Task> PerformQuery(TorznabQuery query, string baseUrl) + public async Task> PerformQuery(TorznabQuery query) { var releases = new List(); 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(); diff --git a/src/Jackett/Indexers/SpeedCD.cs b/src/Jackett/Indexers/SpeedCD.cs index bc4009333..ab7e442a0 100644 --- a/src/Jackett/Indexers/SpeedCD.cs +++ b/src/Jackett/Indexers/SpeedCD.cs @@ -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 { @@ -25,7 +26,13 @@ namespace Jackett.Indexers private string SearchFormData { get { return "c53=1&c49=1&c2=1&c52=1&c41=1&c50=1&c30=1&jxt=4&jxw=b"; } } 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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/Strike.cs b/src/Jackett/Indexers/Strike.cs index 997b55eac..5bc4f55d2 100644 --- a/src/Jackett/Indexers/Strike.cs +++ b/src/Jackett/Indexers/Strike.cs @@ -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 GetConfigurationForSetup() + public async Task ApplyConfiguration(JToken configJson) { - return Task.FromResult(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("base_url")); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); } public async Task> PerformQuery(TorznabQuery query) diff --git a/src/Jackett/Indexers/T411.cs b/src/Jackett/Indexers/T411.cs index 17b2a6d67..d2d49f1bb 100644 --- a/src/Jackett/Indexers/T411.cs +++ b/src/Jackett/Indexers/T411.cs @@ -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 GetConfigurationForSetup() - { - var config = new ConfigurationDataBasicLogin(); - return Task.FromResult(config); - } - async Task 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 { - { "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("token"); ; + configData.Username.Value = jsonConfig.Value("username"); + configData.Password.Value = jsonConfig.Value("password"); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); } public async Task> PerformQuery(TorznabQuery query) diff --git a/src/Jackett/Indexers/ThePirateBay.cs b/src/Jackett/Indexers/ThePirateBay.cs index f37a91f10..8115a62b0 100644 --- a/src/Jackett/Indexers/ThePirateBay.cs +++ b/src/Jackett/Indexers/ThePirateBay.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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("base_url")); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); } public async Task> PerformQuery(TorznabQuery query) - { - return await PerformQuery(query, BaseUrl); - } - - async Task> PerformQuery(TorznabQuery query, string baseUrl) { var releases = new List(); 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"); diff --git a/src/Jackett/Indexers/TorrentBytes.cs b/src/Jackett/Indexers/TorrentBytes.cs index 033040127..d58d567ba 100644 --- a/src/Jackett/Indexers/TorrentBytes.cs +++ b/src/Jackett/Indexers/TorrentBytes.cs @@ -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,9 +37,10 @@ namespace Jackett.Indexers caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(), manager: i, client: wc, - logger: l) + logger: l, + configData: new ConfigurationDataBasicLogin()) { - + AddCategoryMapping(41, TorznabCatType.TV); AddCategoryMapping(33, TorznabCatType.TVSD); AddCategoryMapping(38, TorznabCatType.TVHD); @@ -62,18 +70,12 @@ namespace Jackett.Indexers AddCategoryMapping(24, TorznabCatType.XXXImg); } - public Task GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var incomingConfig = new ConfigurationDataBasicLogin(); - incomingConfig.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } @@ -118,7 +120,7 @@ namespace Jackett.Indexers searchUrl += "?" + queryCollection.GetQueryString(); // 15 results per page - really don't want to call the server twice but only 15 results per page is a bit crap! - await ProcessPage(releases, searchUrl); + await ProcessPage(releases, searchUrl); await ProcessPage(releases, searchUrl + "&page=1"); return releases; } diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs index cbb9daefa..ee02843a5 100644 --- a/src/Jackett/Indexers/TorrentDay.cs +++ b/src/Jackett/Indexers/TorrentDay.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 { - { "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); }); } diff --git a/src/Jackett/Indexers/TorrentLeech.cs b/src/Jackett/Indexers/TorrentLeech.cs index 306786100..4284d68e4 100644 --- a/src/Jackett/Indexers/TorrentLeech.cs +++ b/src/Jackett/Indexers/TorrentLeech.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/TorrentShack.cs b/src/Jackett/Indexers/TorrentShack.cs index 3823ce379..31327f932 100644 --- a/src/Jackett/Indexers/TorrentShack.cs +++ b/src/Jackett/Indexers/TorrentShack.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(new ConfigurationDataBasicLogin()); - } - public async Task ApplyConfiguration(JToken configJson) { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + configData.LoadValuesFromJson(configJson); var pairs = new Dictionary { - { "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); }); } diff --git a/src/Jackett/Indexers/Torrentz.cs b/src/Jackett/Indexers/Torrentz.cs index c1d846da4..d54b2d17d 100644 --- a/src/Jackett/Indexers/Torrentz.cs +++ b/src/Jackett/Indexers/Torrentz.cs @@ -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 GetConfigurationForSetup() - { - return Task.FromResult(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 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> 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("base_url")); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); + } + + public async Task> PerformQuery(TorznabQuery query) { var releases = new List(); 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> PerformQuery(TorznabQuery query) - { - return await PerformQuery(query, BaseUrl); - } - public override Task Download(Uri link) { throw new NotImplementedException(); @@ -178,7 +185,7 @@ namespace Jackett.Indexers switch (counter) { case 0: - this.Size = ReleaseInfo.GetBytes(val); + this.Size = ReleaseInfo.GetBytes(val); break; case 1: this.Seeders = ParseUtil.CoerceInt(val.Contains(",") ? val.Remove(val.IndexOf(","), 1) : val); diff --git a/src/Jackett/Indexers/nCore.cs b/src/Jackett/Indexers/nCore.cs index a4f808b67..c26be2b15 100644 --- a/src/Jackett/Indexers/nCore.cs +++ b/src/Jackett/Indexers/nCore.cs @@ -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 GetConfigurationForSetup() - { - //var config = configData == null ? new ConfigurationDatanCore() : new ConfigurationDatanCore(configData); - //return Task.FromResult(config); - return Task.FromResult(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 { - { "nev", incomingConfig.Username.Value }, - { "pass", incomingConfig.Password.Value }, - { "ne_leptessen_ki", "on"} - }; - - 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); - }); + { "nev", configData.Username.Value }, + { "pass", configData.Password.Value }, + { "ne_leptessen_ki", "1"}, + { "set_lang", "en" }, + { "submitted", "1" }, + { "submit", "Access!" } + }; - //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> CreateKeyValueList(params string[][] keyValues) + { + var list = new List>(); + foreach (var d in keyValues) + { + list.Add(new KeyValuePair(d[0], d[1])); + } + return list; + } + private IEnumerable> 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> PerformQuery(TorznabQuery query) { List releases = new List(); 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[] configDictionary = JsonConvert.DeserializeObject[]>(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"]; - //} - } - } } \ No newline at end of file diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index fd642e1c4..4b3a48955 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -187,7 +187,7 @@ - + @@ -206,11 +206,12 @@ - - - - - + + + + + + @@ -233,10 +234,10 @@ - - - - + + + + diff --git a/src/Jackett/Models/ConfigurationData.cs b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs similarity index 69% rename from src/Jackett/Models/ConfigurationData.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationData.cs index be1841446..d8cdd75c5 100644 --- a/src/Jackett/Models/ConfigurationData.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs @@ -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 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("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("value"); break; case ItemType.HiddenData: - ((HiddenItem)item).Value = (string)dictionary[item.ID]; + ((HiddenItem)item).Value = arrItem.Value("value"); + break; + case ItemType.InputBool: + ((BoolItem)item).Value = arrItem.Value("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(); } } diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs similarity index 68% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs index 249bec8d7..47ddb275e 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginAnimeBytes.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs @@ -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 }; - } } } diff --git a/src/Jackett/Models/ConfigurationDataBasicLogin.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs similarity index 79% rename from src/Jackett/Models/ConfigurationDataBasicLogin.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs index fc7550284..b3023f9f0 100644 --- a/src/Jackett/Models/ConfigurationDataBasicLogin.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLogin.cs @@ -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 }; - } + } } diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs deleted file mode 100644 index 9cfbb6d6d..000000000 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginFrenchTorrentDb.cs +++ /dev/null @@ -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 }; - } - } -} diff --git a/src/Jackett/Models/IndexerConfig/BmtvConfig.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs similarity index 78% rename from src/Jackett/Models/IndexerConfig/BmtvConfig.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs index c7f1af558..a3ae9b896 100644 --- a/src/Jackett/Models/IndexerConfig/BmtvConfig.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataCaptchaLogin.cs @@ -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 }; - } } } diff --git a/src/Jackett/Models/ConfigurationDataCookie.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs similarity index 61% rename from src/Jackett/Models/ConfigurationDataCookie.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs index afa3e46e5..bb1e06322 100644 --- a/src/Jackett/Models/ConfigurationDataCookie.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataCookie.cs @@ -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( - "
  1. Login to BeyondHD in your browser
  2. Open the developer console, go the network tab
  3. Find 'cookie' in the request headers
  4. Copy & paste it to here
") + "
  1. Login to this tracker in your browser
  2. Open the developer console, go the network tab
  3. Find 'cookie' in the request headers
  4. Copy & paste it to here
") { 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[] { '"' }); - } - } } } diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs new file mode 100644 index 000000000..b9e697332 --- /dev/null +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginTokin.cs @@ -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; + } + } +} diff --git a/src/Jackett/Models/ConfigurationDatanCore.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs similarity index 83% rename from src/Jackett/Models/ConfigurationDatanCore.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs index 84173dbde..1dc5aaad0 100644 --- a/src/Jackett/Models/ConfigurationDatanCore.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs @@ -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)) diff --git a/src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs similarity index 57% rename from src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs index 27cb36688..f67002a84 100644 --- a/src/Jackett/Models/IndexerConfig/PretomeConfiguration.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataPinNumber.cs @@ -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 }; - } } } diff --git a/src/Jackett/Models/ConfigurationDataUrl.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs similarity index 56% rename from src/Jackett/Models/ConfigurationDataUrl.cs rename to src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs index abf834d58..71c23eaeb 100644 --- a/src/Jackett/Models/ConfigurationDataUrl.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataUrl.cs @@ -4,31 +4,20 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett.Models +namespace Jackett.Models.IndexerConfig { public class ConfigurationDataUrl : ConfigurationData { public StringItem Url { get; private set; } - public ConfigurationDataUrl(Uri defaultUrl) + public ConfigurationDataUrl(Uri defaultUrl) { - Url = new StringItem { Name = "Url", Value = defaultUrl.ToString() }; + Url = new StringItem { Name = "Url", Value = defaultUrl.ToString() }; } public ConfigurationDataUrl(string defaultUrl) { 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); - } } } diff --git a/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs b/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs new file mode 100644 index 000000000..c96756300 --- /dev/null +++ b/src/Jackett/Models/IndexerConfig/ISerializableConfig.cs @@ -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); + } +} diff --git a/src/Jackett/Services/IndexerManagerService.cs b/src/Jackett/Services/IndexerManagerService.cs index f95c44a52..e94751227 100644 --- a/src/Jackett/Services/IndexerManagerService.cs +++ b/src/Jackett/Services/IndexerManagerService.cs @@ -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); + } } } } diff --git a/src/Jackett/Utils/Clients/HttpWebClient.cs b/src/Jackett/Utils/Clients/HttpWebClient.cs index 92a88b99f..89e7eed01 100644 --- a/src/Jackett/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett/Utils/Clients/HttpWebClient.cs @@ -69,7 +69,7 @@ namespace Jackett.Utils.Clients client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); HttpResponseMessage response = null; - + if (request.Type == RequestType.POST) { var content = new FormUrlEncodedContent(request.PostData); @@ -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(); diff --git a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs index 58f2e024f..b9cd459a8 100644 --- a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs @@ -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?"":result.Content.Length.ToString()))); + logger.Debug(string.Format("UnixLibCurlWebClient:GetBytes Returning {0} => {1} bytes", result.Status, (result.Content == 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?"": Encoding.UTF8.GetString(result.Content)))); + logger.Debug(string.Format("UnixLibCurlWebClient:GetString Returning {0} => {1}", result.Status, (result.Content == null ? "" : Encoding.UTF8.GetString(result.Content)))); return Mapper.Map(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); diff --git a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs index 7f3d8fe47..fcd4211a9 100644 --- a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs @@ -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++; diff --git a/src/Jackett/Utils/Clients/WebRequest.cs b/src/Jackett/Utils/Clients/WebRequest.cs index 78fc2f463..2d8862b18 100644 --- a/src/Jackett/Utils/Clients/WebRequest.cs +++ b/src/Jackett/Utils/Clients/WebRequest.cs @@ -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(); + PostData = new List>(); Type = RequestType.GET; } public WebRequest(string url) { - PostData = new Dictionary(); + PostData = new List>(); Type = RequestType.GET; Url = url; } public string Url { get; set; } - public Dictionary PostData { get; set; } + public IEnumerable> 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; } diff --git a/src/Jackett/Utils/DateTimeUtil.cs b/src/Jackett/Utils/DateTimeUtil.cs index 81b0c5c0c..355ae603c 100644 --- a/src/Jackett/Utils/DateTimeUtil.cs +++ b/src/Jackett/Utils/DateTimeUtil.cs @@ -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) { diff --git a/src/Jackett/Utils/ParseUtil.cs b/src/Jackett/Utils/ParseUtil.cs index 7af729426..4da725187 100644 --- a/src/Jackett/Utils/ParseUtil.cs +++ b/src/Jackett/Utils/ParseUtil.cs @@ -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); diff --git a/src/Jackett/Utils/StringUtil.cs b/src/Jackett/Utils/StringUtil.cs index 6fa5864e4..a8d045e35 100644 --- a/src/Jackett/Utils/StringUtil.cs +++ b/src/Jackett/Utils/StringUtil.cs @@ -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> 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) })