From b3ba9492156b28cab2f448187a4834292e879537 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Jul 2015 01:13:16 -0600 Subject: [PATCH] Implemented T411 --- src/Jackett/Indexers/T411.cs | 200 ++++++++++++++++++++++++++ src/Jackett/Jackett.csproj | 4 + src/Jackett/WebContent/logos/t411.png | Bin 0 -> 28583 bytes 3 files changed, 204 insertions(+) create mode 100644 src/Jackett/Indexers/T411.cs create mode 100644 src/Jackett/WebContent/logos/t411.png diff --git a/src/Jackett/Indexers/T411.cs b/src/Jackett/Indexers/T411.cs new file mode 100644 index 000000000..cbaff7445 --- /dev/null +++ b/src/Jackett/Indexers/T411.cs @@ -0,0 +1,200 @@ +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.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Web; + +namespace Jackett.Indexers +{ + public class T411 : IndexerInterface + { + + public event Action OnSaveConfigurationRequested; + + public event Action OnResultParsingError; + + public string DisplayName + { + get { return "T411"; } + } + + public string DisplayDescription + { + get { return "French Torrent Tracker"; } + } + + public Uri SiteLink + { + get { return new Uri(BaseUrl); } + } + + public bool IsConfigured { get; private set; } + + const string BaseUrl = "http://www.t411.io"; + const string CommentsUrl = BaseUrl + "/torrents/{0}"; + + const string ApiUrl = "http://api.t411.io"; + const string AuthUrl = ApiUrl + "/auth"; + const string SearchUrl = ApiUrl + "/torrents/search/{0}"; + const string DownloadUrl = ApiUrl + "/torrents/download/{0}"; + + HttpClientHandler handler; + HttpClient client; + + string username = string.Empty; + string password = string.Empty; + string token = string.Empty; + DateTime lastTokenFetch = DateTime.MinValue; + + public T411() + { + IsConfigured = false; + handler = new HttpClientHandler + { + AllowAutoRedirect = true + }; + client = new HttpClient(handler); + } + + public Task GetConfigurationForSetup() + { + var config = new ConfigurationDataBasicLogin(); + return Task.FromResult(config); + } + + async Task GetAuthToken(bool forceFetch = false) + { + if (!forceFetch && lastTokenFetch > DateTime.Now - TimeSpan.FromHours(48)) + { + return token; + } + + var pairs = new Dictionary { + { "username", username }, + { "password", password } + }; + + var content = new FormUrlEncodedContent(pairs); + + var response = await client.PostAsync(AuthUrl, content); + var responseContent = await response.Content.ReadAsStringAsync(); + var jsonResponse = JObject.Parse(responseContent); + if (jsonResponse["error"] != null) + { + throw new ApplicationException((string)jsonResponse["error"]); + } + token = (string)jsonResponse["token"]; + lastTokenFetch = DateTime.Now; + return token; + } + + public async Task ApplyConfiguration(JToken configJson) + { + var config = new ConfigurationDataBasicLogin(); + config.LoadValuesFromJson(configJson); + + username = config.Username.Value; + password = config.Password.Value; + + try + { + await GetAuthToken(true); + } + catch (Exception ex) + { + throw new ExceptionWithConfigData(ex.Message, (ConfigurationData)config); + } + + var configSaveData = new JObject(); + configSaveData["username"] = username; + configSaveData["password"] = password; + configSaveData["token"] = token; + configSaveData["last_token_fetch"] = lastTokenFetch; + + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested(this, configSaveData); + + IsConfigured = true; + } + + public void LoadFromSavedConfiguration(JToken jsonConfig) + { + username = (string)jsonConfig["username"]; + password = (string)jsonConfig["password"]; + token = (string)jsonConfig["token"]; + lastTokenFetch = (DateTime)jsonConfig["last_token_fetch"]; + IsConfigured = true; + } + + public async Task PerformQuery(TorznabQuery query) + { + List releases = new List(); + + foreach (var title in query.ShowTitles ?? new string[] { "%20" }) + { + var searchString = title + " " + query.GetEpisodeSearchString(); + var episodeSearchUrl = string.Format(SearchUrl, HttpUtility.UrlEncode(searchString)); + + var message = new HttpRequestMessage(); + message.Method = HttpMethod.Get; + message.RequestUri = new Uri(episodeSearchUrl); + message.Headers.TryAddWithoutValidation("Authorization", token); + + var response = await client.SendAsync(message); + var results = await response.Content.ReadAsStringAsync(); + + var jsonResult = JObject.Parse(results); + try + { + var items = (JArray)jsonResult["torrents"]; + foreach (var item in items) + { + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + var torrentId = (string)item["id"]; + release.Link = new Uri(string.Format(DownloadUrl, torrentId)); + release.Title = (string)item["name"]; + release.Description = release.Title; + release.Comments = new Uri(string.Format(CommentsUrl, (string)item["rewritename"])); + release.Guid = release.Comments; + + var dateUtc = DateTime.ParseExact((string)item["added"], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = DateTime.SpecifyKind(dateUtc, DateTimeKind.Utc).ToLocalTime(); + + release.Seeders = ParseUtil.CoerceInt((string)item["seeders"]); + release.Peers = ParseUtil.CoerceInt((string)item["leechers"]) + release.Seeders; + + release.Size = ParseUtil.CoerceLong((string)item["size"]); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnResultParsingError(this, results, ex); + throw ex; + } + } + return releases.ToArray(); + } + + public async Task Download(Uri link) + { + var message = new HttpRequestMessage(); + message.Method = HttpMethod.Get; + message.RequestUri = link; + message.Headers.TryAddWithoutValidation("Authorization", token); + + var response = await client.SendAsync(message); + return await response.Content.ReadAsByteArrayAsync(); + } + } +} diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 532f6f42f..e53951a72 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -107,6 +107,7 @@ + @@ -181,6 +182,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/WebContent/logos/t411.png b/src/Jackett/WebContent/logos/t411.png new file mode 100644 index 0000000000000000000000000000000000000000..30e13134a219fcb3892657209c8f356aad8744f0 GIT binary patch literal 28583 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 V1dH!m{QQ3>vXY7tm14$${|Ch)o(=#2 literal 0 HcmV?d00001