From 226c27f90369a190808342005c14d181dda636f1 Mon Sep 17 00:00:00 2001 From: some-guy-23 Date: Mon, 21 Dec 2015 16:10:39 -0500 Subject: [PATCH 1/3] Added new tracker/indexer class for RevolutionTT.me --- src/Jackett/Content/logos/revolutiontt.png | Bin 0 -> 5047 bytes src/Jackett/Indexers/RevolutionTT.cs | 244 +++++++++++++++++++++ src/Jackett/Jackett.csproj | 4 + 3 files changed, 248 insertions(+) create mode 100644 src/Jackett/Content/logos/revolutiontt.png create mode 100644 src/Jackett/Indexers/RevolutionTT.cs diff --git a/src/Jackett/Content/logos/revolutiontt.png b/src/Jackett/Content/logos/revolutiontt.png new file mode 100644 index 0000000000000000000000000000000000000000..b674732c169e766f71d1556d3bce5b15705f7383 GIT binary patch literal 5047 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 literal 0 HcmV?d00001 diff --git a/src/Jackett/Indexers/RevolutionTT.cs b/src/Jackett/Indexers/RevolutionTT.cs new file mode 100644 index 000000000..db7197cc4 --- /dev/null +++ b/src/Jackett/Indexers/RevolutionTT.cs @@ -0,0 +1,244 @@ +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; + +namespace Jackett.Indexers +{ + public class RevolutionTT : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + private string SearchUrl { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataCookie configData + { + get { return (ConfigurationDataCookie)base.configData; } + set { base.configData = value; } + } + + public RevolutionTT(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "RevolutionTT", + description: "The Revolution has begun", + link: "https://revolutiontt.me/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + downloadBase: "https://revolutiontt.me/download.php/", + configData: new ConfigurationDataCookie()) + { + + /* Original RevolutionTT Categories - + + Anime - 23 + Appz/Misc - 22 + Appz/PC-ISO - 1 + E-Book - 36 + Games/PC-ISO - 4 + Games/PC-Rips - 21 + Games/PS3 - 16 + Games/Wii - 40 + Games/XBOX360 - 39 + Handheld/NDS - 35 + Handheld/PSP - 34 + Mac - 2 + Movies/BluRay - 10 + Movies/DVDR - 20 + Movies/HDx264 - 12 + Movies/Packs - 44 + Movies/SDx264 - 11 + Movies/XviD - 19 + Music - 6 + Music/FLAC - 8 + Music/Packs - 46 + MusicVideos - 29 + TV/DVDR - 43 + TV/HDx264 - 42 + TV/Packs - 45 + TV/SDx264 - 41 + TV/XViD - 7 + + */ + + //AddCategoryMapping("cat_id", TorznabCatType.Console); + AddCategoryMapping("35", TorznabCatType.ConsoleNDS); + AddCategoryMapping("34", TorznabCatType.ConsolePSP); + AddCategoryMapping("40", TorznabCatType.ConsoleWii); + //AddCategoryMapping("cat_id", TorznabCatType.ConsoleXbox); + AddCategoryMapping("39", TorznabCatType.ConsoleXbox360); + //AddCategoryMapping("cat_id", TorznabCatType.ConsoleWiiwareVC); + //AddCategoryMapping("cat_id", TorznabCatType.ConsoleXBOX360DLC); + AddCategoryMapping("16", TorznabCatType.ConsolePS3); + //AddCategoryMapping("cat_id", TorznabCatType.ConsoleOther); + //AddCategoryMapping("cat_id", TorznabCatType.Console3DS); + //AddCategoryMapping("cat_id", TorznabCatType.ConsolePSVita); + AddCategoryMapping("40", TorznabCatType.ConsoleWiiU); + //AddCategoryMapping("cat_id", TorznabCatType.ConsoleXboxOne); + //AddCategoryMapping("cat_id", TorznabCatType.ConsolePS4); + AddCategoryMapping("44", TorznabCatType.Movies); + //AddCategoryMapping("cat_id", TorznabCatType.MoviesForeign); + //AddCategoryMapping("cat_id", TorznabCatType.MoviesOther); + //Movies/DVDR, Movies/SDx264, Movies/XviD + AddMultiCategoryMapping(TorznabCatType.MoviesSD, 20, 11, 19); + //Movies/BluRay, Movies/HDx264 + AddMultiCategoryMapping(TorznabCatType.MoviesHD, 10, 12); + //AddCategoryMapping("cat_id", TorznabCatType.Movies3D); + AddCategoryMapping("10", TorznabCatType.MoviesBluRay); + AddCategoryMapping("20", TorznabCatType.MoviesDVD); + //AddCategoryMapping("cat_id", TorznabCatType.MoviesWEBDL); + //Music, Music/Packs + AddMultiCategoryMapping(TorznabCatType.Audio, 6, 46); + //AddCategoryMapping("cat_id", TorznabCatType.AudioMP3); + AddCategoryMapping("29", TorznabCatType.AudioVideo); + //AddCategoryMapping("cat_id", TorznabCatType.AudioAudiobook); + AddCategoryMapping("8", TorznabCatType.AudioLossless); + //AddCategoryMapping("cat_id", TorznabCatType.AudioOther); + //AddCategoryMapping("cat_id", TorznabCatType.AudioForeign); + AddCategoryMapping("21", TorznabCatType.PC); + AddCategoryMapping("22", TorznabCatType.PC0day); + AddCategoryMapping("4", TorznabCatType.PCISO); + AddCategoryMapping("2", TorznabCatType.PCMac); + //AddCategoryMapping("cat_id", TorznabCatType.PCPhoneOther); + //Games/PC-ISO, Games/PC-Rips + AddMultiCategoryMapping(TorznabCatType.PCGames, 4, 21); + //AddCategoryMapping("cat_id", TorznabCatType.PCPhoneIOS); + //AddCategoryMapping("cat_id", TorznabCatType.PCPhoneAndroid); + AddCategoryMapping("45", TorznabCatType.TV); + //AddCategoryMapping("cat_id", TorznabCatType.TVWEBDL); + //AddCategoryMapping("cat_id", TorznabCatType.TVFOREIGN); + //TV/DVDR, TV/SDx264, TV/XViD + AddMultiCategoryMapping(TorznabCatType.TVSD, 43, 41, 7); + AddCategoryMapping("42", TorznabCatType.TVHD); + //AddCategoryMapping("cat_id", TorznabCatType.TVOTHER); + //AddCategoryMapping("cat_id", TorznabCatType.TVSport); + AddCategoryMapping("23", TorznabCatType.TVAnime); + //AddCategoryMapping("cat_id", TorznabCatType.TVDocumentary); + //AddCategoryMapping("cat_id", TorznabCatType.XXX); + //AddCategoryMapping("cat_id", TorznabCatType.XXXDVD); + //AddCategoryMapping("cat_id", TorznabCatType.XXXWMV); + //AddCategoryMapping("cat_id", TorznabCatType.XXXXviD); + //AddCategoryMapping("cat_id", TorznabCatType.XXXx264); + //AddCategoryMapping("cat_id", TorznabCatType.XXXOther); + //AddCategoryMapping("cat_id", TorznabCatType.XXXImageset); + //AddCategoryMapping("cat_id", TorznabCatType.XXXPacks); + //AddCategoryMapping("cat_id", TorznabCatType.Other); + //AddCategoryMapping("cat_id", TorznabCatType.OtherMisc); + //AddCategoryMapping("cat_id", TorznabCatType.OtherHashed); + AddCategoryMapping("36", TorznabCatType.Books); + AddCategoryMapping("36", TorznabCatType.BooksEbook); + //AddCategoryMapping("cat_id", TorznabCatType.BooksComics); + //AddCategoryMapping("cat_id", TorznabCatType.BooksMagazines); + //AddCategoryMapping("cat_id", TorznabCatType.BooksTechnical); + //AddCategoryMapping("cat_id", TorznabCatType.BooksOther); + //AddCategoryMapping("cat_id", TorznabCatType.BooksForeign); + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + var result = await RequestStringWithCookies(SearchUrl, configData.Cookie.Value, null, null); + await ConfigureIfOK(configData.Cookie.Value, result.Content != null && result.Content.Contains("/logout.php"), () => + { + CQ dom = result.Content; + var messageEl = dom[".error"]; + var errorMessage = messageEl.Text().Trim(); + //--CloudFlare error? + if (errorMessage == "") + { + errorMessage = result.Content; + } + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + + if (!string.IsNullOrWhiteSpace(searchString)) + { + searchUrl += "?titleonly=1&search=" + HttpUtility.UrlEncode(searchString); + } + string.Format(SearchUrl, HttpUtility.UrlEncode(searchString)); + + var cats = MapTorznabCapsToTrackers(query); + if (cats.Count > 0) + { + foreach (var cat in cats) + { + searchUrl += "&c" + cat + "=1"; + } + } + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + + //--table header is the first in table body, get all rows except this + CQ qRows = dom["#torrents-table > tbody > tr:not(:first-child)"]; + + foreach (var row in qRows) + { + var release = new ReleaseInfo(); + + var qRow = row.Cq(); + + var debug = qRow.Html(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + CQ qLink = qRow.Find(".br_right > a").First(); + release.Guid = new Uri(SiteLink + qLink.Attr("href")); + release.Comments = new Uri(SiteLink + qLink.Attr("href") + "&tocomm=1"); + release.Title = qLink.Find("b").Text(); + release.Description = release.Title; + + release.Link = new Uri(SiteLink + qRow.Find("td:nth-child(4) > a").Attr("href")); + + var dateString = qRow.Find("td:nth-child(6) nobr")[0].InnerText.Trim(); + //"2015-04-25 23:38:12" + //"yyyy-MMM-dd hh:mm:ss" + release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); + + var sizeStr = qRow.Children().ElementAt(6).InnerText.Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").Text()); + + var category = qRow.Find(".br_type > a").Attr("href").Replace("browse.php?cat=", string.Empty); + release.Category = MapTrackerCatToNewznab(category); + + releases.Add(release); + } + } + + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} \ No newline at end of file diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 08e3f039a..0c83b159a 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -199,6 +199,7 @@ + @@ -478,6 +479,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From e4a47927b95a0ea49dbdfbf26ad7fd0ace254412 Mon Sep 17 00:00:00 2001 From: some-guy-23 Date: Mon, 21 Dec 2015 18:18:07 -0500 Subject: [PATCH 2/3] Fixed RevolutionTT so that login can use username/password (instead of cookie) --- src/Jackett/Indexers/RevolutionTT.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Jackett/Indexers/RevolutionTT.cs b/src/Jackett/Indexers/RevolutionTT.cs index db7197cc4..c39baa02d 100644 --- a/src/Jackett/Indexers/RevolutionTT.cs +++ b/src/Jackett/Indexers/RevolutionTT.cs @@ -19,13 +19,14 @@ using Jackett.Models.IndexerConfig; namespace Jackett.Indexers { public class RevolutionTT : BaseIndexer, IIndexer - { + { + private string LandingPageURL { get { return SiteLink + "login.php"; } } private string LoginUrl { get { return SiteLink + "takelogin.php"; } } private string SearchUrl { get { return SiteLink + "browse.php"; } } - new ConfigurationDataCookie configData + new ConfigurationDataBasicLogin configData { - get { return (ConfigurationDataCookie)base.configData; } + get { return (ConfigurationDataBasicLogin)base.configData; } set { base.configData = value; } } @@ -39,7 +40,7 @@ namespace Jackett.Indexers logger: l, p: ps, downloadBase: "https://revolutiontt.me/download.php/", - configData: new ConfigurationDataCookie()) + configData: new ConfigurationDataBasicLogin()) { /* Original RevolutionTT Categories - @@ -151,8 +152,16 @@ namespace Jackett.Indexers { configData.LoadValuesFromJson(configJson); - var result = await RequestStringWithCookies(SearchUrl, configData.Cookie.Value, null, null); - await ConfigureIfOK(configData.Cookie.Value, result.Content != null && result.Content.Contains("/logout.php"), () => + var pairs = new Dictionary { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + //--need to do an initial request to get PHP session cookie (any better way to do this?) + var homePageLoad = await RequestLoginAndFollowRedirect(LandingPageURL, new Dictionary { }, null, true, null, SiteLink); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, homePageLoad.Cookies, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("/logout.php"), () => { CQ dom = result.Content; var messageEl = dom[".error"]; From 6b1dba2dc3a5bc3032143ec6f9a942da3a235b26 Mon Sep 17 00:00:00 2001 From: some-guy-23 Date: Mon, 21 Dec 2015 20:03:50 -0500 Subject: [PATCH 3/3] Added RSS feed to RevolutionTT --- src/Jackett/Indexers/RevolutionTT.cs | 230 ++++++++++++++++++++------- 1 file changed, 169 insertions(+), 61 deletions(-) diff --git a/src/Jackett/Indexers/RevolutionTT.cs b/src/Jackett/Indexers/RevolutionTT.cs index c39baa02d..923219d84 100644 --- a/src/Jackett/Indexers/RevolutionTT.cs +++ b/src/Jackett/Indexers/RevolutionTT.cs @@ -15,6 +15,8 @@ using System.Text; using System.Threading.Tasks; using System.Web; using Jackett.Models.IndexerConfig; +using System.Text.RegularExpressions; +using System.Xml.Linq; namespace Jackett.Indexers { @@ -22,11 +24,15 @@ namespace Jackett.Indexers { private string LandingPageURL { get { return SiteLink + "login.php"; } } private string LoginUrl { get { return SiteLink + "takelogin.php"; } } - private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string GetRSSKeyUrl { get { return SiteLink + "getrss.php"; } } + private string RSSUrl { get { return SiteLink + "rss.php?feed=dl&passkey="; } } + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string DetailsURL { get { return SiteLink + "details.php?id={0}&hit=1"; } } - new ConfigurationDataBasicLogin configData + + new ConfigurationDataBasicLoginWithRSS configData { - get { return (ConfigurationDataBasicLogin)base.configData; } + get { return (ConfigurationDataBasicLoginWithRSS)base.configData; } set { base.configData = value; } } @@ -40,7 +46,7 @@ namespace Jackett.Indexers logger: l, p: ps, downloadBase: "https://revolutiontt.me/download.php/", - configData: new ConfigurationDataBasicLogin()) + configData: new ConfigurationDataBasicLoginWithRSS()) { /* Original RevolutionTT Categories - @@ -146,6 +152,35 @@ namespace Jackett.Indexers //AddCategoryMapping("cat_id", TorznabCatType.BooksTechnical); //AddCategoryMapping("cat_id", TorznabCatType.BooksOther); //AddCategoryMapping("cat_id", TorznabCatType.BooksForeign); + + // RSS Textual categories + AddCategoryMapping("Anime", TorznabCatType.TVAnime); + AddCategoryMapping("Appz/Misc", TorznabCatType.PC0day); + AddCategoryMapping("Appz/PC-ISO", TorznabCatType.Books); + AddCategoryMapping("E-Book", TorznabCatType.BooksEbook); + AddCategoryMapping("Games/PC-ISO", TorznabCatType.PCGames); + AddCategoryMapping("Games/PC-Rips", TorznabCatType.PCGames); + AddCategoryMapping("Games/PS3", TorznabCatType.ConsolePS3); + AddCategoryMapping("Games/Wii", TorznabCatType.ConsoleWii); + AddCategoryMapping("Games/XBOX360", TorznabCatType.ConsoleXbox360); + AddCategoryMapping("Handheld/NDS", TorznabCatType.ConsoleNDS); + AddCategoryMapping("Handheld/PSP", TorznabCatType.ConsolePSP); + AddCategoryMapping("Mac", TorznabCatType.PCMac); + AddCategoryMapping("Movies/BluRay", TorznabCatType.MoviesBluRay); + AddCategoryMapping("Movies/DVDR", TorznabCatType.MoviesDVD); + AddCategoryMapping("Movies/HDx264", TorznabCatType.MoviesHD); + AddCategoryMapping("Movies/Packs", TorznabCatType.Movies); + AddCategoryMapping("Movies/SDx264", TorznabCatType.MoviesSD); + AddCategoryMapping("Movies/XviD", TorznabCatType.MoviesSD); + AddCategoryMapping("Music", TorznabCatType.Audio); + AddCategoryMapping("Music/FLAC", TorznabCatType.AudioLossless); + AddCategoryMapping("Music/Packs", TorznabCatType.AudioOther); + AddCategoryMapping("MusicVideos", TorznabCatType.AudioVideo); + AddCategoryMapping("TV/DVDR", TorznabCatType.TV); + AddCategoryMapping("TV/HDx264", TorznabCatType.TVHD); + AddCategoryMapping("TV/Packs", TorznabCatType.TV); + AddCategoryMapping("TV/SDx264", TorznabCatType.TVSD); + AddCategoryMapping("TV/XViD", TorznabCatType.TVSD); } public async Task ApplyConfiguration(JToken configJson) @@ -157,22 +192,38 @@ namespace Jackett.Indexers { "password", configData.Password.Value } }; - //--need to do an initial request to get PHP session cookie (any better way to do this?) + // need to do an initial request to get PHP session cookie (any better way to do this?) var homePageLoad = await RequestLoginAndFollowRedirect(LandingPageURL, new Dictionary { }, null, true, null, SiteLink); - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, homePageLoad.Cookies, true, null, LoginUrl); + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, homePageLoad.Cookies, true, null, LandingPageURL); await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("/logout.php"), () => { CQ dom = result.Content; var messageEl = dom[".error"]; var errorMessage = messageEl.Text().Trim(); - //--CloudFlare error? - if (errorMessage == "") - { - errorMessage = result.Content; - } throw new ExceptionWithConfigData(errorMessage, configData); }); + + // Store RSS key from feed generator page + try + { + var rssParams = new Dictionary { + { "feed", "dl" } + }; + var rssPage = await PostDataWithCookies(GetRSSKeyUrl, rssParams, result.Cookies); + var match = Regex.Match(rssPage.Content, "(?<=passkey\\=)([a-zA-z0-9]*)"); + configData.RSSKey.Value = match.Success ? match.Value : string.Empty; + if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) + throw new Exception("Failed to get RSS Key"); + SaveConfig(); + } + catch (Exception e) + { + IsConfigured = false; + throw e; + } + + return IndexerConfigurationStatus.RequiresTesting; } @@ -182,69 +233,126 @@ namespace Jackett.Indexers var searchString = query.GetQueryString(); var searchUrl = SearchUrl; - if (!string.IsNullOrWhiteSpace(searchString)) + // If query is empty, use the RSS Feed + if (string.IsNullOrWhiteSpace(searchString)) { - searchUrl += "?titleonly=1&search=" + HttpUtility.UrlEncode(searchString); - } - string.Format(SearchUrl, HttpUtility.UrlEncode(searchString)); + var rssPage = await RequestStringWithCookiesAndRetry(RSSUrl + configData.RSSKey.Value); + var rssDoc = XDocument.Parse(rssPage.Content); - var cats = MapTorznabCapsToTrackers(query); - if (cats.Count > 0) - { - foreach (var cat in cats) + foreach (var item in rssDoc.Descendants("item")) { - searchUrl += "&c" + cat + "=1"; - } - } + var title = item.Descendants("title").First().Value; + var description = item.Descendants("description").First().Value; + var link = item.Descendants("link").First().Value; + var date = item.Descendants("pubDate").First().Value; - var results = await RequestStringWithCookiesAndRetry(searchUrl); - try - { - CQ dom = results.Content; + var torrentIdMatch = Regex.Match(link, "(?<=download\\.php/)([a-zA-z0-9]*)"); + var torrentId = torrentIdMatch.Success ? torrentIdMatch.Value : string.Empty; + if (string.IsNullOrWhiteSpace(torrentId)) + throw new Exception("Missing torrent id"); - //--table header is the first in table body, get all rows except this - CQ qRows = dom["#torrents-table > tbody > tr:not(:first-child)"]; + var infoMatch = Regex.Match(description, @"Category:\W(?.*)\W\n\WSize:\W(?.*)\n\WStatus:\W(?.*)\Wseeder(.*)\Wand\W(?.*)\Wleecher(.*)\n\WAdded:\W(?.*)\n\WDescription:"); + if (!infoMatch.Success) + throw new Exception("Unable to find info"); - foreach (var row in qRows) - { - var release = new ReleaseInfo(); + var imdbMatch = Regex.Match(description, "(?<=http://www.imdb.com/title/tt)([0-9]*)"); + long? imdbID = null; + if(imdbMatch.Success) + { + long l; + if(long.TryParse(imdbMatch.Value, out l)) + { + imdbID = l; + } + } - var qRow = row.Cq(); + var release = new ReleaseInfo() + { + Title = title, + Description = title, + Guid = new Uri(string.Format(DetailsURL, torrentId)), + Comments = new Uri(string.Format(DetailsURL, torrentId) + "&tocomm=1"), + PublishDate = DateTime.ParseExact(infoMatch.Groups["added"].Value, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 + Link = new Uri(link), + Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value == "no" ? "0" : infoMatch.Groups["seeders"].Value), + Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value == "no" ? "0" : infoMatch.Groups["leechers"].Value), + Size = ReleaseInfo.GetBytes(infoMatch.Groups["size"].Value), + Category = MapTrackerCatToNewznab(infoMatch.Groups["cat"].Value), + Imdb = imdbID + }; - var debug = qRow.Html(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - CQ qLink = qRow.Find(".br_right > a").First(); - release.Guid = new Uri(SiteLink + qLink.Attr("href")); - release.Comments = new Uri(SiteLink + qLink.Attr("href") + "&tocomm=1"); - release.Title = qLink.Find("b").Text(); - release.Description = release.Title; - - release.Link = new Uri(SiteLink + qRow.Find("td:nth-child(4) > a").Attr("href")); - - var dateString = qRow.Find("td:nth-child(6) nobr")[0].InnerText.Trim(); - //"2015-04-25 23:38:12" - //"yyyy-MMM-dd hh:mm:ss" - release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); - - var sizeStr = qRow.Children().ElementAt(6).InnerText.Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").Text()); - release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").Text()); - - var category = qRow.Find(".br_type > a").Attr("href").Replace("browse.php?cat=", string.Empty); - release.Category = MapTrackerCatToNewznab(category); + // if unknown category, set to "other" + if (release.Category == 0) + release.Category = 7000; + release.Peers += release.Seeders; releases.Add(release); } - } - catch (Exception ex) + } + else { - OnParseError(results.Content, ex); + + searchUrl += "?titleonly=1&search=" + HttpUtility.UrlEncode(searchString); + string.Format(SearchUrl, HttpUtility.UrlEncode(searchString)); + + var cats = MapTorznabCapsToTrackers(query); + if (cats.Count > 0) + { + foreach (var cat in cats) + { + searchUrl += "&c" + cat + "=1"; + } + } + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + + // table header is the first in table body, get all rows except this + CQ qRows = dom["#torrents-table > tbody > tr:not(:first-child)"]; + + foreach (var row in qRows) + { + var release = new ReleaseInfo(); + + var qRow = row.Cq(); + + var debug = qRow.Html(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + CQ qLink = qRow.Find(".br_right > a").First(); + release.Guid = new Uri(SiteLink + qLink.Attr("href")); + release.Comments = new Uri(SiteLink + qLink.Attr("href") + "&tocomm=1"); + release.Title = qLink.Find("b").Text(); + release.Description = release.Title; + + release.Link = new Uri(SiteLink + qRow.Find("td:nth-child(4) > a").Attr("href")); + + var dateString = qRow.Find("td:nth-child(6) nobr")[0].InnerText.Trim(); + //"2015-04-25 23:38:12" + //"yyyy-MMM-dd hh:mm:ss" + release.PublishDate = DateTime.ParseExact(dateString, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture); + + var sizeStr = qRow.Children().ElementAt(6).InnerText.Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").Text()); + + var category = qRow.Find(".br_type > a").Attr("href").Replace("browse.php?cat=", string.Empty); + release.Category = MapTrackerCatToNewznab(category); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } } return releases;