From bfb58f53f5f3ff33ecceef8c64fc0df0cbc79ac3 Mon Sep 17 00:00:00 2001 From: JigSaw Date: Sun, 3 Apr 2016 20:31:44 +0200 Subject: [PATCH] Xthor Provider French Private Tracker --- README.md | 1 + src/Jackett/Content/logos/xthor.png | Bin 0 -> 52300 bytes src/Jackett/Indexers/Xthor.cs | 592 ++++++++++++++++++ src/Jackett/Jackett.csproj | 5 + .../Bespoke/ConfigurationDataXthor.cs | 27 + 5 files changed, 625 insertions(+) create mode 100644 src/Jackett/Content/logos/xthor.png create mode 100644 src/Jackett/Indexers/Xthor.cs create mode 100644 src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs diff --git a/README.md b/README.md index 9d19f2a4d..3a0a939b8 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/ * TV Chaos UK * World-In-HD * XSpeeds + * Xthor #### Installation on Windows diff --git a/src/Jackett/Content/logos/xthor.png b/src/Jackett/Content/logos/xthor.png new file mode 100644 index 0000000000000000000000000000000000000000..104fbe5c2150a8b1d33bc55df5c669666cb344a7 GIT binary patch literal 52300 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 + /// Provider for Xthor Private French Tracker + /// + public class Xthor : BaseIndexer, IIndexer + { + private static string ApiEndpoint => "https://api.xthor.bz/"; + private string TorrentCommentUrl => TorrentDescriptionUrl; + private string TorrentDescriptionUrl => SiteLink + "details.php?id={id}"; + private bool DevMode => ConfigData.DevMode.Value; + private bool CacheMode => ConfigData.HardDriveCache.Value; + private static string Directory => System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType?.Name + "\\"; + public Dictionary EmulatedBrowserHeaders { get; } = new Dictionary(); + private ConfigurationDataXthor ConfigData => (ConfigurationDataXthor)configData; + + public Xthor(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) + : base( + name: "Xthor", + description: "General French Private Tracker", + link: "https://xthor.bz/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + downloadBase: "https://xthor.bz/download.php?torrent=", + configData: new ConfigurationDataXthor()) + { + // Clean capabilities + TorznabCaps.Categories.Clear(); + + // Movies + AddCategoryMapping(6, TorznabCatType.MoviesSD); // XVID + AddCategoryMapping(7, TorznabCatType.MoviesSD); // X264 + AddCategoryMapping(95, TorznabCatType.MoviesSD); // WEBRIP + AddCategoryMapping(5, TorznabCatType.MoviesHD); // HD 720P + AddCategoryMapping(4, TorznabCatType.MoviesHD); // HD 1080P X264 + AddCategoryMapping(100, TorznabCatType.MoviesHD); // HD 1080P X265 + AddCategoryMapping(94, TorznabCatType.MoviesHD); // WEBDL + AddCategoryMapping(1, TorznabCatType.MoviesBluRay); // FULL BLURAY + AddCategoryMapping(2, TorznabCatType.MoviesBluRay); // BLURAY REMUX + AddCategoryMapping(3, TorznabCatType.MoviesBluRay); // FULL BLURAY 3D + AddCategoryMapping(8, TorznabCatType.MoviesDVD); // FULL DVD + AddCategoryMapping(9, TorznabCatType.MoviesOther); // VOSTFR + AddCategoryMapping(36, TorznabCatType.XXX); // XXX + + // Series + AddCategoryMapping(14, TorznabCatType.TVSD); // SD VF + AddCategoryMapping(16, TorznabCatType.TVSD); // SD VF VOSTFR + AddCategoryMapping(15, TorznabCatType.TVHD); // HD VF + AddCategoryMapping(17, TorznabCatType.TVHD); // HD VF VOSTFR + AddCategoryMapping(13, TorznabCatType.TVOTHER); // PACK + AddCategoryMapping(98, TorznabCatType.TVOTHER); // PACK VOSTFR HD + AddCategoryMapping(16, TorznabCatType.TVOTHER); // PACK VOSTFR SD + AddCategoryMapping(30, TorznabCatType.TVOTHER); // EMISSIONS + AddCategoryMapping(34, TorznabCatType.TVOTHER); // EMISSIONS + AddCategoryMapping(33, TorznabCatType.TVOTHER); // SHOWS + + // Anime + AddCategoryMapping(31, TorznabCatType.TVAnime); // MOVIES ANIME + AddCategoryMapping(32, TorznabCatType.TVAnime); // SERIES ANIME + + // Documentaries + AddCategoryMapping(12, TorznabCatType.TVDocumentary); // DOCS + + // Music + AddCategoryMapping(20, TorznabCatType.AudioVideo); // CONCERT + + // Other + AddCategoryMapping(21, TorznabCatType.PC); // PC + AddCategoryMapping(22, TorznabCatType.PCMac); // PC + AddCategoryMapping(25, TorznabCatType.PCGames); // GAMES + AddCategoryMapping(26, TorznabCatType.ConsoleXbox360); // GAMES + AddCategoryMapping(28, TorznabCatType.ConsoleWii); // GAMES + AddCategoryMapping(27, TorznabCatType.ConsolePS3); // GAMES + AddCategoryMapping(29, TorznabCatType.ConsoleNDS); // GAMES + AddCategoryMapping(24, TorznabCatType.BooksEbook); // EBOOKS + AddCategoryMapping(96, TorznabCatType.BooksEbook); // EBOOKS MAGAZINES + AddCategoryMapping(99, TorznabCatType.BooksEbook); // EBOOKS ANIME + AddCategoryMapping(23, TorznabCatType.PCPhoneAndroid); // ANDROID + } + + /// + /// Configure our Provider + /// + /// Our params in Json + /// Configuration state + #pragma warning disable 1998 + public async Task ApplyConfiguration(JToken configJson) + #pragma warning restore 1998 + { + // Provider not yet configured + IsConfigured = false; + + // Retrieve config values set by Jackett's user + ConfigData.LoadValuesFromJson(configJson); + + // Check & Validate Config + ValidateConfig(); + + // Setting our data for a better emulated browser (maximum security) + // TODO: Encoded Content not supported by Jackett at this time + // emulatedBrowserHeaders.Add("Accept-Encoding", "gzip, deflate"); + + // Clean headers + EmulatedBrowserHeaders.Clear(); + + // Inject headers + EmulatedBrowserHeaders.Add("Accept", "application/json-rpc, application/json"); + EmulatedBrowserHeaders.Add("Content-Type", "application/json-rpc"); + + // Tracker is now configured + IsConfigured = true; + + // Saving data + SaveConfig(); + + return IndexerConfigurationStatus.RequiresTesting; + } + + /// + /// Execute our search query + /// + /// Query + /// Releases + public async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var searchTerm = query.GetQueryString(); + + // Check cache first so we don't query the server (if search term used or not in dev mode) + if(!DevMode && !string.IsNullOrEmpty(searchTerm)) + { + lock (cache) + { + // Remove old cache items + CleanCache(); + + // Search in cache + var cachedResult = cache.FirstOrDefault(i => i.Query == searchTerm); + if (cachedResult != null) + return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); + } + } + + // Build our query + var request = BuildQuery(searchTerm, query, ApiEndpoint); + + // Getting results & Store content + var results = await QueryExec(request); + + try + { + // Deserialize our Json Response + var xthorResponse = JsonConvert.DeserializeObject(results.Content); + + // Check Tracker's State + CheckApiState(xthorResponse.error); + + // If contains torrents + if (xthorResponse.torrents != null) + { + // Adding each torrent row to releases + releases.AddRange(xthorResponse.torrents.Select(torrent => new ReleaseInfo + { + // Mapping data + Category = MapTrackerCatToNewznab(torrent.category.ToString()), + Title = torrent.name, Seeders = torrent.seeders, + Peers = torrent.seeders + torrent.leechers, + MinimumRatio = 1, + MinimumSeedTime = 345600, + PublishDate = DateTimeUtil.UnixTimestampToDateTime(torrent.added), + Size = torrent.size, + Guid = new Uri(TorrentDescriptionUrl.Replace("{id}", torrent.id.ToString())), + Comments = new Uri(TorrentCommentUrl.Replace("{id}", torrent.id.ToString())), + Link = new Uri(torrent.download_link) + })); + } + } + catch (Exception ex) + { + OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); + } + + // Return found releases + return releases; + } + + /// + /// Response from Tracker's API + /// + public class XthorResponse + { + public XthorError error { get; set; } + public XthorUser user { get; set; } + public List torrents { get; set; } + } + + /// + /// State of API + /// + public class XthorError + { + public int code { get; set; } + public string descr { get; set; } + } + + /// + /// User Informations + /// + public class XthorUser + { + public int id { get; set; } + public string username { get; set; } + public long uploaded { get; set; } + public long downloaded { get; set; } + public int uclass { get; set; } // Class is a reserved keyword. + public decimal bonus_point { get; set; } + public int hits_and_run { get; set; } + public string avatar_url { get; set; } + } + + /// + /// Torrent Informations + /// + public class XthorTorrent + { + public int id { get; set; } + public int category { get; set; } + public int seeders { get; set; } + public int leechers { get; set; } + public string name { get; set; } + public int times_completed { get; set; } + public long size { get; set; } + public int added { get; set; } + public int freeleech { get; set; } + public int numfiles { get; set; } + public string release_group { get; set; } + public string download_link { get; set; } + } + + /// + /// Build query to process + /// + /// Term to search + /// Torznab Query for categories mapping + /// Search url for provider + /// URL to query for parsing and processing results + private string BuildQuery(string term, TorznabQuery query, string url) + { + var parameters = new NameValueCollection(); + var categoriesList = MapTorznabCapsToTrackers(query); + + // Passkey + parameters.Add("passkey", ConfigData.PassKey.Value); + + // If search term provided + if (!string.IsNullOrWhiteSpace(term)) + { + // Add search term + // ReSharper disable once AssignNullToNotNullAttribute + parameters.Add("search", HttpUtility.UrlEncode(term)); + } + else + { + parameters.Add("search", string.Empty); + // Showing all torrents (just for output function) + term = "all"; + } + + // Loop on Categories needed + switch (categoriesList.Count) + { + case 0: + // No category + parameters.Add("category", string.Empty); + break; + case 1: + // One category + parameters.Add("category", categoriesList[0]); + break; + default: + // Multiple Categories + string categories = null; + foreach (var category in categoriesList) + { + // Initiate our categories parameter + if (categoriesList.First() == category) + { + categories = categoriesList[0]; + } + // Adding next categories + categories += "+" + category; + } + // Add categories + if (categories != null) parameters.Add("category", categories); + break; + } + + // If Only Freeleech Enabled + if (ConfigData.Freeleech.Value) + { + parameters.Add("freeleech", "1"); + } + + // Building our query -- Cannot use GetQueryString due to UrlEncode (generating wrong category param) + url += "?" + string.Join("&", parameters.AllKeys.Select(a => a + "=" + parameters[a])); + + Output("\nBuilded query for \"" + term + "\"... " + url); + + // Return our search url + return url; + } + + /// + /// Switch Method for Querying + /// + /// URL created by Query Builder + /// Results from query + private async Task QueryExec(string request) + { + WebClientStringResult results; + + // Switch in we are in DEV mode with Hard Drive Cache or not + if (DevMode && CacheMode) + { + // Check Cache before querying and load previous results if available + results = await QueryCache(request); + } + else + { + // Querying tracker directly + results = await QueryTracker(request); + } + return results; + } + + /// + /// Get Torrents Page from Cache by Query Provided + /// + /// URL created by Query Builder + /// Results from query + private async Task QueryCache(string request) + { + WebClientStringResult results; + + // Create Directory if not exist + System.IO.Directory.CreateDirectory(Directory); + + // Clean Storage Provider Directory from outdated cached queries + CleanCacheStorage(); + + // Create fingerprint for request + string file = Directory + request.GetHashCode() + ".json"; + + // Checking modes states + if (System.IO.File.Exists(file)) + { + // File exist... loading it right now ! + Output("Loading results from hard drive cache ..." + request.GetHashCode() + ".json"); + results = JsonConvert.DeserializeObject(System.IO.File.ReadAllText(file)); + } + else + { + // No cached file found, querying tracker directly + results = await QueryTracker(request); + + // Cached file didn't exist for our query, writing it right now ! + Output("Writing results to hard drive cache ..." + request.GetHashCode() + ".json"); + System.IO.File.WriteAllText(file, JsonConvert.SerializeObject(results)); + } + return results; + } + + /// + /// Get Torrents Page from Tracker by Query Provided + /// + /// URL created by Query Builder + /// Results from query + private async Task QueryTracker(string request) + { + // Cache mode not enabled or cached file didn't exist for our query + Output("\nQuerying tracker for results...."); + + // Build WebRequest for index + var myIndexRequest = new WebRequest() + { + Type = RequestType.GET, + Url = request, + Headers = EmulatedBrowserHeaders + }; + + // Request our first page + var results = await webclient.GetString(myIndexRequest); + + // Return results from tracker + return results; + } + + /// + /// Check API's state + /// + /// State of API + private void CheckApiState(XthorError state) + { + // Switch on state + switch (state.code) + { + case 0: + // Everything OK + Output("\nAPI State : Everything OK ... -> " + state.descr); + break; + case 1: + // Passkey not found + Output("\nAPI State : Error, Passkey not found in tracker's database, aborting... -> " + state.descr); + throw new Exception("API State : Error, Passkey not found in tracker's database, aborting... -> " + state.descr); + case 2: + // No results + Output("\nAPI State : No results for query ... -> " + state.descr); + break; + case 3: + // Power Saver + Output("\nAPI State : Power Saver mode, only cached query with no parameters available ... -> " + state.descr); + break; + case 4: + // DDOS Attack, API disabled + Output("\nAPI State : Tracker is under DDOS attack, API disabled, aborting ... -> " + state.descr); + throw new Exception("\nAPI State : Tracker is under DDOS attack, API disabled, aborting ... -> " + state.descr); + default: + // Unknown state + Output("\nAPI State : Unknown state, aborting querying ... -> " + state.descr); + throw new Exception("API State : Unknown state, aborting querying ... -> " + state.descr); + } + } + + /// + /// Clean Hard Drive Cache Storage + /// + /// Force Provider Folder deletion + private void CleanCacheStorage(bool force = false) + { + // Check cleaning method + if(force) + { + // Deleting Provider Storage folder and all files recursively + Output("\nDeleting Provider Storage folder and all files recursively ..."); + + // Check if directory exist + if(System.IO.Directory.Exists(Directory)) + { + // Delete storage directory of provider + System.IO.Directory.Delete(Directory, true); + Output("-> Storage folder deleted successfully."); + } + else + { + // No directory, so nothing to do + Output("-> No Storage folder found for this provider !"); + } + } + else + { + var i = 0; + // Check if there is file older than ... and delete them + Output("\nCleaning Provider Storage folder... in progress."); + System.IO.Directory.GetFiles(Directory) + .Select(f => new System.IO.FileInfo(f)) + .Where(f => f.LastAccessTime < DateTime.Now.AddMilliseconds(-Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value))) + .ToList() + .ForEach(f => { + Output("Deleting cached file << " + f.Name + " >> ... done."); + f.Delete(); + i++; + }); + + // Inform on what was cleaned during process + if(i > 0) { + Output("-> Deleted " + i + " cached files during cleaning."); + } + else { + Output("-> Nothing deleted during cleaning."); + } + } + } + + /// + /// Output message for logging or developpment (console) + /// + /// Message to output + /// Level for Logger + private void Output(string message, string level = "debug") + { + // Check if we are in dev mode + if(DevMode) + { + // Output message to console + Console.WriteLine(message); + } + else + { + // Send message to logger with level + switch (level) + { + default: + goto case "debug"; + case "debug": + // Only if Debug Level Enabled on Jackett + if (Engine.Logger.IsDebugEnabled) + { + logger.Debug(message); + } + break; + case "info": + logger.Info(message); + break; + case "error": + logger.Error(message); + break; + } + } + } + + /// + /// Validate Config entered by user on Jackett + /// + private void ValidateConfig() + { + Output("\nValidating Settings ... \n"); + + // Check Passkey Setting + if (string.IsNullOrEmpty(ConfigData.PassKey.Value)) + { + throw new ExceptionWithConfigData("You must provide your passkey for this tracker to be allowed to use API !", ConfigData); + } + else + { + Output("Validated Setting -- PassKey (auth) => " + ConfigData.PassKey.Value); + } + + // Check Dev Cache Settings + if (ConfigData.HardDriveCache.Value) + { + Output("\nValidated Setting -- DEV Hard Drive Cache enabled"); + + // Check if Dev Mode enabled ! + if (!ConfigData.DevMode.Value) + { + throw new ExceptionWithConfigData("Hard Drive is enabled but not in DEV MODE, Please enable DEV MODE !", ConfigData); + } + + // Check Cache Keep Time Setting + if (!string.IsNullOrEmpty(ConfigData.HardDriveCacheKeepTime.Value)) + { + try + { + Output("Validated Setting -- Cache Keep Time (ms) => " + Convert.ToInt32(ConfigData.HardDriveCacheKeepTime.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric hard drive keep time in ms !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Hard Drive Cache enabled, Please enter a maximum keep time for cache !", ConfigData); + } + } + else + { + // Delete cache if previously existed + CleanCacheStorage(true); + } + } + } +} \ No newline at end of file diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index 25c2c5a32..a50663c57 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -186,6 +186,7 @@ + @@ -221,6 +222,7 @@ + @@ -442,6 +444,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs new file mode 100644 index 000000000..b0f8c9dc3 --- /dev/null +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs @@ -0,0 +1,27 @@ +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataXthor : ConfigurationData + { + public DisplayItem CredentialsWarning { get; private set; } + public StringItem PassKey { get; set; } + public DisplayItem PagesWarning { get; private set; } + public BoolItem Freeleech { get; private set; } + public DisplayItem DevWarning { get; private set; } + public BoolItem DevMode { get; private set; } + public BoolItem HardDriveCache { get; private set; } + public StringItem HardDriveCacheKeepTime { get; private set; } + + public ConfigurationDataXthor() + : base() + { + CredentialsWarning = new DisplayItem("Credentials Configuration (Private Tracker),

  • PassKey is your private key on your account
") { Name = "Credentials" }; + PassKey = new StringItem { Name = "PassKey", Value = "" }; + PagesWarning = new DisplayItem("Preferences Configuration (Tweak your search settings),

  • Freeleech Only let you search only for torrents which are marked Freeleech.
") { Name = "Preferences" }; + Freeleech = new BoolItem() { Name = "Freeleech Only (Optional)", Value = false }; + DevWarning = new DisplayItem("Development Facility (For Developers ONLY),

  • By enabling development mode, Jackett will bypass his cache and will output debug messages to console instead of his log file.
  • By enabling Hard Drive Cache, This provider will save each query answers from tracker in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, Jackett will search for a cached query answer on hard drive before executing query on tracker side ! DEV MODE must be enabled to use it !
") { Name = "Development" }; + DevMode = new BoolItem { Name = "Enable DEV MODE (Developers ONLY)", Value = false }; + HardDriveCache = new BoolItem { Name = "Enable HARD DRIVE CACHE (Developers ONLY)", Value = false }; + HardDriveCacheKeepTime = new StringItem { Name = "Keep Cached files for (ms)", Value = "300000" }; + } + } +}