diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs new file mode 100644 index 000000000..54693ce56 --- /dev/null +++ b/src/Jackett/Indexers/BitHdtv.cs @@ -0,0 +1,171 @@ +using CsQuery; +using Newtonsoft.Json.Linq; +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; + +namespace Jackett.Indexers +{ + public class BitHdtv : IndexerInterface + { + public string DisplayName + { + get { return "BIT-HDTV"; } + } + + public string DisplayDescription + { + get { return "Home of high definition invites"; } + } + + public Uri SiteLink + { + get { return new Uri(BaseUrl); } + } + + static string BaseUrl = "https://www.bit-hdtv.com"; + static string LoginUrl = BaseUrl + "/takelogin.php"; + static string SearchUrl = BaseUrl + "/torrents.php?cat=0&search="; + static string DownloadUrl = BaseUrl + "/download.php?/{0}/dl.torrent"; + + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; + + public BitHdtv() + { + IsConfigured = false; + cookies = new CookieContainer(); + handler = new HttpClientHandler + { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient(handler); + } + + public Task GetConfigurationForSetup() + { + var config = new ConfigurationDataBasicLogin(); + return Task.FromResult(config); + } + + public async Task ApplyConfiguration(JToken configJson) + { + var config = new ConfigurationDataBasicLogin(); + config.LoadValuesFromJson(configJson); + + var pairs = new Dictionary + { + { "username", config.Username.Value}, + { "password", config.Password.Value} + }; + + var content = new FormUrlEncodedContent(pairs); + + var response = await client.PostAsync(LoginUrl, content); + var responseContent = await response.Content.ReadAsStringAsync(); + + if (!responseContent.Contains("logout.php")) + { + CQ dom = responseContent; + var messageEl = dom["table.detail td.text"].Last(); + messageEl.Children("a").Remove(); + messageEl.Children("style").Remove(); + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); + } + else + { + var configSaveData = new JObject(); + configSaveData["cookies"] = new JArray(( + from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() + select cookie.Name + ":" + cookie.Value + ).ToArray()); + + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested(this, configSaveData); + + IsConfigured = true; + } + } + + public async Task VerifyConnection() + { + var browseQuery = new TorznabQuery(); + var results = await PerformQuery(browseQuery); + if (results.Length == 0) + throw new Exception("Found no results while trying to browse this tracker"); + } + + public event Action OnSaveConfigurationRequested; + + public bool IsConfigured { get; private set; } + + public void LoadFromSavedConfiguration(JToken jsonConfig) + { + cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + IsConfigured = true; + } + + public async Task PerformQuery(TorznabQuery query) + { + List releases = new List(); + + + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) + { + var searchString = title + " " + query.GetEpisodeSearchString(); + var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); + var results = await client.GetStringAsync(episodeSearchUrl); + CQ dom = results; + dom["#needseed"].Remove(); + var rows = dom["table[width='750'] > tbody"].Children(); + foreach (var row in rows.Skip(1)) + { + + var release = new ReleaseInfo(); + + var qRow = row.Cq(); + var qLink = qRow.Children().ElementAt(2).Cq().Children("a").First(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.Title = qLink.Attr("title"); + release.Description = release.Title; + release.Guid = new Uri(BaseUrl + qLink.Attr("href")); + release.Comments = release.Guid; + release.Link = new Uri(string.Format(DownloadUrl, qLink.Attr("href").Split('=')[1])); + + var dateString = qRow.Children().ElementAt(5).Cq().Text().Trim(); + var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = pubDate; + + var sizeCol = qRow.Children().ElementAt(6); + var sizeVal = sizeCol.ChildNodes[0].NodeValue; + var sizeUnit = sizeCol.ChildNodes[2].NodeValue; + release.Size = ReleaseInfo.GetBytes(sizeUnit, float.Parse(sizeVal)); + + release.Seeders = int.Parse(qRow.Children().ElementAt(8).Cq().Text().Trim()); + release.Peers = int.Parse(qRow.Children().ElementAt(9).Cq().Text().Trim()) + release.Seeders; + + releases.Add(release); + } + } + + return releases.ToArray(); + } + + public Task Download(Uri link) + { + return client.GetByteArrayAsync(link); + } + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index f014b2c92..710fe375c 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -87,6 +87,7 @@ + diff --git a/src/Jackett/WebContent/logos/bithdtv.png b/src/Jackett/WebContent/logos/bithdtv.png index 10e48a5ae..7a9f1afde 100644 Binary files a/src/Jackett/WebContent/logos/bithdtv.png and b/src/Jackett/WebContent/logos/bithdtv.png differ