diff --git a/README.md b/README.md index c98f0d151..18056f62c 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ We were previously focused on TV but are working on extending searches to allow * [NextGen](https://nxtgn.org/) * [pretome](https://pretome.info) * [PrivateHD](https://privatehd.to/) - * [RARGB](https://rarbg.to/) + * [RARBG](https://rarbg.to/) * [RuTor](http://rutor.org/) * [SceneAccess](https://sceneaccess.eu/login) * [SceneTime](https://www.scenetime.com/) diff --git a/src/Jackett/Content/custom.js b/src/Jackett/Content/custom.js index 931da5a68..fa026e9c1 100644 --- a/src/Jackett/Content/custom.js +++ b/src/Jackett/Content/custom.js @@ -367,7 +367,7 @@ function bindUIButtons() { var count = 0; this.api().columns().every(function () { count++; - if (count === 5 || count === 7) { + if (count === 5 || count === 9) { var column = this; var select = $('') .appendTo($(column.footer()).empty()) @@ -495,7 +495,7 @@ function bindUIButtons() { var count = 0; this.api().columns().every(function () { count++; - if (count === 3 || count === 5) { + if (count === 3 || count === 7) { var column = this; var select = $('') .appendTo($(column.footer()).empty()) diff --git a/src/Jackett/Content/logos/broadcastthenet.png b/src/Jackett/Content/logos/broadcastthenet.png new file mode 100644 index 000000000..60379279a Binary files /dev/null and b/src/Jackett/Content/logos/broadcastthenet.png differ diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs index 6875324da..8a76f7452 100644 --- a/src/Jackett/Indexers/AnimeBytes.cs +++ b/src/Jackett/Indexers/AnimeBytes.cs @@ -1,393 +1,394 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Web; - -namespace Jackett.Indexers -{ - public class AnimeBytes : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "user/login"; } } - private string SearchUrl { get { return SiteLink + "torrents.php?"; } } - public bool AllowRaws { get { return configData.IncludeRaw.Value; } } - - new ConfigurationDataAnimeBytes configData - { - get { return (ConfigurationDataAnimeBytes)base.configData; } - set { base.configData = value; } - } - - public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps) - : base(name: "AnimeBytes", - link: "https://animebytes.tv/", - description: "Powered by Tentacles", - manager: i, - client: client, - caps: new TorznabCapabilities(TorznabCatType.TVAnime, - TorznabCatType.Movies, - TorznabCatType.BooksComics, - TorznabCatType.ConsolePSP, - TorznabCatType.ConsoleOther, - TorznabCatType.PCGames), - logger: l, - p: ps, - configData: new ConfigurationDataAnimeBytes()) - { - - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - - lock (cache) - { - cache.Clear(); - } - - // Get the login form as we need the CSRF Token - var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() - { - Url = LoginUrl - }); - - CQ loginPageDom = loginPage.Content; - var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last(); - - // Build login form - var pairs = new Dictionary { - { "csrf_token", csrfToken.Attr("value") }, - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "keeplogged_sent", "true" }, - { "keeplogged", "on" }, - { "login", "Log In!" } - }; - - // Do the login - var request = new Utils.Clients.WebRequest() - { - Cookies = loginPage.Cookies, - PostData = pairs, - Referer = LoginUrl, - Type = RequestType.POST, - Url = LoginUrl - }; - var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null); - - // Follow the redirect - await FollowIfRedirect(response, request.Url, SearchUrl); - - await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () => - { - // Their login page appears to be broken and just gives a 500 error. - throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - // Override to load legacy config format - public override void LoadFromSavedConfiguration(JToken jsonConfig) - { - if (jsonConfig is JObject) - { - configData.CookieHeader.Value = jsonConfig.Value("cookies"); - configData.IncludeRaw.Value = jsonConfig.Value("raws"); - SaveConfig(); - IsConfigured = true; - return; - } - - base.LoadFromSavedConfiguration(jsonConfig); - } - - public async Task> PerformQuery(TorznabQuery query) - { - // The result list - var releases = new List(); - - foreach (var result in await GetResults(query.SanitizedSearchTerm)) - { - releases.Add(result); - } - - return releases.ToArray(); - } - - public async Task> GetResults(string searchTerm) - { - var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm); - - // This tracker only deals with full seasons so chop off the episode/season number if we have it D: - if (!string.IsNullOrWhiteSpace(searchTerm)) - { - var splitindex = searchTerm.LastIndexOf(' '); - if (splitindex > -1) - searchTerm = searchTerm.Substring(0, splitindex); - } - - // The result list - var releases = new List(); - - // Check cache first so we don't query the server for each episode when searching for each episode in a series. - lock (cache) - { - // Remove old cache items - CleanCache(); - - var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault(); - if (cachedResult != null) - return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); - } - - var queryUrl = SearchUrl; - // Only include the query bit if its required as hopefully the site caches the non query page - if (!string.IsNullOrWhiteSpace(searchTerm)) - { - queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm); - } - - // Get the content from the tracker - var response = await RequestStringWithCookiesAndRetry(queryUrl); - CQ dom = response.Content; - - // Parse - try - { - var releaseInfo = "S01"; - var root = dom.Find(".group_cont"); - // We may have got redirected to the series page if we have none of these - if (root.Count() == 0) - root = dom.Find(".torrent_table"); - - foreach (var series in root) - { - var seriesCq = series.Cq(); - - var synonyms = new List(); - var mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim(); - - var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim(); - int yearIndex = yearStr.LastIndexOf("["); - if (yearIndex > -1) - yearStr = yearStr.Substring(yearIndex + 1); - - int year = 0; - if (!int.TryParse(yearStr, out year)) - year = DateTime.Now.Year; - - synonyms.Add(mainTitle); - - // If the title contains a comma then we can't use the synonyms as they are comma seperated - if (!mainTitle.Contains(",")) - { - var symnomnNames = string.Empty; - foreach (var e in seriesCq.Find(".group_statbox li")) - { - if (e.FirstChild.InnerText == "Synonyms:") - { - symnomnNames = e.InnerText; - } - } - - if (!string.IsNullOrWhiteSpace(symnomnNames)) - { - foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) - { - var theName = name.Trim(); - if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName)) - { - synonyms.Add(theName); - } - } - } - } - - foreach (var title in synonyms) - { - var releaseRows = seriesCq.Find(".torrent_group tr"); - - // Skip the first two info rows - for (int r = 1; r < releaseRows.Count(); r++) - { - var row = releaseRows.Get(r); - var rowCq = row.Cq(); - if (rowCq.HasClass("edition_info")) - { - releaseInfo = rowCq.Find("td").Text(); - - if (string.IsNullOrWhiteSpace(releaseInfo)) - { - // Single episodes alpha - Reported that this info is missing. - // It should self correct when availible - break; - } - - releaseInfo = releaseInfo.Replace("Episode ", ""); - releaseInfo = releaseInfo.Replace("Season ", "S"); - releaseInfo = releaseInfo.Trim(); - } - else if (rowCq.HasClass("torrent")) - { - var links = rowCq.Find("a"); - // Protect against format changes - if (links.Count() != 2) - { - continue; - } - - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 259200; - var downloadLink = links.Get(0); - - // We dont know this so try to fake based on the release year - release.PublishDate = new DateTime(year, 1, 1); - release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1); - - var infoLink = links.Get(1); - release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href")); - release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name. - release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative); - - var category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim(); - if (category == "TV Series") - release.Category = TorznabCatType.TVAnime.ID; - - // Ignore these categories as they'll cause hell with the matcher - // TV Special, OVA, ONA, DVD Special, BD Special - - if (category == "Movie") - release.Category = TorznabCatType.Movies.ID; - - if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel") - release.Category = TorznabCatType.BooksComics.ID; - - if (category == "Novel" || category == "Artbook") - release.Category = TorznabCatType.BooksComics.ID; - - if (category == "Game" || category == "Visual Novel") - { - var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); - if (description.Contains(" PSP ")) - release.Category = TorznabCatType.ConsolePSP.ID; - if (description.Contains("PSX")) - release.Category = TorznabCatType.ConsoleOther.ID; - if (description.Contains(" NES ")) - release.Category = TorznabCatType.ConsoleOther.ID; - if (description.Contains(" PC ")) - release.Category = TorznabCatType.PCGames.ID; - } - - - - // We dont actually have a release name >.> so try to create one - var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList(); - for (int i = releaseTags.Count - 1; i >= 0; i--) - { - releaseTags[i] = releaseTags[i].Trim(); - if (string.IsNullOrWhiteSpace(releaseTags[i])) - releaseTags.RemoveAt(i); - } - - var group = releaseTags.Last(); - if (group.Contains("(") && group.Contains(")")) - { - // Skip raws if set - if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws) - { - continue; - } - - var start = group.IndexOf("("); - group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] "; - } - else - { - group = string.Empty; - } - - var infoString = ""; - - for (int i = 0; i + 1 < releaseTags.Count(); i++) - { - if (releaseTags[i] == "Raw" && !AllowRaws) - continue; - infoString += "[" + releaseTags[i] + "]"; - } - - if (category == "Movie") - { - release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString); - } - else - { - release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString); - } - release.Description = title; - - var size = rowCq.Find(".torrent_size"); - if (size.Count() > 0) - { - release.Size = ReleaseInfo.GetBytes(size.First().Text()); - } - - // Additional 5 hours per GB - release.MinimumSeedTime += (release.Size / 1000000000) * 18000; - - // Peer info - release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text()); - release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text()); - - if (release.Category != 0) - releases.Add(release); - } - } - } - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - - // Add to the cache - lock (cache) - { - cache.Add(new CachedQueryResult(searchTerm, releases)); - } - - return releases.Select(s => (ReleaseInfo)s.Clone()); - } - - - public async override Task Download(Uri link) - { - // The urls for this tracker are quite long so append the domain after the incoming request. - var response = await webclient.GetBytes(new Utils.Clients.WebRequest() - { - Url = SiteLink + link.ToString(), - Cookies = CookieHeader - }); - - return response.Content; - } - } -} +using CsQuery; +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Models.IndexerConfig.Bespoke; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; + +namespace Jackett.Indexers +{ + public class AnimeBytes : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "user/login"; } } + private string SearchUrl { get { return SiteLink + "torrents.php?"; } } + public bool AllowRaws { get { return configData.IncludeRaw.Value; } } + + new ConfigurationDataAnimeBytes configData + { + get { return (ConfigurationDataAnimeBytes)base.configData; } + set { base.configData = value; } + } + + public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps) + : base(name: "AnimeBytes", + link: "https://animebytes.tv/", + description: "Powered by Tentacles", + manager: i, + client: client, + caps: new TorznabCapabilities(TorznabCatType.TVAnime, + TorznabCatType.Movies, + TorznabCatType.BooksComics, + TorznabCatType.ConsolePSP, + TorznabCatType.ConsoleOther, + TorznabCatType.PCGames), + logger: l, + p: ps, + configData: new ConfigurationDataAnimeBytes()) + { + + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + lock (cache) + { + cache.Clear(); + } + + // Get the login form as we need the CSRF Token + var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl + }); + + CQ loginPageDom = loginPage.Content; + var csrfToken = loginPageDom["input[name=\"csrf_token\"]"].Last(); + + // Build login form + var pairs = new Dictionary { + { "csrf_token", csrfToken.Attr("value") }, + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "keeplogged_sent", "true" }, + { "keeplogged", "on" }, + { "login", "Log In!" } + }; + + // Do the login + var request = new Utils.Clients.WebRequest() + { + Cookies = loginPage.Cookies, + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + Url = LoginUrl + }; + var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null); + + // Follow the redirect + await FollowIfRedirect(response, request.Url, SearchUrl); + + await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () => + { + // Their login page appears to be broken and just gives a 500 error. + throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + // Override to load legacy config format + public override void LoadFromSavedConfiguration(JToken jsonConfig) + { + if (jsonConfig is JObject) + { + configData.CookieHeader.Value = jsonConfig.Value("cookies"); + configData.IncludeRaw.Value = jsonConfig.Value("raws"); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); + } + + public async Task> PerformQuery(TorznabQuery query) + { + // The result list + var releases = new List(); + + foreach (var result in await GetResults(query.SanitizedSearchTerm)) + { + releases.Add(result); + } + + return releases.ToArray(); + } + + public async Task> GetResults(string searchTerm) + { + var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm); + + // This tracker only deals with full seasons so chop off the episode/season number if we have it D: + if (!string.IsNullOrWhiteSpace(searchTerm)) + { + var splitindex = searchTerm.LastIndexOf(' '); + if (splitindex > -1) + searchTerm = searchTerm.Substring(0, splitindex); + } + + // The result list + var releases = new List(); + + // Check cache first so we don't query the server for each episode when searching for each episode in a series. + lock (cache) + { + // Remove old cache items + CleanCache(); + + var cachedResult = cache.Where(i => i.Query == searchTerm).FirstOrDefault(); + if (cachedResult != null) + return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); + } + + var queryUrl = SearchUrl; + // Only include the query bit if its required as hopefully the site caches the non query page + if (!string.IsNullOrWhiteSpace(searchTerm)) + { + queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm); + } + + // Get the content from the tracker + var response = await RequestStringWithCookiesAndRetry(queryUrl); + CQ dom = response.Content; + + // Parse + try + { + var releaseInfo = "S01"; + var root = dom.Find(".group_cont"); + // We may have got redirected to the series page if we have none of these + if (root.Count() == 0) + root = dom.Find(".torrent_table"); + + foreach (var series in root) + { + var seriesCq = series.Cq(); + + var synonyms = new List(); + var mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim(); + + var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim(); + int yearIndex = yearStr.LastIndexOf("["); + if (yearIndex > -1) + yearStr = yearStr.Substring(yearIndex + 1); + + int year = 0; + if (!int.TryParse(yearStr, out year)) + year = DateTime.Now.Year; + + synonyms.Add(mainTitle); + + // If the title contains a comma then we can't use the synonyms as they are comma seperated + if (!mainTitle.Contains(",")) + { + var symnomnNames = string.Empty; + foreach (var e in seriesCq.Find(".group_statbox li")) + { + if (e.FirstChild.InnerText == "Synonyms:") + { + symnomnNames = e.InnerText; + } + } + + if (!string.IsNullOrWhiteSpace(symnomnNames)) + { + foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) + { + var theName = name.Trim(); + if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName)) + { + synonyms.Add(theName); + } + } + } + } + + foreach (var title in synonyms) + { + var releaseRows = seriesCq.Find(".torrent_group tr"); + + // Skip the first two info rows + for (int r = 1; r < releaseRows.Count(); r++) + { + var row = releaseRows.Get(r); + var rowCq = row.Cq(); + if (rowCq.HasClass("edition_info")) + { + releaseInfo = rowCq.Find("td").Text(); + + if (string.IsNullOrWhiteSpace(releaseInfo)) + { + // Single episodes alpha - Reported that this info is missing. + // It should self correct when availible + break; + } + + releaseInfo = releaseInfo.Replace("Episode ", ""); + releaseInfo = releaseInfo.Replace("Season ", "S"); + releaseInfo = releaseInfo.Trim(); + } + else if (rowCq.HasClass("torrent")) + { + var links = rowCq.Find("a"); + // Protect against format changes + if (links.Count() != 2) + { + continue; + } + + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 259200; + var downloadLink = links.Get(0); + + // We dont know this so try to fake based on the release year + release.PublishDate = new DateTime(year, 1, 1); + release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1); + + var infoLink = links.Get(1); + release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href")); + release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name. + release.Link = new Uri(downloadLink.Attributes.GetAttribute("href"), UriKind.Relative); + + var category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim(); + if (category == "TV Series") + release.Category = TorznabCatType.TVAnime.ID; + + // Ignore these categories as they'll cause hell with the matcher + // TV Special, OVA, ONA, DVD Special, BD Special + + if (category == "Movie") + release.Category = TorznabCatType.Movies.ID; + + if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel") + release.Category = TorznabCatType.BooksComics.ID; + + if (category == "Novel" || category == "Artbook") + release.Category = TorznabCatType.BooksComics.ID; + + if (category == "Game" || category == "Visual Novel") + { + var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); + if (description.Contains(" PSP ")) + release.Category = TorznabCatType.ConsolePSP.ID; + if (description.Contains("PSX")) + release.Category = TorznabCatType.ConsoleOther.ID; + if (description.Contains(" NES ")) + release.Category = TorznabCatType.ConsoleOther.ID; + if (description.Contains(" PC ")) + release.Category = TorznabCatType.PCGames.ID; + } + + + + // We dont actually have a release name >.> so try to create one + var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList(); + for (int i = releaseTags.Count - 1; i >= 0; i--) + { + releaseTags[i] = releaseTags[i].Trim(); + if (string.IsNullOrWhiteSpace(releaseTags[i])) + releaseTags.RemoveAt(i); + } + + var group = releaseTags.Last(); + if (group.Contains("(") && group.Contains(")")) + { + // Skip raws if set + if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws) + { + continue; + } + + var start = group.IndexOf("("); + group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] "; + } + else + { + group = string.Empty; + } + + var infoString = ""; + + for (int i = 0; i + 1 < releaseTags.Count(); i++) + { + if (releaseTags[i] == "Raw" && !AllowRaws) + continue; + infoString += "[" + releaseTags[i] + "]"; + } + + if (category == "Movie") + { + release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString); + } + else + { + release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString); + } + release.Description = title; + + var size = rowCq.Find(".torrent_size"); + if (size.Count() > 0) + { + release.Size = ReleaseInfo.GetBytes(size.First().Text()); + } + + // Additional 5 hours per GB + release.MinimumSeedTime += (release.Size / 1000000000) * 18000; + + // Peer info + release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text()); + + if (release.Category != 0) + releases.Add(release); + } + } + } + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + // Add to the cache + lock (cache) + { + cache.Add(new CachedQueryResult(searchTerm, releases)); + } + + return releases.Select(s => (ReleaseInfo)s.Clone()); + } + + + public async override Task Download(Uri link) + { + // The urls for this tracker are quite long so append the domain after the incoming request. + var response = await webclient.GetBytes(new Utils.Clients.WebRequest() + { + Url = SiteLink + link.ToString(), + Cookies = CookieHeader + }); + + return response.Content; + } + } +} diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs index 17aa321cf..2c7a34d64 100644 --- a/src/Jackett/Indexers/BaseIndexer.cs +++ b/src/Jackett/Indexers/BaseIndexer.cs @@ -311,7 +311,7 @@ namespace Jackett.Indexers return await webclient.GetBytes(request); } - protected async Task PostDataWithCookies(string url, IEnumerable> data, string cookieOverride = null, string referer = null) + protected async Task PostDataWithCookies(string url, IEnumerable> data, string cookieOverride = null, string referer = null, Dictionary headers = null, string rawbody = null) { var request = new Utils.Clients.WebRequest() { @@ -319,19 +319,20 @@ namespace Jackett.Indexers Type = RequestType.POST, Cookies = cookieOverride ?? CookieHeader, PostData = data, - Referer = referer + Referer = referer, + Headers = headers }; return await webclient.GetString(request); } - protected async Task PostDataWithCookiesAndRetry(string url, IEnumerable> data, string cookieOverride = null, string referer = null) + protected async Task PostDataWithCookiesAndRetry(string url, IEnumerable> data, string cookieOverride = null, string referer = null, Dictionary headers = null, string rawbody = null) { Exception lastException = null; for (int i = 0; i < 3; i++) { try { - return await PostDataWithCookies(url, data, cookieOverride, referer); + return await PostDataWithCookies(url, data, cookieOverride, referer, headers, rawbody); } catch (Exception e) { diff --git a/src/Jackett/Indexers/BroadcastTheNet.cs b/src/Jackett/Indexers/BroadcastTheNet.cs new file mode 100644 index 000000000..309dfbb9f --- /dev/null +++ b/src/Jackett/Indexers/BroadcastTheNet.cs @@ -0,0 +1,151 @@ +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.Dynamic; + +namespace Jackett.Indexers +{ + public class BroadcastTheNet : BaseIndexer, IIndexer + { + string APIBASE = "http://api.btnapps.net/"; + + new ConfigurationDataAPIKey configData + { + get { return (ConfigurationDataAPIKey)base.configData; } + set { base.configData = value; } + } + + public BroadcastTheNet(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "BroadcastTheNet", + description: "Needs no description..", + link: "https://broadcasthe.net/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataAPIKey()) + { + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + IsConfigured = false; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (results.Count() == 0) + throw new Exception("Testing returned no results!"); + IsConfigured = true; + SaveConfig(); + } + catch(Exception e) + { + throw new ExceptionWithConfigData(e.Message, configData); + } + + return IndexerConfigurationStatus.Completed; + } + + + private string JsonRPCRequest(string method, dynamic parameters) + { + dynamic request = new ExpandoObject(); + request["jsonrpc"] = "2.0"; + request["method"] = method; + request["params"] = parameters; + request["id"] = Guid.NewGuid().ToString().Substring(0, 8); + return request.ToString(); + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + + + var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary() + { + { "Accept", "application/json-rpc, application/json"}, + {"ContentType", "application/json-rpc"} + }, JsonRPCRequest("getTorrents", new Object[] + { + configData.Key.Value + })); + + /* + var searchUrl = BrowsePage; + + if (!string.IsNullOrWhiteSpace(query.GetQueryString())) + { + searchUrl += string.Format(QueryString, HttpUtility.UrlEncode(query.GetQueryString())); + } + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + + try + { + CQ dom = results.Content; + + var rows = dom["#sortabletable tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + release.Title = qRow.Find(".tooltip-content div").First().Text(); + if (string.IsNullOrWhiteSpace(release.Title)) + continue; + release.Description = qRow.Find(".tooltip-content div").Get(1).InnerText.Trim(); + + var qLink = row.Cq().Find("td:eq(2) a:eq(1)"); + release.Link = new Uri(qLink.Attr("href")); + release.Guid = release.Link; + release.Comments = new Uri(qRow.Find(".tooltip-target a").First().Attr("href")); + + // 07-22-2015 11:08 AM + var dateString = qRow.Find("td:eq(1) div").Last().Children().Remove().End().Text().Trim(); + release.PublishDate = DateTime.ParseExact(dateString, "MM-dd-yyyy hh:mm tt", CultureInfo.InvariantCulture); + + var sizeStr = qRow.Find("td:eq(4)").Text().Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()) + release.Seeders; + + var catLink = row.Cq().Find("td:eq(0) a").First().Attr("href"); + var catSplit = catLink.IndexOf("category="); + if (catSplit > -1) + { + catLink = catLink.Substring(catSplit + 9); + } + + release.Category = MapTrackerCatToNewznab(catLink); + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + }*/ + + return releases; + } + + + } +} diff --git a/src/Jackett/Indexers/FileList.cs b/src/Jackett/Indexers/FileList.cs index 9ca4e219f..06d8c090d 100644 --- a/src/Jackett/Indexers/FileList.cs +++ b/src/Jackett/Indexers/FileList.cs @@ -1,156 +1,157 @@ -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 FileList : BaseIndexer, IIndexer - { - string LoginUrl { get { return SiteLink + "takelogin.php"; } } - string BrowseUrl { get { return SiteLink + "browse.php"; } } - - new ConfigurationDataFileList configData - { - get { return (ConfigurationDataFileList)base.configData; } - set { base.configData = value; } - } - - public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "FileList", - description: "The best Romanian site.", - link: "http://filelist.ro/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataFileList()) - { - AddCategoryMapping(24, TorznabCatType.TVAnime); - AddCategoryMapping(11, TorznabCatType.Audio); - AddCategoryMapping(15, TorznabCatType.TV); - //AddCategoryMapping(18, TorznabCatType.); Other - AddCategoryMapping(16, TorznabCatType.TVDocumentary); - AddCategoryMapping(25, TorznabCatType.Movies3D); - AddCategoryMapping(20, TorznabCatType.MoviesBluRay); - AddCategoryMapping(2, TorznabCatType.MoviesSD); - AddCategoryMapping(3, TorznabCatType.MoviesForeign); //RO - AddCategoryMapping(4, TorznabCatType.MoviesHD); - AddCategoryMapping(19, TorznabCatType.MoviesForeign); // RO - AddCategoryMapping(1, TorznabCatType.MoviesSD); - AddCategoryMapping(10, TorznabCatType.Console); - AddCategoryMapping(9, TorznabCatType.PCGames); - //AddCategoryMapping(17, TorznabCatType); Linux No cat - AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile - AddCategoryMapping(8, TorznabCatType.PC); - AddCategoryMapping(21, TorznabCatType.TVHD); - AddCategoryMapping(23, TorznabCatType.TVSD); - AddCategoryMapping(13, TorznabCatType.TVSport); - AddCategoryMapping(14, TorznabCatType.TV); - AddCategoryMapping(12, TorznabCatType.AudioVideo); - AddCategoryMapping(7, TorznabCatType.XXX); - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var pairs = new Dictionary { - { "username", configData.Username.Value }, - { "password", configData.Password.Value } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var errorMessage = dom[".main"].Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task> PerformQuery(TorznabQuery query) - { - var releases = new List(); - var searchUrl = BrowseUrl; - var searchString = query.GetQueryString(); - - var cats = MapTorznabCapsToTrackers(query); - string cat = "0"; - if (cats.Count == 1) - { - cat = cats[0]; - } - - if (!string.IsNullOrWhiteSpace(searchString) || cat != "0") - searchUrl += string.Format("?search={0}&cat={1}&searchin=0&sort=0", HttpUtility.UrlEncode(searchString), cat); - - - - var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); - var results = response.Content; - try - { - CQ dom = results; - var rows = dom[".torrentrow"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First(); - release.Title = qRow.Find(".torrenttable:eq(1) a b").Text().Trim(); - release.Description = release.Title; - release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); - release.Comments = release.Guid; - - //22:05:3716/02/2013 - var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim(); - release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy", CultureInfo.InvariantCulture).AddHours(-2); - - var qLink = qRow.Find(".torrenttable:eq(2) a").First(); - release.Link = new Uri(SiteLink + qLink.Attr("href")); - - var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders; - - var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15); - release.Category = MapTrackerCatToNewznab(catId); - - // Skip other - if (release.Category != 0) - { - // Skip Romanian releases - if (release.Category == TorznabCatType.MoviesForeign.ID && !configData.IncludeRomanianReleases.Value) - continue; - - releases.Add(release); - } - } - } - catch (Exception ex) - { - OnParseError(results, ex); - } - - return releases; - } - } -} +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; +using Jackett.Models.IndexerConfig.Bespoke; + +namespace Jackett.Indexers +{ + public class FileList : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "takelogin.php"; } } + string BrowseUrl { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataFileList configData + { + get { return (ConfigurationDataFileList)base.configData; } + set { base.configData = value; } + } + + public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "FileList", + description: "The best Romanian site.", + link: "http://filelist.ro/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataFileList()) + { + AddCategoryMapping(24, TorznabCatType.TVAnime); + AddCategoryMapping(11, TorznabCatType.Audio); + AddCategoryMapping(15, TorznabCatType.TV); + //AddCategoryMapping(18, TorznabCatType.); Other + AddCategoryMapping(16, TorznabCatType.TVDocumentary); + AddCategoryMapping(25, TorznabCatType.Movies3D); + AddCategoryMapping(20, TorznabCatType.MoviesBluRay); + AddCategoryMapping(2, TorznabCatType.MoviesSD); + AddCategoryMapping(3, TorznabCatType.MoviesForeign); //RO + AddCategoryMapping(4, TorznabCatType.MoviesHD); + AddCategoryMapping(19, TorznabCatType.MoviesForeign); // RO + AddCategoryMapping(1, TorznabCatType.MoviesSD); + AddCategoryMapping(10, TorznabCatType.Console); + AddCategoryMapping(9, TorznabCatType.PCGames); + //AddCategoryMapping(17, TorznabCatType); Linux No cat + AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile + AddCategoryMapping(8, TorznabCatType.PC); + AddCategoryMapping(21, TorznabCatType.TVHD); + AddCategoryMapping(23, TorznabCatType.TVSD); + AddCategoryMapping(13, TorznabCatType.TVSport); + AddCategoryMapping(14, TorznabCatType.TV); + AddCategoryMapping(12, TorznabCatType.AudioVideo); + AddCategoryMapping(7, TorznabCatType.XXX); + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var pairs = new Dictionary { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom[".main"].Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var searchUrl = BrowseUrl; + var searchString = query.GetQueryString(); + + var cats = MapTorznabCapsToTrackers(query); + string cat = "0"; + if (cats.Count == 1) + { + cat = cats[0]; + } + + if (!string.IsNullOrWhiteSpace(searchString) || cat != "0") + searchUrl += string.Format("?search={0}&cat={1}&searchin=0&sort=0", HttpUtility.UrlEncode(searchString), cat); + + + + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + var results = response.Content; + try + { + CQ dom = results; + var rows = dom[".torrentrow"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First(); + release.Title = qRow.Find(".torrenttable:eq(1) a b").Text().Trim(); + release.Description = release.Title; + release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); + release.Comments = release.Guid; + + //22:05:3716/02/2013 + var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim(); + release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy", CultureInfo.InvariantCulture).AddHours(-2); + + var qLink = qRow.Find(".torrenttable:eq(2) a").First(); + release.Link = new Uri(SiteLink + qLink.Attr("href")); + + var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders; + + var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15); + release.Category = MapTrackerCatToNewznab(catId); + + // Skip other + if (release.Category != 0) + { + // Skip Romanian releases + if (release.Category == TorznabCatType.MoviesForeign.ID && !configData.IncludeRomanianReleases.Value) + continue; + + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/RUTor.cs b/src/Jackett/Indexers/RUTor.cs index 91b136437..cbee08d1e 100644 --- a/src/Jackett/Indexers/RUTor.cs +++ b/src/Jackett/Indexers/RUTor.cs @@ -1,232 +1,233 @@ -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; -using Jackett.Models.IndexerConfig; -using System.Globalization; -using Newtonsoft.Json; - -namespace Jackett.Indexers -{ - public class RuTor : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "search/0/{0}/000/0/{1}"; } } - private string BrowseUrl { get { return SiteLink + "browse/0/{0}/0/0"; } } - readonly static string defaultSiteLink = "http://rutor.org/"; - - new ConfigurationDataRuTor configData - { - get { return (ConfigurationDataRuTor)base.configData; } - set { base.configData = value; } - } - - public RuTor(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "RUTor", - description: "Свободный торрент трекер", - link: "http://rutor.org/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataRuTor(defaultSiteLink)) - { - TorznabCaps.Categories.Add(TorznabCatType.TVAnime); - TorznabCaps.Categories.Add(TorznabCatType.Movies); - TorznabCaps.Categories.Add(TorznabCatType.Audio); - TorznabCaps.Categories.Add(TorznabCatType.Books); - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var oldConfig = configData; - var releases = await PerformQuery(new TorznabQuery()); - - await ConfigureIfOK(string.Empty, releases.Count() > 0, () => - { - configData = oldConfig; - throw new Exception("Could not find releases from this URL"); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - - protected override void SaveConfig() - { - indexerService.SaveConfig(this as IIndexer, JsonConvert.SerializeObject(configData)); - } - - // Override to load legacy config format - public override void LoadFromSavedConfiguration(JToken jsonConfig) - { - var json = jsonConfig.ToString(); - configData = JsonConvert.DeserializeObject(json); - IsConfigured = true; - } - - private readonly int CAT_ANY = 0; - private readonly int CAT_FOREIGN_MOVIE = 1; - // private readonly int CAT_OUR_MOVIES = 5; - // private readonly int CAT_POP_SCIFI_MOVIES = 12; - private readonly int CAT_TV_SERIES = 4; - // private readonly int CAT_TV = 6; - // private readonly int CAT_ANIMATION = 7; - private readonly int CAT_ANIME = 10; - private readonly int CAT_MUSIC = 2; - // private readonly int CAT_GAMES = 8; - // private readonly int CAT_SOFTWARE = 9; - // private readonly int CAT_SPORTS_HEALTH = 13; - // private readonly int CAT_HUMOR = 15; - // private readonly int CAT_ECONOMY_LIFE = 14; - private readonly int CAT_BOOKS = 11; - // private readonly int CAT_OTHER = 3; - - public async Task> PerformQuery(TorznabQuery query) - { - var releases = new List(); - var searchString = query.GetQueryString(); - var searchCategory = CAT_ANY; - - if (query.Categories.Contains(TorznabCatType.TV.ID) || - query.Categories.Contains(TorznabCatType.TVHD.ID) || - query.Categories.Contains(TorznabCatType.TVSD.ID)) - { - searchCategory = CAT_TV_SERIES; - } - - if ((searchCategory == CAT_ANY) && - (query.Categories.Contains(TorznabCatType.Movies.ID) || - query.Categories.Contains(TorznabCatType.MoviesForeign.ID) || - query.Categories.Contains(TorznabCatType.MoviesHD.ID) || - query.Categories.Contains(TorznabCatType.MoviesSD.ID))) - { - searchCategory = CAT_FOREIGN_MOVIE; - } - - if ((searchCategory == CAT_ANY) && - (query.Categories.Contains(TorznabCatType.TVAnime.ID))) - { - searchCategory = CAT_ANIME; - } - - if ((searchCategory == CAT_ANY) && - (query.Categories.Contains(TorznabCatType.Books.ID))) - { - searchCategory = CAT_BOOKS; - } - - if ((searchCategory == CAT_ANY) && - (query.Categories.Contains(TorznabCatType.Audio.ID) || - query.Categories.Contains(TorznabCatType.AudioLossless.ID) || - query.Categories.Contains(TorznabCatType.AudioMP3.ID))) - { - searchCategory = CAT_MUSIC; - } - - string queryUrl = string.Empty; - if (string.IsNullOrWhiteSpace(searchString)) - { - queryUrl = string.Format(BrowseUrl, searchCategory); - } - else - { - queryUrl = string.Format(SearchUrl, searchCategory, HttpUtility.UrlEncode(searchString.Trim())); - } - - var results = await RequestStringWithCookiesAndRetry(queryUrl, string.Empty); - try - { - CQ dom = results.Content; - var rows = dom["#index table tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - var date = StringUtil.StripNonAlphaNumeric(row.Cq().Find("td:eq(0)").Text().Trim() - .Replace("Янв", "01") - .Replace("Фев", "02") - .Replace("Мар", "03") - .Replace("Апр", "04") - .Replace("Май", "05") - .Replace("Июн", "06") - .Replace("Июл", "07") - .Replace("Авг", "08") - .Replace("Сен", "09") - .Replace("Окт", "10") - .Replace("Ноя", "11") - .Replace("Дек", "12")); - - release.PublishDate = DateTime.ParseExact(date, "ddMMyy", CultureInfo.InvariantCulture); - - var hasTorrent = row.Cq().Find("td:eq(1) a").Length == 3; - var titleIndex = 1; - if (hasTorrent) - titleIndex++; - - release.Title = row.Cq().Find("td:eq(" + titleIndex + ")").Text().Trim(); - if (configData.StripRussian.Value) - { - var split = release.Title.IndexOf('/'); - if (split > -1) - { - release.Title = release.Title.Substring(split + 1).Trim(); - } - } - - release.Description = release.Title; - - var hasComments = row.Cq().Find("td:eq(2) img").Length > 0; - var sizeCol = 2; - - if (hasComments) - sizeCol++; - - var sizeStr = StringUtil.StripRegex(row.Cq().Find("td:eq(" + sizeCol + ")").Text(), "[^a-zA-Z0-9\\. -]", " ").Trim(); - string[] sizeSplit = sizeStr.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); - - release.Seeders = ParseUtil.CoerceInt(row.Cq().Find(".green").Text().Trim()); - release.Peers = ParseUtil.CoerceInt(row.Cq().Find(".red").Text().Trim()) + release.Seeders; - - release.Guid = new Uri(configData.Url.Value + row.Cq().Find("td:eq(1) a:eq(" + titleIndex + ")").Attr("href").Substring(1)); - release.Comments = release.Guid; - - if (hasTorrent) - { - release.Link = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href")); - release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(1)").Attr("href")); - } - else - { - release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href")); - } - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} +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; +using Jackett.Models.IndexerConfig; +using System.Globalization; +using Newtonsoft.Json; +using Jackett.Models.IndexerConfig.Bespoke; + +namespace Jackett.Indexers +{ + public class RuTor : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "search/0/{0}/000/0/{1}"; } } + private string BrowseUrl { get { return SiteLink + "browse/0/{0}/0/0"; } } + readonly static string defaultSiteLink = "http://rutor.org/"; + + new ConfigurationDataRuTor configData + { + get { return (ConfigurationDataRuTor)base.configData; } + set { base.configData = value; } + } + + public RuTor(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "RUTor", + description: "Свободный торрент трекер", + link: "http://rutor.org/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataRuTor(defaultSiteLink)) + { + TorznabCaps.Categories.Add(TorznabCatType.TVAnime); + TorznabCaps.Categories.Add(TorznabCatType.Movies); + TorznabCaps.Categories.Add(TorznabCatType.Audio); + TorznabCaps.Categories.Add(TorznabCatType.Books); + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var oldConfig = configData; + var releases = await PerformQuery(new TorznabQuery()); + + await ConfigureIfOK(string.Empty, releases.Count() > 0, () => + { + configData = oldConfig; + throw new Exception("Could not find releases from this URL"); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + + protected override void SaveConfig() + { + indexerService.SaveConfig(this as IIndexer, JsonConvert.SerializeObject(configData)); + } + + // Override to load legacy config format + public override void LoadFromSavedConfiguration(JToken jsonConfig) + { + var json = jsonConfig.ToString(); + configData = JsonConvert.DeserializeObject(json); + IsConfigured = true; + } + + private readonly int CAT_ANY = 0; + private readonly int CAT_FOREIGN_MOVIE = 1; + // private readonly int CAT_OUR_MOVIES = 5; + // private readonly int CAT_POP_SCIFI_MOVIES = 12; + private readonly int CAT_TV_SERIES = 4; + // private readonly int CAT_TV = 6; + // private readonly int CAT_ANIMATION = 7; + private readonly int CAT_ANIME = 10; + private readonly int CAT_MUSIC = 2; + // private readonly int CAT_GAMES = 8; + // private readonly int CAT_SOFTWARE = 9; + // private readonly int CAT_SPORTS_HEALTH = 13; + // private readonly int CAT_HUMOR = 15; + // private readonly int CAT_ECONOMY_LIFE = 14; + private readonly int CAT_BOOKS = 11; + // private readonly int CAT_OTHER = 3; + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var searchString = query.GetQueryString(); + var searchCategory = CAT_ANY; + + if (query.Categories.Contains(TorznabCatType.TV.ID) || + query.Categories.Contains(TorznabCatType.TVHD.ID) || + query.Categories.Contains(TorznabCatType.TVSD.ID)) + { + searchCategory = CAT_TV_SERIES; + } + + if ((searchCategory == CAT_ANY) && + (query.Categories.Contains(TorznabCatType.Movies.ID) || + query.Categories.Contains(TorznabCatType.MoviesForeign.ID) || + query.Categories.Contains(TorznabCatType.MoviesHD.ID) || + query.Categories.Contains(TorznabCatType.MoviesSD.ID))) + { + searchCategory = CAT_FOREIGN_MOVIE; + } + + if ((searchCategory == CAT_ANY) && + (query.Categories.Contains(TorznabCatType.TVAnime.ID))) + { + searchCategory = CAT_ANIME; + } + + if ((searchCategory == CAT_ANY) && + (query.Categories.Contains(TorznabCatType.Books.ID))) + { + searchCategory = CAT_BOOKS; + } + + if ((searchCategory == CAT_ANY) && + (query.Categories.Contains(TorznabCatType.Audio.ID) || + query.Categories.Contains(TorznabCatType.AudioLossless.ID) || + query.Categories.Contains(TorznabCatType.AudioMP3.ID))) + { + searchCategory = CAT_MUSIC; + } + + string queryUrl = string.Empty; + if (string.IsNullOrWhiteSpace(searchString)) + { + queryUrl = string.Format(BrowseUrl, searchCategory); + } + else + { + queryUrl = string.Format(SearchUrl, searchCategory, HttpUtility.UrlEncode(searchString.Trim())); + } + + var results = await RequestStringWithCookiesAndRetry(queryUrl, string.Empty); + try + { + CQ dom = results.Content; + var rows = dom["#index table tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + var date = StringUtil.StripNonAlphaNumeric(row.Cq().Find("td:eq(0)").Text().Trim() + .Replace("Янв", "01") + .Replace("Фев", "02") + .Replace("Мар", "03") + .Replace("Апр", "04") + .Replace("Май", "05") + .Replace("Июн", "06") + .Replace("Июл", "07") + .Replace("Авг", "08") + .Replace("Сен", "09") + .Replace("Окт", "10") + .Replace("Ноя", "11") + .Replace("Дек", "12")); + + release.PublishDate = DateTime.ParseExact(date, "ddMMyy", CultureInfo.InvariantCulture); + + var hasTorrent = row.Cq().Find("td:eq(1) a").Length == 3; + var titleIndex = 1; + if (hasTorrent) + titleIndex++; + + release.Title = row.Cq().Find("td:eq(" + titleIndex + ")").Text().Trim(); + if (configData.StripRussian.Value) + { + var split = release.Title.IndexOf('/'); + if (split > -1) + { + release.Title = release.Title.Substring(split + 1).Trim(); + } + } + + release.Description = release.Title; + + var hasComments = row.Cq().Find("td:eq(2) img").Length > 0; + var sizeCol = 2; + + if (hasComments) + sizeCol++; + + var sizeStr = StringUtil.StripRegex(row.Cq().Find("td:eq(" + sizeCol + ")").Text(), "[^a-zA-Z0-9\\. -]", " ").Trim(); + string[] sizeSplit = sizeStr.Split(' '); + release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); + + release.Seeders = ParseUtil.CoerceInt(row.Cq().Find(".green").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(row.Cq().Find(".red").Text().Trim()) + release.Seeders; + + release.Guid = new Uri(configData.Url.Value + row.Cq().Find("td:eq(1) a:eq(" + titleIndex + ")").Attr("href").Substring(1)); + release.Comments = release.Guid; + + if (hasTorrent) + { + release.Link = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href")); + release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(1)").Attr("href")); + } + else + { + release.MagnetUri = new Uri(row.Cq().Find("td:eq(1) a:eq(0)").Attr("href")); + } + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Shazbat.cs b/src/Jackett/Indexers/Shazbat.cs index a9a636ee1..a8ff134e1 100644 --- a/src/Jackett/Indexers/Shazbat.cs +++ b/src/Jackett/Indexers/Shazbat.cs @@ -17,6 +17,8 @@ using System.Web; using Jackett.Models.IndexerConfig; using System.Globalization; using System.Text.RegularExpressions; +using System.Xml.Linq; +using System.Xml.XPath; namespace Jackett.Indexers { @@ -25,10 +27,11 @@ namespace Jackett.Indexers private string LoginUrl { get { return SiteLink + "login"; } } private string SearchUrl { get { return SiteLink + "search"; } } private string TorrentsUrl { get { return SiteLink + "torrents"; } } + private string RSSProfile { get { return SiteLink + "rss_feeds"; } } - new ConfigurationDataBasicLogin configData + new ConfigurationDataBasicLoginWithRSS configData { - get { return (ConfigurationDataBasicLogin)base.configData; } + get { return (ConfigurationDataBasicLoginWithRSS)base.configData; } set { base.configData = value; } } @@ -43,7 +46,7 @@ namespace Jackett.Indexers client: c, logger: l, p: ps, - configData: new ConfigurationDataBasicLogin()) + configData: new ConfigurationDataBasicLoginWithRSS()) { } @@ -67,6 +70,15 @@ namespace Jackett.Indexers throw new ExceptionWithConfigData("The username and password entered do not match.", configData); }); + var rssProfile = await RequestStringWithCookiesAndRetry(RSSProfile); + CQ rssDom = rssProfile.Content; + configData.RSSKey.Value = rssDom.Find(".col-sm-9:eq(0)").Text().Trim(); + if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) + { + throw new ExceptionWithConfigData("Failed to find RSS key.", configData); + } + + SaveConfig(); return IndexerConfigurationStatus.RequiresTesting; } @@ -87,64 +99,115 @@ namespace Jackett.Indexers }; results = await PostDataWithCookiesAndRetry(SearchUrl, pairs, null, TorrentsUrl); + + try + { + CQ dom = results.Content; + var rows = dom["#torrent-table tr"]; + + if (!string.IsNullOrWhiteSpace(queryString)) + { + rows = dom["table tr"]; + } + + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + var titleRow = qRow.Find("td:eq(2)").First(); + titleRow.Children().Remove(); + release.Title = titleRow.Text().Trim(); + if (string.IsNullOrWhiteSpace(release.Title)) + continue; + release.Description = release.Title; + + var qLink = row.Cq().Find("td:eq(4) a:eq(0)"); + release.Link = new Uri(SiteLink + qLink.Attr("href")); + release.Guid = release.Link; + var qLinkComm = row.Cq().Find("td:eq(4) a:eq(1)"); + release.Comments = new Uri(SiteLink + qLinkComm.Attr("href")); + + var dateString = qRow.Find(".datetime").Attr("data-timestamp"); + release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)); + var infoString = row.Cq().Find("td:eq(3)").Text(); + + release.Size = ParseUtil.CoerceLong(Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(", "").Replace(")", "")); + + var infosplit = infoString.Replace("/", string.Empty).Split(":".ToCharArray()); + release.Seeders = ParseUtil.CoerceInt(infosplit[1]); + release.Peers = release.Seeders + ParseUtil.CoerceInt(infosplit[2]); + + // var tags = row.Cq().Find(".label-tag").Text(); These don't see to parse - bad tags? + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } } else { - var pairs = new Dictionary { - { "portlet", "true"} - }; + var rssUrl = SiteLink + "rss/recent?passkey=" + configData.RSSKey.Value; - results = await PostDataWithCookiesAndRetry(TorrentsUrl, pairs, null, TorrentsUrl); - } - - try - { - CQ dom = results.Content; - var rows = dom["#torrent-table tr"]; - foreach (var row in rows.Skip(1)) + results = await RequestStringWithCookiesAndRetry(rssUrl); + try { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - var titleRow = qRow.Find("td:eq(2)").First(); - titleRow.Children().Remove(); - release.Title = titleRow.Text().Trim(); - if (string.IsNullOrWhiteSpace(release.Title)) - continue; - release.Description = release.Title; - - var qLink = row.Cq().Find("td:eq(4) a:eq(0)"); - release.Link = new Uri(SiteLink + qLink.Attr("href")); - release.Guid = release.Link; - var qLinkComm = row.Cq().Find("td:eq(4) a:eq(1)"); - release.Comments = new Uri(SiteLink + qLinkComm.Attr("href")); - - // 07-22-2015 11:08 AM - var dateString = qRow.Find(".datetime").Attr("data-timestamp"); - release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)); - var infoString = row.Cq().Find("td:eq(3)").Text(); - - release.Size = ParseUtil.CoerceLong(Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(","").Replace(")", "")); - - var infosplit = infoString.Replace("/", string.Empty).Split(":".ToCharArray()); - release.Seeders = ParseUtil.CoerceInt(infosplit[1]); - release.Peers = release.Seeders + ParseUtil.CoerceInt(infosplit[2]); - - // var tags = row.Cq().Find(".label-tag").Text(); These don't see to parse - bad tags? - - if(release.Title.Contains("1080p") || release.Title.Contains("720p")) + var doc = XDocument.Parse(results.Content); + foreach (var result in doc.Descendants("item")) { - release.Category = TorznabCatType.TVHD.ID; - } else - { - release.Category = TorznabCatType.TVSD.ID; + var xTitle = result.Element("title").Value; + var xLink = result.Element("link").Value; + var xGUID = result.Element("guid").Value; + var xDesc = result.Element("description").Value; + var xDate = result.Element("pubDate").Value; + var release = new ReleaseInfo(); + release.Guid =release.Link = new Uri(xLink); + release.MinimumRatio = 1; + release.Seeders = 1; // We are not supplied with peer info so just mark it as one. + foreach (var element in xDesc.Split(";".ToCharArray())) + { + var split = element.IndexOf(':'); + if (split > -1) + { + var key = element.Substring(0, split).Trim(); + var value = element.Substring(split+1).Trim(); + + switch (key) + { + case "Filename": + release.Title = release.Description = value; + break; + } + } + } + + //"Thu, 24 Sep 2015 18:07:07 +0000" + release.PublishDate = DateTime.ParseExact(xDate, "ddd, dd MMM yyyy HH:mm:ss +0000", CultureInfo.InvariantCulture); + + if (!string.IsNullOrWhiteSpace(release.Title)) + { + releases.Add(release); + } } - - releases.Add(release); + } + catch (Exception ex) + { + OnParseError(results.Content, ex); } } - catch (Exception ex) + + foreach(var release in releases) { - OnParseError(results.Content, ex); + if (release.Title.Contains("1080p") || release.Title.Contains("720p")) + { + release.Category = TorznabCatType.TVHD.ID; + } + else + { + release.Category = TorznabCatType.TVSD.ID; + } } return releases; diff --git a/src/Jackett/Indexers/Strike.cs b/src/Jackett/Indexers/Strike.cs index 18986602c..74bdf59cd 100644 --- a/src/Jackett/Indexers/Strike.cs +++ b/src/Jackett/Indexers/Strike.cs @@ -1,172 +1,173 @@ -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; - -namespace Jackett.Indexers -{ - public class Strike : BaseIndexer, IIndexer - { - readonly static string defaultSiteLink = "https://getstrike.net/"; - - private Uri BaseUri - { - get { return new Uri(configData.Url.Value); } - set { configData.Url.Value = value.ToString(); } - } - - private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?phrase={0}"; } } - private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } } - - new ConfigurationDataStrike configData - { - get { return (ConfigurationDataStrike)base.configData; } - set { base.configData = value; } - } - - - public Strike(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "Strike", - description: "Torrent search engine", - link: defaultSiteLink, - caps: new TorznabCapabilities(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataStrike(defaultSiteLink)) - { - AddCategoryMapping("Anime", TorznabCatType.TVAnime); - AddCategoryMapping("Applications", TorznabCatType.PC); - AddCategoryMapping("Books", TorznabCatType.Books); - AddCategoryMapping("Games", TorznabCatType.PCGames); - AddCategoryMapping("Movies", TorznabCatType.Movies); - AddCategoryMapping("TV", TorznabCatType.TV); - AddCategoryMapping("XXX", TorznabCatType.XXX); - AddCategoryMapping("Music", TorznabCatType.Audio); - - /*AddCategoryMapping("Movies:Highres Movies", TorznabCatType.MoviesHD); - AddCategoryMapping("Movies:3D Movies", TorznabCatType.Movies3D); - AddCategoryMapping("Books:Ebooks", TorznabCatType.BooksEbook); - AddCategoryMapping("Books:Comics", TorznabCatType.BooksComics); - AddCategoryMapping("Books:Audio Books", TorznabCatType.AudioAudiobook); - AddCategoryMapping("Games:XBOX360", TorznabCatType.ConsoleXbox360); - AddCategoryMapping("Games:Wii", TorznabCatType.ConsoleWii); - AddCategoryMapping("Games:PSP", TorznabCatType.ConsolePSP); - AddCategoryMapping("Games:PS3", TorznabCatType.ConsolePS3); - AddCategoryMapping("Games:PC", TorznabCatType.PCGames); - AddCategoryMapping("Games:Android", TorznabCatType.PCPhoneAndroid); - AddCategoryMapping("Music:Mp3", TorznabCatType.AudioMP3);*/ - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var releases = await PerformQuery(new TorznabQuery()); - - await ConfigureIfOK(string.Empty, releases.Count() > 0, () => - { - throw new Exception("Could not find releases from this URL"); - }); - - return IndexerConfigurationStatus.Completed; - } - - // Override to load legacy config format - public override void LoadFromSavedConfiguration(JToken jsonConfig) - { - if (jsonConfig is JObject) - { - BaseUri = new Uri(jsonConfig.Value("base_url")); - SaveConfig(); - IsConfigured = true; - return; - } - - base.LoadFromSavedConfiguration(jsonConfig); - } - - public async Task> PerformQuery(TorznabQuery query) - { - List releases = new List(); - var queryString = query.GetQueryString(); - var searchTerm = string.IsNullOrEmpty(queryString) ? DateTime.Now.Year.ToString() : queryString; - var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchTerm)); - - var trackerCategories = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true); - - // This tracker can only search one cat at a time, otherwise search all and filter results - if (trackerCategories.Count == 1) - { - episodeSearchUrl += "&category=" + trackerCategories[0]; - } - - var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty); - try - { - var jResults = JObject.Parse(results.Content); - foreach (JObject result in (JArray)jResults["torrents"]) - { - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - if (trackerCategories.Count > 0 && !trackerCategories.Contains((string)result["torrent_category"])) - { - continue; - } - release.Category = MapTrackerCatToNewznab((string)result["torrent_category"]); - - release.Title = (string)result["torrent_title"]; - release.Description = release.Title; - release.Seeders = (int)result["seeds"]; - release.Peers = (int)result["leeches"] + release.Seeders; - release.Size = (long)result["size"]; - - // "Apr 2, 2015", "Apr 12, 2015" (note the spacing) - // some are unix timestamps, some are not.. :/ - var dateString = string.Join(" ", ((string)result["upload_date"]).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); - float dateVal; - if (ParseUtil.TryCoerceFloat(dateString, out dateVal)) - release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(dateVal); - else - release.PublishDate = DateTime.ParseExact(dateString, "MMM d, yyyy", CultureInfo.InvariantCulture); - - release.Guid = new Uri((string)result["page"]); - release.Comments = release.Guid; - - release.InfoHash = (string)result["torrent_hash"]; - release.MagnetUri = new Uri((string)result["magnet_uri"]); - release.Link = new Uri(string.Format(DownloadUrl, release.InfoHash)); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - - public override Task Download(Uri link) - { - throw new NotImplementedException(); - } - } -} +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 Jackett.Models.IndexerConfig.Bespoke; + +namespace Jackett.Indexers +{ + public class Strike : BaseIndexer, IIndexer + { + readonly static string defaultSiteLink = "https://getstrike.net/"; + + private Uri BaseUri + { + get { return new Uri(configData.Url.Value); } + set { configData.Url.Value = value.ToString(); } + } + + private string SearchUrl { get { return BaseUri + "api/v2/torrents/search/?phrase={0}"; } } + private string DownloadUrl { get { return BaseUri + "torrents/api/download/{0}.torrent"; } } + + new ConfigurationDataStrike configData + { + get { return (ConfigurationDataStrike)base.configData; } + set { base.configData = value; } + } + + + public Strike(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "Strike", + description: "Torrent search engine", + link: defaultSiteLink, + caps: new TorznabCapabilities(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataStrike(defaultSiteLink)) + { + AddCategoryMapping("Anime", TorznabCatType.TVAnime); + AddCategoryMapping("Applications", TorznabCatType.PC); + AddCategoryMapping("Books", TorznabCatType.Books); + AddCategoryMapping("Games", TorznabCatType.PCGames); + AddCategoryMapping("Movies", TorznabCatType.Movies); + AddCategoryMapping("TV", TorznabCatType.TV); + AddCategoryMapping("XXX", TorznabCatType.XXX); + AddCategoryMapping("Music", TorznabCatType.Audio); + + /*AddCategoryMapping("Movies:Highres Movies", TorznabCatType.MoviesHD); + AddCategoryMapping("Movies:3D Movies", TorznabCatType.Movies3D); + AddCategoryMapping("Books:Ebooks", TorznabCatType.BooksEbook); + AddCategoryMapping("Books:Comics", TorznabCatType.BooksComics); + AddCategoryMapping("Books:Audio Books", TorznabCatType.AudioAudiobook); + AddCategoryMapping("Games:XBOX360", TorznabCatType.ConsoleXbox360); + AddCategoryMapping("Games:Wii", TorznabCatType.ConsoleWii); + AddCategoryMapping("Games:PSP", TorznabCatType.ConsolePSP); + AddCategoryMapping("Games:PS3", TorznabCatType.ConsolePS3); + AddCategoryMapping("Games:PC", TorznabCatType.PCGames); + AddCategoryMapping("Games:Android", TorznabCatType.PCPhoneAndroid); + AddCategoryMapping("Music:Mp3", TorznabCatType.AudioMP3);*/ + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var releases = await PerformQuery(new TorznabQuery()); + + await ConfigureIfOK(string.Empty, releases.Count() > 0, () => + { + throw new Exception("Could not find releases from this URL"); + }); + + return IndexerConfigurationStatus.Completed; + } + + // Override to load legacy config format + public override void LoadFromSavedConfiguration(JToken jsonConfig) + { + if (jsonConfig is JObject) + { + BaseUri = new Uri(jsonConfig.Value("base_url")); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); + } + + public async Task> PerformQuery(TorznabQuery query) + { + List releases = new List(); + var queryString = query.GetQueryString(); + var searchTerm = string.IsNullOrEmpty(queryString) ? DateTime.Now.Year.ToString() : queryString; + var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchTerm)); + + var trackerCategories = MapTorznabCapsToTrackers(query, mapChildrenCatsToParent: true); + + // This tracker can only search one cat at a time, otherwise search all and filter results + if (trackerCategories.Count == 1) + { + episodeSearchUrl += "&category=" + trackerCategories[0]; + } + + var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty); + try + { + var jResults = JObject.Parse(results.Content); + foreach (JObject result in (JArray)jResults["torrents"]) + { + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + if (trackerCategories.Count > 0 && !trackerCategories.Contains((string)result["torrent_category"])) + { + continue; + } + release.Category = MapTrackerCatToNewznab((string)result["torrent_category"]); + + release.Title = (string)result["torrent_title"]; + release.Description = release.Title; + release.Seeders = (int)result["seeds"]; + release.Peers = (int)result["leeches"] + release.Seeders; + release.Size = (long)result["size"]; + + // "Apr 2, 2015", "Apr 12, 2015" (note the spacing) + // some are unix timestamps, some are not.. :/ + var dateString = string.Join(" ", ((string)result["upload_date"]).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); + float dateVal; + if (ParseUtil.TryCoerceFloat(dateString, out dateVal)) + release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(dateVal); + else + release.PublishDate = DateTime.ParseExact(dateString, "MMM d, yyyy", CultureInfo.InvariantCulture); + + release.Guid = new Uri((string)result["page"]); + release.Comments = release.Guid; + + release.InfoHash = (string)result["torrent_hash"]; + release.MagnetUri = new Uri((string)result["magnet_uri"]); + release.Link = new Uri(string.Format(DownloadUrl, release.InfoHash)); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + + public override Task Download(Uri link) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Jackett/Indexers/nCore.cs b/src/Jackett/Indexers/nCore.cs index 8f4979896..98c55d2e5 100644 --- a/src/Jackett/Indexers/nCore.cs +++ b/src/Jackett/Indexers/nCore.cs @@ -1,168 +1,169 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json; -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 NCore : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string SearchUrl { get { return SiteLink + "torrents.php"; } } - - new ConfigurationDataNCore configData - { - get { return (ConfigurationDataNCore)base.configData; } - set { base.configData = value; } - } - - public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "nCore", - description: "A Hungarian private torrent site.", - link: "https://ncore.cc/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataNCore()) - { - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - - if (configData.Hungarian.Value == false && configData.English.Value == false) - throw new ExceptionWithConfigData("Please select atleast one language.", configData); - - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - var pairs = new Dictionary { - { "nev", configData.Username.Value }, - { "pass", configData.Password.Value }, - { "ne_leptessen_ki", "1"}, - { "set_lang", "en" }, - { "submitted", "1" }, - { "submit", "Access!" } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["#hibauzenet table tbody tr"]; - var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1); - var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login."; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - List> CreateKeyValueList(params string[][] keyValues) - { - var list = new List>(); - foreach (var d in keyValues) - { - list.Add(new KeyValuePair(d[0], d[1])); - } - return list; - } - - private IEnumerable> GetSearchFormData(string searchString) - { - const string searchTypeKey = "kivalasztott_tipus[]"; - var baseList = CreateKeyValueList( - new[] { "nyit_sorozat_resz", "true" }, - new[] { "miben", "name" }, - new[] { "tipus", "kivalasztottak_kozott" }, - new[] { "submit.x", "1" }, - new[] { "submit.y", "1" }, - new[] { "submit", "Ok" }, - new[] { "mire", searchString } - ); - - if (configData.English.Value) - { - baseList.AddRange(CreateKeyValueList( - new[] { searchTypeKey, "xvidser" }, - new[] { searchTypeKey, "dvdser" }, - new[] { searchTypeKey, "hdser" } - )); - } - - if (configData.Hungarian.Value) - { - baseList.AddRange(CreateKeyValueList( - new[] { searchTypeKey, "xvidser_hun" }, - new[] { searchTypeKey, "dvdser_hun" }, - new[] { searchTypeKey, "hdser_hun" } - )); - } - return baseList; - } - - public async Task> PerformQuery(TorznabQuery query) - { - var releases = new List(); - var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(query.GetQueryString())); - - try - { - CQ dom = results.Content; - - ReleaseInfo release; - var rows = dom[".box_torrent_all"].Find(".box_torrent"); - - foreach (var row in rows) - { - CQ qRow = row.Cq(); - - release = new ReleaseInfo(); - var torrentTxt = qRow.Find(".torrent_txt").Find("a").Get(0); - if (torrentTxt == null) continue; - release.Title = torrentTxt.GetAttribute("title"); - release.Description = release.Title; - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - string downloadLink = SiteLink + torrentTxt.GetAttribute("href"); - string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4); - - release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId); - release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId); - release.Guid = new Uri(release.Comments.ToString() + "#comments"); ; - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders; - release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("
", " "), CultureInfo.InvariantCulture); - string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - - return releases.ToArray(); - } - - } +using CsQuery; +using Jackett.Models; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json; +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 Jackett.Models.IndexerConfig.Bespoke; + +namespace Jackett.Indexers +{ + public class NCore : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string SearchUrl { get { return SiteLink + "torrents.php"; } } + + new ConfigurationDataNCore configData + { + get { return (ConfigurationDataNCore)base.configData; } + set { base.configData = value; } + } + + public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "nCore", + description: "A Hungarian private torrent site.", + link: "https://ncore.cc/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataNCore()) + { + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + if (configData.Hungarian.Value == false && configData.English.Value == false) + throw new ExceptionWithConfigData("Please select atleast one language.", configData); + + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + var pairs = new Dictionary { + { "nev", configData.Username.Value }, + { "pass", configData.Password.Value }, + { "ne_leptessen_ki", "1"}, + { "set_lang", "en" }, + { "submitted", "1" }, + { "submit", "Access!" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["#hibauzenet table tbody tr"]; + var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1); + var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login."; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + List> CreateKeyValueList(params string[][] keyValues) + { + var list = new List>(); + foreach (var d in keyValues) + { + list.Add(new KeyValuePair(d[0], d[1])); + } + return list; + } + + private IEnumerable> GetSearchFormData(string searchString) + { + const string searchTypeKey = "kivalasztott_tipus[]"; + var baseList = CreateKeyValueList( + new[] { "nyit_sorozat_resz", "true" }, + new[] { "miben", "name" }, + new[] { "tipus", "kivalasztottak_kozott" }, + new[] { "submit.x", "1" }, + new[] { "submit.y", "1" }, + new[] { "submit", "Ok" }, + new[] { "mire", searchString } + ); + + if (configData.English.Value) + { + baseList.AddRange(CreateKeyValueList( + new[] { searchTypeKey, "xvidser" }, + new[] { searchTypeKey, "dvdser" }, + new[] { searchTypeKey, "hdser" } + )); + } + + if (configData.Hungarian.Value) + { + baseList.AddRange(CreateKeyValueList( + new[] { searchTypeKey, "xvidser_hun" }, + new[] { searchTypeKey, "dvdser_hun" }, + new[] { searchTypeKey, "hdser_hun" } + )); + } + return baseList; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var results = await PostDataWithCookiesAndRetry(SearchUrl, GetSearchFormData(query.GetQueryString())); + + try + { + CQ dom = results.Content; + + ReleaseInfo release; + var rows = dom[".box_torrent_all"].Find(".box_torrent"); + + foreach (var row in rows) + { + CQ qRow = row.Cq(); + + release = new ReleaseInfo(); + var torrentTxt = qRow.Find(".torrent_txt").Find("a").Get(0); + if (torrentTxt == null) continue; + release.Title = torrentTxt.GetAttribute("title"); + release.Description = release.Title; + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + string downloadLink = SiteLink + torrentTxt.GetAttribute("href"); + string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4); + + release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId); + release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId); + release.Guid = new Uri(release.Comments.ToString() + "#comments"); ; + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders; + release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("
", " "), CultureInfo.InvariantCulture); + string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' '); + release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + + return releases.ToArray(); + } + + } } \ No newline at end of file diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 81e2cde6d..2f128f417 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -185,6 +185,7 @@ + @@ -195,6 +196,7 @@ + @@ -222,14 +224,14 @@ - + - + - - + + @@ -265,7 +267,7 @@ - + @@ -429,6 +431,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs similarity index 90% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs rename to src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs index 47ddb275e..858239823 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataAnimeBytes.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs @@ -1,22 +1,22 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin - { - public BoolItem IncludeRaw { get; private set; } - public DisplayItem DateWarning { get; private set; } - - public ConfigurationDataAnimeBytes() - : base() - { - IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false }; - DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" }; - } - } -} +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin + { + public BoolItem IncludeRaw { get; private set; } + public DisplayItem DateWarning { get; private set; } + + public ConfigurationDataAnimeBytes() + : base() + { + IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false }; + DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataFileList.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs similarity index 90% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataFileList.cs rename to src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs index db58b34d0..54c475ddc 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataFileList.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs @@ -1,22 +1,22 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - class ConfigurationDataFileList : ConfigurationDataBasicLogin - { - public BoolItem IncludeRomanianReleases { get; private set; } - public DisplayItem CatWarning { get; private set; } - - public ConfigurationDataFileList() - : base() - { - IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false }; - CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" }; - } - } -} +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataFileList : ConfigurationDataBasicLogin + { + public BoolItem IncludeRomanianReleases { get; private set; } + public DisplayItem CatWarning { get; private set; } + + public ConfigurationDataFileList() + : base() + { + IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false }; + CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs similarity index 95% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs rename to src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs index 1dc5aaad0..067a312d8 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataNCore.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs @@ -1,62 +1,62 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - public class ConfigurationDataNCore : ConfigurationData - { - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public BoolItem Hungarian { get; set; } - public BoolItem English { get; set; } - - public ConfigurationDataNCore() - { - Username = new StringItem { Name = "Username", Value = "" }; - Password = new StringItem { Name = "Password", Value = "" }; - Hungarian = new BoolItem { Name = "Hungarian", Value = true }; - English = new BoolItem { Name = "English", Value = true }; - } - - public ConfigurationDataNCore(JToken json) - { - ConfigurationDataNCore configData = new ConfigurationDataNCore(); - - dynamic configArray = JsonConvert.DeserializeObject(json.ToString()); - foreach (var config in configArray) - { - string propertyName = UppercaseFirst((string)config.id); - switch (propertyName) - { - case "Username": - Username = new StringItem { Name = propertyName, Value = config.value }; - break; - case "Password": - Password = new StringItem { Name = propertyName, Value = config.value }; - break; - case "Hungarian": - Hungarian = new BoolItem { Name = propertyName, Value = config.value }; - break; - case "English": - English = new BoolItem { Name = propertyName, Value = config.value }; - break; - default: - break; - } - } - } - - static string UppercaseFirst(string s) - { - if (string.IsNullOrEmpty(s)) - return string.Empty; - return char.ToUpper(s[0]) + s.Substring(1); - } - } +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataNCore : ConfigurationData + { + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public BoolItem Hungarian { get; set; } + public BoolItem English { get; set; } + + public ConfigurationDataNCore() + { + Username = new StringItem { Name = "Username", Value = "" }; + Password = new StringItem { Name = "Password", Value = "" }; + Hungarian = new BoolItem { Name = "Hungarian", Value = true }; + English = new BoolItem { Name = "English", Value = true }; + } + + public ConfigurationDataNCore(JToken json) + { + ConfigurationDataNCore configData = new ConfigurationDataNCore(); + + dynamic configArray = JsonConvert.DeserializeObject(json.ToString()); + foreach (var config in configArray) + { + string propertyName = UppercaseFirst((string)config.id); + switch (propertyName) + { + case "Username": + Username = new StringItem { Name = propertyName, Value = config.value }; + break; + case "Password": + Password = new StringItem { Name = propertyName, Value = config.value }; + break; + case "Hungarian": + Hungarian = new BoolItem { Name = propertyName, Value = config.value }; + break; + case "English": + English = new BoolItem { Name = propertyName, Value = config.value }; + break; + default: + break; + } + } + } + + static string UppercaseFirst(string s) + { + if (string.IsNullOrEmpty(s)) + return string.Empty; + return char.ToUpper(s[0]) + s.Substring(1); + } + } } \ No newline at end of file diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs similarity index 90% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs rename to src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs index 49c1024ea..aed0f1391 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataRuTor.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs @@ -1,27 +1,27 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - public class ConfigurationDataRuTor : ConfigurationData - { - [JsonProperty] - public StringItem Url { get; private set; } - [JsonProperty] - public BoolItem StripRussian { get; private set; } - - public ConfigurationDataRuTor() - { - } - - public ConfigurationDataRuTor(string defaultUrl) - { - Url = new StringItem { Name = "Url", Value = defaultUrl }; - StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true }; - } - } -} +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataRuTor : ConfigurationData + { + [JsonProperty] + public StringItem Url { get; private set; } + [JsonProperty] + public BoolItem StripRussian { get; private set; } + + public ConfigurationDataRuTor() + { + } + + public ConfigurationDataRuTor(string defaultUrl) + { + Url = new StringItem { Name = "Url", Value = defaultUrl }; + StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataStrike.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs similarity index 87% rename from src/Jackett/Models/IndexerConfig/ConfigurationDataStrike.cs rename to src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs index 124ed0c2c..ba39425b0 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataStrike.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs @@ -1,18 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - public class ConfigurationDataStrike : ConfigurationDataUrl - { - public DisplayItem StrikeWarning { get; private set; } - - public ConfigurationDataStrike(string url) : base(url) - { - StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" }; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataStrike : ConfigurationDataUrl + { + public DisplayItem StrikeWarning { get; private set; } + + public ConfigurationDataStrike(string url) : base(url) + { + StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs new file mode 100644 index 000000000..30fd25ee5 --- /dev/null +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig +{ + public class ConfigurationDataAPIKey : ConfigurationData + { + public ConfigurationData.StringItem Key { get; private set; } + + public ConfigurationDataAPIKey() + { + Key = new ConfigurationData.StringItem { Name = "APIKey", Value = string.Empty }; + } + } +}