From bb32831e9fbd8d97a393a065fc7d8ce2840ee490 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Jul 2015 21:21:29 -0600 Subject: [PATCH 1/3] Fixed bug with download proxy url using indexerName instead of indexerID --- src/Jackett/Controllers/APIController.cs | 6 +++--- src/Jackett/Controllers/DownloadController.cs | 6 +++--- src/Jackett/Startup.cs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Jackett/Controllers/APIController.cs b/src/Jackett/Controllers/APIController.cs index 8b28ef0bc..6435cff45 100644 --- a/src/Jackett/Controllers/APIController.cs +++ b/src/Jackett/Controllers/APIController.cs @@ -29,9 +29,9 @@ namespace Jackett.Controllers } [HttpGet] - public async Task Call(string indexerName) + public async Task Call(string indexerID) { - var indexer = indexerService.GetIndexer(indexerName); + var indexer = indexerService.GetIndexer(indexerID); var torznabQuery = TorznabQuery.FromHttpQuery(HttpUtility.ParseQueryString(Request.RequestUri.Query)); if (string.Equals(torznabQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase)) @@ -70,7 +70,7 @@ namespace Jackett.Controllers continue; var originalLink = release.Link; var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/download.torrent"; - var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexer.DisplayName, encodedLink); + var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexer.ID, encodedLink); release.Link = new Uri(proxyLink); } diff --git a/src/Jackett/Controllers/DownloadController.cs b/src/Jackett/Controllers/DownloadController.cs index a43fcb6ff..1b7496b0c 100644 --- a/src/Jackett/Controllers/DownloadController.cs +++ b/src/Jackett/Controllers/DownloadController.cs @@ -26,11 +26,11 @@ namespace Jackett.Controllers } [HttpGet] - public async Task Download(string indexerName, string path) + public async Task Download(string indexerID, string path) { try { - var indexer = indexerService.GetIndexer(indexerName); + var indexer = indexerService.GetIndexer(indexerID); var remoteFile = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); var downloadBytes = await indexer.Download(new Uri(remoteFile)); @@ -41,7 +41,7 @@ namespace Jackett.Controllers } catch (Exception e) { - logger.Error(e, "Error downloading " + indexerName + " " + path); + logger.Error(e, "Error downloading " + indexerID + " " + path); return new HttpResponseMessage(HttpStatusCode.NotFound); } } diff --git a/src/Jackett/Startup.cs b/src/Jackett/Startup.cs index a69a022b5..01c1cf70a 100644 --- a/src/Jackett/Startup.cs +++ b/src/Jackett/Startup.cs @@ -51,19 +51,19 @@ namespace Jackett config.Routes.MapHttpRoute( name: "apiDefault", - routeTemplate: "api/{indexerName}", + routeTemplate: "api/{indexerID}", defaults: new { controller = "API", action = "Call" } ); config.Routes.MapHttpRoute( name: "api", - routeTemplate: "api/{indexerName}/api", + routeTemplate: "api/{indexerID}/api", defaults: new { controller = "API", action = "Call" } ); config.Routes.MapHttpRoute( name: "download", - routeTemplate: "api/{indexerName}/download/{path}/download.torrent", + routeTemplate: "api/{indexerID}/download/{path}/download.torrent", defaults: new { controller = "Download", action = "Download" } ); From 15ee194035ce7d8b0dfd8beda14a47910efcd546 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Jul 2015 23:16:13 -0600 Subject: [PATCH 2/3] Abstracted common "time ago" date string parsing logic --- src/Jackett/Indexers/BB.cs | 23 +---------------- src/Jackett/Indexers/BeyondHD.cs | 19 +------------- src/Jackett/Indexers/HDTorrents.cs | 17 +------------ src/Jackett/Indexers/IPTorrents.cs | 35 ++++--------------------- src/Jackett/Indexers/TorrentDay.cs | 19 +------------- src/Jackett/Indexers/TorrentShack.cs | 26 +------------------ src/Jackett/Utils/DateTimeUtil.cs | 38 ++++++++++++++++++++++++++++ src/Jackett/Utils/ParseUtil.cs | 12 ++++----- 8 files changed, 54 insertions(+), 135 deletions(-) diff --git a/src/Jackett/Indexers/BB.cs b/src/Jackett/Indexers/BB.cs index e23c56f82..6eadcee5a 100644 --- a/src/Jackett/Indexers/BB.cs +++ b/src/Jackett/Indexers/BB.cs @@ -130,28 +130,7 @@ namespace Jackett.Indexers release.Link = new Uri(BaseUrl + "/" + qDownload.Attr("href")); var dateStr = row.ChildElements.ElementAt(3).Cq().Text().Trim().Replace(" and", ""); - var dateParts = dateStr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - TimeSpan timeAgo = TimeSpan.Zero; - for (var i = 0; i < dateParts.Length / 2; i++) - { - var val = ParseUtil.CoerceInt(dateParts[i * 2]); - var unit = dateParts[i * 2 + 1]; - if (unit.Contains("sec")) - timeAgo += TimeSpan.FromSeconds(val); - else if (unit.Contains("min")) - timeAgo += TimeSpan.FromMinutes(val); - else if (unit.Contains("hour")) - timeAgo += TimeSpan.FromHours(val); - else if (unit.Contains("day")) - timeAgo += TimeSpan.FromDays(val); - else if (unit.Contains("week")) - timeAgo += TimeSpan.FromDays(val * 7); - else if (unit.Contains("month")) - timeAgo += TimeSpan.FromDays(val * 30); - else if (unit.Contains("year")) - timeAgo += TimeSpan.FromDays(val * 365); - } - release.PublishDate = DateTime.SpecifyKind(DateTime.Now - timeAgo, DateTimeKind.Local); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = row.ChildElements.ElementAt(4).Cq().Text().Trim(); var sizeParts = sizeStr.Split(' '); diff --git a/src/Jackett/Indexers/BeyondHD.cs b/src/Jackett/Indexers/BeyondHD.cs index b8e082d00..c71f5d86f 100644 --- a/src/Jackett/Indexers/BeyondHD.cs +++ b/src/Jackett/Indexers/BeyondHD.cs @@ -114,24 +114,7 @@ namespace Jackett.Indexers release.Guid = release.Comments; var dateStr = descCol.ChildElements.Last().Cq().Text().Split('|').Last().ToLowerInvariant().Replace("ago.", "").Trim(); - var dateParts = dateStr.Split(new char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries); - var timeSpan = TimeSpan.Zero; - for (var i = 0; i < dateParts.Length / 2; i++) - { - var timeVal = ParseUtil.CoerceInt(dateParts[i * 2]); - var timeUnit = dateParts[i * 2 + 1]; - if (timeUnit.Contains("year")) - timeSpan += TimeSpan.FromDays(365 * timeVal); - else if (timeUnit.Contains("month")) - timeSpan += TimeSpan.FromDays(30 * timeVal); - else if (timeUnit.Contains("day")) - timeSpan += TimeSpan.FromDays(timeVal); - else if (timeUnit.Contains("hour")) - timeSpan += TimeSpan.FromHours(timeVal); - else if (timeUnit.Contains("min")) - timeSpan += TimeSpan.FromMinutes(timeVal); - } - release.PublishDate = DateTime.SpecifyKind(DateTime.Now - timeSpan, DateTimeKind.Local); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeEl = row.ChildElements.ElementAt(7); var sizeVal = ParseUtil.CoerceFloat(sizeEl.ChildNodes.First().NodeValue); diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs index 73ccdb38e..643c5385f 100644 --- a/src/Jackett/Indexers/HDTorrents.cs +++ b/src/Jackett/Indexers/HDTorrents.cs @@ -169,22 +169,7 @@ namespace Jackett.Indexers string fullSize = qRow.Find("td.mainblockcontent").Get(6).InnerText; string[] sizeSplit = fullSize.Split(' '); - switch (sizeSplit[1].ToLower()) - { - case "kb": - size = ReleaseInfo.BytesFromKB(ParseUtil.CoerceFloat(sizeSplit[0])); - break; - case "mb": - size = ReleaseInfo.BytesFromMB(ParseUtil.CoerceFloat(sizeSplit[0])); - break; - case "gb": - size = ReleaseInfo.BytesFromGB(ParseUtil.CoerceFloat(sizeSplit[0])); - break; - default: - size = null; - break; - } - release.Size = size; + release.Size = ReleaseInfo.GetBytes(sizeSplit[1], ParseUtil.CoerceFloat(sizeSplit[0])); release.Guid = new Uri(SiteLink + "/" + qRow.Find("td.mainblockcontent b a").Attr("href")); release.Link = new Uri(SiteLink + "/" + qRow.Find("td.mainblockcontent").Get(3).FirstChild.GetAttribute("href")); diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index dd351fbf5..802e7c02e 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -33,7 +33,7 @@ namespace Jackett.Indexers logger: l) { SearchUrl = SiteLink + "t?q="; - webclient =wc; + webclient = wc; } public Task GetConfigurationForSetup() @@ -58,7 +58,8 @@ namespace Jackett.Indexers Url = SiteLink.ToString(), PostData = pairs, Referer = SiteLink.ToString(), - Type = RequestType.POST + Type = RequestType.POST, + AutoRedirect = true }); cookieHeader = response.Cookies; @@ -91,16 +92,7 @@ namespace Jackett.Indexers } } - HttpRequestMessage CreateHttpRequest(Uri uri) - { - var message = new HttpRequestMessage(); - message.Method = HttpMethod.Get; - message.RequestUri = uri; - message.Headers.UserAgent.ParseAdd(BrowserUtil.ChromeUserAgent); - return message; - } - - public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) + public void LoadFromSavedConfiguration(JToken jsonConfig) { cookieHeader = (string)jsonConfig["cookies"]; IsConfigured = true; @@ -137,27 +129,10 @@ namespace Jackett.Indexers release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); release.Comments = release.Guid; - DateTime pubDate; var descString = qRow.Find(".t_ctime").Text(); var dateString = descString.Split('|').Last().Trim(); dateString = dateString.Split(new string[] { " by " }, StringSplitOptions.None)[0]; - var dateValue = ParseUtil.CoerceFloat(dateString.Split(' ')[0]); - var dateUnit = dateString.Split(' ')[1]; - if (dateUnit.Contains("minute")) - pubDate = DateTime.Now - TimeSpan.FromMinutes(dateValue); - else if (dateUnit.Contains("hour")) - pubDate = DateTime.Now - TimeSpan.FromHours(dateValue); - else if (dateUnit.Contains("day")) - pubDate = DateTime.Now - TimeSpan.FromDays(dateValue); - else if (dateUnit.Contains("week")) - pubDate = DateTime.Now - TimeSpan.FromDays(7 * dateValue); - else if (dateUnit.Contains("month")) - pubDate = DateTime.Now - TimeSpan.FromDays(30 * dateValue); - else if (dateUnit.Contains("year")) - pubDate = DateTime.Now - TimeSpan.FromDays(365 * dateValue); - else - pubDate = DateTime.MinValue; - release.PublishDate = pubDate; + release.PublishDate = DateTimeUtil.FromTimeAgo(dateString); var qLink = row.ChildElements.ElementAt(3).Cq().Children("a"); release.Link = new Uri(SiteLink + qLink.Attr("href")); diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs index ca4107c8d..e5fa4323d 100644 --- a/src/Jackett/Indexers/TorrentDay.cs +++ b/src/Jackett/Indexers/TorrentDay.cs @@ -137,24 +137,7 @@ namespace Jackett.Indexers release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); var dateStr = qRow.Find(".ulInfo").Text().Split('|').Last().Trim(); - var dateParts = dateStr.Split(' '); - var dateValue = ParseUtil.CoerceInt(dateParts[0]); - TimeSpan ts = TimeSpan.Zero; - if (dateStr.Contains("sec")) - ts = TimeSpan.FromSeconds(dateValue); - else if (dateStr.Contains("min")) - ts = TimeSpan.FromMinutes(dateValue); - else if (dateStr.Contains("hour")) - ts = TimeSpan.FromHours(dateValue); - else if (dateStr.Contains("day")) - ts = TimeSpan.FromDays(dateValue); - else if (dateStr.Contains("week")) - ts = TimeSpan.FromDays(dateValue * 7); - else if (dateStr.Contains("month")) - ts = TimeSpan.FromDays(dateValue * 30); - else if (dateStr.Contains("year")) - ts = TimeSpan.FromDays(dateValue * 365); - release.PublishDate = DateTime.Now - ts; + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seedersInfo").Text()); release.Peers = ParseUtil.CoerceInt(qRow.Find(".leechersInfo").Text()) + release.Seeders; diff --git a/src/Jackett/Indexers/TorrentShack.cs b/src/Jackett/Indexers/TorrentShack.cs index b466f7568..321ce56c6 100644 --- a/src/Jackett/Indexers/TorrentShack.cs +++ b/src/Jackett/Indexers/TorrentShack.cs @@ -118,31 +118,7 @@ namespace Jackett.Indexers release.Link = new Uri(SiteLink + "/" + qRow.Find(".torrent_handle_links > a").First().Attr("href")); var dateStr = qRow.Find(".time").Text().Trim(); - if (dateStr.ToLower().Contains("just now")) - release.PublishDate = DateTime.Now; - else - { - var dateParts = dateStr.Split(' '); - var dateValue = ParseUtil.CoerceInt(dateParts[0]); - TimeSpan ts = TimeSpan.Zero; - if (dateStr.Contains("Just now")) - ts = TimeSpan.Zero; - else if (dateStr.Contains("sec")) - ts = TimeSpan.FromSeconds(dateValue); - else if (dateStr.Contains("min")) - ts = TimeSpan.FromMinutes(dateValue); - else if (dateStr.Contains("hour")) - ts = TimeSpan.FromHours(dateValue); - else if (dateStr.Contains("day")) - ts = TimeSpan.FromDays(dateValue); - else if (dateStr.Contains("week")) - ts = TimeSpan.FromDays(dateValue * 7); - else if (dateStr.Contains("month")) - ts = TimeSpan.FromDays(dateValue * 30); - else if (dateStr.Contains("year")) - ts = TimeSpan.FromDays(dateValue * 365); - release.PublishDate = DateTime.Now - ts; - } + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); var sizeStr = qRow.Find(".size")[0].ChildNodes[0].NodeValue.Trim(); var sizeParts = sizeStr.Split(' '); diff --git a/src/Jackett/Utils/DateTimeUtil.cs b/src/Jackett/Utils/DateTimeUtil.cs index 093df7a76..81b0c5c0c 100644 --- a/src/Jackett/Utils/DateTimeUtil.cs +++ b/src/Jackett/Utils/DateTimeUtil.cs @@ -14,5 +14,43 @@ namespace Jackett.Utils long unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond); return new DateTime(unixStart.Ticks + unixTimeStampInTicks); } + + // ex: "2 hours 1 day" + public static DateTime FromTimeAgo(string str) + { + str = str.ToLowerInvariant(); + if (str.Contains("now")) + { + return DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); + } + + var dateParts = str.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); + TimeSpan timeAgo = TimeSpan.Zero; + for (var i = 0; i < dateParts.Length / 2; i++) + { + var val = ParseUtil.CoerceFloat(dateParts[i * 2]); + var unit = dateParts[i * 2 + 1]; + if (unit.Contains("sec")) + timeAgo += TimeSpan.FromSeconds(val); + else if (unit.Contains("min")) + timeAgo += TimeSpan.FromMinutes(val); + else if (unit.Contains("hour")) + timeAgo += TimeSpan.FromHours(val); + else if (unit.Contains("day")) + timeAgo += TimeSpan.FromDays(val); + else if (unit.Contains("week")) + timeAgo += TimeSpan.FromDays(val * 7); + else if (unit.Contains("month")) + timeAgo += TimeSpan.FromDays(val * 30); + else if (unit.Contains("year")) + timeAgo += TimeSpan.FromDays(val * 365); + else + { + throw new Exception("TimeAgo parsing failed"); + } + } + + return DateTime.SpecifyKind(DateTime.Now - timeAgo, DateTimeKind.Local); + } } } diff --git a/src/Jackett/Utils/ParseUtil.cs b/src/Jackett/Utils/ParseUtil.cs index c96e2be7a..7af729426 100644 --- a/src/Jackett/Utils/ParseUtil.cs +++ b/src/Jackett/Utils/ParseUtil.cs @@ -11,33 +11,33 @@ namespace Jackett.Utils { public static float CoerceFloat(string str) { - return float.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + return float.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); } public static int CoerceInt(string str) { - return int.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + return int.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); } public static long CoerceLong(string str) { - return long.Parse(str, NumberStyles.Any, CultureInfo.InvariantCulture); + return long.Parse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture); } public static bool TryCoerceFloat(string str, out float result) { - return float.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out result); + return float.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result); } public static bool TryCoerceInt(string str, out int result) { - return int.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out result); + return int.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result); } public static bool TryCoerceLong(string str, out long result) { - return long.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out result); + return long.TryParse(str.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out result); } } From 8a7ab0c5f1023f7a385f1ff0e411df484c78e1fb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Jul 2015 23:16:35 -0600 Subject: [PATCH 3/3] Implemented PrivateHD --- src/Jackett/Content/logos/privatehd.png | Bin 0 -> 23271 bytes src/Jackett/Indexers/PrivateHD.cs | 167 ++++++++++++++++++ src/Jackett/Jackett.csproj | 4 + src/Jackett/Utils/Clients/WebRequest.cs | 1 + src/Jackett/Utils/Clients/WindowsWebClient.cs | 8 +- 5 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 src/Jackett/Content/logos/privatehd.png create mode 100644 src/Jackett/Indexers/PrivateHD.cs diff --git a/src/Jackett/Content/logos/privatehd.png b/src/Jackett/Content/logos/privatehd.png new file mode 100644 index 0000000000000000000000000000000000000000..bb3eb495fa67380c477277a47d66e394702b9f22 GIT binary patch literal 23271 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 CzJu`q literal 0 HcmV?d00001 diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs new file mode 100644 index 000000000..6c41ada3d --- /dev/null +++ b/src/Jackett/Indexers/PrivateHD.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models; +using Newtonsoft.Json.Linq; +using NLog; +using Jackett.Utils; +using System.Net; +using System.Net.Http; +using CsQuery; +using System.Web; +using Jackett.Services; +using Jackett.Utils.Clients; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class PrivateHD : BaseIndexer, IIndexer + { + private readonly string LoginUrl = ""; + private readonly string SearchUrl = ""; + private string cookieHeader = ""; + + private IWebClient webclient; + + public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l) + : base(name: "PrivateHD", + description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", + link: new Uri("https://privatehd.to"), + caps: TorznabCapsUtil.CreateDefaultTorznabTVCaps(), + manager: i, + logger: l) + { + LoginUrl = SiteLink + "auth/login"; + SearchUrl = SiteLink + "torrents?in=1&type=2&search={0}"; + webclient = wc; + } + + public async Task ApplyConfiguration(JToken configJson) + { + var config = new ConfigurationDataBasicLogin(); + config.LoadValuesFromJson(configJson); + + var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl, + Type = RequestType.GET, + AutoRedirect = true, + }); + + var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString(); + var pairs = new Dictionary { + { "_token", token }, + { "username_email", config.Username.Value }, + { "password", config.Password.Value }, + { "remember", "on" } + }; + + var response = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl, + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + AutoRedirect = true, + Cookies = loginPage.Cookies + }); + + if (!response.Content.Contains("auth/logout")) + { + CQ dom = response.Content; + var messageEl = dom[".form-error"]; + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); + } + else + { + cookieHeader = response.Cookies; + var configSaveData = new JObject(); + configSaveData["cookies"] = cookieHeader; + SaveConfig(configSaveData); + IsConfigured = true; + } + + } + + public async Task Download(Uri link) + { + var response = await webclient.GetBytes(new Utils.Clients.WebRequest() + { + Url = link.ToString(), + Cookies = cookieHeader + }); + + return response.Content; + } + + public Task GetConfigurationForSetup() + { + var config = new ConfigurationDataBasicLogin(); + return Task.FromResult(config); + } + + public void LoadFromSavedConfiguration(JToken jsonConfig) + { + cookieHeader = (string)jsonConfig["cookies"]; + IsConfigured = true; + } + + 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 response = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = episodeSearchUrl, + Referer = SiteLink.ToString(), + Cookies = cookieHeader + }); + var results = response.Content; + + try + { + CQ dom = results; + var rows = dom["table > tbody > tr"]; + foreach (var row in rows) + { + CQ qRow = row.Cq(); + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + var qLink = row.ChildElements.ElementAt(1).FirstElementChild.Cq(); + release.Title = qLink.Text().Trim(); + release.Comments = new Uri(qLink.Attr("href")); + release.Guid = release.Comments; + + var qDownload = row.ChildElements.ElementAt(3).FirstElementChild.Cq(); + release.Link = new Uri(qDownload.Attr("href")); + + var dateStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + + var sizeStr = row.ChildElements.ElementAt(6).Cq().Text().Trim(); + var sizeParts = sizeStr.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); + release.Size = ReleaseInfo.GetBytes(sizeParts[1], ParseUtil.CoerceFloat(sizeParts[0])); + + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + return releases.ToArray(); + } + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 1091c6eb6..f3128a72b 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -155,6 +155,7 @@ + @@ -283,6 +284,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Utils/Clients/WebRequest.cs b/src/Jackett/Utils/Clients/WebRequest.cs index b18e6a860..487b844e9 100644 --- a/src/Jackett/Utils/Clients/WebRequest.cs +++ b/src/Jackett/Utils/Clients/WebRequest.cs @@ -19,6 +19,7 @@ namespace Jackett.Utils.Clients public string Cookies { get; set; } public string Referer { get; set; } public RequestType Type { get; set; } + public bool AutoRedirect { get; set; } } public enum RequestType diff --git a/src/Jackett/Utils/Clients/WindowsWebClient.cs b/src/Jackett/Utils/Clients/WindowsWebClient.cs index 1c7ff8be9..7be704154 100644 --- a/src/Jackett/Utils/Clients/WindowsWebClient.cs +++ b/src/Jackett/Utils/Clients/WindowsWebClient.cs @@ -13,16 +13,18 @@ namespace Jackett.Utils.Clients class WindowsWebClient : IWebClient { private Logger logger; + CookieContainer cookies; public WindowsWebClient(Logger l) { logger = l; + cookies = new CookieContainer(); } public async Task GetBytes(WebRequest request) { logger.Debug(string.Format("WindowsWebClient:GetBytes(Url:{0})", request.Url)); - var cookies = new CookieContainer(); + if (!string.IsNullOrEmpty(request.Cookies)) { @@ -45,7 +47,6 @@ namespace Jackett.Utils.Clients CookieContainer = cookies, AllowAutoRedirect = false, UseCookies = true, - }); client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); @@ -92,9 +93,8 @@ namespace Jackett.Utils.Clients var client = new HttpClient(new HttpClientHandler { CookieContainer = cookies, - AllowAutoRedirect = false, + AllowAutoRedirect = request.AutoRedirect, UseCookies = true, - }); client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent);