diff --git a/README.md b/README.md index 95efd8faa..7941d9a74 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ We were previously focused on TV but are working on extending searches to allow #### Supported Trackers * [AlphaRatio](https://alpharatio.cc/) * [AnimeBytes](https://animebytes.tv/) + * [Avistaz](https://avistaz.to/) * [BakaBT](http://bakabt.me/) * [bB](http://reddit.com/r/baconbits) * [BeyondHD](https://beyondhd.me/) diff --git a/src/Jackett/Content/logos/avistaz.png b/src/Jackett/Content/logos/avistaz.png new file mode 100644 index 000000000..4944a926e Binary files /dev/null and b/src/Jackett/Content/logos/avistaz.png differ diff --git a/src/Jackett/Indexers/Abstract/AvistazTracker.cs b/src/Jackett/Indexers/Abstract/AvistazTracker.cs new file mode 100644 index 000000000..72ef2a29e --- /dev/null +++ b/src/Jackett/Indexers/Abstract/AvistazTracker.cs @@ -0,0 +1,136 @@ +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; + +namespace Jackett.Indexers +{ + public abstract class AvistazTracker : BaseIndexer + { + private string LoginUrl { get { return SiteLink + "auth/login"; } } + private string SearchUrl { get { return SiteLink + "torrents?in=1&type={0}&search={1}"; } } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public AvistazTracker(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService, string name, string desc, string link) + : base(name: name, + description: desc, + link: link, + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: indexerManager, + client: webClient, + logger: logger, + p: protectionService, + configData: new ConfigurationDataBasicLogin()) + { + AddCategoryMapping(1, TorznabCatType.Movies); + AddCategoryMapping(1, TorznabCatType.MoviesForeign); + AddCategoryMapping(1, TorznabCatType.MoviesHD); + AddCategoryMapping(1, TorznabCatType.MoviesSD); + AddCategoryMapping(2, TorznabCatType.TV); + AddCategoryMapping(3, TorznabCatType.Audio); + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString(); + var pairs = new Dictionary { + { "_token", token }, + { "username_email", configData.Username.Value }, + { "password", configData.Password.Value }, + { "remember", "on" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("auth/logout"), () => + { + CQ dom = result.Content; + var messageEl = dom[".form-error"]; + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + + var categoryMapping = MapTorznabCapsToTrackers(query).Distinct(); + string category = "0"; // Aka all + if (categoryMapping.Count() == 1) + { + category = categoryMapping.First(); + } + + + var episodeSearchUrl = string.Format(SearchUrl, category, HttpUtility.UrlEncode(query.GetQueryString())); + + var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl); + + try + { + CQ dom = response.Content; + var rows = dom["table > tbody > tr"]; + foreach (var row in rows) + { + CQ qRow = row.Cq(); + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + var qLink = row.ChildElements.ElementAt(1).FirstElementChild.Cq(); + release.Title = qLink.Text().Trim(); + release.Comments = new Uri(qLink.Attr("href")); + release.Guid = release.Comments; + + var qDownload = row.ChildElements.ElementAt(3).FirstElementChild.Cq(); + release.Link = new Uri(qDownload.Attr("href")); + + var dateStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + + var sizeStr = row.ChildElements.ElementAt(6).Cq().Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; + + var cat = row.Cq().Find("td:eq(0) i").First().Attr("class") + .Replace("gi gi-film", "1") + .Replace("gi gi-tv", "2") + .Replace("gi gi-music", "3") + .Replace("text-pink", string.Empty); + release.Category = MapTrackerCatToNewznab(cat.Trim()); + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + return releases; + } + } +} \ No newline at end of file diff --git a/src/Jackett/Indexers/Avistaz.cs b/src/Jackett/Indexers/Avistaz.cs new file mode 100644 index 000000000..ea99df3a0 --- /dev/null +++ b/src/Jackett/Indexers/Avistaz.cs @@ -0,0 +1,35 @@ +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; + +namespace Jackett.Indexers +{ + public class Avistaz : AvistazTracker, IIndexer + { + public Avistaz(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) + : base(name: "Avistaz", + desc: "Aka AsiaTorrents", + link: "https://avistaz.to/", + indexerManager: indexerManager, + logger: logger, + protectionService: protectionService, + webClient: webClient + ) + { + } + } +} \ No newline at end of file diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs index 48393fc65..6bb387ca1 100644 --- a/src/Jackett/Indexers/PrivateHD.cs +++ b/src/Jackett/Indexers/PrivateHD.cs @@ -18,119 +18,18 @@ using Jackett.Models.IndexerConfig; namespace Jackett.Indexers { - public class PrivateHD : BaseIndexer, IIndexer + public class PrivateHD : AvistazTracker, IIndexer { - private string LoginUrl { get { return SiteLink + "auth/login"; } } - private string SearchUrl { get { return SiteLink + "torrents?in=1&type={0}&search={1}"; } } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public PrivateHD(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + public PrivateHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) : base(name: "PrivateHD", - description: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", + desc: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", link: "https://privatehd.to/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) + indexerManager: indexerManager, + logger: logger, + protectionService: protectionService, + webClient: webClient + ) { - AddCategoryMapping(1, TorznabCatType.Movies); - AddCategoryMapping(1, TorznabCatType.MoviesForeign); - AddCategoryMapping(1, TorznabCatType.MoviesHD); - AddCategoryMapping(1, TorznabCatType.MoviesSD); - AddCategoryMapping(2, TorznabCatType.TV); - AddCategoryMapping(3, TorznabCatType.Audio); - } - - public async Task ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - var token = new Regex("Avz.CSRF_TOKEN = '(.*?)';").Match(loginPage.Content).Groups[1].ToString(); - var pairs = new Dictionary { - { "_token", token }, - { "username_email", configData.Username.Value }, - { "password", configData.Password.Value }, - { "remember", "on" } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("auth/logout"), () => - { - CQ dom = result.Content; - var messageEl = dom[".form-error"]; - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task> PerformQuery(TorznabQuery query) - { - var releases = new List(); - - var categoryMapping = MapTorznabCapsToTrackers(query).Distinct(); - string category = "0"; // Aka all - if (categoryMapping.Count() == 1) - { - category = categoryMapping.First(); - } - - - var episodeSearchUrl = string.Format(SearchUrl, category, HttpUtility.UrlEncode(query.GetQueryString())); - - var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl); - - try - { - CQ dom = response.Content; - var rows = dom["table > tbody > tr"]; - foreach (var row in rows) - { - CQ qRow = row.Cq(); - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - var qLink = row.ChildElements.ElementAt(1).FirstElementChild.Cq(); - release.Title = qLink.Text().Trim(); - release.Comments = new Uri(qLink.Attr("href")); - release.Guid = release.Comments; - - var qDownload = row.ChildElements.ElementAt(3).FirstElementChild.Cq(); - release.Link = new Uri(qDownload.Attr("href")); - - var dateStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); - release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); - - var sizeStr = row.ChildElements.ElementAt(6).Cq().Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()); - release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; - - var cat = row.Cq().Find("td:eq(0) i").First().Attr("class") - .Replace("gi gi-film", "1") - .Replace("gi gi-tv", "2") - .Replace("gi gi-music", "3") - .Replace("text-pink", string.Empty); - release.Category = MapTrackerCatToNewznab(cat.Trim()); - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - return releases; } } } diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 8a78bd149..e5a39b615 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -175,6 +175,7 @@ + @@ -189,7 +190,8 @@ - + + @@ -405,6 +407,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Indexers/ManualSearchResult.cs b/src/Jackett/Models/ManualSearchResult.cs similarity index 91% rename from src/Jackett/Indexers/ManualSearchResult.cs rename to src/Jackett/Models/ManualSearchResult.cs index 0831640bf..59e1a35bd 100644 --- a/src/Jackett/Indexers/ManualSearchResult.cs +++ b/src/Jackett/Models/ManualSearchResult.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett.Indexers +namespace Jackett { public class ManualSearchResult {