diff --git a/src/Jackett.Console/ConsoleOptions.cs b/src/Jackett.Console/ConsoleOptions.cs index 635eb2e2ac4dc6b6d89e8c6b1e6eb5684d1e46bf..74982506bbc13e008eead3763dedb66506b62c52 100644 --- a/src/Jackett.Console/ConsoleOptions.cs +++ b/src/Jackett.Console/ConsoleOptions.cs @@ -27,6 +27,9 @@ namespace Jackett.Console [Option('c', "UseClient", HelpText = "Override web client selection. [automatic(Default)/libcurl/safecurl/httpclient]")] public string Client { get; set; } + [Option('j', "ProxyConnection", HelpText = "use proxy - e.g. 127.0.0.1:8888")] + public string ProxyConnection { get; set; } + [Option('s', "Start", HelpText = "Start the Jacket Windows service (Must be admin)")] public bool StartService { get; set; } diff --git a/src/Jackett.Console/Program.cs b/src/Jackett.Console/Program.cs index a5b5ad94119f1ff243547f34da39aa87d8c5df04..64abc0a3a814c2298e3c3b925610e46042525e8b 100644 --- a/src/Jackett.Console/Program.cs +++ b/src/Jackett.Console/Program.cs @@ -65,6 +65,11 @@ namespace JackettConsole if (options.Client != null) Startup.ClientOverride = options.Client.ToLowerInvariant(); + // Use Proxy + if (options.ProxyConnection != null) + { + Startup.ProxyConnection = options.ProxyConnection.ToLowerInvariant(); + } // Logging if (options.Logging) Startup.LogRequests = true; diff --git a/src/Jackett/CurlHelper.cs b/src/Jackett/CurlHelper.cs index c2a94cdd9e9c886fe573c19c5277f4351482f4c0..fe58143e4b15dde2cec63ec46b52230cc1460ee9 100644 --- a/src/Jackett/CurlHelper.cs +++ b/src/Jackett/CurlHelper.cs @@ -85,6 +85,7 @@ namespace Jackett using (var easy = new CurlEasy()) { + easy.Url = curlRequest.Url; easy.BufferSize = 64 * 1024; easy.UserAgent = BrowserUtil.ChromeUserAgent; @@ -139,7 +140,12 @@ namespace Jackett { easy.SetOpt(CurlOption.SslVerifyhost, false); easy.SetOpt(CurlOption.SslVerifyPeer, false); - } + } + + if (Startup.ProxyConnection != null) + { + easy.SetOpt(CurlOption.Proxy, Startup.ProxyConnection); + } easy.Perform(); @@ -155,6 +161,15 @@ namespace Jackett var headerBytes = Combine(headerBuffers.ToArray()); var headerString = Encoding.UTF8.GetString(headerBytes); + if (Startup.ProxyConnection != null) + { + var firstcrlf = headerString.IndexOf("\r\n\r\n"); + var secondcrlf = headerString.IndexOf("\r\n\r\n", firstcrlf + 1); + if (secondcrlf > 0) + { + headerString = headerString.Substring(firstcrlf + 4, secondcrlf - (firstcrlf)); + } + } var headerParts = headerString.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var headers = new List<string[]>(); var headerCount = 0; diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs index 84cdbef320d8246dd19b4f9dbf01b2d1673fc6e0..c80c9479ad4aff95906967047cdd4b3c593fb854 100644 --- a/src/Jackett/Indexers/BaseIndexer.cs +++ b/src/Jackett/Indexers/BaseIndexer.cs @@ -147,28 +147,28 @@ namespace Jackett.Indexers } } - protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null) + protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) { var byteResult = new WebClientByteResult(); // Map to byte Mapper.Map(response, byteResult); - await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies); + await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); // Map to string Mapper.Map(byteResult, response); } - protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null) + protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) { // Follow up to 5 redirects for (int i = 0; i < 5; i++) { if (!response.IsRedirect) break; - await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies); - if (response.Cookies != null && overrideCookies != null) + await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); + if (accumulateCookies) { - response.Cookies = overrideCookies + " " + response.Cookies; - overrideCookies = response.Cookies; + CookieHeader = ResolveCookies(response.Cookies); + response.Cookies = CookieHeader; } if (overrideCookies != null && response.Cookies == null) { @@ -177,16 +177,39 @@ namespace Jackett.Indexers } } - private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null) + private String ResolveCookies(String incomingCookies = "") + { + var redirRequestCookies = (CookieHeader != "" ? CookieHeader + " " : "") + incomingCookies; + System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\s]+)=([^=]+)(?:\s|$)"); + Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>(); + var matches = expression.Match(redirRequestCookies); + while (matches.Success) + { + if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value; + matches = matches.NextMatch(); + } + return string.Join(" ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray()); + + } + + private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) { if (incomingResponse.IsRedirect) { + var redirRequestCookies = ""; + if (accumulateCookies) + { + redirRequestCookies = ResolveCookies((CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null ? overrideCookies : "")); + } else + { + redirRequestCookies = (overrideCookies != null ? overrideCookies : ""); + } // Do redirect var redirectedResponse = await webclient.GetBytes(new WebRequest() { Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo, Referer = referrer, - Cookies = overrideCookies ?? CookieHeader + Cookies = redirRequestCookies }); Mapper.Map(redirectedResponse, incomingResponse); } @@ -371,30 +394,20 @@ namespace Jackett.Indexers var response = await webclient.GetString(request); if (accumulateCookies) { - response.Cookies = (request.Cookies == null ? "" : request.Cookies + " ") + response.Cookies; + response.Cookies = ResolveCookies((request.Cookies == null ? "" : request.Cookies + " ") + response.Cookies); } var firstCallCookies = response.Cookies; if (response.IsRedirect) { - await FollowIfRedirect(response, request.Url, redirectUrlOverride, response.Cookies); + await FollowIfRedirect(response, request.Url, redirectUrlOverride, response.Cookies, accumulateCookies); } if (returnCookiesFromFirstCall) { - response.Cookies = firstCallCookies + (accumulateCookies ? " " + response.Cookies : ""); - } - // resolve cookie conflicts - really no need for this as the webclient will handle it - System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\s]+)=([^=]+)(?:\s|$)"); - Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>(); - var matches = expression.Match(response.Cookies); - while (matches.Success) - { - if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value; - matches = matches.NextMatch(); + response.Cookies = ResolveCookies(firstCallCookies + (accumulateCookies ? " " + response.Cookies : "")); } - response.Cookies = string.Join(" ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray()); - + return response; } diff --git a/src/Jackett/Indexers/BitSoup.cs b/src/Jackett/Indexers/BitSoup.cs index 7af224584d8150eec6e07b14ed4e8c918f50d56a..accc6fb2c5ccdc0c123335e688b96867251a0bd6 100644 --- a/src/Jackett/Indexers/BitSoup.cs +++ b/src/Jackett/Indexers/BitSoup.cs @@ -1,46 +1,53 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; - -namespace Jackett.Indexers -{ - public class BitSoup : BaseIndexer, IIndexer - { - 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 BitSoup(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "BitSoup", - description: "SoupieBits", - link: "https://www.bitsoup.me/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) +using CsQuery; +using Jackett.Models; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class BitSoup : BaseIndexer, IIndexer + { + private string UseLink { get { return (this.configData.AlternateLink.Value != "" ? this.configData.AlternateLink.Value : SiteLink); } } + private string BrowseUrl { get { return UseLink + "browse.php"; } } + private string LoginUrl { get { return UseLink + "takelogin.php"; } } + private string LoginReferer { get { return UseLink + "login.php"; } } + private List<String> KnownURLs = new List<String>{ "https://www.bitsoup.me/","https://www.bitsoup.org/"}; + + new NxtGnConfigurationData configData + { + get { return (NxtGnConfigurationData)base.configData; } + set { base.configData = value; } + } + + public BitSoup(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "BitSoup", + description: "SoupieBits", + link: "https://www.bitsoup.me/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new NxtGnConfigurationData()) { + this.configData.DisplayText.Value = this.DisplayName + " has multiple URLs. The default (" + this.SiteLink + ") can be changed by entering a new value in the box below."; + this.configData.DisplayText.Value += "The following are some known URLs for " + this.DisplayName; + this.configData.DisplayText.Value += "<ul><li>" + String.Join("</li><li>", this.KnownURLs.ToArray()) + "</li></ul>"; //AddCategoryMapping("624", TorznabCatType.Console); //AddCategoryMapping("307", TorznabCatType.ConsoleNDS); @@ -134,45 +141,58 @@ namespace Jackett.Indexers //AddCategoryMapping("1", TorznabCatType.BooksTechnical); //AddCategoryMapping("1", TorznabCatType.BooksOther); //AddCategoryMapping("1", TorznabCatType.BooksForeign); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "returnto", "/" }, - { "login", "Log in!" } - }; - - var loginPage = await RequestStringWithCookies(SiteLink, string.Empty); - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, SiteLink, SiteLink, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["body > div"].First(); - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var trackerCats = MapTorznabCapsToTrackers(query); - var queryCollection = new NameValueCollection(); - - - - if (!string.IsNullOrWhiteSpace(searchString)) + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + if (configData.AlternateLink.Value != null && configData.AlternateLink.Value != "") + { + if (!configData.AlternateLink.Value.EndsWith("/")) + { + configData.AlternateLink.Value = null; + throw new Exception("AlternateLink must end with a slash."); + } + var match = Regex.Match(configData.AlternateLink.Value, "^https?:\\/\\/(?:[\\w]+\\.)+(?:[a-zA-Z]+)\\/$"); + if (!match.Success) + { + configData.AlternateLink.Value = null; + throw new Exception("AlternateLink must be a valid url."); + } + } + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + + }; + + var loginPage = await RequestStringWithCookies(UseLink, string.Empty); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginReferer, true); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["body > table.statusbar1 > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td"].First(); + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var trackerCats = MapTorznabCapsToTrackers(query); + var queryCollection = new NameValueCollection(); + + + + if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("search", searchString); - queryCollection.Add("incldead", "0"); + queryCollection.Add("incldead", "0"); queryCollection.Add("cat", "0"); // Tracker cannot search multi categories // so we either search "all" @@ -190,37 +210,37 @@ namespace Jackett.Indexers searchUrl += "?" + queryCollection.GetQueryString(); await ProcessPage(releases, searchUrl); } - } + } - } - else + } + else { - queryCollection.Add("search", ""); - queryCollection.Add("cat", "0"); - searchUrl += "?" + queryCollection.GetQueryString(); - await ProcessPage(releases, searchUrl); - } - - return releases; - } - - private async Task ProcessPage(List<ReleaseInfo> releases, string searchUrl) - { - var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); - var results = response.Content; - try - { - CQ dom = results; - - var rows = dom["table.koptekst tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - + queryCollection.Add("search", ""); + queryCollection.Add("cat", "0"); + searchUrl += "?" + queryCollection.GetQueryString(); + await ProcessPage(releases, searchUrl); + } + + return releases; + } + + private async Task ProcessPage(List<ReleaseInfo> releases, string searchUrl) + { + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + var results = response.Content; + try + { + CQ dom = results; + + var rows = dom["table.koptekst tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.Title = row.Cq().Find("td:eq(1) a").First().Text().Trim(); - release.Comments = new Uri(SiteLink + row.Cq().Find("td:eq(1) a").First().Attr("href")); - - release.Link = new Uri(SiteLink + row.Cq().Find("td:eq(2) a").First().Attr("href")); + release.Comments = new Uri(UseLink + row.Cq().Find("td:eq(1) a").First().Attr("href")); + + release.Link = new Uri(UseLink + row.Cq().Find("td:eq(2) a").First().Attr("href")); release.Description = release.Title; var cat = row.Cq().Find("td:eq(0) a").First().Attr("href").Substring(15); release.Category = MapTrackerCatToNewznab(cat); @@ -234,13 +254,31 @@ namespace Jackett.Indexers release.Seeders = ParseUtil.CoerceInt(row.Cq().Find("td:eq(10)").First().Text().Trim()); release.Peers = ParseUtil.CoerceInt(row.Cq().Find("td:eq(11)").First().Text().Trim()) + release.Seeders; - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results, ex); - } - } - } -} + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + } + + public class NxtGnConfigurationData : ConfigurationData + { + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public DisplayItem DisplayText { get; private set; } + public StringItem AlternateLink { get; set; } + + + public NxtGnConfigurationData() + { + Username = new StringItem { Name = "Username" }; + Password = new StringItem { Name = "Password" }; + DisplayText = new DisplayItem("") { Name = "" }; + AlternateLink = new StringItem { Name = "AlternateLinks" }; + } + + } + } +} diff --git a/src/Jackett/Indexers/XSpeeds.cs b/src/Jackett/Indexers/XSpeeds.cs index 1c74b4df45802ddc93bc6390a2839c4fe627e8f0..5abe5a01b18dba4e653fab5d19e58c3f9b5cddd8 100644 --- a/src/Jackett/Indexers/XSpeeds.cs +++ b/src/Jackett/Indexers/XSpeeds.cs @@ -127,6 +127,9 @@ namespace Jackett.Indexers if (string.IsNullOrWhiteSpace(searchString)) { var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value)); + if (rssPage.Content.EndsWith("\0")) { + rssPage.Content = rssPage.Content.Substring(0, rssPage.Content.Length - 1); + } var rssDoc = XDocument.Parse(rssPage.Content); foreach (var item in rssDoc.Descendants("item")) @@ -170,6 +173,11 @@ namespace Jackett.Indexers } else { + if (searchString.Length < 3) + { + OnParseError("", new Exception("Minimum search length is 3")); + return releases; + } var searchParams = new Dictionary<string, string> { { "do", "search" }, { "keywords", searchString }, diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationData.cs b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs index 499a6879128186ab072a5e4ed79a6fc096f4773a..134968542926d5c905ff86dfc6963e2a4cd6fe48 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationData.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs @@ -132,7 +132,7 @@ namespace Jackett.Models.IndexerConfig if (!forDisplay) { properties = properties - .Where(p => p.ItemType == ItemType.HiddenData || p.ItemType == ItemType.InputBool || p.ItemType == ItemType.InputString || p.ItemType == ItemType.Recaptcha) + .Where(p => p.ItemType == ItemType.HiddenData || p.ItemType == ItemType.InputBool || p.ItemType == ItemType.InputString || p.ItemType == ItemType.Recaptcha || p.ItemType == ItemType.DisplayInfo) .ToArray(); } diff --git a/src/Jackett/Startup.cs b/src/Jackett/Startup.cs index 7426088f0cece811088e3c0ea07e643a9129bc44..d462836f33b21eff36182a420d8ad40badb95f1f 100644 --- a/src/Jackett/Startup.cs +++ b/src/Jackett/Startup.cs @@ -40,6 +40,11 @@ namespace Jackett set; } + public static string ProxyConnection + { + get; + set; + } public static bool? DoSSLFix { get; diff --git a/src/Jackett/Utils/Clients/HttpWebClient.cs b/src/Jackett/Utils/Clients/HttpWebClient.cs index e4848ec148511d59c952b912960f8dace220a3bd..2e2602d05b634e74bdacf2d1144e56fd648e8465 100644 --- a/src/Jackett/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett/Utils/Clients/HttpWebClient.cs @@ -62,18 +62,28 @@ namespace Jackett.Utils.Clients } } } - + var useProxy = false; + WebProxy proxyServer = null; + if (Startup.ProxyConnection != null) + { + proxyServer = new WebProxy(Startup.ProxyConnection, false); + useProxy = true; + } var client = new HttpClient(new HttpClientHandler { CookieContainer = cookies, AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. UseCookies = true, + Proxy = proxyServer, + UseProxy = useProxy }); + - if(webRequest.EmulateBrowser) + if (webRequest.EmulateBrowser) client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); else client.DefaultRequestHeaders.Add("User-Agent", "Jackett/" + configService.GetVersion()); + HttpResponseMessage response = null; var request = new HttpRequestMessage(); request.Headers.ExpectContinue = false; @@ -158,6 +168,7 @@ namespace Jackett.Utils.Clients // http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer IEnumerable<string> cookieHeaders; var responseCookies = new List<Tuple<string, string>>(); + if (response.Headers.TryGetValues("set-cookie", out cookieHeaders)) { foreach (var value in cookieHeaders) diff --git a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs index 39eeec4e1aadbac75d6d477e5406b14ba02b59bd..1bb92ee0d9ea550284bc5ddbda776e8c15f53f16 100644 --- a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs @@ -104,6 +104,28 @@ namespace Jackett.Utils.Clients case "location": result.RedirectingTo = header[1]; break; + case "refresh": + if (response.Status == System.Net.HttpStatusCode.ServiceUnavailable) + { + //"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R" + var redirval = ""; + var value = header[1]; + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + result.Status = System.Net.HttpStatusCode.Redirect; + var redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); + } + } + break; } } } diff --git a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs index 7c124ddc5547a6a2dfc2dc66a620e044d3fbb364..cecef59eaa38158c0a71651f8c29d6ae07ddeb5b 100644 --- a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs @@ -50,6 +50,11 @@ namespace Jackett.Utils.Clients private async Task<WebClientByteResult> Run(WebRequest request) { var args = new StringBuilder(); + if (Startup.ProxyConnection != null) + { + args.AppendFormat("-x " + Startup.ProxyConnection + " "); + } + args.AppendFormat("--url \"{0}\" ", request.Url); if (request.EmulateBrowser) @@ -86,11 +91,16 @@ namespace Jackett.Utils.Clients // https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html args.Append("--cipher " + SSLFix.CipherList); } - + if (Startup.IgnoreSslErrors == true) + { + args.Append("-k "); + } + args.Append("-H \"Accept-Language: en-US,en\" "); + args.Append("-H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\" "); 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); @@ -101,6 +111,16 @@ namespace Jackett.Utils.Clients if (headSplit < 0) throw new Exception("Invalid response"); var headers = stdout.Substring(0, headSplit); + if (Startup.ProxyConnection != null) + { + // the proxy provided headers too so we need to split headers again + var headSplit1 = stdout.IndexOf("\r\n\r\n",headSplit + 4); + if (headSplit1 > 0) + { + headers = stdout.Substring(headSplit + 4,headSplit1 - (headSplit + 4)); + headSplit = headSplit1; + } + } var headerCount = 0; var cookieBuilder = new StringBuilder(); var cookies = new List<Tuple<string, string>>(); @@ -131,6 +151,24 @@ namespace Jackett.Utils.Clients case "location": result.RedirectingTo = value.Trim(); break; + case "refresh": + //"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R" + var redirval = ""; + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + result.Status = System.Net.HttpStatusCode.Redirect; + var redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); + } + break; } } }