From b71cd56d7642bd4eebbae71be2718261827e5472 Mon Sep 17 00:00:00 2001 From: flightlevel Date: Sun, 4 Oct 2015 15:42:37 +1100 Subject: [PATCH] Add TehConnection Indexer Conflicts: src/Jackett/Jackett.csproj --- README.md | 1 + src/Jackett/Content/logos/tehconnection.png | Bin 0 -> 6609 bytes src/Jackett/Indexers/TehConnection.cs | 183 ++++++++++++++++++ src/Jackett/Jackett.csproj | 2 + .../ConfigurationDataBasicLoginWithFilter.cs | 30 +++ 5 files changed, 216 insertions(+) create mode 100644 src/Jackett/Content/logos/tehconnection.png create mode 100644 src/Jackett/Indexers/TehConnection.cs create mode 100644 src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithFilter.cs diff --git a/README.md b/README.md index a659c27f5..e93f13f75 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ We were previously focused on TV but are working on extending searches to allow * [ShowRSS](https://showrss.info/) * [Strike](https://getstrike.net/) * [T411](http://www.t411.io/) + * [TehConnection](https://tehconnection.eu/) * [The Pirate Bay](https://thepiratebay.se/) * [TorrentBytes](https://www.torrentbytes.net/) * [TorrentDay](https://torrentday.eu/) diff --git a/src/Jackett/Content/logos/tehconnection.png b/src/Jackett/Content/logos/tehconnection.png new file mode 100644 index 0000000000000000000000000000000000000000..4a859cec9b4d3c97a806a0291ce99d7197045a62 GIT binary patch literal 6609 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 literal 0 HcmV?d00001 diff --git a/src/Jackett/Indexers/TehConnection.cs b/src/Jackett/Indexers/TehConnection.cs new file mode 100644 index 000000000..308e31665 --- /dev/null +++ b/src/Jackett/Indexers/TehConnection.cs @@ -0,0 +1,183 @@ +using CsQuery; +using Jackett.Indexers; +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.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; + +namespace Jackett.Indexers +{ + public class TehConnection : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string indexUrl { get { return SiteLink + "index.php"; } } + private string SearchUrl { get { return SiteLink + "torrents.php"; } } + + new ConfigurationDataBasicLoginWithFilter configData + { + get { return (ConfigurationDataBasicLoginWithFilter)base.configData; } + set { base.configData = value; } + } + + public TehConnection(IIndexerManagerService i, Logger l, IWebClient c, IProtectionService ps) + : base(name: "TehConnection", + description: "Working towards providing a well-seeded archive of all available digital forms of cinema and film in their highest possible quality", + link: "https://tehconnection.eu/", + caps: new TorznabCapabilities(), + manager: i, + client: c, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithFilter(@"Enter filter options below to restrict search results. + Separate options with a space if using more than one option.
Filter options available: +
QualityEncodeOnly
FreeLeechOnly")) + { + AddCategoryMapping(7, TorznabCatType.Movies); + AddCategoryMapping(7, TorznabCatType.MoviesForeign); + AddCategoryMapping(7, TorznabCatType.MoviesOther); + AddCategoryMapping(7, TorznabCatType.MoviesSD); + AddCategoryMapping(7, TorznabCatType.MoviesHD); + AddCategoryMapping(7, TorznabCatType.Movies3D); + AddCategoryMapping(7, TorznabCatType.MoviesBluRay); + AddCategoryMapping(7, TorznabCatType.MoviesDVD); + AddCategoryMapping(7, TorznabCatType.MoviesWEBDL); + } + + public async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var pairs = new Dictionary { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "keeplogged", "1" }, + { "login", "Log In!" } + }; + + var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, indexUrl, SiteLink); + + await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/logout.php"), () => + { + CQ dom = response.Content; + string errorMessage = "Unable to login to TehConnection"; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + bool configFreeLeechOnly = configData.FilterString.Value.ToLowerInvariant().Contains("freeleechonly"); + bool configQualityEncodeOnly = configData.FilterString.Value.ToLowerInvariant().Contains("qualityencodeonly"); + string movieListSearchUrl; + + if (string.IsNullOrEmpty(query.GetQueryString())) + movieListSearchUrl = SearchUrl; + else + { + movieListSearchUrl = string.Format("{0}?action=basic&searchstr={1}", SearchUrl, HttpUtility.UrlEncode(query.GetQueryString())); + } + + var results = await RequestStringWithCookiesAndRetry(movieListSearchUrl); + try + { + CQ mdom = results.Content; + + var mrows = mdom[".torrent_title_box"]; + foreach (var mrow in mrows.Take(5)) + { + var mqRow = mrow.Cq(); + + Uri movieReleasesLink = new Uri(SiteLink.TrimEnd('/') + mqRow.Find("a[title='View Torrent']").First().Attr("href").Trim()); + bool commentsPresent = !mqRow.Find("font[class='tags'] > strong > a:contains('Comment')").First().Text().Trim().Contains("0 Comments"); + Uri commentsLink = new Uri(SiteLink.TrimEnd('/') + mqRow.Find("font[class='tags'] > strong > a:contains('Comment')").First().Attr("href").Trim()); + + string imdblink = mqRow.Find("span[class='imdb-number-rating']").Length > 0 ? mqRow.Find("span[class='imdb-number-rating'] > a").First().Attr("href").Trim() : ""; + long imdb_id = 0; + try + { + if (!string.IsNullOrWhiteSpace(imdblink) && imdblink.ToLowerInvariant().Contains("tt")) + { + imdb_id = long.Parse(imdblink.Substring(imdblink.LastIndexOf('t') + 1).Replace("/", "")); + } + } + catch { imdb_id = 0; } + + var release_results = await RequestStringWithCookiesAndRetry(movieReleasesLink.ToString()); + + //Iterate over the releases for each movie + + CQ dom = release_results.Content; + + var rows = dom[".torrent_widget.box.pad"]; + foreach (var row in rows) + { + var qRow = row.Cq(); + + string title = qRow.Find("[id^=desc_] > h2 > strong").First().Text().Trim(); + Uri link = new Uri(SiteLink.TrimEnd('/') + qRow.Find("a[title='Download']").First().Attr("href").Trim()); + Uri guid = new Uri(SiteLink.TrimEnd('/') + qRow.Find("a[title='Permalink']").First().Attr("href").Trim()); + string pubDateStr = qRow.Find("div[class='box pad'] > p:contains('Uploaded by') > span").First().Attr("title").Trim(); + DateTime pubDate = DateTime.ParseExact(pubDateStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); + string sizeStr = qRow.Find("[id^=desc_] > div > table > tbody > tr > td > strong:contains('Size:')").First().Parent().Parent().Find("td").Last().Text().Trim(); + Int32 seeders = Convert.ToInt32(qRow.Find("img[title='Seeders']").First().Parent().Text().Trim()); + Int32 peers = Convert.ToInt32(qRow.Find("img[title='Leechers']").First().Parent().Text().Trim()) + seeders; + Uri CoverUrl = new Uri(SiteLink.TrimEnd('/') + dom.Find("div[id='poster'] > a > img").First().Attr("src").Trim()); + bool freeleech = qRow.Find("span[class='freeleech']").Length == 1 ? true : false; + bool qualityEncode = qRow.Find("img[class='approved']").Length == 1 ? true : false; + string grabs = qRow.Find("img[title='Snatches']").First().Parent().Text().Trim(); + if (String.IsNullOrWhiteSpace(sizeStr)) + { + string secondSizeStr = qRow.Find("div[class='details_title'] > strong:contains('(')").Last().Text().Trim(); + if (secondSizeStr.Length > 3 && secondSizeStr.Contains("(") && secondSizeStr.Contains(")")) + { sizeStr = secondSizeStr.Replace("(", "").Replace(")", "").Trim(); } + } + + var release = new ReleaseInfo(); + + release.Title = title; + release.Guid = guid; + release.Link = link; + release.PublishDate = pubDate; + release.Size = ReleaseInfo.GetBytes(sizeStr); + release.Description = release.Title; + release.Seeders = seeders; + release.Peers = peers; + release.MinimumRatio = 1; + release.MinimumSeedTime = 345600; + release.Category = 2000; + if (commentsPresent) { release.Comments = commentsLink; } + if (imdb_id > 0) { release.Imdb = imdb_id; } + + if (configFreeLeechOnly && !freeleech) + { + continue; //Skip release if user only wants FreeLeech + } + if (configQualityEncodeOnly && !qualityEncode) + { + continue; //Skip release if user only wants Quality Encode + } + + releases.Add(release); + } + + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 2f128f417..91a21df0b 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -186,6 +186,7 @@ + @@ -196,6 +197,7 @@ + diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithFilter.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithFilter.cs new file mode 100644 index 000000000..10a029db2 --- /dev/null +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithFilter.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig +{ + public class ConfigurationDataBasicLoginWithFilter : ConfigurationData + { + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public DisplayItem FilterExample { get; private set; } + public StringItem FilterString { get; private set; } + + public ConfigurationDataBasicLoginWithFilter(string FilterInstructions) + { + Username = new StringItem { Name = "Username" }; + Password = new StringItem { Name = "Password" }; + FilterExample = new DisplayItem(FilterInstructions) + { + Name = "" + }; + FilterString = new StringItem { Name = "Filters (optional)" }; + } + + + } +}