diff --git a/README.md b/README.md index b932e0a81..bf7f52c89 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/ * Avistaz * BakaBT * bB + * Best Friends * BeyondHD * Bit-City Reloaded * BIT-HDTV @@ -38,7 +39,9 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/ * HD-Space * HD-Torrents * Hebits + * New Real World * Hounddawgs + * House-of-Torrents * ILoveTorrents * Immortalseed * IPTorrents diff --git a/src/Jackett/Content/logos/bestfriends.png b/src/Jackett/Content/logos/bestfriends.png new file mode 100644 index 000000000..1c5edcb45 Binary files /dev/null and b/src/Jackett/Content/logos/bestfriends.png differ diff --git a/src/Jackett/Content/logos/houseoftorrents.png b/src/Jackett/Content/logos/houseoftorrents.png new file mode 100644 index 000000000..fffa0e550 Binary files /dev/null and b/src/Jackett/Content/logos/houseoftorrents.png differ diff --git a/src/Jackett/Content/logos/newrealworld.png b/src/Jackett/Content/logos/newrealworld.png new file mode 100644 index 000000000..03e00bd38 Binary files /dev/null and b/src/Jackett/Content/logos/newrealworld.png differ diff --git a/src/Jackett/Indexers/BestFriends.cs b/src/Jackett/Indexers/BestFriends.cs new file mode 100644 index 000000000..599e6ed89 --- /dev/null +++ b/src/Jackett/Indexers/BestFriends.cs @@ -0,0 +1,211 @@ +using Jackett.Utils.Clients; +using NLog; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Models; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using CsQuery; +using System; +using System.Globalization; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + public class BestFriends : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "login.php"; } } + string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } } + string BrowseUrl { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataCaptchaLogin configData + { + get { return (ConfigurationDataCaptchaLogin)base.configData; } + set { base.configData = value; } + } + + public BestFriends(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "Best Friends", + description: "A German general tracker.", + link: "http://bf.mine.nu/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataCaptchaLogin()) + { + AddCategoryMapping(18, TorznabCatType.TVAnime); // Anime + AddCategoryMapping(8, TorznabCatType.PCMac); // Appz MAC + AddCategoryMapping(9, TorznabCatType.PC); // Appz other + AddCategoryMapping(7, TorznabCatType.PC); // Appz Windows + AddCategoryMapping(23, TorznabCatType.TVDocumentary); // Dokumentationen + AddCategoryMapping(32, TorznabCatType.Movies3D); // DVD 3D + AddCategoryMapping(15, TorznabCatType.Books); // eBooks + AddCategoryMapping(12, TorznabCatType.PCGames); // Games PC + AddCategoryMapping(37, TorznabCatType.PCPhoneOther); // Handy_Mobile + AddCategoryMapping(24, TorznabCatType.TVHD); // HDTV + AddCategoryMapping(22, TorznabCatType.AudioAudiobook); // Hörbücher + AddCategoryMapping(1, TorznabCatType.MoviesHD); // Movies 1080p/1080i + AddCategoryMapping(31, TorznabCatType.Movies3D); // Movies 3D + AddCategoryMapping(2, TorznabCatType.MoviesHD); // Movies 720p/720i + AddCategoryMapping(21, TorznabCatType.MoviesBluRay); // Movies BluRay + AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movies DVD/HDDVD + AddCategoryMapping(6, TorznabCatType.MoviesSD); // Movies M/SVCD/Other + AddCategoryMapping(4, TorznabCatType.MoviesSD); // Movies XVID/DIVX/h.264 + AddCategoryMapping(10, TorznabCatType.Audio); // Music + AddCategoryMapping(25, TorznabCatType.AudioVideo); // Musikvideo + AddCategoryMapping(29, TorznabCatType.ConsoleNDS); // Nintendo DS + AddCategoryMapping(16, TorznabCatType.Other); // other + AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Playstation + AddCategoryMapping(28, TorznabCatType.TVHD); // Serien HD + AddCategoryMapping(11, TorznabCatType.TVSD); // Serien XviD + AddCategoryMapping(33, TorznabCatType.Other); // Specials + AddCategoryMapping(30, TorznabCatType.TVSport); // Sport + AddCategoryMapping(19, TorznabCatType.TVOTHER); // TVRip + AddCategoryMapping(38, TorznabCatType.TVDocumentary); // US Dokus + AddCategoryMapping(20, TorznabCatType.MoviesForeign); // US Movies + AddCategoryMapping(14, TorznabCatType.TVFOREIGN); // US Serien + AddCategoryMapping(36, TorznabCatType.Other); // Wallpaper + AddCategoryMapping(26, TorznabCatType.ConsoleWii); // Wii + AddCategoryMapping(27, TorznabCatType.ConsoleXbox360); // Xbox 360 + AddCategoryMapping(3, TorznabCatType.XXX); // XXX + } + + public override async Task GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + CQ dom = loginPage.Content; + CQ qCaptchaImg = dom.Find("td.tablea > img").First(); + + var CaptchaUrl = SiteLink + qCaptchaImg.Attr("src"); + var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies); + configData.CaptchaImage.Value = captchaImage.Content; + configData.CaptchaCookie.Value = loginPage.Cookies; + return configData; + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + var pairs1 = new Dictionary + { + { "proofcode", configData.CaptchaText.Value } + }; + var cookies = configData.CaptchaCookie.Value; + var result1 = await RequestLoginAndFollowRedirect(LoginUrl, pairs1, cookies, true, null, LoginUrl, true); + if(result1.Content == null || !result1.Content.Contains("takelogin.php")) + { + CQ dom = result1.Content; + var errorMessage = dom["#login_error"].Text().Trim(); + errorMessage = result1.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + } + + var pairs2 = new Dictionary + { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var result = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs2, result1.Cookies, true, null, LoginUrl, true); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom["#login_error"].Text().Trim(); + errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); + + var releases = new List(); + + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "1"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("blah", "0"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + searchUrl += "?" + queryCollection.GetQueryString(); + + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + var results = response.Content; + try + { + CQ dom = results; + var rows = dom["table.tableinborder > tbody > tr:has(td.tableb)"]; + + foreach (var row in rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 0.75; + release.MinimumSeedTime = 0; + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Attr("title"); + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qSeeders = qRow.Find("td:eq(7)"); + var qLeechers = qRow.Find("td:eq(8)"); + var qDateStr = qRow.Find("td:eq(4)"); + var qSize = qRow.Find("td:eq(5)"); + + var torrentId = qDetailsLink.Attr("href").Replace("&hit=1", "").Split('=')[1]; + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + "download.php?torrent="+torrentId); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(",", ".")); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var dateStr = qDateStr.Text(); + var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyyHH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + release.PublishDate = pubDateUtc; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + + return releases; + } + } +} + diff --git a/src/Jackett/Indexers/Hebits.cs b/src/Jackett/Indexers/Hebits.cs index ecd595f08..57bc91b5f 100644 --- a/src/Jackett/Indexers/Hebits.cs +++ b/src/Jackett/Indexers/Hebits.cs @@ -12,7 +12,8 @@ using System.Threading.Tasks; using System.Web; using Jackett.Models.IndexerConfig; using System.Text.RegularExpressions; - +using System.Text; + namespace Jackett.Indexers { public class Hebits : BaseIndexer, IIndexer @@ -94,10 +95,11 @@ namespace Jackett.Indexers } } - var results = await RequestStringWithCookiesAndRetry(searchUrl); + var response = await RequestBytesWithCookies(searchUrl); + var results = Encoding.GetEncoding("windows-1255").GetString(response.Content); try { - CQ dom = results.Content; + CQ dom = results; CQ qRows = dom[".browse > div > div"]; @@ -140,7 +142,7 @@ namespace Jackett.Indexers catch (Exception ex) { - OnParseError(results.Content, ex); + OnParseError(results, ex); } return releases; diff --git a/src/Jackett/Indexers/HouseOfTorrents.cs b/src/Jackett/Indexers/HouseOfTorrents.cs new file mode 100644 index 000000000..7a2f9fb49 --- /dev/null +++ b/src/Jackett/Indexers/HouseOfTorrents.cs @@ -0,0 +1,210 @@ +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.Linq; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class HouseOfTorrents : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public HouseOfTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "House-of-Torrents", + description: "A general tracker", + link: "https://houseoftorrents.me/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + AddCategoryMapping(42, TorznabCatType.PCMac); // Applications/Mac + AddCategoryMapping(34, TorznabCatType.PC); // Applications/PC + AddCategoryMapping(66, TorznabCatType.MoviesForeign); // Foreign + AddCategoryMapping(38, TorznabCatType.MoviesForeign); // Foreign/French + AddCategoryMapping(39, TorznabCatType.MoviesForeign); // Foreign/German + AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Foreign/Spanish + AddCategoryMapping(41, TorznabCatType.MoviesForeign); // Foreign/Swedish + AddCategoryMapping(67, TorznabCatType.ConsoleNDS); // Games/Nintendo + AddCategoryMapping(9 , TorznabCatType.PCGames); // Games/PC + AddCategoryMapping(8, TorznabCatType.ConsolePS3); // Games/PS3 + AddCategoryMapping(30, TorznabCatType.ConsolePS4); // Games/PS4 + AddCategoryMapping(7, TorznabCatType.ConsolePSP); // Games/PSP + AddCategoryMapping(29, TorznabCatType.ConsoleWii); // Games/Wii + AddCategoryMapping(31, TorznabCatType.ConsoleXbox360); // Games/XBOX360 + AddCategoryMapping(32, TorznabCatType.ConsoleXboxOne); // Games/XBOXONE + AddCategoryMapping(71, TorznabCatType.PCPhoneAndroid); // Mobile/Android + AddCategoryMapping(72, TorznabCatType.PCPhoneIOS); // Mobile/iOS + AddCategoryMapping(47, TorznabCatType.Movies3D); // Movies/3D + AddCategoryMapping(43, TorznabCatType.MoviesBluRay); // Movies/Bluray + AddCategoryMapping(84, TorznabCatType.MoviesSD); // Movies/Cam + AddCategoryMapping(44, TorznabCatType.MoviesDVD); // Movies/DVD-R + AddCategoryMapping(45, TorznabCatType.Movies); // Movies/MP4 + AddCategoryMapping(69, TorznabCatType.Movies); // Movies/Packs + AddCategoryMapping(46, TorznabCatType.MoviesSD); // Movies/SD + AddCategoryMapping(11, TorznabCatType.MoviesHD); // Movies/x264 + AddCategoryMapping(83, TorznabCatType.MoviesHD); // Movies/x265 + AddCategoryMapping(10, TorznabCatType.MoviesOther); // Movies/XviD + AddCategoryMapping(36, TorznabCatType.AudioLossless); // Music/FLAC + AddCategoryMapping(12, TorznabCatType.AudioMP3); // Music/MP3 + AddCategoryMapping(79, TorznabCatType.Audio); // Music/Pack + AddCategoryMapping(28, TorznabCatType.AudioVideo); // Music/Video + AddCategoryMapping(49, TorznabCatType.TVAnime); // Others/Anime + AddCategoryMapping(80, TorznabCatType.AudioAudiobook); // Others/AudioBook + AddCategoryMapping(60, TorznabCatType.Other); // Others/Boxsets + AddCategoryMapping(65, TorznabCatType.TVDocumentary); // Others/Documentary + AddCategoryMapping(61, TorznabCatType.Books); // Others/E-Book + AddCategoryMapping(51, TorznabCatType.Other); // Others/RARFIX + AddCategoryMapping(74, TorznabCatType.TVSport); // Sports + AddCategoryMapping(75, TorznabCatType.TVSport); // Sports/Boxing + AddCategoryMapping(76, TorznabCatType.TVSport); // Sports/Racing + AddCategoryMapping(77, TorznabCatType.TVSport); // Sports/UFC + AddCategoryMapping(78, TorznabCatType.TVSport); // Sports/WWE + AddCategoryMapping(68, TorznabCatType.TV); // TV/Packs + AddCategoryMapping(53, TorznabCatType.TVSD); // TV/SD + AddCategoryMapping(54, TorznabCatType.TVHD); // TV/x264 + AddCategoryMapping(82, TorznabCatType.TVHD); // TV/x265 + AddCategoryMapping(55, TorznabCatType.TVOTHER); // Tv/XviD + AddCategoryMapping(63, TorznabCatType.XXX); // XXX + AddCategoryMapping(57, TorznabCatType.XXX); // XXX/0-DAY + AddCategoryMapping(58, TorznabCatType.XXXImageset); // XXX/IMAGESET + AddCategoryMapping(81, TorznabCatType.XXXPacks); // XXX/Pack + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + var result1 = await RequestStringWithCookies(CaptchaUrl); + var json1 = JObject.Parse(result1.Content); + var captchaSelection = json1["images"][0]["hash"]; + + var pairs = new Dictionary { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "captchaSelection", (string)captchaSelection }, + { "submitme", "X" } + }; + + var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); + + await ConfigureIfOK(result2.Cookies, result2.Content.Contains("logout.php"), () => + { + var errorMessage = result2.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + List releases = new List(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("searchin", "title"); + queryCollection.Add("incldead", "1"); + if (!string.IsNullOrWhiteSpace(searchString)) + { + // use AND+wildcard operator to avoid getting to many useless results + var searchStringArray = Regex.Split(searchString.Trim(), "[ _.-]+", RegexOptions.Compiled).ToList(); + searchStringArray = searchStringArray.Where(x => x.Length >= 3).ToList(); // remove words with less than 3 characters + searchStringArray = searchStringArray.Select(x => "+" + x).ToList(); // add AND operators+wildcards + var searchStringFinal = String.Join("", searchStringArray); + queryCollection.Add("search", searchStringFinal); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + var rows = dom["table.tt > tbody > tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Text().Trim(); + + // HoT search returns should support AND search but it simply doesn't work, so we AND filter it manualy + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qSeeders = qRow.Find("td:eq(8)"); + var qLeechers = qRow.Find("td:eq(9)"); + var qDownloadLink = qRow.Find("a[href^=download.php]").First(); + var qTimeAgo = qRow.Find("td:eq(5)"); + var qSize = qRow.Find("td:eq(6)"); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var dateStr = qTimeAgo.Text(); + DateTime pubDateUtc; + var Timeparts = dateStr.Split(new char[] { ' ' }, 2)[1]; + if (dateStr.StartsWith("Today ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay; + else if (dateStr.StartsWith("Yesterday ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay - TimeSpan.FromDays(1); + else + pubDateUtc = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy hh:mm tt", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + release.PublishDate = pubDateUtc.ToLocalTime(); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/NewRealWorld.cs b/src/Jackett/Indexers/NewRealWorld.cs new file mode 100644 index 000000000..74dbfd2f0 --- /dev/null +++ b/src/Jackett/Indexers/NewRealWorld.cs @@ -0,0 +1,210 @@ +using Jackett.Utils.Clients; +using NLog; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Models; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using CsQuery; +using System; +using System.Globalization; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Text; + +namespace Jackett.Indexers +{ + public class NewRealWorld : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "login.php"; } } + string BrowseUrl { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public NewRealWorld(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "New Real World", + description: "A German general tracker.", + link: "http://nrw-tracker.eu/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + AddCategoryMapping(39, TorznabCatType.TVAnime); // Anime: HD|1080p + AddCategoryMapping(38, TorznabCatType.TVAnime); // Anime: HD|720p + AddCategoryMapping(1, TorznabCatType.TVAnime); // Anime: SD + AddCategoryMapping(7, TorznabCatType.PCPhoneOther); // Appz: Handy-PDA + AddCategoryMapping(36, TorznabCatType.PCMac); // Appz: Mac + AddCategoryMapping(18, TorznabCatType.PC); // Appz: Sonstiges + AddCategoryMapping(17, TorznabCatType.PC); // Appz: Win + AddCategoryMapping(15, TorznabCatType.Audio); // Audio: DVD-R + AddCategoryMapping(49, TorznabCatType.AudioLossless); // Audio: Flac + AddCategoryMapping(30, TorznabCatType.AudioAudiobook); // Audio: Hörspiele + AddCategoryMapping(14, TorznabCatType.AudioMP3); // Audio: MP3 + AddCategoryMapping(22, TorznabCatType.AudioVideo); // Audio: Videoclip + AddCategoryMapping(19, TorznabCatType.Other); // Diverses: Sonstiges + AddCategoryMapping(43, TorznabCatType.TVDocumentary); // Dokus: HD + AddCategoryMapping(2, TorznabCatType.TVDocumentary); // Dokus: SD + AddCategoryMapping(3, TorznabCatType.Books); // Ebooks: Bücher + AddCategoryMapping(52, TorznabCatType.BooksComics); // Ebooks: Comics + AddCategoryMapping(53, TorznabCatType.BooksMagazines); // Ebooks: Magazine + AddCategoryMapping(55, TorznabCatType.BooksOther); // Ebooks: XXX + AddCategoryMapping(54, TorznabCatType.BooksOther); // Ebooks: Zeitungen + AddCategoryMapping(47, TorznabCatType.PCPhoneOther); // Games: Andere + AddCategoryMapping(32, TorznabCatType.PCMac); // Games: Mac + AddCategoryMapping(41, TorznabCatType.ConsoleNDS); // Games: NDS/3DS + AddCategoryMapping(4, TorznabCatType.PCGames); // Games: PC + AddCategoryMapping(5, TorznabCatType.ConsolePS3); // Games: PS2 + AddCategoryMapping(9, TorznabCatType.ConsolePS3); // Games: PS3 + AddCategoryMapping(6, TorznabCatType.ConsolePSP); // Games: PSP + AddCategoryMapping(28, TorznabCatType.ConsoleWii); // Games: Wii + AddCategoryMapping(31, TorznabCatType.ConsoleXbox); // Games: XboX + AddCategoryMapping(51, TorznabCatType.Movies3D); // Movies: 3D + AddCategoryMapping(37, TorznabCatType.MoviesBluRay); // Movies: BluRay + AddCategoryMapping(25, TorznabCatType.MoviesHD); // Movies: HD|1080p + AddCategoryMapping(29, TorznabCatType.MoviesHD); // Movies: HD|720p + AddCategoryMapping(11, TorznabCatType.MoviesDVD); // Movies: SD|DVD-R + AddCategoryMapping(8, TorznabCatType.MoviesSD); // Movies: SD|x264 + AddCategoryMapping(13, TorznabCatType.MoviesSD); // Movies: SD|XviD + AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Movies: US Movies + AddCategoryMapping(33, TorznabCatType.TV); // Serien: DVD-R + AddCategoryMapping(34, TorznabCatType.TVHD); // Serien: HD + AddCategoryMapping(56, TorznabCatType.TVHD); // Serien: Packs|HD + AddCategoryMapping(44, TorznabCatType.TVSD); // Serien: Packs|SD + AddCategoryMapping(16, TorznabCatType.TVSD); // Serien: SD + AddCategoryMapping(10, TorznabCatType.TVOTHER); // Serien: TV/Shows + AddCategoryMapping(21, TorznabCatType.TVFOREIGN); // Serien: US TV + AddCategoryMapping(24, TorznabCatType.TVSport); // Sport: Diverses + AddCategoryMapping(23, TorznabCatType.TVSport); // Sport: Wrestling + AddCategoryMapping(57, TorznabCatType.Movies); // Tracker - Crew: pmHD + AddCategoryMapping(58, TorznabCatType.MoviesHD); // Ultra-HD: 4K + AddCategoryMapping(46, TorznabCatType.XXXOther); // XXX: Diverses + AddCategoryMapping(50, TorznabCatType.XXX); // XXX: HD + AddCategoryMapping(45, TorznabCatType.XXXPacks); // XXX: Packs + AddCategoryMapping(27, TorznabCatType.XXX); // XXX: SD + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + var pairs = new Dictionary + { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "submit", "Log+in!" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom["table.tableinborder"].Html(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); + + var releases = new List(); + + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "1"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + var cats = MapTorznabCapsToTrackers(query); + string cat = "0"; + if (cats.Count == 1) + { + cat = cats[0]; + } + queryCollection.Add("cat", cat); + + searchUrl += "?" + queryCollection.GetQueryString(); + + var response = await RequestBytesWithCookies(searchUrl); + var results = Encoding.GetEncoding("iso-8859-1").GetString(response.Content); + try + { + CQ dom = results; + var rows = dom["table.testtable> tbody > tr:has(td.tableb)"]; + + foreach (var row in rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 0.75; + release.MinimumSeedTime = 0; + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Text(); + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qSeeders = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(3)"); + var qLeechers = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(4)"); + var qDateStr = qRow.Find("td > table.testtable > tbody > tr > td:eq(6)"); + var qSize = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(1)"); + var qDownloadLink = qRow.Find("a[href*=download]").First(); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + var dlLink = qDownloadLink.Attr("href"); + if(dlLink.Contains("javascript")) // depending on the user agent the DL link is a javascript call + { + var dlLinkParts = dlLink.Split(new char[] { '\'', ',' }); + dlLink = SiteLink + "download/" + dlLinkParts[3] + "/" + dlLinkParts[5]; + } + release.Link = new Uri(dlLink); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + logger.Error(sizeStr); + release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(".", "").Replace(",", ".")); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var dateStr = qDateStr.Text().Replace('\xA0', ' '); + var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + release.PublishDate = pubDateUtc; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + + return releases; + } + } +} + diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 97c76434b..34df40230 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -156,6 +156,8 @@ + + @@ -163,6 +165,7 @@ + @@ -424,15 +427,24 @@ PreserveNewest + + PreserveNewest + PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest + + PreserveNewest + PreserveNewest