From 751f6bd5f210209e2d3b2bba3e67e767e38de04d Mon Sep 17 00:00:00 2001 From: flightlevel <flightlevel@users.noreply.github.com> Date: Sat, 15 Apr 2017 18:45:10 +1000 Subject: [PATCH] Normalise Line endings (#1284) * Add .gitattributes * Normalise line endings --- .gitattributes | 15 + src/Jackett.Console/Program.cs | 472 +-- src/Jackett.Test/TestWebClient.cs | 8 +- src/Jackett.Updater/Program.cs | 518 +-- src/Jackett.Updater/UpdaterConsoleOptions.cs | 4 +- src/Jackett/Controllers/AdminController.cs | 1190 +++--- src/Jackett/Controllers/PotatoController.cs | 346 +- src/Jackett/Controllers/TorznabController.cs | 44 +- src/Jackett/CurlHelper.cs | 82 +- src/Jackett/Definitions/2fast4you.yml | 276 +- src/Jackett/Definitions/3dtorrents.yml | 202 +- src/Jackett/Definitions/aox.yml | 246 +- src/Jackett/Definitions/apollo.yml | 188 +- src/Jackett/Definitions/arabafenice.yml | 328 +- src/Jackett/Definitions/audiobooktorrents.yml | 270 +- src/Jackett/Definitions/bigtorrent.yml | 192 +- src/Jackett/Definitions/bitspyder.yml | 266 +- src/Jackett/Definitions/blubits.yml | 294 +- src/Jackett/Definitions/bluebird.yml | 178 +- src/Jackett/Definitions/chdbits.yml | 208 +- src/Jackett/Definitions/cinemageddon.yml | 196 +- src/Jackett/Definitions/cinematik.yml | 186 +- src/Jackett/Definitions/classix.yml | 126 +- src/Jackett/Definitions/czteam.yml | 186 +- src/Jackett/Definitions/datascene.yml | 236 +- src/Jackett/Definitions/dragonworld.yml | 308 +- .../Definitions/dragonworldreloaded.yml | 476 +-- src/Jackett/Definitions/dreamteam.yml | 640 ++-- src/Jackett/Definitions/eotforum.yml | 360 +- src/Jackett/Definitions/estone.yml | 238 +- src/Jackett/Definitions/ethor.yml | 238 +- src/Jackett/Definitions/freedomhd.yml | 258 +- src/Jackett/Definitions/gfxpeers.yml | 160 +- src/Jackett/Definitions/gods.yml | 322 +- src/Jackett/Definitions/gormogon.yml | 384 +- src/Jackett/Definitions/hdbits.yml | 164 +- src/Jackett/Definitions/hdbitscom.yml | 194 +- src/Jackett/Definitions/hdchina.yml | 240 +- src/Jackett/Definitions/hdhome.yml | 282 +- src/Jackett/Definitions/hdsky.yml | 236 +- src/Jackett/Definitions/hyperay.yml | 214 +- src/Jackett/Definitions/icetorrent.yml | 302 +- src/Jackett/Definitions/iloveclassics.yml | 210 +- src/Jackett/Definitions/infinityt.yml | 210 +- src/Jackett/Definitions/inperil.yml | 208 +- src/Jackett/Definitions/insanetracker.yml | 280 +- src/Jackett/Definitions/jpopsuki.yml | 208 +- src/Jackett/Definitions/karagarga.yml | 166 +- src/Jackett/Definitions/leparadisdunet.yml | 326 +- src/Jackett/Definitions/losslessclub.yml | 164 +- src/Jackett/Definitions/mteamtp.yml | 262 +- src/Jackett/Definitions/myspleen.yml | 196 +- src/Jackett/Definitions/nachtwerk.yml | 304 +- src/Jackett/Definitions/nethd.yml | 196 +- src/Jackett/Definitions/newretro.yml | 240 +- src/Jackett/Definitions/ourbits.yml | 218 +- src/Jackett/Definitions/passionetorrent.yml | 314 +- src/Jackett/Definitions/polishsource.yml | 230 +- src/Jackett/Definitions/qctorrent.yml | 212 +- src/Jackett/Definitions/redacted-scrape.yml | 204 +- src/Jackett/Definitions/rockhardlossless.yml | 160 +- src/Jackett/Definitions/rodvd.yml | 250 +- src/Jackett/Definitions/sdbits.yml | 186 +- src/Jackett/Definitions/secretcinema.yml | 258 +- src/Jackett/Definitions/shareisland.yml | 340 +- src/Jackett/Definitions/sharespacedb.yml | 310 +- src/Jackett/Definitions/shellife.yml | 160 +- src/Jackett/Definitions/skytorrents.yml | 114 +- src/Jackett/Definitions/tasmanit.yml | 216 +- src/Jackett/Definitions/tenyardtracker.yml | 146 +- src/Jackett/Definitions/theempire.yml | 240 +- src/Jackett/Definitions/thehorrorcharnel.yml | 208 +- src/Jackett/Definitions/theshinning.yml | 314 +- src/Jackett/Definitions/tntvillage.yml | 138 +- src/Jackett/Definitions/torrent9.yml | 150 +- src/Jackett/Definitions/torrentbd.yml | 302 +- src/Jackett/Definitions/torrentccf.yml | 236 +- src/Jackett/Definitions/torrenthr.yml | 256 +- src/Jackett/Definitions/torrentsectorcrew.yml | 352 +- src/Jackett/Definitions/torrentsmd.yml | 188 +- src/Jackett/Definitions/torviet.yml | 260 +- src/Jackett/Definitions/totheglory.yml | 290 +- src/Jackett/Definitions/uhdbits.yml | 268 +- src/Jackett/Definitions/ultimategamerclub.yml | 248 +- src/Jackett/Definitions/utorrents.yml | 256 +- src/Jackett/Definitions/waffles.yml | 328 +- src/Jackett/Definitions/worldofp2p.yml | 272 +- src/Jackett/Definitions/xtremezone.yml | 234 +- src/Jackett/Definitions/ztracker.yml | 256 +- src/Jackett/Engine.cs | 382 +- src/Jackett/Indexers/7tor.cs | 3278 ++++++++--------- src/Jackett/Indexers/Abnormal.cs | 1764 ++++----- .../Indexers/Abstract/AvistazTracker.cs | 24 +- .../Indexers/Abstract/GazelleTracker.cs | 412 +-- src/Jackett/Indexers/AlphaRatio.cs | 438 +-- src/Jackett/Indexers/Andraste.cs | 208 +- src/Jackett/Indexers/AnimeBytes.cs | 948 ++--- src/Jackett/Indexers/AnimeTorrents.cs | 50 +- src/Jackett/Indexers/BB.cs | 26 +- src/Jackett/Indexers/BJShare.cs | 390 +- src/Jackett/Indexers/BaseIndexer.cs | 1290 +++---- src/Jackett/Indexers/BestFriends.cs | 220 +- src/Jackett/Indexers/BeyondHD.cs | 6 +- src/Jackett/Indexers/BitCityReloaded.cs | 138 +- src/Jackett/Indexers/BitMeTV.cs | 2 +- src/Jackett/Indexers/BitSoup.cs | 462 +-- src/Jackett/Indexers/BroadcastTheNet.cs | 354 +- src/Jackett/Indexers/CardigannIndexer.cs | 2854 +++++++------- src/Jackett/Indexers/DanishBits.cs | 18 +- src/Jackett/Indexers/Demonoid.cs | 344 +- src/Jackett/Indexers/DigitalHive.cs | 466 +-- src/Jackett/Indexers/EliteTracker.cs | 484 +-- src/Jackett/Indexers/FileList.cs | 392 +- src/Jackett/Indexers/Freshon.cs | 30 +- src/Jackett/Indexers/FunFile.cs | 316 +- src/Jackett/Indexers/Fuzer.cs | 4 +- src/Jackett/Indexers/GFTracker.cs | 80 +- src/Jackett/Indexers/GhostCity.cs | 368 +- src/Jackett/Indexers/HD4Free.cs | 732 ++-- src/Jackett/Indexers/HDOnly.cs | 62 +- src/Jackett/Indexers/HDSpace.cs | 40 +- src/Jackett/Indexers/HDTorrents.cs | 76 +- src/Jackett/Indexers/Hardbay.cs | 290 +- src/Jackett/Indexers/Hebits.cs | 14 +- src/Jackett/Indexers/Hounddawgs.cs | 158 +- src/Jackett/Indexers/HouseOfTorrents.cs | 460 +-- src/Jackett/Indexers/IIndexer.cs | 6 +- src/Jackett/Indexers/IPTorrents.cs | 180 +- src/Jackett/Indexers/ImmortalSeed.cs | 30 +- src/Jackett/Indexers/MoreThanTV.cs | 18 +- src/Jackett/Indexers/MyAnonamouse.cs | 18 +- src/Jackett/Indexers/NCore.cs | 396 +- src/Jackett/Indexers/NewRealWorld.cs | 232 +- src/Jackett/Indexers/Norbits.cs | 1740 ++++----- src/Jackett/Indexers/PassThePopcorn.cs | 88 +- src/Jackett/Indexers/PiXELHD.cs | 340 +- src/Jackett/Indexers/PirateTheNet.cs | 452 +-- src/Jackett/Indexers/Pretome.cs | 16 +- src/Jackett/Indexers/PrivateHD.cs | 68 +- src/Jackett/Indexers/Psytorrents.cs | 8 +- src/Jackett/Indexers/Rarbg.cs | 472 +-- src/Jackett/Indexers/Redacted.cs | 16 +- src/Jackett/Indexers/SceneAccess.cs | 338 +- src/Jackett/Indexers/SceneFZ.cs | 100 +- src/Jackett/Indexers/SceneTime.cs | 16 +- src/Jackett/Indexers/Shazbat.cs | 530 +-- src/Jackett/Indexers/ShowRSS.cs | 228 +- src/Jackett/Indexers/SpeedCD.cs | 4 +- src/Jackett/Indexers/Superbits.cs | 392 +- src/Jackett/Indexers/T411.cs | 556 +-- src/Jackett/Indexers/TVChaosUK.cs | 36 +- src/Jackett/Indexers/TVVault.cs | 130 +- src/Jackett/Indexers/TehConnection.cs | 38 +- src/Jackett/Indexers/TorrentBytes.cs | 20 +- src/Jackett/Indexers/TorrentDay.cs | 444 +-- src/Jackett/Indexers/TorrentHeaven.cs | 286 +- src/Jackett/Indexers/TorrentLeech.cs | 16 +- src/Jackett/Indexers/TorrentNetwork.cs | 208 +- src/Jackett/Indexers/TorrentSyndikat.cs | 430 +-- src/Jackett/Indexers/Torrentech.cs | 260 +- src/Jackett/Indexers/TransmitheNet.cs | 18 +- src/Jackett/Indexers/XSpeeds.cs | 646 ++-- src/Jackett/Indexers/Xthor.cs | 1214 +++--- src/Jackett/Indexers/cgpeers.cs | 18 +- src/Jackett/Indexers/myAmity.cs | 172 +- src/Jackett/Indexers/notwhatcd.cs | 16 +- src/Jackett/Indexers/rutracker.cs | 2962 +++++++-------- src/Jackett/Indexers/x264.cs | 398 +- src/Jackett/JackettModule.cs | 278 +- src/Jackett/Models/Config/ServerConfig.cs | 94 +- src/Jackett/Models/GitHub/Asset.cs | 28 +- src/Jackett/Models/GitHub/Release.cs | 32 +- .../Bespoke/ConfigurationDataAbnormal.cs | 114 +- .../Bespoke/ConfigurationDataAnimeBytes.cs | 48 +- .../Bespoke/ConfigurationDataFileList.cs | 44 +- .../Bespoke/ConfigurationDataNCore.cs | 122 +- .../Bespoke/ConfigurationDataPhxBit.cs | 110 +- .../Bespoke/ConfigurationDataRuTor.cs | 54 +- .../Bespoke/ConfigurationDataStrike.cs | 36 +- .../Bespoke/ConfigurationDataXthor.cs | 54 +- .../Models/IndexerConfig/ConfigurationData.cs | 40 +- .../IndexerConfig/ConfigurationDataAPIKey.cs | 36 +- ...gurationDataBasicLoginWithRSSAndDisplay.cs | 50 +- .../ConfigurationDataLoginLink.cs | 46 +- src/Jackett/Models/ReleaseInfo.cs | 8 +- src/Jackett/Models/TorznabCatType.cs | 10 +- src/Jackett/Models/TorznabCategory.cs | 44 +- src/Jackett/Models/TorznabQuery.cs | 56 +- src/Jackett/Properties/AssemblyInfo.cs | 72 +- src/Jackett/Services/ConfigurationService.cs | 4 +- src/Jackett/Services/IndexerManagerService.cs | 222 +- src/Jackett/Services/ProtectionService.cs | 6 +- src/Jackett/Services/ServerService.cs | 320 +- src/Jackett/Services/ServiceConfigService.cs | 8 +- src/Jackett/Services/UpdateService.cs | 618 ++-- src/Jackett/Startup.cs | 378 +- src/Jackett/Utils/BrowserUtil.cs | 62 +- src/Jackett/Utils/Clients/HttpWebClient.cs | 494 +-- src/Jackett/Utils/Clients/HttpWebClient2.cs | 482 +-- src/Jackett/Utils/Clients/IWebClient.cs | 244 +- .../Utils/Clients/UnixLibCurlWebClient.cs | 130 +- .../Utils/Clients/UnixSafeCurlWebClient.cs | 62 +- src/Jackett/Utils/Clients/WebRequest.cs | 206 +- src/Jackett/Utils/DateTimeUtil.cs | 430 +-- src/Jackett/Utils/JsonContent.cs | 24 +- src/Jackett/Utils/ParseUtil.cs | 238 +- src/Jackett/Utils/StringCipher.cs | 212 +- src/Jackett/Utils/StringUtil.cs | 44 +- src/Jackett/Utils/TorznabCapsUtil.cs | 188 +- .../Utils/WebApiRootRedirectMiddleware.cs | 82 +- src/Jackett/WebAPIExceptionHandler.cs | 96 +- 211 files changed, 29717 insertions(+), 29702 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..01b559c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. + +# Declare files that will always have LF line endings on checkout. +*.yml text eol=lf + +# Declare files that will always have CRLF line endings on checkout. +*.cs text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary diff --git a/src/Jackett.Console/Program.cs b/src/Jackett.Console/Program.cs index a11037ac..59976e8c 100644 --- a/src/Jackett.Console/Program.cs +++ b/src/Jackett.Console/Program.cs @@ -1,236 +1,236 @@ -using CommandLine; -using CommandLine.Text; -using Jackett; -using Jackett.Console; -using Jackett.Indexers; -using Jackett.Utils; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; - -namespace JackettConsole -{ - public class Program - { - static void Main(string[] args) - { - try - { - var options = new ConsoleOptions(); - if (!Parser.Default.ParseArguments(args, options) || options.ShowHelp == true) - { - if (options.LastParserState != null && options.LastParserState.Errors.Count > 0) - { - var help = new HelpText(); - var errors = help.RenderParsingErrorsText(options, 2); // indent with two spaces - Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion()); - Console.WriteLine("Switch error: " + errors); - Console.WriteLine("See --help for further details on switches."); - Environment.ExitCode = 1; - return; - } - else - { - - var text = HelpText.AutoBuild(options, (HelpText current) => HelpText.DefaultParsingErrorsHandler(options, current)); - text.Copyright = " "; - text.Heading = "Jackett v" + Engine.ConfigService.GetVersion() + " options:"; - Console.WriteLine(text); - Environment.ExitCode = 1; - return; - } - } - else - { - - if (options.ListenPublic && options.ListenPrivate) - { - Console.WriteLine("You can only use listen private OR listen publicly."); - Environment.ExitCode = 1; - return; - } - /* ====== Options ===== */ - - // SSL Fix - Startup.DoSSLFix = options.SSLFix; - - // Use curl - if (options.Client != null) - Startup.ClientOverride = options.Client.ToLowerInvariant(); - - // Use Proxy - if (options.ProxyConnection != null) - { - Startup.ProxyConnection = options.ProxyConnection.ToLowerInvariant(); - Engine.Logger.Info("Proxy enabled. " + Startup.ProxyConnection); - } - // Logging - if (options.Logging) - Startup.LogRequests = true; - - // Tracing - if (options.Tracing) - Startup.TracingEnabled = true; - - // Log after the fact as using the logger will cause the options above to be used - - if (options.Logging) - Engine.Logger.Info("Logging enabled."); - - if (options.Tracing) - Engine.Logger.Info("Tracing enabled."); - - if (options.SSLFix == true) - Engine.Logger.Info("SSL ECC workaround enabled."); - else if (options.SSLFix == false) - Engine.Logger.Info("SSL ECC workaround has been disabled."); - - // Ignore SSL errors on Curl - Startup.IgnoreSslErrors = options.IgnoreSslErrors; - if (options.IgnoreSslErrors == true) - { - Engine.Logger.Info("Jackett will ignore SSL certificate errors."); - } - - // Choose Data Folder - if (!string.IsNullOrWhiteSpace(options.DataFolder)) - { - Startup.CustomDataFolder = options.DataFolder.Replace("\"", string.Empty).Replace("'", string.Empty).Replace(@"\\", @"\"); - Engine.Logger.Info("Jackett Data will be stored in: " + Startup.CustomDataFolder); - } - - /* ====== Actions ===== */ - - // Install service - if (options.Install) - { - Engine.ServiceConfig.Install(); - return; - } - - // Uninstall service - if (options.Uninstall) - { - Engine.Server.ReserveUrls(doInstall: false); - Engine.ServiceConfig.Uninstall(); - return; - } - - // Reserve urls - if (options.ReserveUrls) - { - Engine.Server.ReserveUrls(doInstall: true); - return; - } - - // Start Service - if (options.StartService) - { - if (!Engine.ServiceConfig.ServiceRunning()) - { - Engine.ServiceConfig.Start(); - } - return; - } - - // Stop Service - if (options.StopService) - { - if (Engine.ServiceConfig.ServiceRunning()) - { - Engine.ServiceConfig.Stop(); - } - return; - } - - // Migrate settings - if (options.MigrateSettings) - { - Engine.ConfigService.PerformMigration(); - return; - } - - - // Show Version - if (options.ShowVersion) - { - Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion()); - return; - } - - /* ====== Overrides ===== */ - - // Override listen public - if (options.ListenPublic || options.ListenPrivate) - { - if (Engine.Server.Config.AllowExternal != options.ListenPublic) - { - Engine.Logger.Info("Overriding external access to " + options.ListenPublic); - Engine.Server.Config.AllowExternal = options.ListenPublic; - if (System.Environment.OSVersion.Platform != PlatformID.Unix) - { - if (ServerUtil.IsUserAdministrator()) - { - Engine.Server.ReserveUrls(doInstall: true); - } - else - { - Engine.Logger.Error("Unable to switch to public listening without admin rights."); - Environment.ExitCode = 1; - return; - } - } - - Engine.Server.SaveConfig(); - } - } - - // Override port - if (options.Port != 0) - { - if (Engine.Server.Config.Port != options.Port) - { - Engine.Logger.Info("Overriding port to " + options.Port); - Engine.Server.Config.Port = options.Port; - if (System.Environment.OSVersion.Platform != PlatformID.Unix) - { - if (ServerUtil.IsUserAdministrator()) - { - Engine.Server.ReserveUrls(doInstall: true); - } - else - { - Engine.Logger.Error("Unable to switch ports when not running as administrator"); - Environment.ExitCode = 1; - return; - } - } - - Engine.Server.SaveConfig(); - } - } - - Startup.NoRestart = options.NoRestart; - } - - Engine.Server.Initalize(); - Engine.Server.Start(); - Engine.RunTime.Spin(); - Engine.Logger.Info("Server thread exit"); - } - catch (Exception e) - { - Engine.Logger.Error(e, "Top level exception"); - } - } - } -} - +using CommandLine; +using CommandLine.Text; +using Jackett; +using Jackett.Console; +using Jackett.Indexers; +using Jackett.Utils; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace JackettConsole +{ + public class Program + { + static void Main(string[] args) + { + try + { + var options = new ConsoleOptions(); + if (!Parser.Default.ParseArguments(args, options) || options.ShowHelp == true) + { + if (options.LastParserState != null && options.LastParserState.Errors.Count > 0) + { + var help = new HelpText(); + var errors = help.RenderParsingErrorsText(options, 2); // indent with two spaces + Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion()); + Console.WriteLine("Switch error: " + errors); + Console.WriteLine("See --help for further details on switches."); + Environment.ExitCode = 1; + return; + } + else + { + + var text = HelpText.AutoBuild(options, (HelpText current) => HelpText.DefaultParsingErrorsHandler(options, current)); + text.Copyright = " "; + text.Heading = "Jackett v" + Engine.ConfigService.GetVersion() + " options:"; + Console.WriteLine(text); + Environment.ExitCode = 1; + return; + } + } + else + { + + if (options.ListenPublic && options.ListenPrivate) + { + Console.WriteLine("You can only use listen private OR listen publicly."); + Environment.ExitCode = 1; + return; + } + /* ====== Options ===== */ + + // SSL Fix + Startup.DoSSLFix = options.SSLFix; + + // Use curl + if (options.Client != null) + Startup.ClientOverride = options.Client.ToLowerInvariant(); + + // Use Proxy + if (options.ProxyConnection != null) + { + Startup.ProxyConnection = options.ProxyConnection.ToLowerInvariant(); + Engine.Logger.Info("Proxy enabled. " + Startup.ProxyConnection); + } + // Logging + if (options.Logging) + Startup.LogRequests = true; + + // Tracing + if (options.Tracing) + Startup.TracingEnabled = true; + + // Log after the fact as using the logger will cause the options above to be used + + if (options.Logging) + Engine.Logger.Info("Logging enabled."); + + if (options.Tracing) + Engine.Logger.Info("Tracing enabled."); + + if (options.SSLFix == true) + Engine.Logger.Info("SSL ECC workaround enabled."); + else if (options.SSLFix == false) + Engine.Logger.Info("SSL ECC workaround has been disabled."); + + // Ignore SSL errors on Curl + Startup.IgnoreSslErrors = options.IgnoreSslErrors; + if (options.IgnoreSslErrors == true) + { + Engine.Logger.Info("Jackett will ignore SSL certificate errors."); + } + + // Choose Data Folder + if (!string.IsNullOrWhiteSpace(options.DataFolder)) + { + Startup.CustomDataFolder = options.DataFolder.Replace("\"", string.Empty).Replace("'", string.Empty).Replace(@"\\", @"\"); + Engine.Logger.Info("Jackett Data will be stored in: " + Startup.CustomDataFolder); + } + + /* ====== Actions ===== */ + + // Install service + if (options.Install) + { + Engine.ServiceConfig.Install(); + return; + } + + // Uninstall service + if (options.Uninstall) + { + Engine.Server.ReserveUrls(doInstall: false); + Engine.ServiceConfig.Uninstall(); + return; + } + + // Reserve urls + if (options.ReserveUrls) + { + Engine.Server.ReserveUrls(doInstall: true); + return; + } + + // Start Service + if (options.StartService) + { + if (!Engine.ServiceConfig.ServiceRunning()) + { + Engine.ServiceConfig.Start(); + } + return; + } + + // Stop Service + if (options.StopService) + { + if (Engine.ServiceConfig.ServiceRunning()) + { + Engine.ServiceConfig.Stop(); + } + return; + } + + // Migrate settings + if (options.MigrateSettings) + { + Engine.ConfigService.PerformMigration(); + return; + } + + + // Show Version + if (options.ShowVersion) + { + Console.WriteLine("Jackett v" + Engine.ConfigService.GetVersion()); + return; + } + + /* ====== Overrides ===== */ + + // Override listen public + if (options.ListenPublic || options.ListenPrivate) + { + if (Engine.Server.Config.AllowExternal != options.ListenPublic) + { + Engine.Logger.Info("Overriding external access to " + options.ListenPublic); + Engine.Server.Config.AllowExternal = options.ListenPublic; + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + { + if (ServerUtil.IsUserAdministrator()) + { + Engine.Server.ReserveUrls(doInstall: true); + } + else + { + Engine.Logger.Error("Unable to switch to public listening without admin rights."); + Environment.ExitCode = 1; + return; + } + } + + Engine.Server.SaveConfig(); + } + } + + // Override port + if (options.Port != 0) + { + if (Engine.Server.Config.Port != options.Port) + { + Engine.Logger.Info("Overriding port to " + options.Port); + Engine.Server.Config.Port = options.Port; + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + { + if (ServerUtil.IsUserAdministrator()) + { + Engine.Server.ReserveUrls(doInstall: true); + } + else + { + Engine.Logger.Error("Unable to switch ports when not running as administrator"); + Environment.ExitCode = 1; + return; + } + } + + Engine.Server.SaveConfig(); + } + } + + Startup.NoRestart = options.NoRestart; + } + + Engine.Server.Initalize(); + Engine.Server.Start(); + Engine.RunTime.Spin(); + Engine.Logger.Info("Server thread exit"); + } + catch (Exception e) + { + Engine.Logger.Error(e, "Top level exception"); + } + } + } +} + diff --git a/src/Jackett.Test/TestWebClient.cs b/src/Jackett.Test/TestWebClient.cs index 33e1bee0..d299175a 100644 --- a/src/Jackett.Test/TestWebClient.cs +++ b/src/Jackett.Test/TestWebClient.cs @@ -1,6 +1,6 @@ -using Jackett.Services; +using Jackett.Services; using Jackett.Utils.Clients; -using NLog; +using NLog; using System; using System.Collections.Generic; using System.Linq; @@ -14,10 +14,10 @@ namespace JackettTest private Dictionary<WebRequest, Func<WebRequest, WebClientByteResult>> byteCallbacks = new Dictionary<WebRequest, Func<WebRequest, WebClientByteResult>>(); private Dictionary<WebRequest, Func<WebRequest, WebClientStringResult>> stringCallbacks = new Dictionary<WebRequest, Func<WebRequest, WebClientStringResult>>(); - public TestWebClient(IProcessService p, Logger l, IConfigurationService c) + public TestWebClient(IProcessService p, Logger l, IConfigurationService c) : base(p: p, l: l, - c: c) + c: c) { } diff --git a/src/Jackett.Updater/Program.cs b/src/Jackett.Updater/Program.cs index 0959a149..5ad1d5ea 100644 --- a/src/Jackett.Updater/Program.cs +++ b/src/Jackett.Updater/Program.cs @@ -1,259 +1,259 @@ -using CommandLine; -using Jackett.Services; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -/* -// no supported by appveyor, disabeling for now -#if __MonoCS__ -using Mono.Unix.Native; -#endif -*/ - -namespace Jackett.Updater -{ - class Program - { - static void Main(string[] args) - { - new Program().Run(args); - } - - private void Run(string[] args) - { - Engine.SetupLogging(null, "updater.txt"); - Engine.Logger.Info("Jackett Updater v" + GetCurrentVersion()); - Engine.Logger.Info("Options \"" + string.Join("\" \"", args) + "\""); - try { - var options = new UpdaterConsoleOptions(); - if (Parser.Default.ParseArguments(args, options)) - { - ProcessUpdate(options); - } - else - { - Engine.Logger.Error("Failed to process update arguments!"); - Console.ReadKey(); - } - } - catch (Exception e) - { - Engine.Logger.Error(e, "Exception applying update!"); - } - } - - private string GetCurrentVersion() - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); - return fvi.FileVersion; - } - - private void KillPids(int[] pids) - { - foreach (var pid in pids) - { - try - { - var proc = Process.GetProcessById(pid); - Engine.Logger.Info("Killing process " + proc.Id); - proc.Kill(); - var exited = proc.WaitForExit(5000); - if (!exited) - Engine.Logger.Info("Process " + pid.ToString() + " didn't exit within 5 seconds"); -/* -// no supported by appveyor, disabeling for now -#if __MonoCS__ - Engine.Logger.Info("Sending SIGKILL to process " + pid.ToString()); - Syscall.kill(proc.Id, Signum.SIGKILL); -#endif -*/ - } - catch (ArgumentException e) - { - Engine.Logger.Info("Process " + pid.ToString() + " is already dead"); - } - catch (Exception e) - { - Engine.Logger.Info("Error killing process " + pid.ToString()); - Engine.Logger.Info(e); - } - } - } - - private void ProcessUpdate(UpdaterConsoleOptions options) - { - var updateLocation = GetUpdateLocation(); - if(!(updateLocation.EndsWith("\\") || updateLocation.EndsWith("/"))) - { - updateLocation += Path.DirectorySeparatorChar; - } - - var pids = new int[] { }; - if (options.KillPids != null) - { - var pidsStr = options.KillPids.Split(',').Where(pid => !string.IsNullOrWhiteSpace(pid)).ToArray(); - pids = Array.ConvertAll(pidsStr, pid => int.Parse(pid)); - } - - var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix; - var trayRunning = false; - var trayProcesses = Process.GetProcessesByName("JackettTray"); - if (isWindows) - { - if (trayProcesses.Count() > 0) - { - foreach (var proc in trayProcesses) - { - try - { - Engine.Logger.Info("Killing tray process " + proc.Id); - proc.Kill(); - trayRunning = true; - } - catch { } - } - } - - // on unix we don't have to wait (we can overwrite files which are in use) - // On unix we kill the PIDs after the update so e.g. systemd can automatically restart the process - KillPids(pids); - } - Engine.Logger.Info("Finding files in: " + updateLocation); - var files = Directory.GetFiles(updateLocation, "*.*", SearchOption.AllDirectories); - foreach(var file in files) - { - var fileName = Path.GetFileName(file).ToLowerInvariant(); - - if (fileName.EndsWith(".zip") || - fileName.EndsWith(".tar") || - fileName.EndsWith(".gz")) - { - continue; - } - try { - Engine.Logger.Info("Copying " + fileName); - var dest = Path.Combine(options.Path, file.Substring(updateLocation.Length)); - var destDir = Path.GetDirectoryName(dest); - if (!Directory.Exists(destDir)) - { - Engine.Logger.Info("Creating directory " + destDir); - Directory.CreateDirectory(destDir); - } - File.Copy(file, dest, true); - } - catch(Exception e) - { - Engine.Logger.Error(e); - } - } - - // delete old dirs - string[] oldDirs = new string[] { "Content/logos" }; - - foreach (var oldDir in oldDirs) - { - try - { - var deleteDir = Path.Combine(options.Path, oldDir); - if (Directory.Exists(deleteDir)) - { - Engine.Logger.Info("Deleting directory " + deleteDir); - Directory.Delete(deleteDir, true); - } - } - catch (Exception e) - { - Engine.Logger.Error(e); - } - } - - - // delete old files - string[] oldFiles = new string[] { - "Content/css/jquery.dataTables.css", - "Content/css/jquery.dataTables_themeroller.css", - "Definitions/tspate.yml", - "Definitions/freakstrackingsystem.yml", - "Definitions/rarbg.yml", - "Definitions/t411.yml", - "Definitions/hdbc.yml", // renamed to hdbitscom - }; - - foreach (var oldFIle in oldFiles) - { - try - { - var deleteFile = Path.Combine(options.Path, oldFIle); - if (File.Exists(deleteFile)) - { - Engine.Logger.Info("Deleting file " + deleteFile); - File.Delete(deleteFile); - } - } - catch (Exception e) - { - Engine.Logger.Error(e); - } - } - - // kill pids after the update on UNIX - if (!isWindows) - KillPids(pids); - - if (options.NoRestart == false) - { - if (trayRunning) - { - var startInfo = new ProcessStartInfo() - { - Arguments = options.Args, - FileName = Path.Combine(options.Path, "JackettTray.exe"), - UseShellExecute = true - }; - - Process.Start(startInfo); - } - - if(string.Equals(options.Type, "JackettService.exe", StringComparison.InvariantCultureIgnoreCase)) - { - var serviceHelper = new ServiceConfigService(null, null); - if (serviceHelper.ServiceExists()) - { - serviceHelper.Start(); - } - } else - { - var startInfo = new ProcessStartInfo() - { - Arguments = options.Args, - FileName = Path.Combine(options.Path, "JackettConsole.exe"), - UseShellExecute = true - }; - - if (!isWindows) - { - startInfo.Arguments = startInfo.FileName + " " + startInfo.Arguments; - startInfo.FileName = "mono"; - } - - Engine.Logger.Info("Starting Jackett: " + startInfo.FileName + " " + startInfo.Arguments); - Process.Start(startInfo); - } - } - } - - private string GetUpdateLocation() - { - var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); - return new FileInfo(HttpUtility.UrlDecode(location.AbsolutePath)).DirectoryName; - } - } -} +using CommandLine; +using Jackett.Services; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +/* +// no supported by appveyor, disabeling for now +#if __MonoCS__ +using Mono.Unix.Native; +#endif +*/ + +namespace Jackett.Updater +{ + class Program + { + static void Main(string[] args) + { + new Program().Run(args); + } + + private void Run(string[] args) + { + Engine.SetupLogging(null, "updater.txt"); + Engine.Logger.Info("Jackett Updater v" + GetCurrentVersion()); + Engine.Logger.Info("Options \"" + string.Join("\" \"", args) + "\""); + try { + var options = new UpdaterConsoleOptions(); + if (Parser.Default.ParseArguments(args, options)) + { + ProcessUpdate(options); + } + else + { + Engine.Logger.Error("Failed to process update arguments!"); + Console.ReadKey(); + } + } + catch (Exception e) + { + Engine.Logger.Error(e, "Exception applying update!"); + } + } + + private string GetCurrentVersion() + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); + return fvi.FileVersion; + } + + private void KillPids(int[] pids) + { + foreach (var pid in pids) + { + try + { + var proc = Process.GetProcessById(pid); + Engine.Logger.Info("Killing process " + proc.Id); + proc.Kill(); + var exited = proc.WaitForExit(5000); + if (!exited) + Engine.Logger.Info("Process " + pid.ToString() + " didn't exit within 5 seconds"); +/* +// no supported by appveyor, disabeling for now +#if __MonoCS__ + Engine.Logger.Info("Sending SIGKILL to process " + pid.ToString()); + Syscall.kill(proc.Id, Signum.SIGKILL); +#endif +*/ + } + catch (ArgumentException e) + { + Engine.Logger.Info("Process " + pid.ToString() + " is already dead"); + } + catch (Exception e) + { + Engine.Logger.Info("Error killing process " + pid.ToString()); + Engine.Logger.Info(e); + } + } + } + + private void ProcessUpdate(UpdaterConsoleOptions options) + { + var updateLocation = GetUpdateLocation(); + if(!(updateLocation.EndsWith("\\") || updateLocation.EndsWith("/"))) + { + updateLocation += Path.DirectorySeparatorChar; + } + + var pids = new int[] { }; + if (options.KillPids != null) + { + var pidsStr = options.KillPids.Split(',').Where(pid => !string.IsNullOrWhiteSpace(pid)).ToArray(); + pids = Array.ConvertAll(pidsStr, pid => int.Parse(pid)); + } + + var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix; + var trayRunning = false; + var trayProcesses = Process.GetProcessesByName("JackettTray"); + if (isWindows) + { + if (trayProcesses.Count() > 0) + { + foreach (var proc in trayProcesses) + { + try + { + Engine.Logger.Info("Killing tray process " + proc.Id); + proc.Kill(); + trayRunning = true; + } + catch { } + } + } + + // on unix we don't have to wait (we can overwrite files which are in use) + // On unix we kill the PIDs after the update so e.g. systemd can automatically restart the process + KillPids(pids); + } + Engine.Logger.Info("Finding files in: " + updateLocation); + var files = Directory.GetFiles(updateLocation, "*.*", SearchOption.AllDirectories); + foreach(var file in files) + { + var fileName = Path.GetFileName(file).ToLowerInvariant(); + + if (fileName.EndsWith(".zip") || + fileName.EndsWith(".tar") || + fileName.EndsWith(".gz")) + { + continue; + } + try { + Engine.Logger.Info("Copying " + fileName); + var dest = Path.Combine(options.Path, file.Substring(updateLocation.Length)); + var destDir = Path.GetDirectoryName(dest); + if (!Directory.Exists(destDir)) + { + Engine.Logger.Info("Creating directory " + destDir); + Directory.CreateDirectory(destDir); + } + File.Copy(file, dest, true); + } + catch(Exception e) + { + Engine.Logger.Error(e); + } + } + + // delete old dirs + string[] oldDirs = new string[] { "Content/logos" }; + + foreach (var oldDir in oldDirs) + { + try + { + var deleteDir = Path.Combine(options.Path, oldDir); + if (Directory.Exists(deleteDir)) + { + Engine.Logger.Info("Deleting directory " + deleteDir); + Directory.Delete(deleteDir, true); + } + } + catch (Exception e) + { + Engine.Logger.Error(e); + } + } + + + // delete old files + string[] oldFiles = new string[] { + "Content/css/jquery.dataTables.css", + "Content/css/jquery.dataTables_themeroller.css", + "Definitions/tspate.yml", + "Definitions/freakstrackingsystem.yml", + "Definitions/rarbg.yml", + "Definitions/t411.yml", + "Definitions/hdbc.yml", // renamed to hdbitscom + }; + + foreach (var oldFIle in oldFiles) + { + try + { + var deleteFile = Path.Combine(options.Path, oldFIle); + if (File.Exists(deleteFile)) + { + Engine.Logger.Info("Deleting file " + deleteFile); + File.Delete(deleteFile); + } + } + catch (Exception e) + { + Engine.Logger.Error(e); + } + } + + // kill pids after the update on UNIX + if (!isWindows) + KillPids(pids); + + if (options.NoRestart == false) + { + if (trayRunning) + { + var startInfo = new ProcessStartInfo() + { + Arguments = options.Args, + FileName = Path.Combine(options.Path, "JackettTray.exe"), + UseShellExecute = true + }; + + Process.Start(startInfo); + } + + if(string.Equals(options.Type, "JackettService.exe", StringComparison.InvariantCultureIgnoreCase)) + { + var serviceHelper = new ServiceConfigService(null, null); + if (serviceHelper.ServiceExists()) + { + serviceHelper.Start(); + } + } else + { + var startInfo = new ProcessStartInfo() + { + Arguments = options.Args, + FileName = Path.Combine(options.Path, "JackettConsole.exe"), + UseShellExecute = true + }; + + if (!isWindows) + { + startInfo.Arguments = startInfo.FileName + " " + startInfo.Arguments; + startInfo.FileName = "mono"; + } + + Engine.Logger.Info("Starting Jackett: " + startInfo.FileName + " " + startInfo.Arguments); + Process.Start(startInfo); + } + } + } + + private string GetUpdateLocation() + { + var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); + return new FileInfo(HttpUtility.UrlDecode(location.AbsolutePath)).DirectoryName; + } + } +} diff --git a/src/Jackett.Updater/UpdaterConsoleOptions.cs b/src/Jackett.Updater/UpdaterConsoleOptions.cs index 2466bcb0..931de42e 100644 --- a/src/Jackett.Updater/UpdaterConsoleOptions.cs +++ b/src/Jackett.Updater/UpdaterConsoleOptions.cs @@ -13,8 +13,8 @@ namespace Jackett.Updater public string Path { get; set; } [Option('t', "Type", HelpText = "Install type")] - public string Type { get; set; } - + public string Type { get; set; } + [Option('a', "Args", HelpText = "Launch arguments")] public string Args { get; set; } diff --git a/src/Jackett/Controllers/AdminController.cs b/src/Jackett/Controllers/AdminController.cs index e5bf8d89..58d557f1 100644 --- a/src/Jackett/Controllers/AdminController.cs +++ b/src/Jackett/Controllers/AdminController.cs @@ -1,595 +1,595 @@ -using Autofac; -using AutoMapper; -using Jackett.Indexers; -using Jackett.Models; -using Jackett.Services; -using Jackett.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Claims; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http; -using System.Web.Http.Results; -using System.Web.Security; -using System.Windows.Forms; - -namespace Jackett.Controllers -{ - [RoutePrefix("admin")] - [JackettAuthorized] - [JackettAPINoCache] - public class AdminController : ApiController - { - private IConfigurationService config; - private IIndexerManagerService indexerService; - private IServerService serverService; - private ISecuityService securityService; - private IProcessService processService; - private ICacheService cacheService; - private Logger logger; - private ILogCacheService logCache; - private IUpdateService updater; - - public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l, ILogCacheService lc, IUpdateService u) - { - this.config = config; - indexerService = i; - serverService = ss; - securityService = s; - processService = p; - cacheService = c; - logger = l; - logCache = lc; - updater = u; - } - - private async Task<JToken> ReadPostDataJson() - { - var content = await Request.Content.ReadAsStringAsync(); - return JObject.Parse(content); - } - - - private HttpResponseMessage GetFile(string path) - { - var result = new HttpResponseMessage(HttpStatusCode.OK); - var mappedPath = Path.Combine(config.GetContentFolder(), path); - var stream = new FileStream(mappedPath, FileMode.Open, FileAccess.Read, FileShare.Read); - result.Content = new StreamContent(stream); - result.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(mappedPath)); - - return result; - } - - [HttpGet] - [AllowAnonymous] - public RedirectResult Logout() - { - var ctx = Request.GetOwinContext(); - var authManager = ctx.Authentication; - authManager.SignOut("ApplicationCookie"); - return Redirect("Admin/Dashboard"); - } - - [HttpGet] - [HttpPost] - [AllowAnonymous] - public async Task<HttpResponseMessage> Dashboard() - { - if (Request.RequestUri.Query != null && Request.RequestUri.Query.Contains("logout")) - { - var file = GetFile("login.html"); - securityService.Logout(file); - return file; - } - - - if (securityService.CheckAuthorised(Request)) - { - return GetFile("index.html"); - - } - else - { - var formData = await Request.Content.ReadAsFormDataAsync(); - - if (formData != null && securityService.HashPassword(formData["password"]) == serverService.Config.AdminPassword) - { - var file = GetFile("index.html"); - securityService.Login(file); - return file; - } - else - { - return GetFile("login.html"); - } - } - } - - [Route("set_admin_password")] - [HttpPost] - public async Task<IHttpActionResult> SetAdminPassword() - { - var jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(); - var password = (string)postData["password"]; - if (string.IsNullOrEmpty(password)) - { - serverService.Config.AdminPassword = string.Empty; - } - else - { - serverService.Config.AdminPassword = securityService.HashPassword(password); - } - - serverService.SaveConfig(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - logger.Error(ex, "Exception in SetAdminPassword"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("get_config_form")] - [HttpPost] - public async Task<IHttpActionResult> GetConfigForm() - { - var jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(); - var indexer = indexerService.GetIndexer((string)postData["indexer"]); - var config = await indexer.GetConfigurationForSetup(); - jsonReply["config"] = config.ToJson(null); - jsonReply["caps"] = indexer.TorznabCaps.CapsToJson(); - jsonReply["name"] = indexer.DisplayName; - jsonReply["alternativesitelinks"] = JToken.FromObject(indexer.AlternativeSiteLinks); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - logger.Error(ex, "Exception in GetConfigForm"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("configure_indexer")] - [HttpPost] - public async Task<IHttpActionResult> Configure() - { - var jsonReply = new JObject(); - IIndexer indexer = null; - try - { - var postData = await ReadPostDataJson(); - string indexerString = (string)postData["indexer"]; - indexer = indexerService.GetIndexer((string)postData["indexer"]); - jsonReply["name"] = indexer.DisplayName; - var configurationResult = await indexer.ApplyConfiguration(postData["config"]); - if (configurationResult == IndexerConfigurationStatus.RequiresTesting) - { - await indexerService.TestIndexer((string)postData["indexer"]); - } - else if (configurationResult == IndexerConfigurationStatus.Failed) - { - throw new Exception("Configuration Failed"); - } - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - var baseIndexer = indexer as BaseIndexer; - if (null != baseIndexer) - baseIndexer.ResetBaseConfig(); - if (ex is ExceptionWithConfigData) - { - jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(null,false); - } - else - { - logger.Error(ex, "Exception in Configure"); - } - } - return Json(jsonReply); - } - - [Route("get_indexers")] - [HttpGet] - public IHttpActionResult Indexers() - { - var jsonReply = new JObject(); - try - { - jsonReply["result"] = "success"; - JArray items = new JArray(); - - foreach (var indexer in indexerService.GetAllIndexers()) - { - var item = new JObject(); - item["id"] = indexer.ID; - item["name"] = indexer.DisplayName; - item["description"] = indexer.DisplayDescription; - item["type"] = indexer.Type; - item["configured"] = indexer.IsConfigured; - item["site_link"] = indexer.SiteLink; - item["language"] = indexer.Language; - item["last_error"] = indexer.LastError; - item["potatoenabled"] = indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => PotatoController.MOVIE_CATS.Contains(i)); - - var caps = new JObject(); - foreach (var cap in indexer.TorznabCaps.Categories) - caps[cap.ID.ToString()] = cap.Name; - item["caps"] = caps; - items.Add(item); - } - jsonReply["items"] = items; - } - catch (Exception ex) - { - logger.Error(ex, "Exception in get_indexers"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("test_indexer")] - [HttpPost] - public async Task<IHttpActionResult> Test() - { - JToken jsonReply = new JObject(); - IIndexer indexer = null; - try - { - var postData = await ReadPostDataJson(); - string indexerString = (string)postData["indexer"]; - indexer = indexerService.GetIndexer(indexerString); - await indexerService.TestIndexer(indexerString); - jsonReply["name"] = indexer.DisplayName; - jsonReply["result"] = "success"; - indexer.LastError = null; - } - catch (Exception ex) - { - var msg = ex.Message; - if (ex.InnerException != null) - msg += ": " + ex.InnerException.Message; - logger.Error(ex, "Exception in test_indexer"); - jsonReply["result"] = "error"; - jsonReply["error"] = msg; - if (indexer != null) - indexer.LastError = msg; - } - return Json(jsonReply); - } - - [Route("delete_indexer")] - [HttpPost] - public async Task<IHttpActionResult> Delete() - { - var jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(); - string indexerString = (string)postData["indexer"]; - indexerService.DeleteIndexer(indexerString); - } - catch (Exception ex) - { - logger.Error(ex, "Exception in delete_indexer"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("trigger_update")] - [HttpGet] - public IHttpActionResult TriggerUpdates() - { - var jsonReply = new JObject(); - updater.CheckForUpdatesNow(); - return Json(jsonReply); - } - - [Route("get_jackett_config")] - [HttpGet] - public IHttpActionResult GetConfig() - { - var jsonReply = new JObject(); - try - { - var cfg = new JObject(); - cfg["notices"] = JToken.FromObject(serverService.notices); - cfg["port"] = serverService.Config.Port; - cfg["external"] = serverService.Config.AllowExternal; - cfg["api_key"] = serverService.Config.APIKey; - cfg["blackholedir"] = serverService.Config.BlackholeDir; - cfg["updatedisabled"] = serverService.Config.UpdateDisabled; - cfg["prerelease"] = serverService.Config.UpdatePrerelease; - cfg["password"] = string.IsNullOrEmpty(serverService.Config.AdminPassword) ? string.Empty : serverService.Config.AdminPassword.Substring(0, 10); - cfg["logging"] = Startup.TracingEnabled; - cfg["basepathoverride"] = serverService.Config.BasePathOverride; - - - jsonReply["config"] = cfg; - jsonReply["app_version"] = config.GetVersion(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - logger.Error(ex, "Exception in get_jackett_config"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("set_config")] - [HttpPost] - public async Task<IHttpActionResult> SetConfig() - { - var originalPort = Engine.Server.Config.Port; - var originalAllowExternal = Engine.Server.Config.AllowExternal; - var jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(); - int port = (int)postData["port"]; - bool external = (bool)postData["external"]; - string saveDir = (string)postData["blackholedir"]; - bool updateDisabled = (bool)postData["updatedisabled"]; - bool preRelease = (bool)postData["prerelease"]; - bool logging = (bool)postData["logging"]; - string basePathOverride = (string)postData["basepathoverride"]; - - Engine.Server.Config.UpdateDisabled = updateDisabled; - Engine.Server.Config.UpdatePrerelease = preRelease; - Engine.Server.Config.BasePathOverride = basePathOverride; - Startup.BasePath = Engine.Server.BasePath(); - Engine.Server.SaveConfig(); - - Engine.SetLogLevel(logging ? LogLevel.Debug : LogLevel.Info); - Startup.TracingEnabled = logging; - - if (port != Engine.Server.Config.Port || external != Engine.Server.Config.AllowExternal) - { - - if (ServerUtil.RestrictedPorts.Contains(port)) - { - jsonReply["result"] = "error"; - jsonReply["error"] = "The port you have selected is restricted, try a different one."; - return Json(jsonReply); - } - - // Save port to the config so it can be picked up by the if needed when running as admin below. - Engine.Server.Config.AllowExternal = external; - Engine.Server.Config.Port = port; - Engine.Server.SaveConfig(); - - // On Windows change the url reservations - if (System.Environment.OSVersion.Platform != PlatformID.Unix) - { - if (!ServerUtil.IsUserAdministrator()) - { - try - { - processService.StartProcessAndLog(Application.ExecutablePath, "--ReserveUrls", true); - } - catch - { - Engine.Server.Config.Port = originalPort; - Engine.Server.Config.AllowExternal = originalAllowExternal; - Engine.Server.SaveConfig(); - jsonReply["result"] = "error"; - jsonReply["error"] = "Failed to acquire admin permissions to reserve the new port."; - return Json(jsonReply); - } - } - else - { - serverService.ReserveUrls(true); - } - } - - (new Thread(() => - { - Thread.Sleep(500); - serverService.Stop(); - Engine.BuildContainer(); - Engine.Server.Initalize(); - Engine.Server.Start(); - })).Start(); - } - - if (saveDir != Engine.Server.Config.BlackholeDir) - { - if (!string.IsNullOrEmpty(saveDir)) - { - if (!Directory.Exists(saveDir)) - { - throw new Exception("Blackhole directory does not exist"); - } - } - - Engine.Server.Config.BlackholeDir = saveDir; - Engine.Server.SaveConfig(); - } - - jsonReply["result"] = "success"; - jsonReply["port"] = port; - jsonReply["external"] = external; - } - catch (Exception ex) - { - logger.Error(ex, "Exception in set_port"); - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Json(jsonReply); - } - - [Route("GetCache")] - [HttpGet] - public List<TrackerCacheResult> GetCache() - { - var results = cacheService.GetCachedResults(); - ConfigureCacheResults(results); - return results; - } - - - private void ConfigureCacheResults(List<TrackerCacheResult> results) - { - var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); - foreach (var result in results) - { - var link = result.Link; - result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", result.Title + ".torrent"); - if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir)) - result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", string.Empty); - - } - } - - [Route("GetLogs")] - [HttpGet] - public List<CachedLog> GetLogs() - { - return logCache.Logs; - } - - [Route("Search")] - [HttpPost] - public ManualSearchResult Search([FromBody]AdminSearch value) - { - var results = new List<TrackerCacheResult>(); - var stringQuery = new TorznabQuery(); - - var queryStr = value.Query; - if (queryStr != null) - { - var seasonMatch = Regex.Match(queryStr, @"S(\d{2,4})"); - if (seasonMatch.Success) - { - stringQuery.Season = int.Parse(seasonMatch.Groups[1].Value); - queryStr = queryStr.Remove(seasonMatch.Index, seasonMatch.Length); - } - - var episodeMatch = Regex.Match(queryStr, @"E(\d{2,4})"); - if (episodeMatch.Success) - { - stringQuery.Episode = episodeMatch.Groups[1].Value; - queryStr = queryStr.Remove(episodeMatch.Index, episodeMatch.Length); - } - queryStr = queryStr.Trim(); - } - - - stringQuery.SearchTerm = queryStr; - stringQuery.Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category }; - stringQuery.ExpandCatsToSubCats(); - - // try to build an IMDB Query - var imdbID = ParseUtil.GetFullImdbID(stringQuery.SanitizedSearchTerm); - TorznabQuery imdbQuery = null; - if (imdbID != null) - { - imdbQuery = new TorznabQuery() - { - ImdbID = imdbID, - Categories = stringQuery.Categories, - Season = stringQuery.Season, - Episode = stringQuery.Episode, - }; - imdbQuery.ExpandCatsToSubCats(); - } - - var trackers = indexerService.GetAllIndexers().Where(t => t.IsConfigured).ToList(); - if (!string.IsNullOrWhiteSpace(value.Tracker)) - { - trackers = trackers.Where(t => t.ID == value.Tracker).ToList(); - } - - if (value.Category != 0) - { - trackers = trackers.Where(t => t.TorznabCaps.Categories.Select(c => c.ID).Contains(value.Category)).ToList(); - } - - Parallel.ForEach(trackers.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 1000 }, indexer => - { - try - { - var query = stringQuery; - // use imdb Query for trackers which support it - if (imdbQuery != null && indexer.TorznabCaps.SupportsImdbSearch) - query = imdbQuery; - - var searchResults = indexer.PerformQuery(query).Result; - searchResults = indexer.CleanLinks(searchResults); - cacheService.CacheRssResults(indexer, searchResults); - searchResults = indexer.FilterResults(query, searchResults); - - foreach (var result in searchResults) - { - var item = Mapper.Map<TrackerCacheResult>(result); - item.Tracker = indexer.DisplayName; - item.TrackerId = indexer.ID; - item.Peers = item.Peers - item.Seeders; // Use peers as leechers - lock (results) - { - results.Add(item); - } - } - } - catch (Exception e) - { - logger.Error(e, "An error occured during manual search on " + indexer.DisplayName + ": " + e.Message); - } - }); - - ConfigureCacheResults(results); - - if (trackers.Count > 1) - { - results = results.OrderByDescending(d => d.PublishDate).ToList(); - } - - var manualResult = new ManualSearchResult() - { - Results = results, - Indexers = trackers.Select(t => t.DisplayName).ToList() - }; - - - if (manualResult.Indexers.Count == 0) - manualResult.Indexers = new List<string>() { "None" }; - - logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", stringQuery.GetQueryString(), string.Join(", ", manualResult.Indexers), manualResult.Results.Count)); - return manualResult; - } - } -} - +using Autofac; +using AutoMapper; +using Jackett.Indexers; +using Jackett.Models; +using Jackett.Services; +using Jackett.Utils; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; +using System.Web.Http.Results; +using System.Web.Security; +using System.Windows.Forms; + +namespace Jackett.Controllers +{ + [RoutePrefix("admin")] + [JackettAuthorized] + [JackettAPINoCache] + public class AdminController : ApiController + { + private IConfigurationService config; + private IIndexerManagerService indexerService; + private IServerService serverService; + private ISecuityService securityService; + private IProcessService processService; + private ICacheService cacheService; + private Logger logger; + private ILogCacheService logCache; + private IUpdateService updater; + + public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l, ILogCacheService lc, IUpdateService u) + { + this.config = config; + indexerService = i; + serverService = ss; + securityService = s; + processService = p; + cacheService = c; + logger = l; + logCache = lc; + updater = u; + } + + private async Task<JToken> ReadPostDataJson() + { + var content = await Request.Content.ReadAsStringAsync(); + return JObject.Parse(content); + } + + + private HttpResponseMessage GetFile(string path) + { + var result = new HttpResponseMessage(HttpStatusCode.OK); + var mappedPath = Path.Combine(config.GetContentFolder(), path); + var stream = new FileStream(mappedPath, FileMode.Open, FileAccess.Read, FileShare.Read); + result.Content = new StreamContent(stream); + result.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(mappedPath)); + + return result; + } + + [HttpGet] + [AllowAnonymous] + public RedirectResult Logout() + { + var ctx = Request.GetOwinContext(); + var authManager = ctx.Authentication; + authManager.SignOut("ApplicationCookie"); + return Redirect("Admin/Dashboard"); + } + + [HttpGet] + [HttpPost] + [AllowAnonymous] + public async Task<HttpResponseMessage> Dashboard() + { + if (Request.RequestUri.Query != null && Request.RequestUri.Query.Contains("logout")) + { + var file = GetFile("login.html"); + securityService.Logout(file); + return file; + } + + + if (securityService.CheckAuthorised(Request)) + { + return GetFile("index.html"); + + } + else + { + var formData = await Request.Content.ReadAsFormDataAsync(); + + if (formData != null && securityService.HashPassword(formData["password"]) == serverService.Config.AdminPassword) + { + var file = GetFile("index.html"); + securityService.Login(file); + return file; + } + else + { + return GetFile("login.html"); + } + } + } + + [Route("set_admin_password")] + [HttpPost] + public async Task<IHttpActionResult> SetAdminPassword() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + var password = (string)postData["password"]; + if (string.IsNullOrEmpty(password)) + { + serverService.Config.AdminPassword = string.Empty; + } + else + { + serverService.Config.AdminPassword = securityService.HashPassword(password); + } + + serverService.SaveConfig(); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + logger.Error(ex, "Exception in SetAdminPassword"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("get_config_form")] + [HttpPost] + public async Task<IHttpActionResult> GetConfigForm() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + var indexer = indexerService.GetIndexer((string)postData["indexer"]); + var config = await indexer.GetConfigurationForSetup(); + jsonReply["config"] = config.ToJson(null); + jsonReply["caps"] = indexer.TorznabCaps.CapsToJson(); + jsonReply["name"] = indexer.DisplayName; + jsonReply["alternativesitelinks"] = JToken.FromObject(indexer.AlternativeSiteLinks); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + logger.Error(ex, "Exception in GetConfigForm"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("configure_indexer")] + [HttpPost] + public async Task<IHttpActionResult> Configure() + { + var jsonReply = new JObject(); + IIndexer indexer = null; + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + indexer = indexerService.GetIndexer((string)postData["indexer"]); + jsonReply["name"] = indexer.DisplayName; + var configurationResult = await indexer.ApplyConfiguration(postData["config"]); + if (configurationResult == IndexerConfigurationStatus.RequiresTesting) + { + await indexerService.TestIndexer((string)postData["indexer"]); + } + else if (configurationResult == IndexerConfigurationStatus.Failed) + { + throw new Exception("Configuration Failed"); + } + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + var baseIndexer = indexer as BaseIndexer; + if (null != baseIndexer) + baseIndexer.ResetBaseConfig(); + if (ex is ExceptionWithConfigData) + { + jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(null,false); + } + else + { + logger.Error(ex, "Exception in Configure"); + } + } + return Json(jsonReply); + } + + [Route("get_indexers")] + [HttpGet] + public IHttpActionResult Indexers() + { + var jsonReply = new JObject(); + try + { + jsonReply["result"] = "success"; + JArray items = new JArray(); + + foreach (var indexer in indexerService.GetAllIndexers()) + { + var item = new JObject(); + item["id"] = indexer.ID; + item["name"] = indexer.DisplayName; + item["description"] = indexer.DisplayDescription; + item["type"] = indexer.Type; + item["configured"] = indexer.IsConfigured; + item["site_link"] = indexer.SiteLink; + item["language"] = indexer.Language; + item["last_error"] = indexer.LastError; + item["potatoenabled"] = indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => PotatoController.MOVIE_CATS.Contains(i)); + + var caps = new JObject(); + foreach (var cap in indexer.TorznabCaps.Categories) + caps[cap.ID.ToString()] = cap.Name; + item["caps"] = caps; + items.Add(item); + } + jsonReply["items"] = items; + } + catch (Exception ex) + { + logger.Error(ex, "Exception in get_indexers"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("test_indexer")] + [HttpPost] + public async Task<IHttpActionResult> Test() + { + JToken jsonReply = new JObject(); + IIndexer indexer = null; + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + indexer = indexerService.GetIndexer(indexerString); + await indexerService.TestIndexer(indexerString); + jsonReply["name"] = indexer.DisplayName; + jsonReply["result"] = "success"; + indexer.LastError = null; + } + catch (Exception ex) + { + var msg = ex.Message; + if (ex.InnerException != null) + msg += ": " + ex.InnerException.Message; + logger.Error(ex, "Exception in test_indexer"); + jsonReply["result"] = "error"; + jsonReply["error"] = msg; + if (indexer != null) + indexer.LastError = msg; + } + return Json(jsonReply); + } + + [Route("delete_indexer")] + [HttpPost] + public async Task<IHttpActionResult> Delete() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + indexerService.DeleteIndexer(indexerString); + } + catch (Exception ex) + { + logger.Error(ex, "Exception in delete_indexer"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("trigger_update")] + [HttpGet] + public IHttpActionResult TriggerUpdates() + { + var jsonReply = new JObject(); + updater.CheckForUpdatesNow(); + return Json(jsonReply); + } + + [Route("get_jackett_config")] + [HttpGet] + public IHttpActionResult GetConfig() + { + var jsonReply = new JObject(); + try + { + var cfg = new JObject(); + cfg["notices"] = JToken.FromObject(serverService.notices); + cfg["port"] = serverService.Config.Port; + cfg["external"] = serverService.Config.AllowExternal; + cfg["api_key"] = serverService.Config.APIKey; + cfg["blackholedir"] = serverService.Config.BlackholeDir; + cfg["updatedisabled"] = serverService.Config.UpdateDisabled; + cfg["prerelease"] = serverService.Config.UpdatePrerelease; + cfg["password"] = string.IsNullOrEmpty(serverService.Config.AdminPassword) ? string.Empty : serverService.Config.AdminPassword.Substring(0, 10); + cfg["logging"] = Startup.TracingEnabled; + cfg["basepathoverride"] = serverService.Config.BasePathOverride; + + + jsonReply["config"] = cfg; + jsonReply["app_version"] = config.GetVersion(); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + logger.Error(ex, "Exception in get_jackett_config"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("set_config")] + [HttpPost] + public async Task<IHttpActionResult> SetConfig() + { + var originalPort = Engine.Server.Config.Port; + var originalAllowExternal = Engine.Server.Config.AllowExternal; + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + int port = (int)postData["port"]; + bool external = (bool)postData["external"]; + string saveDir = (string)postData["blackholedir"]; + bool updateDisabled = (bool)postData["updatedisabled"]; + bool preRelease = (bool)postData["prerelease"]; + bool logging = (bool)postData["logging"]; + string basePathOverride = (string)postData["basepathoverride"]; + + Engine.Server.Config.UpdateDisabled = updateDisabled; + Engine.Server.Config.UpdatePrerelease = preRelease; + Engine.Server.Config.BasePathOverride = basePathOverride; + Startup.BasePath = Engine.Server.BasePath(); + Engine.Server.SaveConfig(); + + Engine.SetLogLevel(logging ? LogLevel.Debug : LogLevel.Info); + Startup.TracingEnabled = logging; + + if (port != Engine.Server.Config.Port || external != Engine.Server.Config.AllowExternal) + { + + if (ServerUtil.RestrictedPorts.Contains(port)) + { + jsonReply["result"] = "error"; + jsonReply["error"] = "The port you have selected is restricted, try a different one."; + return Json(jsonReply); + } + + // Save port to the config so it can be picked up by the if needed when running as admin below. + Engine.Server.Config.AllowExternal = external; + Engine.Server.Config.Port = port; + Engine.Server.SaveConfig(); + + // On Windows change the url reservations + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + { + if (!ServerUtil.IsUserAdministrator()) + { + try + { + processService.StartProcessAndLog(Application.ExecutablePath, "--ReserveUrls", true); + } + catch + { + Engine.Server.Config.Port = originalPort; + Engine.Server.Config.AllowExternal = originalAllowExternal; + Engine.Server.SaveConfig(); + jsonReply["result"] = "error"; + jsonReply["error"] = "Failed to acquire admin permissions to reserve the new port."; + return Json(jsonReply); + } + } + else + { + serverService.ReserveUrls(true); + } + } + + (new Thread(() => + { + Thread.Sleep(500); + serverService.Stop(); + Engine.BuildContainer(); + Engine.Server.Initalize(); + Engine.Server.Start(); + })).Start(); + } + + if (saveDir != Engine.Server.Config.BlackholeDir) + { + if (!string.IsNullOrEmpty(saveDir)) + { + if (!Directory.Exists(saveDir)) + { + throw new Exception("Blackhole directory does not exist"); + } + } + + Engine.Server.Config.BlackholeDir = saveDir; + Engine.Server.SaveConfig(); + } + + jsonReply["result"] = "success"; + jsonReply["port"] = port; + jsonReply["external"] = external; + } + catch (Exception ex) + { + logger.Error(ex, "Exception in set_port"); + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("GetCache")] + [HttpGet] + public List<TrackerCacheResult> GetCache() + { + var results = cacheService.GetCachedResults(); + ConfigureCacheResults(results); + return results; + } + + + private void ConfigureCacheResults(List<TrackerCacheResult> results) + { + var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); + foreach (var result in results) + { + var link = result.Link; + result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", result.Title + ".torrent"); + if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(Engine.Server.Config.BlackholeDir)) + result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", string.Empty); + + } + } + + [Route("GetLogs")] + [HttpGet] + public List<CachedLog> GetLogs() + { + return logCache.Logs; + } + + [Route("Search")] + [HttpPost] + public ManualSearchResult Search([FromBody]AdminSearch value) + { + var results = new List<TrackerCacheResult>(); + var stringQuery = new TorznabQuery(); + + var queryStr = value.Query; + if (queryStr != null) + { + var seasonMatch = Regex.Match(queryStr, @"S(\d{2,4})"); + if (seasonMatch.Success) + { + stringQuery.Season = int.Parse(seasonMatch.Groups[1].Value); + queryStr = queryStr.Remove(seasonMatch.Index, seasonMatch.Length); + } + + var episodeMatch = Regex.Match(queryStr, @"E(\d{2,4})"); + if (episodeMatch.Success) + { + stringQuery.Episode = episodeMatch.Groups[1].Value; + queryStr = queryStr.Remove(episodeMatch.Index, episodeMatch.Length); + } + queryStr = queryStr.Trim(); + } + + + stringQuery.SearchTerm = queryStr; + stringQuery.Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category }; + stringQuery.ExpandCatsToSubCats(); + + // try to build an IMDB Query + var imdbID = ParseUtil.GetFullImdbID(stringQuery.SanitizedSearchTerm); + TorznabQuery imdbQuery = null; + if (imdbID != null) + { + imdbQuery = new TorznabQuery() + { + ImdbID = imdbID, + Categories = stringQuery.Categories, + Season = stringQuery.Season, + Episode = stringQuery.Episode, + }; + imdbQuery.ExpandCatsToSubCats(); + } + + var trackers = indexerService.GetAllIndexers().Where(t => t.IsConfigured).ToList(); + if (!string.IsNullOrWhiteSpace(value.Tracker)) + { + trackers = trackers.Where(t => t.ID == value.Tracker).ToList(); + } + + if (value.Category != 0) + { + trackers = trackers.Where(t => t.TorznabCaps.Categories.Select(c => c.ID).Contains(value.Category)).ToList(); + } + + Parallel.ForEach(trackers.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 1000 }, indexer => + { + try + { + var query = stringQuery; + // use imdb Query for trackers which support it + if (imdbQuery != null && indexer.TorznabCaps.SupportsImdbSearch) + query = imdbQuery; + + var searchResults = indexer.PerformQuery(query).Result; + searchResults = indexer.CleanLinks(searchResults); + cacheService.CacheRssResults(indexer, searchResults); + searchResults = indexer.FilterResults(query, searchResults); + + foreach (var result in searchResults) + { + var item = Mapper.Map<TrackerCacheResult>(result); + item.Tracker = indexer.DisplayName; + item.TrackerId = indexer.ID; + item.Peers = item.Peers - item.Seeders; // Use peers as leechers + lock (results) + { + results.Add(item); + } + } + } + catch (Exception e) + { + logger.Error(e, "An error occured during manual search on " + indexer.DisplayName + ": " + e.Message); + } + }); + + ConfigureCacheResults(results); + + if (trackers.Count > 1) + { + results = results.OrderByDescending(d => d.PublishDate).ToList(); + } + + var manualResult = new ManualSearchResult() + { + Results = results, + Indexers = trackers.Select(t => t.DisplayName).ToList() + }; + + + if (manualResult.Indexers.Count == 0) + manualResult.Indexers = new List<string>() { "None" }; + + logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", stringQuery.GetQueryString(), string.Join(", ", manualResult.Indexers), manualResult.Results.Count)); + return manualResult; + } + } +} + diff --git a/src/Jackett/Controllers/PotatoController.cs b/src/Jackett/Controllers/PotatoController.cs index f9f97cb0..ac266a79 100644 --- a/src/Jackett/Controllers/PotatoController.cs +++ b/src/Jackett/Controllers/PotatoController.cs @@ -1,173 +1,173 @@ -using AutoMapper; -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.Diagnostics; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http; - -namespace Jackett.Controllers -{ - [AllowAnonymous] - [JackettAPINoCache] - public class PotatoController : ApiController - { - private IIndexerManagerService indexerService; - private Logger logger; - private IServerService serverService; - private ICacheService cacheService; - private IWebClient webClient; - - public static int[] MOVIE_CATS - { - get - { - var torznabQuery = new TorznabQuery() - { - Categories = new int[1] { TorznabCatType.Movies.ID }, - }; - - torznabQuery.ExpandCatsToSubCats(); - return torznabQuery.Categories; - } - } - - public PotatoController(IIndexerManagerService i, Logger l, IServerService s, ICacheService c, IWebClient w) - { - indexerService = i; - logger = l; - serverService = s; - cacheService = c; - webClient = w; - } - - [HttpGet] - public async Task<HttpResponseMessage> Call(string indexerID, [FromUri]TorrentPotatoRequest request) - { - var indexer = indexerService.GetIndexer(indexerID); - - var allowBadApiDueToDebug = false; -#if DEBUG - allowBadApiDueToDebug = Debugger.IsAttached; -#endif - - if (!allowBadApiDueToDebug && !string.Equals(request.passkey, serverService.Config.APIKey, StringComparison.InvariantCultureIgnoreCase)) - { - logger.Warn(string.Format("A request from {0} was made with an incorrect API key.", Request.GetOwinContext().Request.RemoteIpAddress)); - return Request.CreateResponse(HttpStatusCode.Forbidden, "Incorrect API key"); - } - - if (!indexer.IsConfigured) - { - logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); - return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured."); - } - - if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i))){ - logger.Warn(string.Format("Rejected a request to {0} which does not support searching for movies.", indexer.DisplayName)); - return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer does not support movies."); - } - - var year = 0; - - if (string.IsNullOrWhiteSpace(request.search)) - { - // We are searching by IMDB id so look up the name - var omdbapiRequest = new Utils.Clients.WebRequest("http://www.omdbapi.com/?type=movie&i=" + request.imdbid); - omdbapiRequest.Encoding = Encoding.UTF8; - var response = await webClient.GetString(omdbapiRequest); - if (response.Status == HttpStatusCode.OK) - { - JObject result = JObject.Parse(response.Content); - if (result["Title"] != null) - { - request.search = result["Title"].ToString(); - year = ParseUtil.CoerceInt(result["Year"].ToString()); - } - } - } - - var torznabQuery = new TorznabQuery() - { - ApiKey = request.passkey, - Categories = MOVIE_CATS, - SearchTerm = request.search, - ImdbID = request.imdbid, - QueryType = "TorrentPotato" - }; - - IEnumerable<ReleaseInfo> releases = new List<ReleaseInfo>(); - - if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) - { - releases = await indexer.PerformQuery(torznabQuery); - releases = indexer.CleanLinks(releases); - } - - // Cache non query results - if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) - { - cacheService.CacheRssResults(indexer, releases); - } - - releases = indexer.FilterResults(torznabQuery, releases); - var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); - var potatoResponse = new TorrentPotatoResponse(); - - releases = TorznabUtil.FilterResultsToTitle(releases, torznabQuery.SanitizedSearchTerm, year); - releases = TorznabUtil.FilterResultsToImdb(releases, request.imdbid); - - foreach (var r in releases) - { - var release = Mapper.Map<ReleaseInfo>(r); - release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, indexerID, "dl", release.Title + ".torrent"); - - // Only accept torrent links, magnet is not supported - // This seems to be no longer the case, allowing magnet URIs for now - if (release.Link != null || release.MagnetUri != null) - { - potatoResponse.results.Add(new TorrentPotatoResponseItem() - { - release_name = release.Title + "[" + indexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.> - torrent_id = release.Guid.ToString(), - details_url = release.Comments.ToString(), - download_url = (release.Link != null ? release.Link.ToString() : release.MagnetUri.ToString()), - imdb_id = release.Imdb.HasValue ? "tt" + release.Imdb : null, - freeleech = (release.DownloadVolumeFactor == 0 ? true : false), - type = "movie", - size = (long)release.Size / (1024 * 1024), // This is in MB - leechers = (int)release.Peers - (int)release.Seeders, - seeders = (int)release.Seeders, - publish_date = r.PublishDate == DateTime.MinValue ? null : release.PublishDate.ToUniversalTime().ToString("s") - }); - } - } - - // Log info - if (string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) - { - logger.Info(string.Format("Found {0} torrentpotato releases from {1}", releases.Count(), indexer.DisplayName)); - } - else - { - logger.Info(string.Format("Found {0} torrentpotato releases from {1} for: {2}", releases.Count(), indexer.DisplayName, torznabQuery.GetQueryString())); - } - - // Force the return as Json - return new HttpResponseMessage() - { - Content = new JsonContent(potatoResponse) - }; - } - } -} +using AutoMapper; +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.Diagnostics; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; + +namespace Jackett.Controllers +{ + [AllowAnonymous] + [JackettAPINoCache] + public class PotatoController : ApiController + { + private IIndexerManagerService indexerService; + private Logger logger; + private IServerService serverService; + private ICacheService cacheService; + private IWebClient webClient; + + public static int[] MOVIE_CATS + { + get + { + var torznabQuery = new TorznabQuery() + { + Categories = new int[1] { TorznabCatType.Movies.ID }, + }; + + torznabQuery.ExpandCatsToSubCats(); + return torznabQuery.Categories; + } + } + + public PotatoController(IIndexerManagerService i, Logger l, IServerService s, ICacheService c, IWebClient w) + { + indexerService = i; + logger = l; + serverService = s; + cacheService = c; + webClient = w; + } + + [HttpGet] + public async Task<HttpResponseMessage> Call(string indexerID, [FromUri]TorrentPotatoRequest request) + { + var indexer = indexerService.GetIndexer(indexerID); + + var allowBadApiDueToDebug = false; +#if DEBUG + allowBadApiDueToDebug = Debugger.IsAttached; +#endif + + if (!allowBadApiDueToDebug && !string.Equals(request.passkey, serverService.Config.APIKey, StringComparison.InvariantCultureIgnoreCase)) + { + logger.Warn(string.Format("A request from {0} was made with an incorrect API key.", Request.GetOwinContext().Request.RemoteIpAddress)); + return Request.CreateResponse(HttpStatusCode.Forbidden, "Incorrect API key"); + } + + if (!indexer.IsConfigured) + { + logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); + return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured."); + } + + if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i))){ + logger.Warn(string.Format("Rejected a request to {0} which does not support searching for movies.", indexer.DisplayName)); + return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer does not support movies."); + } + + var year = 0; + + if (string.IsNullOrWhiteSpace(request.search)) + { + // We are searching by IMDB id so look up the name + var omdbapiRequest = new Utils.Clients.WebRequest("http://www.omdbapi.com/?type=movie&i=" + request.imdbid); + omdbapiRequest.Encoding = Encoding.UTF8; + var response = await webClient.GetString(omdbapiRequest); + if (response.Status == HttpStatusCode.OK) + { + JObject result = JObject.Parse(response.Content); + if (result["Title"] != null) + { + request.search = result["Title"].ToString(); + year = ParseUtil.CoerceInt(result["Year"].ToString()); + } + } + } + + var torznabQuery = new TorznabQuery() + { + ApiKey = request.passkey, + Categories = MOVIE_CATS, + SearchTerm = request.search, + ImdbID = request.imdbid, + QueryType = "TorrentPotato" + }; + + IEnumerable<ReleaseInfo> releases = new List<ReleaseInfo>(); + + if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) + { + releases = await indexer.PerformQuery(torznabQuery); + releases = indexer.CleanLinks(releases); + } + + // Cache non query results + if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) + { + cacheService.CacheRssResults(indexer, releases); + } + + releases = indexer.FilterResults(torznabQuery, releases); + var serverUrl = string.Format("{0}://{1}:{2}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); + var potatoResponse = new TorrentPotatoResponse(); + + releases = TorznabUtil.FilterResultsToTitle(releases, torznabQuery.SanitizedSearchTerm, year); + releases = TorznabUtil.FilterResultsToImdb(releases, request.imdbid); + + foreach (var r in releases) + { + var release = Mapper.Map<ReleaseInfo>(r); + release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, indexerID, "dl", release.Title + ".torrent"); + + // Only accept torrent links, magnet is not supported + // This seems to be no longer the case, allowing magnet URIs for now + if (release.Link != null || release.MagnetUri != null) + { + potatoResponse.results.Add(new TorrentPotatoResponseItem() + { + release_name = release.Title + "[" + indexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.> + torrent_id = release.Guid.ToString(), + details_url = release.Comments.ToString(), + download_url = (release.Link != null ? release.Link.ToString() : release.MagnetUri.ToString()), + imdb_id = release.Imdb.HasValue ? "tt" + release.Imdb : null, + freeleech = (release.DownloadVolumeFactor == 0 ? true : false), + type = "movie", + size = (long)release.Size / (1024 * 1024), // This is in MB + leechers = (int)release.Peers - (int)release.Seeders, + seeders = (int)release.Seeders, + publish_date = r.PublishDate == DateTime.MinValue ? null : release.PublishDate.ToUniversalTime().ToString("s") + }); + } + } + + // Log info + if (string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) + { + logger.Info(string.Format("Found {0} torrentpotato releases from {1}", releases.Count(), indexer.DisplayName)); + } + else + { + logger.Info(string.Format("Found {0} torrentpotato releases from {1} for: {2}", releases.Count(), indexer.DisplayName, torznabQuery.GetQueryString())); + } + + // Force the return as Json + return new HttpResponseMessage() + { + Content = new JsonContent(potatoResponse) + }; + } + } +} diff --git a/src/Jackett/Controllers/TorznabController.cs b/src/Jackett/Controllers/TorznabController.cs index f309c607..ef299138 100644 --- a/src/Jackett/Controllers/TorznabController.cs +++ b/src/Jackett/Controllers/TorznabController.cs @@ -1,7 +1,7 @@ using AutoMapper; using Jackett.Models; using Jackett.Services; -using Jackett.Utils; +using Jackett.Utils; using NLog; using System; using System.Collections.Generic; @@ -13,8 +13,8 @@ using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.Http; -using System.Xml.Linq; - +using System.Xml.Linq; + namespace Jackett.Controllers { [AllowAnonymous] @@ -34,8 +34,8 @@ namespace Jackett.Controllers cacheService = c; } - public HttpResponseMessage GetErrorXML(int code, string description) - { + public HttpResponseMessage GetErrorXML(int code, string description) + { var xdoc = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("error", @@ -46,10 +46,10 @@ namespace Jackett.Controllers var xml = xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString(); - return new HttpResponseMessage() - { + return new HttpResponseMessage() + { Content = new StringContent(xml, Encoding.UTF8, "application/xml") - }; + }; } [HttpGet] @@ -82,33 +82,33 @@ namespace Jackett.Controllers { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured."); - } - + } + if (torznabQuery.ImdbID != null) { - if (torznabQuery.QueryType != "movie") - { - logger.Warn(string.Format("A non movie request with an imdbid was made from {0}.", Request.GetOwinContext().Request.RemoteIpAddress)); - return GetErrorXML(201, "Incorrect parameter: only movie-search supports the imdbid parameter"); + if (torznabQuery.QueryType != "movie") + { + logger.Warn(string.Format("A non movie request with an imdbid was made from {0}.", Request.GetOwinContext().Request.RemoteIpAddress)); + return GetErrorXML(201, "Incorrect parameter: only movie-search supports the imdbid parameter"); } - if (!string.IsNullOrEmpty(torznabQuery.SearchTerm)) - { - logger.Warn(string.Format("A movie-search request from {0} was made contining q and imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); - return GetErrorXML(201, "Incorrect parameter: please specify either imdbid or q"); + if (!string.IsNullOrEmpty(torznabQuery.SearchTerm)) + { + logger.Warn(string.Format("A movie-search request from {0} was made contining q and imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); + return GetErrorXML(201, "Incorrect parameter: please specify either imdbid or q"); } torznabQuery.ImdbID = ParseUtil.GetFullImdbID(torznabQuery.ImdbID); // normalize ImdbID - if (torznabQuery.ImdbID == null) + if (torznabQuery.ImdbID == null) { logger.Warn(string.Format("A movie-search request from {0} was made with an invalid imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); - return GetErrorXML(201, "Incorrect parameter: invalid imdbid format"); + return GetErrorXML(201, "Incorrect parameter: invalid imdbid format"); } - if (!indexer.TorznabCaps.SupportsImdbSearch) + if (!indexer.TorznabCaps.SupportsImdbSearch) { logger.Warn(string.Format("A movie-search request with imdbid from {0} was made but the indexer {1} doesn't support it.", Request.GetOwinContext().Request.RemoteIpAddress, indexer.DisplayName)); - return GetErrorXML(203, "Function Not Available: imdbid is not supported by this indexer"); + return GetErrorXML(203, "Function Not Available: imdbid is not supported by this indexer"); } } diff --git a/src/Jackett/CurlHelper.cs b/src/Jackett/CurlHelper.cs index a5d1f4a5..327eb522 100644 --- a/src/Jackett/CurlHelper.cs +++ b/src/Jackett/CurlHelper.cs @@ -92,16 +92,16 @@ namespace Jackett easy.BufferSize = 64 * 1024; easy.UserAgent = BrowserUtil.ChromeUserAgent; easy.FollowLocation = false; - easy.ConnectTimeout = 20; - if(curlRequest.Headers != null) - { - CurlSlist curlHeaders = new CurlSlist(); - foreach (var header in curlRequest.Headers) - { - curlHeaders.Append(header.Key + ": " + header.Value); - } - easy.SetOpt(CurlOption.HttpHeader, curlHeaders); - } + easy.ConnectTimeout = 20; + if(curlRequest.Headers != null) + { + CurlSlist curlHeaders = new CurlSlist(); + foreach (var header in curlRequest.Headers) + { + curlHeaders.Append(header.Key + ": " + header.Value); + } + easy.SetOpt(CurlOption.HttpHeader, curlHeaders); + } easy.WriteFunction = (byte[] buf, int size, int nmemb, object data) => { @@ -151,8 +151,8 @@ namespace Jackett { easy.SetOpt(CurlOption.SslVerifyhost, false); easy.SetOpt(CurlOption.SslVerifyPeer, false); - } - + } + if (Startup.ProxyConnection != null) { easy.SetOpt(CurlOption.HttpProxyTunnel, 1); @@ -173,14 +173,14 @@ namespace Jackett var headerBytes = Combine(headerBuffers.ToArray()); var headerString = Encoding.UTF8.GetString(headerBytes); - if (Startup.ProxyConnection != null) - { - var firstcrlf = headerString.IndexOf("\r\n\r\n"); - var secondcrlf = headerString.IndexOf("\r\n\r\n", firstcrlf + 1); - if (secondcrlf > 0) - { - headerString = headerString.Substring(firstcrlf + 4, secondcrlf - (firstcrlf)); - } + if (Startup.ProxyConnection != null) + { + var firstcrlf = headerString.IndexOf("\r\n\r\n"); + var secondcrlf = headerString.IndexOf("\r\n\r\n", firstcrlf + 1); + if (secondcrlf > 0) + { + headerString = headerString.Substring(firstcrlf + 4, secondcrlf - (firstcrlf)); + } } var headerParts = headerString.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var headers = new List<string[]>(); @@ -231,28 +231,28 @@ namespace Jackett } // add some debug output to track down the problem causing people getting InternalServerError results - if (status == HttpStatusCode.NotImplemented || status == HttpStatusCode.InternalServerError) - { - try - { - OnErrorMessage("got NotImplemented/InternalServerError"); - OnErrorMessage("request.Method: " + curlRequest.Method); - OnErrorMessage("request.Url: " + curlRequest.Url); - OnErrorMessage("request.Cookies: " + curlRequest.Cookies); - OnErrorMessage("request.Referer: " + curlRequest.Referer); - OnErrorMessage("request.RawPOSTDdata: " + curlRequest.RawPOSTDdata); - OnErrorMessage("cookies: "+ cookieBuilder.ToString().Trim()); - OnErrorMessage("headerString:\n" + headerString); - - foreach (var headerPart in headerParts) - { - OnErrorMessage("headerParts: "+headerPart); - } + if (status == HttpStatusCode.NotImplemented || status == HttpStatusCode.InternalServerError) + { + try + { + OnErrorMessage("got NotImplemented/InternalServerError"); + OnErrorMessage("request.Method: " + curlRequest.Method); + OnErrorMessage("request.Url: " + curlRequest.Url); + OnErrorMessage("request.Cookies: " + curlRequest.Cookies); + OnErrorMessage("request.Referer: " + curlRequest.Referer); + OnErrorMessage("request.RawPOSTDdata: " + curlRequest.RawPOSTDdata); + OnErrorMessage("cookies: "+ cookieBuilder.ToString().Trim()); + OnErrorMessage("headerString:\n" + headerString); + + foreach (var headerPart in headerParts) + { + OnErrorMessage("headerParts: "+headerPart); + } + } + catch (Exception ex) + { + OnErrorMessage(string.Format("CurlHelper: error while handling NotImplemented/InternalServerError:\n{0}", ex)); } - catch (Exception ex) - { - OnErrorMessage(string.Format("CurlHelper: error while handling NotImplemented/InternalServerError:\n{0}", ex)); - } } var contentBytes = Combine(contentBuffers.ToArray()); diff --git a/src/Jackett/Definitions/2fast4you.yml b/src/Jackett/Definitions/2fast4you.yml index e75af4d8..4625d1df 100644 --- a/src/Jackett/Definitions/2fast4you.yml +++ b/src/Jackett/Definitions/2fast4you.yml @@ -1,139 +1,139 @@ ---- - site: 2fast4you - name: 2 Fast 4 You - language: fr-fr - type: private - encoding: UTF-8 - links: - - http://www.2f4y.me/ - - caps: - categorymappings: - - {id: 10, cat: TV/Anime, desc: "Animation: HD720P"} - - {id: 11, cat: TV/Anime, desc: "Animation: HD1080P"} - - {id: 56, cat: TV/Anime, desc: "Animation: DVDRip"} - - {id: 13, cat: TV/Anime, desc: "Animation: DVD"} - - {id: 18, cat: PC/0day, desc: "Applications: PC"} - - {id: 16, cat: PC/Games, desc: "Applications: Jeux"} - - {id: 19, cat: PC/Phone-Android, desc: "Applications: Android"} - - {id: 38, cat: PC/Phone-IOS, desc: "Applications: Mobile Phone"} - - {id: 17, cat: PC/0day, desc: "Applications: Autres"} - - {id: 67, cat: TV, desc: "Autres: Emission TV"} - - {id: 68, cat: TV/Sport, desc: "Autres: Sport"} - - {id: 40, cat: Other, desc: "Autres: Autres"} - - {id: 14, cat: TV/Documentary, desc: "Documentaires: DivX"} - - {id: 15, cat: TV/Documentary, desc: "Documentaires: HD"} - - {id: 76, cat: TV/Documentary, desc: "Documentaires: TVRip"} - - {id: 62, cat: Audio/Audiobook, desc: "E-Books: E-Books Audio"} - - {id: 50, cat: Books, desc: "E-Books: Manuel Français"} - - {id: 49, cat: Books, desc: "E-Books: Manuel Anglais"} - - {id: 36, cat: Books, desc: "E-Books: Livres Français"} - - {id: 53, cat: Books, desc: "E-Books: Livre Anglais"} - - {id: 52, cat: Books, desc: "E-Books: Revue - Journaux"} - - {id: 51, cat: Books, desc: "E-Books: BD"} - - {id: 66, cat: Movies, desc: "Films: VOSTFR"} - - {id: 71, cat: Movies/WEBDL, desc: "Films: WEB-DL"} - - {id: 65, cat: Movies, desc: "Films: VO"} - - {id: 72, cat: Movies/SD, desc: "Films: TVRip/HDTV"} - - {id: 70, cat: Movies/HD, desc: "Films: MHD X265"} - - {id: 57, cat: Movies/SD, desc: "Films: TS/CAM"} - - {id: 59, cat: Movies, desc: "Films: Spectacle"} - - {id: 55, cat: Movies/HD, desc: "Films: MHD 720P"} - - {id: 54, cat: Movies/HD, desc: "Films: MHD 1080P"} - - {id: 1, cat: Movies/HD, desc: "Films: HD720P"} - - {id: 2, cat: Movies/HD, desc: "Films: HD1080P"} - - {id: 90, cat: Movies/HD, desc: "Films: HD X265"} - - {id: 92, cat: Movies/HD, desc: "Films: 4K"} - - {id: 69, cat: Movies/3D, desc: "Films: Film 3D"} - - {id: 3, cat: Movies/DVD, desc: "Films: DVDRIP"} - - {id: 4, cat: Movies/DVD, desc: "Films: DVD5"} - - {id: 5, cat: Movies/DVD, desc: "Films: DVD9"} - - {id: 91, cat: Movies/HD, desc: "Films: RemuX"} - - {id: 89, cat: Movies/HD, desc: "Films: BD/BR Rip"} - - {id: 88, cat: Movies/BluRay, desc: "Films: Full BD/BR"} - - {id: 77, cat: Other, desc: "GPS: Cartes"} - - {id: 78, cat: Other, desc: "GPS: Radars"} - - {id: 79, cat: TV/Anime, desc: "Mangas: HD"} - - {id: 80, cat: TV/Anime, desc: "Mangas: HD VO"} - - {id: 81, cat: TV/Anime, desc: "Mangas: HD VOSTFR"} - - {id: 82, cat: TV/Anime, desc: "Mangas: DVDRIP"} - - {id: 83, cat: TV/Anime, desc: "Mangas: DVDRIP VO"} - - {id: 84, cat: TV/Anime, desc: "Mangas: DVDRIP VOSTFR"} - - {id: 85, cat: TV/Anime, desc: "Mangas: Web-DL"} - - {id: 86, cat: TV/Anime, desc: "Mangas: TV-RIP"} - - {id: 75, cat: Audio, desc: "Musique: Concert TVRip"} - - {id: 25, cat: Audio/MP3, desc: "Musique: Single MP3"} - - {id: 24, cat: Audio/Lossless, desc: "Musique: Single Flac"} - - {id: 22, cat: Audio/MP3, desc: "Musique: Album MP3"} - - {id: 23, cat: Audio/Lossless, desc: "Musique: Album Flac"} - - {id: 64, cat: Audio, desc: "Musique: Mégamix Maison"} - - {id: 58, cat: Audio, desc: "Musique: Concert"} - - {id: 61, cat: TV, desc: "Serie TV: Episode VOSTFR"} - - {id: 63, cat: TV, desc: "Serie TV: Episode VO"} - - {id: 12, cat: TV/Anime, desc: "Serie TV: Animation"} - - {id: 74, cat: TV, desc: "Serie TV: TVRip"} - - {id: 73, cat: TV/WEB-DL, desc: "Serie TV: WEB-DL"} - - {id: 7, cat: TV, desc: "Serie TV: Episode FR"} - - {id: 6, cat: TV, desc: "Serie TV: Saison FR"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: account-login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: form:contains("Erreur") - message: - selector: form - remove: table - test: - path: torrents-search.php - - search: - path: torrents-search.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - - rows: - selector: table.ttable_headinner > tbody > tr[class^="t-row"] - fields: - download: - selector: a[href^="torrents-details.php?id="] - attribute: href - filters: - - name: replace - args: ["torrents-details.php", "download.php"] - title: - selector: a[href^="torrents-details.php?id="] - category: - selector: a[href^="torrents.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="torrents-details.php?id="] - attribute: href - banner: - selector: img.rounded-img - attribute: src - size: - selector: td:nth-child(5) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - downloadvolumefactor: - case: - img[title="freeleech"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: 2fast4you + name: 2 Fast 4 You + language: fr-fr + type: private + encoding: UTF-8 + links: + - http://www.2f4y.me/ + + caps: + categorymappings: + - {id: 10, cat: TV/Anime, desc: "Animation: HD720P"} + - {id: 11, cat: TV/Anime, desc: "Animation: HD1080P"} + - {id: 56, cat: TV/Anime, desc: "Animation: DVDRip"} + - {id: 13, cat: TV/Anime, desc: "Animation: DVD"} + - {id: 18, cat: PC/0day, desc: "Applications: PC"} + - {id: 16, cat: PC/Games, desc: "Applications: Jeux"} + - {id: 19, cat: PC/Phone-Android, desc: "Applications: Android"} + - {id: 38, cat: PC/Phone-IOS, desc: "Applications: Mobile Phone"} + - {id: 17, cat: PC/0day, desc: "Applications: Autres"} + - {id: 67, cat: TV, desc: "Autres: Emission TV"} + - {id: 68, cat: TV/Sport, desc: "Autres: Sport"} + - {id: 40, cat: Other, desc: "Autres: Autres"} + - {id: 14, cat: TV/Documentary, desc: "Documentaires: DivX"} + - {id: 15, cat: TV/Documentary, desc: "Documentaires: HD"} + - {id: 76, cat: TV/Documentary, desc: "Documentaires: TVRip"} + - {id: 62, cat: Audio/Audiobook, desc: "E-Books: E-Books Audio"} + - {id: 50, cat: Books, desc: "E-Books: Manuel Français"} + - {id: 49, cat: Books, desc: "E-Books: Manuel Anglais"} + - {id: 36, cat: Books, desc: "E-Books: Livres Français"} + - {id: 53, cat: Books, desc: "E-Books: Livre Anglais"} + - {id: 52, cat: Books, desc: "E-Books: Revue - Journaux"} + - {id: 51, cat: Books, desc: "E-Books: BD"} + - {id: 66, cat: Movies, desc: "Films: VOSTFR"} + - {id: 71, cat: Movies/WEBDL, desc: "Films: WEB-DL"} + - {id: 65, cat: Movies, desc: "Films: VO"} + - {id: 72, cat: Movies/SD, desc: "Films: TVRip/HDTV"} + - {id: 70, cat: Movies/HD, desc: "Films: MHD X265"} + - {id: 57, cat: Movies/SD, desc: "Films: TS/CAM"} + - {id: 59, cat: Movies, desc: "Films: Spectacle"} + - {id: 55, cat: Movies/HD, desc: "Films: MHD 720P"} + - {id: 54, cat: Movies/HD, desc: "Films: MHD 1080P"} + - {id: 1, cat: Movies/HD, desc: "Films: HD720P"} + - {id: 2, cat: Movies/HD, desc: "Films: HD1080P"} + - {id: 90, cat: Movies/HD, desc: "Films: HD X265"} + - {id: 92, cat: Movies/HD, desc: "Films: 4K"} + - {id: 69, cat: Movies/3D, desc: "Films: Film 3D"} + - {id: 3, cat: Movies/DVD, desc: "Films: DVDRIP"} + - {id: 4, cat: Movies/DVD, desc: "Films: DVD5"} + - {id: 5, cat: Movies/DVD, desc: "Films: DVD9"} + - {id: 91, cat: Movies/HD, desc: "Films: RemuX"} + - {id: 89, cat: Movies/HD, desc: "Films: BD/BR Rip"} + - {id: 88, cat: Movies/BluRay, desc: "Films: Full BD/BR"} + - {id: 77, cat: Other, desc: "GPS: Cartes"} + - {id: 78, cat: Other, desc: "GPS: Radars"} + - {id: 79, cat: TV/Anime, desc: "Mangas: HD"} + - {id: 80, cat: TV/Anime, desc: "Mangas: HD VO"} + - {id: 81, cat: TV/Anime, desc: "Mangas: HD VOSTFR"} + - {id: 82, cat: TV/Anime, desc: "Mangas: DVDRIP"} + - {id: 83, cat: TV/Anime, desc: "Mangas: DVDRIP VO"} + - {id: 84, cat: TV/Anime, desc: "Mangas: DVDRIP VOSTFR"} + - {id: 85, cat: TV/Anime, desc: "Mangas: Web-DL"} + - {id: 86, cat: TV/Anime, desc: "Mangas: TV-RIP"} + - {id: 75, cat: Audio, desc: "Musique: Concert TVRip"} + - {id: 25, cat: Audio/MP3, desc: "Musique: Single MP3"} + - {id: 24, cat: Audio/Lossless, desc: "Musique: Single Flac"} + - {id: 22, cat: Audio/MP3, desc: "Musique: Album MP3"} + - {id: 23, cat: Audio/Lossless, desc: "Musique: Album Flac"} + - {id: 64, cat: Audio, desc: "Musique: Mégamix Maison"} + - {id: 58, cat: Audio, desc: "Musique: Concert"} + - {id: 61, cat: TV, desc: "Serie TV: Episode VOSTFR"} + - {id: 63, cat: TV, desc: "Serie TV: Episode VO"} + - {id: 12, cat: TV/Anime, desc: "Serie TV: Animation"} + - {id: 74, cat: TV, desc: "Serie TV: TVRip"} + - {id: 73, cat: TV/WEB-DL, desc: "Serie TV: WEB-DL"} + - {id: 7, cat: TV, desc: "Serie TV: Episode FR"} + - {id: 6, cat: TV, desc: "Serie TV: Saison FR"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: account-login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: form:contains("Erreur") + message: + selector: form + remove: table + test: + path: torrents-search.php + + search: + path: torrents-search.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + + rows: + selector: table.ttable_headinner > tbody > tr[class^="t-row"] + fields: + download: + selector: a[href^="torrents-details.php?id="] + attribute: href + filters: + - name: replace + args: ["torrents-details.php", "download.php"] + title: + selector: a[href^="torrents-details.php?id="] + category: + selector: a[href^="torrents.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="torrents-details.php?id="] + attribute: href + banner: + selector: img.rounded-img + attribute: src + size: + selector: td:nth-child(5) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + downloadvolumefactor: + case: + img[title="freeleech"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/3dtorrents.yml b/src/Jackett/Definitions/3dtorrents.yml index f5ccb4e0..c381652d 100644 --- a/src/Jackett/Definitions/3dtorrents.yml +++ b/src/Jackett/Definitions/3dtorrents.yml @@ -1,102 +1,102 @@ ---- - site: 3dtorrents - name: 3D Torrents - description: "3D Movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://www.3dtorrents.org/ - - caps: - categorymappings: - - {id: 14, cat: Movies, desc: "Movies XviD"} - - {id: 34, cat: Movies, desc: "Movies UltraHD"} - - {id: 15, cat: Movies, desc: "Movies DVD-R"} - - {id: 11, cat: Movies, desc: "Movies 720p"} - - {id: 13, cat: Movies, desc: "Movies 1080p"} - - {id: 16, cat: Movies, desc: "Movies 3DTV"} - - {id: 17, cat: Movies, desc: "Movies Blu-ray"} - - {id: 27, cat: Movies, desc: "Movies BD25 Encode"} - - {id: 33, cat: Movies, desc: "Movies BD9 AVCHD"} - - {id: 22, cat: Movies, desc: "Movies 2D to 3D Conv"} - - {id: 32, cat: Movies, desc: "Bluray MKV Remux"} - - {id: 23, cat: Movies, desc: "Movies Evo 3D"} - - {id: 21, cat: PC, desc: "3D Software"} - - {id: 2, cat: Audio, desc: "Music"} - - {id: 28, cat: XXX, desc: "Adult 720p"} - - {id: 29, cat: XXX, desc: "Adult 1080p"} - - {id: 30, cat: XXX, desc: "Adult Blu-ray"} - - {id: 31, cat: Other, desc: "Misc"} - - {id: 19, cat: Audio, desc: "Audio Packs"} - - modes: - search: [q] - - login: - path: index.php?page=login&returnto=index.php - method: form - form: form - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - captcha: - type: image - image: img.captcha - input: private_key - error: - - selector: span.errormsg - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: index.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - page: torrents - category: 0 - 3dformat: 0 - active: 1 - rows: - selector: table[cellspacing!="1"].lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) - fields: - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - title: - remove: span - selector: td:nth-child(2) - download: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: href - filters: - - name: replace - args: ["index.php?page=torrent-details&id=", "download.php?id="] - details: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: td:nth-last-child(4) - seeders: - selector: td:nth-last-child(3) - # leechers: - # selector: td:nth-last-child(2) - date: - selector: td:nth-last-child(5) - filters: - - name: dateparse - args: "02/01/2006" - downloadvolumefactor: - case: - img[title^="You get 50% off download count on this torrent"]: "0.5" - "*": "1" - uploadvolumefactor: - case: +--- + site: 3dtorrents + name: 3D Torrents + description: "3D Movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://www.3dtorrents.org/ + + caps: + categorymappings: + - {id: 14, cat: Movies, desc: "Movies XviD"} + - {id: 34, cat: Movies, desc: "Movies UltraHD"} + - {id: 15, cat: Movies, desc: "Movies DVD-R"} + - {id: 11, cat: Movies, desc: "Movies 720p"} + - {id: 13, cat: Movies, desc: "Movies 1080p"} + - {id: 16, cat: Movies, desc: "Movies 3DTV"} + - {id: 17, cat: Movies, desc: "Movies Blu-ray"} + - {id: 27, cat: Movies, desc: "Movies BD25 Encode"} + - {id: 33, cat: Movies, desc: "Movies BD9 AVCHD"} + - {id: 22, cat: Movies, desc: "Movies 2D to 3D Conv"} + - {id: 32, cat: Movies, desc: "Bluray MKV Remux"} + - {id: 23, cat: Movies, desc: "Movies Evo 3D"} + - {id: 21, cat: PC, desc: "3D Software"} + - {id: 2, cat: Audio, desc: "Music"} + - {id: 28, cat: XXX, desc: "Adult 720p"} + - {id: 29, cat: XXX, desc: "Adult 1080p"} + - {id: 30, cat: XXX, desc: "Adult Blu-ray"} + - {id: 31, cat: Other, desc: "Misc"} + - {id: 19, cat: Audio, desc: "Audio Packs"} + + modes: + search: [q] + + login: + path: index.php?page=login&returnto=index.php + method: form + form: form + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + captcha: + type: image + image: img.captcha + input: private_key + error: + - selector: span.errormsg + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: index.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + page: torrents + category: 0 + 3dformat: 0 + active: 1 + rows: + selector: table[cellspacing!="1"].lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) + fields: + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + title: + remove: span + selector: td:nth-child(2) + download: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: href + filters: + - name: replace + args: ["index.php?page=torrent-details&id=", "download.php?id="] + details: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: td:nth-last-child(4) + seeders: + selector: td:nth-last-child(3) + # leechers: + # selector: td:nth-last-child(2) + date: + selector: td:nth-last-child(5) + filters: + - name: dateparse + args: "02/01/2006" + downloadvolumefactor: + case: + img[title^="You get 50% off download count on this torrent"]: "0.5" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/aox.yml b/src/Jackett/Definitions/aox.yml index 56c87954..149ca5f1 100644 --- a/src/Jackett/Definitions/aox.yml +++ b/src/Jackett/Definitions/aox.yml @@ -1,124 +1,124 @@ ---- - site: aox - name: AOX - language: en-us - type: private - encoding: UTF-8 - links: - - https://aox.to/ - - caps: - categorymappings: - # Japanese - - {id: 1, cat: Movies, desc: "jMovies"} - - {id: 2, cat: TV, desc: "TV Shows"} - - {id: 3, cat: TV/Other, desc: "Variety Shows"} - - # Korean - - {id: 6, cat: Movies, desc: "kMovies"} - - {id: 4, cat: TV, desc: "TV Shows"} - - {id: 14, cat: TV/Other, desc: "Variety Shows"} - - # Chinese - - {id: 8, cat: Movies, desc: "cMovies"} - - {id: 9, cat: TV, desc: "TV Shows"} - - {id: 13, cat: TV/Other, desc: "Variety Shows"} - - # Adult - - {id: 13, cat: XXX, desc: "Adult"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: index.php?page=login - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - error: - - selector: body[onLoad^="makeAlert('"] - message: - selector: body[onLoad^="makeAlert('"] - attribute: onLoad - filters: - - name: replace - args: ["makeAlert('Error' , '", ""] - - name: replace - args: ["');", ""] - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: index.php - inputs: - search: "{{ .Query.Keywords }}" - page: "torrents" - category: "{{range .Categories}}{{.}};{{end}}" - options: "0" - active: "0" - rows: - selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) - fields: - download: - selector: a[href^="index.php?page=downloadcheck&id="] - attribute: href - title: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - banner: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: onmouseover - filters: - - name: regexp - args: "src=(.*?) " - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - details: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: td:nth-child(12) - date: - selector: td:nth-child(7) - filters: - - name: append - args: " +01:00" - - name: dateparse - args: "02/01/2006 -07:00" - grabs: - selector: td:nth-child(10) - filters: - - name: replace - args: ["---", "0"] - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - downloadvolumefactor: - case: - img[alt="Full Star 100% Free"]: "0" - img[alt="Half Star 50% Free"]: "0.5" - img[alt="Empty Star 25% Free"]: "0.75" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(2) - remove: a - description|append: - selector: td:nth-child(3) > img - attribute: title - filters: - - name: prepend - args: "<br>Language: " - +--- + site: aox + name: AOX + language: en-us + type: private + encoding: UTF-8 + links: + - https://aox.to/ + + caps: + categorymappings: + # Japanese + - {id: 1, cat: Movies, desc: "jMovies"} + - {id: 2, cat: TV, desc: "TV Shows"} + - {id: 3, cat: TV/Other, desc: "Variety Shows"} + + # Korean + - {id: 6, cat: Movies, desc: "kMovies"} + - {id: 4, cat: TV, desc: "TV Shows"} + - {id: 14, cat: TV/Other, desc: "Variety Shows"} + + # Chinese + - {id: 8, cat: Movies, desc: "cMovies"} + - {id: 9, cat: TV, desc: "TV Shows"} + - {id: 13, cat: TV/Other, desc: "Variety Shows"} + + # Adult + - {id: 13, cat: XXX, desc: "Adult"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + error: + - selector: body[onLoad^="makeAlert('"] + message: + selector: body[onLoad^="makeAlert('"] + attribute: onLoad + filters: + - name: replace + args: ["makeAlert('Error' , '", ""] + - name: replace + args: ["');", ""] + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: index.php + inputs: + search: "{{ .Query.Keywords }}" + page: "torrents" + category: "{{range .Categories}}{{.}};{{end}}" + options: "0" + active: "0" + rows: + selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) + fields: + download: + selector: a[href^="index.php?page=downloadcheck&id="] + attribute: href + title: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + banner: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: onmouseover + filters: + - name: regexp + args: "src=(.*?) " + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + details: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: td:nth-child(12) + date: + selector: td:nth-child(7) + filters: + - name: append + args: " +01:00" + - name: dateparse + args: "02/01/2006 -07:00" + grabs: + selector: td:nth-child(10) + filters: + - name: replace + args: ["---", "0"] + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + downloadvolumefactor: + case: + img[alt="Full Star 100% Free"]: "0" + img[alt="Half Star 50% Free"]: "0.5" + img[alt="Empty Star 25% Free"]: "0.75" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(2) + remove: a + description|append: + selector: td:nth-child(3) > img + attribute: title + filters: + - name: prepend + args: "<br>Language: " + \ No newline at end of file diff --git a/src/Jackett/Definitions/apollo.yml b/src/Jackett/Definitions/apollo.yml index 88bf3a4c..80a76cf4 100644 --- a/src/Jackett/Definitions/apollo.yml +++ b/src/Jackett/Definitions/apollo.yml @@ -1,95 +1,95 @@ ---- - site: apollo - name: Apollo - description: "A music tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://apollo.rip - - caps: - categorymappings: - - {id: 1, cat: Audio, desc: "Music"} - - {id: 2, cat: PC, desc: "Applications"} - - {id: 3, cat: Books, desc: "E-Books"} - - {id: 4, cat: Audio/Audiobook, desc: "Audiobooks"} - - {id: 5, cat: Movies, desc: "E-Learning Videos"} - - {id: 6, cat: TV, desc: "Comedy"} - - {id: 7, cat: Books/Comics, desc: "Comics"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: 1 - login: "Log in" - error: - - selector: form#loginform > span.warning - test: - path: torrents.php - - ratio: - path: torrents.php - selector: li#stats_ratio > span - - search: - path: torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: time - order_way: desc - action: basic - searchsubmit: 1 - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - description: - selector: div.group_info - remove: span - title: - selector: div.group_info - remove: span, div.tags - category: - selector: td.cats_col - case: - div.cats_music: 1 - div.cats_applications: 2 - div.cats_ebooks: 3 - div.cats_audiobooks: 4 - div.cats_elearningvideos: 5 - div.cats_comedy: 6 - div.cats_comics: 7 - comments: - selector: a[href^="torrents.php?id="] - attribute: href - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(4) - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - ":root div.alertbar:contains(\"freeleech\")": "0" - ":root div.alertbar:contains(\"FREELEECH\")": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: apollo + name: Apollo + description: "A music tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://apollo.rip + + caps: + categorymappings: + - {id: 1, cat: Audio, desc: "Music"} + - {id: 2, cat: PC, desc: "Applications"} + - {id: 3, cat: Books, desc: "E-Books"} + - {id: 4, cat: Audio/Audiobook, desc: "Audiobooks"} + - {id: 5, cat: Movies, desc: "E-Learning Videos"} + - {id: 6, cat: TV, desc: "Comedy"} + - {id: 7, cat: Books/Comics, desc: "Comics"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: 1 + login: "Log in" + error: + - selector: form#loginform > span.warning + test: + path: torrents.php + + ratio: + path: torrents.php + selector: li#stats_ratio > span + + search: + path: torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: time + order_way: desc + action: basic + searchsubmit: 1 + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + description: + selector: div.group_info + remove: span + title: + selector: div.group_info + remove: span, div.tags + category: + selector: td.cats_col + case: + div.cats_music: 1 + div.cats_applications: 2 + div.cats_ebooks: 3 + div.cats_audiobooks: 4 + div.cats_elearningvideos: 5 + div.cats_comedy: 6 + div.cats_comics: 7 + comments: + selector: a[href^="torrents.php?id="] + attribute: href + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(4) + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + ":root div.alertbar:contains(\"freeleech\")": "0" + ":root div.alertbar:contains(\"FREELEECH\")": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/arabafenice.yml b/src/Jackett/Definitions/arabafenice.yml index 75a532d5..5f9e7e88 100644 --- a/src/Jackett/Definitions/arabafenice.yml +++ b/src/Jackett/Definitions/arabafenice.yml @@ -1,164 +1,164 @@ ---- - site: arabafenice - name: ArabaFenice - language: it-it - type: private - encoding: UTF-8 - links: - - http://www.arabafenice.me/ - - caps: - categorymappings: - # HRS - - {id: 34, cat: Movies/HD, desc: "1080p HRS x264"} - - {id: 47, cat: Movies/HD, desc: "2160p 4k UltraHD HRS"} - - {id: 35, cat: TV, desc: "Serie TV HRS"} - - {id: 36, cat: Movies/SD, desc: "DVDRip HRS"} - - {id: 41, cat: Movies/SD, desc: "BDRip 576p HRS"} - - {id: 39, cat: Movies/HD, desc: "1080p HRS x265 HEVC"} - - # VIDEO - - {id: 1, cat: Movies, desc: "News Cinema"} - - {id: 2, cat: Movies/SD, desc: "BD-DVDRip"} - - {id: 3, cat: Movies/DVD, desc: "DVD 5"} - - {id: 5, cat: Movies/DVD, desc: "DVD 9"} - - {id: 6, cat: Movies/BluRay, desc: "BluRay Full"} - - {id: 4, cat: Movies/HD, desc: "1080p 3D x264"} - - {id: 7, cat: Movies/HD, desc: "1080p x264"} - - {id: 46, cat: Movies/HD, desc: "1080p Video Untouch"} - - {id: 44, cat: Movies/HD, desc: "1080p x265"} - - {id: 9, cat: TV/Anime, desc: "Cartoons"} - - {id: 8, cat: TV/Anime, desc: "720p x264"} - - {id: 12, cat: TV, desc: "He concluded seasons"} - - {id: 13, cat: TV, desc: "Seasons in Onda"} - - {id: 14, cat: TV, desc: "TV Show"} - - {id: 42, cat: TV, desc: "Serie Tv Sub Ita"} - - {id: 15, cat: TV/Documentary, desc: "documentaries"} - - {id: 33, cat: TV, desc: "mp4"} - - {id: 40, cat: TV/HD, desc: "2160p 4K UltraHD"} - - {id: 38, cat: XXX, desc: "xXx"} - - {id: 43, cat: Other, desc: "Arabic for social"} - - # MUSICA - - {id: 17, cat: Audio, desc: "Italian music"} - - {id: 45, cat: Audio, desc: "Discography"} - - {id: 18, cat: Audio, desc: "MusicaInternazionale"} - - {id: 19, cat: Audio, desc: "Compilation"} - - # PDF - - {id: 21, cat: Books, desc: "Ebook"} - - {id: 22, cat: Books/Comics, desc: "Comics"} - - {id: 23, cat: Books, desc: "Newsstand"} - - # GAMES - - {id: 25, cat: Console/PS4, desc: "Sony Games"} - - {id: 26, cat: Console/Xbox, desc: "XboX Games"} - - {id: 27, cat: Console/Other, desc: "Nintendo Games"} - - {id: 28, cat: PC/Games, desc: "PC Games"} - - # SOFTWARE - - {id: 30, cat: PC/ISO, desc: "Windows APP"} - - {id: 31, cat: PC/Phone-IOS, desc: "Apple APP"} - - {id: 32, cat: PC/Phone-Android, desc: "Android APP"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: index.php?page=login - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - error: - - selector: body[onLoad^="makeAlert('"] - message: - selector: body[onLoad^="makeAlert('"] - attribute: onLoad - filters: - - name: replace - args: ["makeAlert('Error' , '", ""] - - name: replace - args: ["');", ""] - test: - path: index.php - - download: - before: - path: "thanks.php" - method: "post" - inputs: - infohash: "{{ .DownloadUri.Query.id }}" - thanks: "1" - rndval: "1487013827343" - selector: a[href^="download.php?id="] - - search: - path: index.php - inputs: - search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" - page: "torrents" - category: "{{range .Categories}}{{.}};{{end}}" - options: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - active: "0" - rows: - selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) - fields: - download: - selector: a[href^="index.php?page=downloadcheck&id="] - attribute: href - title: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - banner: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: onmouseover - filters: - - name: regexp - args: "src=(.*?) " - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - details: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: td:nth-last-child(4) - date: - selector: td:nth-last-child(9) - filters: - - name: append - args: " +01:00" - - name: dateparse - args: "02/01/2006 -07:00" - grabs: - selector: td:nth-last-child(6) - filters: - - name: replace - args: ["---", "0"] - seeders: - selector: td:nth-last-child(8) - leechers: - selector: td:nth-last-child(7) - downloadvolumefactor: - case: - img[alt="Gold 100% Free"]: "0" - img[alt="Silver 50% Free"]: "0.5" - img[alt="Bronze 25% Free"]: "0.75" - "*": "1" - uploadvolumefactor: - case: - img[alt="2x Upload Multiplier"]: "2" - img[alt="3x Upload Multiplier"]: "3" - img[alt="4x Upload Multiplier"]: "4" - img[alt="5x Upload Multiplier"]: "5" - img[alt="6x Upload Multiplier"]: "6" - img[alt="7x Upload Multiplier"]: "7" - img[alt="8x Upload Multiplier"]: "8" - img[alt="9x Upload Multiplier"]: "9" - img[alt="10x Upload Multiplier"]: "10" - "*": "1" +--- + site: arabafenice + name: ArabaFenice + language: it-it + type: private + encoding: UTF-8 + links: + - http://www.arabafenice.me/ + + caps: + categorymappings: + # HRS + - {id: 34, cat: Movies/HD, desc: "1080p HRS x264"} + - {id: 47, cat: Movies/HD, desc: "2160p 4k UltraHD HRS"} + - {id: 35, cat: TV, desc: "Serie TV HRS"} + - {id: 36, cat: Movies/SD, desc: "DVDRip HRS"} + - {id: 41, cat: Movies/SD, desc: "BDRip 576p HRS"} + - {id: 39, cat: Movies/HD, desc: "1080p HRS x265 HEVC"} + + # VIDEO + - {id: 1, cat: Movies, desc: "News Cinema"} + - {id: 2, cat: Movies/SD, desc: "BD-DVDRip"} + - {id: 3, cat: Movies/DVD, desc: "DVD 5"} + - {id: 5, cat: Movies/DVD, desc: "DVD 9"} + - {id: 6, cat: Movies/BluRay, desc: "BluRay Full"} + - {id: 4, cat: Movies/HD, desc: "1080p 3D x264"} + - {id: 7, cat: Movies/HD, desc: "1080p x264"} + - {id: 46, cat: Movies/HD, desc: "1080p Video Untouch"} + - {id: 44, cat: Movies/HD, desc: "1080p x265"} + - {id: 9, cat: TV/Anime, desc: "Cartoons"} + - {id: 8, cat: TV/Anime, desc: "720p x264"} + - {id: 12, cat: TV, desc: "He concluded seasons"} + - {id: 13, cat: TV, desc: "Seasons in Onda"} + - {id: 14, cat: TV, desc: "TV Show"} + - {id: 42, cat: TV, desc: "Serie Tv Sub Ita"} + - {id: 15, cat: TV/Documentary, desc: "documentaries"} + - {id: 33, cat: TV, desc: "mp4"} + - {id: 40, cat: TV/HD, desc: "2160p 4K UltraHD"} + - {id: 38, cat: XXX, desc: "xXx"} + - {id: 43, cat: Other, desc: "Arabic for social"} + + # MUSICA + - {id: 17, cat: Audio, desc: "Italian music"} + - {id: 45, cat: Audio, desc: "Discography"} + - {id: 18, cat: Audio, desc: "MusicaInternazionale"} + - {id: 19, cat: Audio, desc: "Compilation"} + + # PDF + - {id: 21, cat: Books, desc: "Ebook"} + - {id: 22, cat: Books/Comics, desc: "Comics"} + - {id: 23, cat: Books, desc: "Newsstand"} + + # GAMES + - {id: 25, cat: Console/PS4, desc: "Sony Games"} + - {id: 26, cat: Console/Xbox, desc: "XboX Games"} + - {id: 27, cat: Console/Other, desc: "Nintendo Games"} + - {id: 28, cat: PC/Games, desc: "PC Games"} + + # SOFTWARE + - {id: 30, cat: PC/ISO, desc: "Windows APP"} + - {id: 31, cat: PC/Phone-IOS, desc: "Apple APP"} + - {id: 32, cat: PC/Phone-Android, desc: "Android APP"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + error: + - selector: body[onLoad^="makeAlert('"] + message: + selector: body[onLoad^="makeAlert('"] + attribute: onLoad + filters: + - name: replace + args: ["makeAlert('Error' , '", ""] + - name: replace + args: ["');", ""] + test: + path: index.php + + download: + before: + path: "thanks.php" + method: "post" + inputs: + infohash: "{{ .DownloadUri.Query.id }}" + thanks: "1" + rndval: "1487013827343" + selector: a[href^="download.php?id="] + + search: + path: index.php + inputs: + search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" + page: "torrents" + category: "{{range .Categories}}{{.}};{{end}}" + options: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + active: "0" + rows: + selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) + fields: + download: + selector: a[href^="index.php?page=downloadcheck&id="] + attribute: href + title: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + banner: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: onmouseover + filters: + - name: regexp + args: "src=(.*?) " + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + details: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: td:nth-last-child(4) + date: + selector: td:nth-last-child(9) + filters: + - name: append + args: " +01:00" + - name: dateparse + args: "02/01/2006 -07:00" + grabs: + selector: td:nth-last-child(6) + filters: + - name: replace + args: ["---", "0"] + seeders: + selector: td:nth-last-child(8) + leechers: + selector: td:nth-last-child(7) + downloadvolumefactor: + case: + img[alt="Gold 100% Free"]: "0" + img[alt="Silver 50% Free"]: "0.5" + img[alt="Bronze 25% Free"]: "0.75" + "*": "1" + uploadvolumefactor: + case: + img[alt="2x Upload Multiplier"]: "2" + img[alt="3x Upload Multiplier"]: "3" + img[alt="4x Upload Multiplier"]: "4" + img[alt="5x Upload Multiplier"]: "5" + img[alt="6x Upload Multiplier"]: "6" + img[alt="7x Upload Multiplier"]: "7" + img[alt="8x Upload Multiplier"]: "8" + img[alt="9x Upload Multiplier"]: "9" + img[alt="10x Upload Multiplier"]: "10" + "*": "1" diff --git a/src/Jackett/Definitions/audiobooktorrents.yml b/src/Jackett/Definitions/audiobooktorrents.yml index 5f9f8f78..b7d1d28f 100644 --- a/src/Jackett/Definitions/audiobooktorrents.yml +++ b/src/Jackett/Definitions/audiobooktorrents.yml @@ -1,136 +1,136 @@ ---- - site: audiobooktorrents - name: Audiobook Torrents - language: en-us - type: private - encoding: UTF-8 - links: - - https://abtorrents.me - - caps: - categorymappings: - - {id: 10, cat: Audio/Audiobook, desc: "Adventure"} - - {id: 20, cat: Audio/Audiobook, desc: "Biographies & Memoirs"} - - {id: 30, cat: Audio/Audiobook, desc: "Business "} - - {id: 40, cat: Audio/Audiobook, desc: "Childrens"} - - {id: 50, cat: Audio/Audiobook, desc: "Comedy"} - - {id: 60, cat: Audio/Audiobook, desc: "Comics"} - - {id: 70, cat: Audio/Audiobook, desc: "Computers "} - - {id: 80, cat: Audio/Audiobook, desc: "Erotica"} - - {id: 90, cat: Audio/Audiobook, desc: "Fantasy-General"} - - {id: 100, cat: Audio/Audiobook, desc: "Fantasy-Youth"} - - {id: 110, cat: Audio/Audiobook, desc: "Files"} - - {id: 120, cat: Audio/Audiobook, desc: "Foreign Language"} - - {id: 130, cat: Audio/Audiobook, desc: "General Fiction"} - - {id: 140, cat: Audio/Audiobook, desc: "Historical Fiction"} - - {id: 150, cat: Audio/Audiobook, desc: "History"} - - {id: 160, cat: Audio/Audiobook, desc: "Horror"} - - {id: 170, cat: Audio/Audiobook, desc: "Literature "} - - {id: 180, cat: Audio/Audiobook, desc: "Mystery "} - - {id: 190, cat: Audio/Audiobook, desc: "Non-Fiction"} - - {id: 200, cat: Audio/Audiobook, desc: "Radio Drama"} - - {id: 210, cat: Audio/Audiobook, desc: "Romance"} - - {id: 235, cat: Audio/Audiobook, desc: "Sci-Fi Apocalypse"} - - {id: 220, cat: Audio/Audiobook, desc: "Science"} - - {id: 230, cat: Audio/Audiobook, desc: "Science Fiction "} - - {id: 240, cat: Audio/Audiobook, desc: "Self Improvement"} - - {id: 250, cat: Audio/Audiobook, desc: "Suspense"} - - {id: 260, cat: Audio/Audiobook, desc: "Talk Radio"} - - {id: 245, cat: Audio/Audiobook, desc: "Thriller"} - - {id: 270, cat: Audio/Audiobook, desc: "Urban Fantasy"} - - {id: 280, cat: Audio/Audiobook, desc: "Western"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - use_ssl: "1" - perm_ssl: "1" - submitme: "X" - error: - - selector: td.embedded:has(h2:contains("Oops")) - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Keywords }}" - searchin: "title" - incldead: "1" - rows: - selector: tr.browse_color, tr.freeleech_color, tr[id^="kdescr"] - after: 1 - fields: - banner: - selector: a[href^="details.php?id="][onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: src=\'(.*?)\' - title: - selector: a[href^="details.php?id="][onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: Tip\('<b>(.*?)</b> - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="][onmouseover] - attribute: href - download: - selector: a[href^="download.php"] - attribute: href - files: - selector: td:nth-child(4) - size: - selector: td:nth-child(7) - grabs: - selector: td:nth-child(8) - filters: - - name: regexp - args: ([\d,]+) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - date: - selector: td:nth-child(6) - downloadvolumefactor: - case: - "a.info > b:contains(\"[FREE]\")": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: a[href^="details.php?id="][onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: <br /><b>(.*?)</b><br /> - description: - selector: td:nth-child(2) > i - optional: true - filters: - - name: prepend - args: "{{ .Result.description }}<br>\n" - description: - selector: td[colspan=13] - filters: - - name: prepend +--- + site: audiobooktorrents + name: Audiobook Torrents + language: en-us + type: private + encoding: UTF-8 + links: + - https://abtorrents.me + + caps: + categorymappings: + - {id: 10, cat: Audio/Audiobook, desc: "Adventure"} + - {id: 20, cat: Audio/Audiobook, desc: "Biographies & Memoirs"} + - {id: 30, cat: Audio/Audiobook, desc: "Business "} + - {id: 40, cat: Audio/Audiobook, desc: "Childrens"} + - {id: 50, cat: Audio/Audiobook, desc: "Comedy"} + - {id: 60, cat: Audio/Audiobook, desc: "Comics"} + - {id: 70, cat: Audio/Audiobook, desc: "Computers "} + - {id: 80, cat: Audio/Audiobook, desc: "Erotica"} + - {id: 90, cat: Audio/Audiobook, desc: "Fantasy-General"} + - {id: 100, cat: Audio/Audiobook, desc: "Fantasy-Youth"} + - {id: 110, cat: Audio/Audiobook, desc: "Files"} + - {id: 120, cat: Audio/Audiobook, desc: "Foreign Language"} + - {id: 130, cat: Audio/Audiobook, desc: "General Fiction"} + - {id: 140, cat: Audio/Audiobook, desc: "Historical Fiction"} + - {id: 150, cat: Audio/Audiobook, desc: "History"} + - {id: 160, cat: Audio/Audiobook, desc: "Horror"} + - {id: 170, cat: Audio/Audiobook, desc: "Literature "} + - {id: 180, cat: Audio/Audiobook, desc: "Mystery "} + - {id: 190, cat: Audio/Audiobook, desc: "Non-Fiction"} + - {id: 200, cat: Audio/Audiobook, desc: "Radio Drama"} + - {id: 210, cat: Audio/Audiobook, desc: "Romance"} + - {id: 235, cat: Audio/Audiobook, desc: "Sci-Fi Apocalypse"} + - {id: 220, cat: Audio/Audiobook, desc: "Science"} + - {id: 230, cat: Audio/Audiobook, desc: "Science Fiction "} + - {id: 240, cat: Audio/Audiobook, desc: "Self Improvement"} + - {id: 250, cat: Audio/Audiobook, desc: "Suspense"} + - {id: 260, cat: Audio/Audiobook, desc: "Talk Radio"} + - {id: 245, cat: Audio/Audiobook, desc: "Thriller"} + - {id: 270, cat: Audio/Audiobook, desc: "Urban Fantasy"} + - {id: 280, cat: Audio/Audiobook, desc: "Western"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + use_ssl: "1" + perm_ssl: "1" + submitme: "X" + error: + - selector: td.embedded:has(h2:contains("Oops")) + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Keywords }}" + searchin: "title" + incldead: "1" + rows: + selector: tr.browse_color, tr.freeleech_color, tr[id^="kdescr"] + after: 1 + fields: + banner: + selector: a[href^="details.php?id="][onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: src=\'(.*?)\' + title: + selector: a[href^="details.php?id="][onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: Tip\('<b>(.*?)</b> + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="][onmouseover] + attribute: href + download: + selector: a[href^="download.php"] + attribute: href + files: + selector: td:nth-child(4) + size: + selector: td:nth-child(7) + grabs: + selector: td:nth-child(8) + filters: + - name: regexp + args: ([\d,]+) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + date: + selector: td:nth-child(6) + downloadvolumefactor: + case: + "a.info > b:contains(\"[FREE]\")": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: a[href^="details.php?id="][onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: <br /><b>(.*?)</b><br /> + description: + selector: td:nth-child(2) > i + optional: true + filters: + - name: prepend + args: "{{ .Result.description }}<br>\n" + description: + selector: td[colspan=13] + filters: + - name: prepend args: "{{ .Result.description }}<br>\n" \ No newline at end of file diff --git a/src/Jackett/Definitions/bigtorrent.yml b/src/Jackett/Definitions/bigtorrent.yml index 9072de84..c6a463b4 100644 --- a/src/Jackett/Definitions/bigtorrent.yml +++ b/src/Jackett/Definitions/bigtorrent.yml @@ -1,97 +1,97 @@ ---- - site: bigtorrent - name: BIGTorrent - description: "ratio-free Hungarian tracker" - language: hu - type: private - encoding: UTF-8 - links: - - http://www.bigtorrent.eu/ - - caps: - categorymappings: - - {id: 24533, cat: Movies/3D, desc: "3D"} - - {id: 47, cat: Other, desc: "Other"} - - {id: 24541, cat: Movies/DVD, desc: "Film DVD English"} - - {id: 24540, cat: Movies/DVD, desc: "Film DVD Hungarian"} - - {id: 24539, cat: Movies/HD, desc: "Film HD English"} - - {id: 24538, cat: Movies/HD, desc: "Film HD Hungarian"} - - {id: 24537, cat: Movies/SD, desc: "Film SD English"} - - {id: 24536, cat: Movies/SD, desc: "Film SD Hungarian"} - - {id: 69, cat: PC/Games, desc: "Games ISO"} - - {id: 67, cat: PC/Games, desc: "Games Rip"} - - {id: 24534, cat: Audio/Audiobook, desc: "Audiobooks"} - - {id: 65, cat: Other, desc: "Picture"} - - {id: 64, cat: Other, desc: "Video"} - - {id: 68, cat: Console/Xbox360, desc: "Video Game Console"} - - {id: 63, cat: Books, desc: "English Books"} - - {id: 62, cat: Books, desc: "Hungarian Books"} - - {id: 74, cat: Audio/Lossless, desc: "Lossless"} - - {id: 56, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 57, cat: PC, desc: "Programs"} - - {id: 24545, cat: TV/HD, desc: "English HD Series"} - - {id: 24544, cat: TV/HD, desc: "Hungarian HD Series"} - - {id: 24543, cat: TV/SD, desc: "English SD Series"} - - {id: 24542, cat: TV/SD, desc: "Hungarian SD Series"} - - {id: 24535, cat: XXX, desc: "XXX"} - - {id: 59, cat: Audio, desc: "Music"} - - {id: 58, cat: Audio, desc: "Hungarian Music"} - - modes: - search: [q] - - login: - path: /login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - sent: "yes" - returnto: "/" - error: - - selector: table:contains("Login failed!") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table#torrent_table > tbody > tr:has(a[href^="browse.php?cat="]) - fields: - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - title: - selector: td:nth-child(2) a - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - size: - selector: td:nth-child(7) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - date: - selector: td:nth-child(4) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: bigtorrent + name: BIGTorrent + description: "ratio-free Hungarian tracker" + language: hu + type: private + encoding: UTF-8 + links: + - http://www.bigtorrent.eu/ + + caps: + categorymappings: + - {id: 24533, cat: Movies/3D, desc: "3D"} + - {id: 47, cat: Other, desc: "Other"} + - {id: 24541, cat: Movies/DVD, desc: "Film DVD English"} + - {id: 24540, cat: Movies/DVD, desc: "Film DVD Hungarian"} + - {id: 24539, cat: Movies/HD, desc: "Film HD English"} + - {id: 24538, cat: Movies/HD, desc: "Film HD Hungarian"} + - {id: 24537, cat: Movies/SD, desc: "Film SD English"} + - {id: 24536, cat: Movies/SD, desc: "Film SD Hungarian"} + - {id: 69, cat: PC/Games, desc: "Games ISO"} + - {id: 67, cat: PC/Games, desc: "Games Rip"} + - {id: 24534, cat: Audio/Audiobook, desc: "Audiobooks"} + - {id: 65, cat: Other, desc: "Picture"} + - {id: 64, cat: Other, desc: "Video"} + - {id: 68, cat: Console/Xbox360, desc: "Video Game Console"} + - {id: 63, cat: Books, desc: "English Books"} + - {id: 62, cat: Books, desc: "Hungarian Books"} + - {id: 74, cat: Audio/Lossless, desc: "Lossless"} + - {id: 56, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 57, cat: PC, desc: "Programs"} + - {id: 24545, cat: TV/HD, desc: "English HD Series"} + - {id: 24544, cat: TV/HD, desc: "Hungarian HD Series"} + - {id: 24543, cat: TV/SD, desc: "English SD Series"} + - {id: 24542, cat: TV/SD, desc: "Hungarian SD Series"} + - {id: 24535, cat: XXX, desc: "XXX"} + - {id: 59, cat: Audio, desc: "Music"} + - {id: 58, cat: Audio, desc: "Hungarian Music"} + + modes: + search: [q] + + login: + path: /login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + sent: "yes" + returnto: "/" + error: + - selector: table:contains("Login failed!") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table#torrent_table > tbody > tr:has(a[href^="browse.php?cat="]) + fields: + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + title: + selector: td:nth-child(2) a + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + size: + selector: td:nth-child(7) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + date: + selector: td:nth-child(4) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/bitspyder.yml b/src/Jackett/Definitions/bitspyder.yml index 4594b9a5..4dd210d6 100755 --- a/src/Jackett/Definitions/bitspyder.yml +++ b/src/Jackett/Definitions/bitspyder.yml @@ -1,133 +1,133 @@ ---- - site: bitspyder - name: Bitspyder - language: en-us - type: private - encoding: windows-1252 - links: - - http://bitspyder.net/ - - caps: - categorymappings: - - {id: 61, cat: Books, desc: "3D"} - - {id: 69, cat: Books, desc: "Anim|GFX"} - - {id: 56, cat: Books, desc: "Art"} - - {id: 40, cat: Audio/Audiobook, desc: "Audio Books"} - - {id: 55, cat: Books, desc: "Business"} - - {id: 46, cat: Books, desc: "Career"} - - {id: 2, cat: Books, desc: "CBTs"} - - {id: 39, cat: Books, desc: "Cert QA"} - - {id: 63, cat: Books, desc: "College"} - - {id: 53, cat: Books, desc: "Cooking"} - - {id: 42, cat: Books, desc: "Documentary"} - - {id: 37, cat: Books, desc: "e-Books"} - - {id: 65, cat: Books, desc: "Engineering"} - - {id: 54, cat: Books, desc: "Health-Fitness"} - - {id: 64, cat: Books, desc: "Kids"} - - {id: 47, cat: Books, desc: "Languages"} - - {id: 49, cat: Books, desc: "Linux CBTs"} - - {id: 43, cat: Books, desc: "Lynda.com"} - - {id: 57, cat: Books/Magazines, desc: "Magazines"} - - {id: 71, cat: Books, desc: "Magic"} - - {id: 60, cat: Books, desc: "Medical"} - - {id: 44, cat: Books, desc: "Misc Learning"} - - {id: 51, cat: Books, desc: "Music Learning"} - - {id: 41, cat: Books, desc: "Others"} - - {id: 52, cat: Books, desc: "Photography"} - - {id: 35, cat: Books, desc: "PPT 'n Docs"} - - {id: 38, cat: Books, desc: "Religion"} - - {id: 68, cat: Books, desc: "Self Growth"} - - {id: 72, cat: Books, desc: "Templates"} - - {id: 58, cat: Books, desc: "Total Training"} - - {id: 45, cat: Books, desc: "Trainsignal"} - - {id: 59, cat: Books, desc: "VTC"} - - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: processid.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.msg_info > font > b - test: - path: /browse.php - - search: - path: /browse.php - method: post - inputs: - search: "{{ .Query.Keywords }}" - incldead: "1" - rows: - selector: table > tbody > tr[class] - filters: - - name: andmatch - fields: - # there are two styles, we support both - title: - selector: a[href^="details.php?id="] - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php/"] - - name: replace - args: ["&hit=1", "/dummy.torrent"] - size: - selector: td.rowcol:nth-child(6):has(br), font:contains("Size:") + font - files: - selector: a[href*="&filelist=1"] - grabs: - selector: td.rowcol:nth-child(7):has(br) - filters: - - name: regexp - args: ([\d,]+) - seeders: - selector: td.rowcol:nth-last-child(3) - leechers: - selector: td.rowcol:nth-last-child(2) - date|optional|1: - selector: font[color="5F5F5F"] - filters: - - name: split - args: [" (", 0] - - name: replace - args: ["\xA0", " "] - - name: append - args: " +00:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - date|optional|2: - selector: a[title^="Upploaded at"] - attribute: title - filters: - - name: replace - args: ["Upploaded at - ", ""] - - name: append - args: " +00:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description|optional: - selector: font[color="#990000"] +--- + site: bitspyder + name: Bitspyder + language: en-us + type: private + encoding: windows-1252 + links: + - http://bitspyder.net/ + + caps: + categorymappings: + - {id: 61, cat: Books, desc: "3D"} + - {id: 69, cat: Books, desc: "Anim|GFX"} + - {id: 56, cat: Books, desc: "Art"} + - {id: 40, cat: Audio/Audiobook, desc: "Audio Books"} + - {id: 55, cat: Books, desc: "Business"} + - {id: 46, cat: Books, desc: "Career"} + - {id: 2, cat: Books, desc: "CBTs"} + - {id: 39, cat: Books, desc: "Cert QA"} + - {id: 63, cat: Books, desc: "College"} + - {id: 53, cat: Books, desc: "Cooking"} + - {id: 42, cat: Books, desc: "Documentary"} + - {id: 37, cat: Books, desc: "e-Books"} + - {id: 65, cat: Books, desc: "Engineering"} + - {id: 54, cat: Books, desc: "Health-Fitness"} + - {id: 64, cat: Books, desc: "Kids"} + - {id: 47, cat: Books, desc: "Languages"} + - {id: 49, cat: Books, desc: "Linux CBTs"} + - {id: 43, cat: Books, desc: "Lynda.com"} + - {id: 57, cat: Books/Magazines, desc: "Magazines"} + - {id: 71, cat: Books, desc: "Magic"} + - {id: 60, cat: Books, desc: "Medical"} + - {id: 44, cat: Books, desc: "Misc Learning"} + - {id: 51, cat: Books, desc: "Music Learning"} + - {id: 41, cat: Books, desc: "Others"} + - {id: 52, cat: Books, desc: "Photography"} + - {id: 35, cat: Books, desc: "PPT 'n Docs"} + - {id: 38, cat: Books, desc: "Religion"} + - {id: 68, cat: Books, desc: "Self Growth"} + - {id: 72, cat: Books, desc: "Templates"} + - {id: 58, cat: Books, desc: "Total Training"} + - {id: 45, cat: Books, desc: "Trainsignal"} + - {id: 59, cat: Books, desc: "VTC"} + + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: processid.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.msg_info > font > b + test: + path: /browse.php + + search: + path: /browse.php + method: post + inputs: + search: "{{ .Query.Keywords }}" + incldead: "1" + rows: + selector: table > tbody > tr[class] + filters: + - name: andmatch + fields: + # there are two styles, we support both + title: + selector: a[href^="details.php?id="] + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php/"] + - name: replace + args: ["&hit=1", "/dummy.torrent"] + size: + selector: td.rowcol:nth-child(6):has(br), font:contains("Size:") + font + files: + selector: a[href*="&filelist=1"] + grabs: + selector: td.rowcol:nth-child(7):has(br) + filters: + - name: regexp + args: ([\d,]+) + seeders: + selector: td.rowcol:nth-last-child(3) + leechers: + selector: td.rowcol:nth-last-child(2) + date|optional|1: + selector: font[color="5F5F5F"] + filters: + - name: split + args: [" (", 0] + - name: replace + args: ["\xA0", " "] + - name: append + args: " +00:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + date|optional|2: + selector: a[title^="Upploaded at"] + attribute: title + filters: + - name: replace + args: ["Upploaded at - ", ""] + - name: append + args: " +00:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description|optional: + selector: font[color="#990000"] diff --git a/src/Jackett/Definitions/blubits.yml b/src/Jackett/Definitions/blubits.yml index 98ae2ec9..92802625 100644 --- a/src/Jackett/Definitions/blubits.yml +++ b/src/Jackett/Definitions/blubits.yml @@ -1,148 +1,148 @@ ---- - site: blubits - name: Blu-bits - description: "A HD tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://blu-bits.com/ - - caps: - categorymappings: - # Movies - - {id: 14, cat: Movies/BluRay, desc: "Full Blu-ray"} - - {id: 54, cat: Movies/HD, desc: "HD-DVD"} - - {id: 16, cat: Movies/HD, desc: "Remux"} - - {id: 55, cat: Movies/HD, desc: "2160p"} - - {id: 15, cat: Movies/HD, desc: "1080p"} - - {id: 19, cat: Movies/HD, desc: "1080i"} - - {id: 18, cat: Movies/HD, desc: "720p"} - - # Documentaries - - {id: 21, cat: Movies/BluRay, desc: "Full Blu-ray"} - - {id: 39, cat: Movies/HD, desc: "Remux"} - - {id: 56, cat: Movies/HD, desc: "2160p"} - - {id: 23, cat: Movies/HD, desc: "1080p"} - - {id: 24, cat: Movies/HD, desc: "1080i"} - - {id: 25, cat: Movies/HD, desc: "720p"} - - # TV Series - - {id: 27, cat: TV/HD, desc: "Full Blu-ray"} - - {id: 40, cat: TV/HD, desc: "Remux"} - - {id: 28, cat: TV/HD, desc: "1080p"} - - {id: 29, cat: TV/HD, desc: "1080i"} - - {id: 30, cat: TV/HD, desc: "720p"} - - # HDTV - - {id: 35, cat: TV/HD, desc: "1080i"} - - {id: 36, cat: TV/HD, desc: "720p"} - - # XXX - - {id: 59, cat: XXX, desc: "Full Blu-ray"} - - {id: 46, cat: XXX, desc: "1080p"} - - {id: 51, cat: XXX, desc: "720p"} - - # Music - - {id: 53, cat: Audio/Video, desc: "Full Blu-ray"} - - {id: 57, cat: Audio/Video, desc: "Remux"} - - {id: 45, cat: Audio/Video, desc: "1080p"} - - {id: 58, cat: Audio/Video, desc: "720p"} - - {id: 38, cat: Audio/Lossless, desc: "Flac"} - - - {id: 41, cat: TV/Sport, desc: "Sports"} - - {id: 42, cat: TV/Anime, desc: "Anime"} - - {id: 44, cat: PC, desc: "Windows Apps"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: index.php?page=login - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - error: - - selector: table.lista > tbody > tr > td.lista > span[style="color:#FF0000;"] - test: - path: index.php - selector: ul#navlist - - ratio: - path: index.php - selector: "ul#navlist > li:contains(\"Ratio: \")" - filters: - - name: split - args: ["\u00a0", 1] - - name: replace - args: ["---", "0"] - - search: - path: index.php - inputs: - search: "{{ .Query.Keywords }}" - page: torrents - options: 0 - active: 0 - rows: - selector: div.b-content > table.lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: title - filters: - - name: replace - args: ["View details: ", ""] - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - comments: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: p - filters: - - name: replace - args: ["\u00a0", ""] - - name: regexp - args: "\\|\\s+Size:\\s+([\\w\\d\\.,]+ \\w\\w)\\s+\\|" - date: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: onmouseover - filters: - - name: regexp - args: "<center>Added:(.*?)</center>" - grabs: - selector: a[href^="index.php?page=torrent_history&id="] - filters: - - name: replace - args: ["---", "0"] - seeders: - selector: a[title="Click here to view peers details"]:nth-child(1) - leechers: - selector: a[title="Click here to view peers details"]:nth-child(2) - downloadvolumefactor: - case: - img[alt="gold"]: "0" - img[alt="silver"]: "0.5" - "*": "1" - uploadvolumefactor: - case: - img[alt="2x Upload Multiplier"]: "2" - img[alt="3x Upload Multiplier"]: "3" - img[alt="4x Upload Multiplier"]: "4" - img[alt="5x Upload Multiplier"]: "5" - img[alt="6x Upload Multiplier"]: "6" - img[alt="7x Upload Multiplier"]: "7" - img[alt="8x Upload Multiplier"]: "8" - img[alt="9x Upload Multiplier"]: "9" - img[alt="10x Upload Multiplier"]: "10" +--- + site: blubits + name: Blu-bits + description: "A HD tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://blu-bits.com/ + + caps: + categorymappings: + # Movies + - {id: 14, cat: Movies/BluRay, desc: "Full Blu-ray"} + - {id: 54, cat: Movies/HD, desc: "HD-DVD"} + - {id: 16, cat: Movies/HD, desc: "Remux"} + - {id: 55, cat: Movies/HD, desc: "2160p"} + - {id: 15, cat: Movies/HD, desc: "1080p"} + - {id: 19, cat: Movies/HD, desc: "1080i"} + - {id: 18, cat: Movies/HD, desc: "720p"} + + # Documentaries + - {id: 21, cat: Movies/BluRay, desc: "Full Blu-ray"} + - {id: 39, cat: Movies/HD, desc: "Remux"} + - {id: 56, cat: Movies/HD, desc: "2160p"} + - {id: 23, cat: Movies/HD, desc: "1080p"} + - {id: 24, cat: Movies/HD, desc: "1080i"} + - {id: 25, cat: Movies/HD, desc: "720p"} + + # TV Series + - {id: 27, cat: TV/HD, desc: "Full Blu-ray"} + - {id: 40, cat: TV/HD, desc: "Remux"} + - {id: 28, cat: TV/HD, desc: "1080p"} + - {id: 29, cat: TV/HD, desc: "1080i"} + - {id: 30, cat: TV/HD, desc: "720p"} + + # HDTV + - {id: 35, cat: TV/HD, desc: "1080i"} + - {id: 36, cat: TV/HD, desc: "720p"} + + # XXX + - {id: 59, cat: XXX, desc: "Full Blu-ray"} + - {id: 46, cat: XXX, desc: "1080p"} + - {id: 51, cat: XXX, desc: "720p"} + + # Music + - {id: 53, cat: Audio/Video, desc: "Full Blu-ray"} + - {id: 57, cat: Audio/Video, desc: "Remux"} + - {id: 45, cat: Audio/Video, desc: "1080p"} + - {id: 58, cat: Audio/Video, desc: "720p"} + - {id: 38, cat: Audio/Lossless, desc: "Flac"} + + - {id: 41, cat: TV/Sport, desc: "Sports"} + - {id: 42, cat: TV/Anime, desc: "Anime"} + - {id: 44, cat: PC, desc: "Windows Apps"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + error: + - selector: table.lista > tbody > tr > td.lista > span[style="color:#FF0000;"] + test: + path: index.php + selector: ul#navlist + + ratio: + path: index.php + selector: "ul#navlist > li:contains(\"Ratio: \")" + filters: + - name: split + args: ["\u00a0", 1] + - name: replace + args: ["---", "0"] + + search: + path: index.php + inputs: + search: "{{ .Query.Keywords }}" + page: torrents + options: 0 + active: 0 + rows: + selector: div.b-content > table.lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: title + filters: + - name: replace + args: ["View details: ", ""] + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + comments: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: p + filters: + - name: replace + args: ["\u00a0", ""] + - name: regexp + args: "\\|\\s+Size:\\s+([\\w\\d\\.,]+ \\w\\w)\\s+\\|" + date: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: onmouseover + filters: + - name: regexp + args: "<center>Added:(.*?)</center>" + grabs: + selector: a[href^="index.php?page=torrent_history&id="] + filters: + - name: replace + args: ["---", "0"] + seeders: + selector: a[title="Click here to view peers details"]:nth-child(1) + leechers: + selector: a[title="Click here to view peers details"]:nth-child(2) + downloadvolumefactor: + case: + img[alt="gold"]: "0" + img[alt="silver"]: "0.5" + "*": "1" + uploadvolumefactor: + case: + img[alt="2x Upload Multiplier"]: "2" + img[alt="3x Upload Multiplier"]: "3" + img[alt="4x Upload Multiplier"]: "4" + img[alt="5x Upload Multiplier"]: "5" + img[alt="6x Upload Multiplier"]: "6" + img[alt="7x Upload Multiplier"]: "7" + img[alt="8x Upload Multiplier"]: "8" + img[alt="9x Upload Multiplier"]: "9" + img[alt="10x Upload Multiplier"]: "10" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/bluebird.yml b/src/Jackett/Definitions/bluebird.yml index e9c56829..a7b1f459 100644 --- a/src/Jackett/Definitions/bluebird.yml +++ b/src/Jackett/Definitions/bluebird.yml @@ -1,89 +1,89 @@ ---- - site: bluebirdhd - name: BlueBird - language: ru-ru - type: private - encoding: windows-1251 - links: - - https://bluebird-hd.org/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Films"} - - {id: 2, cat: TV/Anime, desc: "Cartoons"} - - {id: 3, cat: TV/Documentary, desc: "documentary"} - - {id: 4, cat: Audio, desc: "Show / Music"} - - {id: 5, cat: TV/Sport, desc: "Sport"} - - {id: 6, cat: TV, desc: "TV series"} - - {id: 7, cat: XXX, desc: "erotica"} - - {id: 8, cat: Other, desc: "Demo / Misc"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.error - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - rows: - selector: table > tbody > tr:has(a[href^="details.php?id="]) - fields: - title: - selector: a[href^="details.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="download.php?id="] - attribute: href - grabs: - selector: a[href*="&snatched=1#snatched"] - filters: - - name: regexp - args: (\d+) - size: - selector: td:nth-child(7) - remove: a - date: - selector: div#cleft > font - seeders: - selector: td:nth-child(5) - leechers: - selector: td:nth-child(6) - banner: - selector: a.tname - attribute: onmouseover - filters: - - name: regexp - args: src=([^\s]+) - downloadvolumefactor: - case: - img[src="pic/diamond.png"]: "0" - img[src="pic/freedownload.gif"]: "0" - img[src="pic/silver.gif"]: "0.5" - img[src="pic/bronze.gif"]: "0.75" - "*": "1" - uploadvolumefactor: - case: - img[src="pic/diamond.png"]: "2" - "*": "1" +--- + site: bluebirdhd + name: BlueBird + language: ru-ru + type: private + encoding: windows-1251 + links: + - https://bluebird-hd.org/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Films"} + - {id: 2, cat: TV/Anime, desc: "Cartoons"} + - {id: 3, cat: TV/Documentary, desc: "documentary"} + - {id: 4, cat: Audio, desc: "Show / Music"} + - {id: 5, cat: TV/Sport, desc: "Sport"} + - {id: 6, cat: TV, desc: "TV series"} + - {id: 7, cat: XXX, desc: "erotica"} + - {id: 8, cat: Other, desc: "Demo / Misc"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.error + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + rows: + selector: table > tbody > tr:has(a[href^="details.php?id="]) + fields: + title: + selector: a[href^="details.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="download.php?id="] + attribute: href + grabs: + selector: a[href*="&snatched=1#snatched"] + filters: + - name: regexp + args: (\d+) + size: + selector: td:nth-child(7) + remove: a + date: + selector: div#cleft > font + seeders: + selector: td:nth-child(5) + leechers: + selector: td:nth-child(6) + banner: + selector: a.tname + attribute: onmouseover + filters: + - name: regexp + args: src=([^\s]+) + downloadvolumefactor: + case: + img[src="pic/diamond.png"]: "0" + img[src="pic/freedownload.gif"]: "0" + img[src="pic/silver.gif"]: "0.5" + img[src="pic/bronze.gif"]: "0.75" + "*": "1" + uploadvolumefactor: + case: + img[src="pic/diamond.png"]: "2" + "*": "1" diff --git a/src/Jackett/Definitions/chdbits.yml b/src/Jackett/Definitions/chdbits.yml index 6d8267b9..98944a5a 100644 --- a/src/Jackett/Definitions/chdbits.yml +++ b/src/Jackett/Definitions/chdbits.yml @@ -1,104 +1,104 @@ ---- - site: chdbits - name: CHDBits - description: "A general tracker" - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://chdbits.co - - caps: - categorymappings: - - {id: 401, cat: Movies, desc: "Movies"} - - {id: 404, cat: TV/Documentary, desc: "Documentaries"} - - {id: 405, cat: TV/Anime, desc: "Animations"} - - {id: 402, cat: TV, desc: "TV Series"} - - {id: 403, cat: TV, desc: "TV Shows"} - - {id: 406, cat: Audio/Video, desc: "Music Videos"} - - {id: 407, cat: TV/Sport, desc: "Sports"} - - {id: 409, cat: Other, desc: "Misc"} - - {id: 408, cat: Audio, desc: "HQ Audio"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - ratio: - path: /torrents.php - selector: table#info_block - filters: - - name: regexp - args: "Ratio:\\s(.*?)\\s\\s" - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[href^="details.php?id="] - title|optional: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - date: - selector: td:nth-child(4) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) - remove: a, img +--- + site: chdbits + name: CHDBits + description: "A general tracker" + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://chdbits.co + + caps: + categorymappings: + - {id: 401, cat: Movies, desc: "Movies"} + - {id: 404, cat: TV/Documentary, desc: "Documentaries"} + - {id: 405, cat: TV/Anime, desc: "Animations"} + - {id: 402, cat: TV, desc: "TV Series"} + - {id: 403, cat: TV, desc: "TV Shows"} + - {id: 406, cat: Audio/Video, desc: "Music Videos"} + - {id: 407, cat: TV/Sport, desc: "Sports"} + - {id: 409, cat: Other, desc: "Misc"} + - {id: 408, cat: Audio, desc: "HQ Audio"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + ratio: + path: /torrents.php + selector: table#info_block + filters: + - name: regexp + args: "Ratio:\\s(.*?)\\s\\s" + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[href^="details.php?id="] + title|optional: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + date: + selector: td:nth-child(4) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) + remove: a, img diff --git a/src/Jackett/Definitions/cinemageddon.yml b/src/Jackett/Definitions/cinemageddon.yml index 5a314d96..596e7301 100644 --- a/src/Jackett/Definitions/cinemageddon.yml +++ b/src/Jackett/Definitions/cinemageddon.yml @@ -1,99 +1,99 @@ ---- - site: cinemageddon - name: Cinemageddon - description: "B-movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://cinemageddon.net/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Action"} - - {id: 2, cat: Movies, desc: "Horror"} - - {id: 3, cat: Movies, desc: "Martial Arts"} - - {id: 4, cat: Movies, desc: "Comedy"} - - {id: 5, cat: Movies, desc: "Other"} - - {id: 6, cat: Movies, desc: "Hidden Gems"} - - {id: 7, cat: Movies, desc: "Sci-Fi"} - - {id: 8, cat: Movies, desc: "Gore"} - - {id: 9, cat: Movies, desc: "Exploitation"} - - {id: 11, cat: Movies, desc: "OST"} - - {id: 12, cat: Movies, desc: "XXX"} - - {id: 13, cat: Movies, desc: "Thriller"} - - {id: 14, cat: Movies, desc: "Adventure"} - - {id: 15, cat: Movies, desc: "Documentary"} - - {id: 16, cat: Movies, desc: "Western"} - - {id: 17, cat: Movies, desc: "Family"} - - {id: 18, cat: Movies, desc: "Drama"} - - {id: 19, cat: Movies, desc: "Ebooks"} - - {id: 20, cat: Movies, desc: "Softcore"} - - {id: 21, cat: Movies, desc: "Tinfoil Hat"} - - {id: 22, cat: Movies, desc: "Trailers"} - - modes: - search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table:contains("Login failed!") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table.torrenttable > tbody > tr:has(a[href^="browse.php?cat="]) - fields: - category: - text: 1 - title: - selector: td:nth-child(2) - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - grabs: - selector: td:nth-child(6) - files: - selector: td:nth-child(5) - filters: - - name: regexp - args: (\d+)\s+file - size: - selector: td:nth-child(5) - filters: - - name: regexp - args: (\d+.*(MB|GB)+) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - date: - selector: td:nth-child(4) - filters: - - name: regexp - args: (\d{4}-\d{2}-\d{2}) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: cinemageddon + name: Cinemageddon + description: "B-movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://cinemageddon.net/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Action"} + - {id: 2, cat: Movies, desc: "Horror"} + - {id: 3, cat: Movies, desc: "Martial Arts"} + - {id: 4, cat: Movies, desc: "Comedy"} + - {id: 5, cat: Movies, desc: "Other"} + - {id: 6, cat: Movies, desc: "Hidden Gems"} + - {id: 7, cat: Movies, desc: "Sci-Fi"} + - {id: 8, cat: Movies, desc: "Gore"} + - {id: 9, cat: Movies, desc: "Exploitation"} + - {id: 11, cat: Movies, desc: "OST"} + - {id: 12, cat: Movies, desc: "XXX"} + - {id: 13, cat: Movies, desc: "Thriller"} + - {id: 14, cat: Movies, desc: "Adventure"} + - {id: 15, cat: Movies, desc: "Documentary"} + - {id: 16, cat: Movies, desc: "Western"} + - {id: 17, cat: Movies, desc: "Family"} + - {id: 18, cat: Movies, desc: "Drama"} + - {id: 19, cat: Movies, desc: "Ebooks"} + - {id: 20, cat: Movies, desc: "Softcore"} + - {id: 21, cat: Movies, desc: "Tinfoil Hat"} + - {id: 22, cat: Movies, desc: "Trailers"} + + modes: + search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table:contains("Login failed!") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table.torrenttable > tbody > tr:has(a[href^="browse.php?cat="]) + fields: + category: + text: 1 + title: + selector: td:nth-child(2) + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + grabs: + selector: td:nth-child(6) + files: + selector: td:nth-child(5) + filters: + - name: regexp + args: (\d+)\s+file + size: + selector: td:nth-child(5) + filters: + - name: regexp + args: (\d+.*(MB|GB)+) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + date: + selector: td:nth-child(4) + filters: + - name: regexp + args: (\d{4}-\d{2}-\d{2}) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/cinematik.yml b/src/Jackett/Definitions/cinematik.yml index d0e31d6b..1a581b3d 100644 --- a/src/Jackett/Definitions/cinematik.yml +++ b/src/Jackett/Definitions/cinematik.yml @@ -1,94 +1,94 @@ ---- - site: cinematik - name: Cinematik - description: "Non-Hollywood movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://www.cinematik.net - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Comedy"} - - {id: 4, cat: Movies, desc: "Action"} - - {id: 6, cat: Movies, desc: "Drama"} - - {id: 7, cat: Movies, desc: "Documentary"} - - {id: 9, cat: Movies, desc: "Crime"} - - {id: 12, cat: Movies, desc: "Sci-Fi"} - - {id: 17, cat: Movies, desc: "War"} - - {id: 21, cat: Movies, desc: "Silent Films"} - - {id: 23, cat: Movies, desc: "TV-Series"} - - {id: 24, cat: Movies, desc: "Animation"} - - {id: 25, cat: Movies, desc: "Exploitation"} - - {id: 26, cat: Movies, desc: "Experimental"} - - {id: 27, cat: Movies, desc: "Fantasy"} - - {id: 29, cat: Movies, desc: "Short"} - - {id: 30, cat: Movies, desc: "Western"} - - {id: 32, cat: Movies, desc: "Foreign Languages"} - - {id: 33, cat: Movies, desc: "Thriller"} - - {id: 34, cat: Movies, desc: "Opera and Musical"} - - modes: - search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table:contains("Login failed!") - test: - path: my.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table[border="1"] tr:not(:first-child) - fields: - category: - text: 1 - title: - selector: td:nth-child(2) a - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - grabs: - selector: td:nth-child(8) - filters: - - name: regexp - args: ([\d,]+) - files: - selector: td:nth-child(5) - size: - selector: td:nth-child(7) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - date: - selector: td:nth-child(11) div.addedtor - downloadvolumefactor: - case: - "img[title=\"Golden Torrent: No Download Stats are Recorded\"]": "0" - "img[title=\"Silver Torrent: Download Stats are 25% Recorded\"]": "0.25" - "img[title=\"Platinum Torrent: No Download Stats are Recorded, Upload Stats are Doubled!\"]": "0" - "*": "1" - uploadvolumefactor: - case: - "img[title=\"Platinum Torrent: No Download Stats are Recorded, Upload Stats are Doubled!\"]": "2" +--- + site: cinematik + name: Cinematik + description: "Non-Hollywood movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://www.cinematik.net + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Comedy"} + - {id: 4, cat: Movies, desc: "Action"} + - {id: 6, cat: Movies, desc: "Drama"} + - {id: 7, cat: Movies, desc: "Documentary"} + - {id: 9, cat: Movies, desc: "Crime"} + - {id: 12, cat: Movies, desc: "Sci-Fi"} + - {id: 17, cat: Movies, desc: "War"} + - {id: 21, cat: Movies, desc: "Silent Films"} + - {id: 23, cat: Movies, desc: "TV-Series"} + - {id: 24, cat: Movies, desc: "Animation"} + - {id: 25, cat: Movies, desc: "Exploitation"} + - {id: 26, cat: Movies, desc: "Experimental"} + - {id: 27, cat: Movies, desc: "Fantasy"} + - {id: 29, cat: Movies, desc: "Short"} + - {id: 30, cat: Movies, desc: "Western"} + - {id: 32, cat: Movies, desc: "Foreign Languages"} + - {id: 33, cat: Movies, desc: "Thriller"} + - {id: 34, cat: Movies, desc: "Opera and Musical"} + + modes: + search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table:contains("Login failed!") + test: + path: my.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table[border="1"] tr:not(:first-child) + fields: + category: + text: 1 + title: + selector: td:nth-child(2) a + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + grabs: + selector: td:nth-child(8) + filters: + - name: regexp + args: ([\d,]+) + files: + selector: td:nth-child(5) + size: + selector: td:nth-child(7) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + date: + selector: td:nth-child(11) div.addedtor + downloadvolumefactor: + case: + "img[title=\"Golden Torrent: No Download Stats are Recorded\"]": "0" + "img[title=\"Silver Torrent: Download Stats are 25% Recorded\"]": "0.25" + "img[title=\"Platinum Torrent: No Download Stats are Recorded, Upload Stats are Doubled!\"]": "0" + "*": "1" + uploadvolumefactor: + case: + "img[title=\"Platinum Torrent: No Download Stats are Recorded, Upload Stats are Doubled!\"]": "2" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/classix.yml b/src/Jackett/Definitions/classix.yml index 2d22f933..8f5d9689 100644 --- a/src/Jackett/Definitions/classix.yml +++ b/src/Jackett/Definitions/classix.yml @@ -1,64 +1,64 @@ ---- - site: classix - name: Classix - description: "Classic movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://classix-unlimited.co.uk/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Movies"} - - modes: - search: [q] - - login: - path: account-login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.myContent:contains("Access Denied") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: torrents-search.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table > tbody > tr:has(a[href^="torrents.php?cat="]) - fields: - category: - text: 1 - title: - selector: td:nth-child(3) - download: - selector: a[href^="torrents-details.php?id="] - attribute: href - filters: - - name: replace - args: ["torrents-details.php?id=", "download.php?id="] - details: - selector: a[href^="torrents-details.php?id="] - attribute: href - size: - selector: td:nth-child(7) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: classix + name: Classix + description: "Classic movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://classix-unlimited.co.uk/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Movies"} + + modes: + search: [q] + + login: + path: account-login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.myContent:contains("Access Denied") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: torrents-search.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table > tbody > tr:has(a[href^="torrents.php?cat="]) + fields: + category: + text: 1 + title: + selector: td:nth-child(3) + download: + selector: a[href^="torrents-details.php?id="] + attribute: href + filters: + - name: replace + args: ["torrents-details.php?id=", "download.php?id="] + details: + selector: a[href^="torrents-details.php?id="] + attribute: href + size: + selector: td:nth-child(7) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/czteam.yml b/src/Jackett/Definitions/czteam.yml index fa44756d..7b1341f5 100644 --- a/src/Jackett/Definitions/czteam.yml +++ b/src/Jackett/Definitions/czteam.yml @@ -1,94 +1,94 @@ ---- - site: czteam - name: CZTeam - language: cs-cz - type: private - encoding: UTF-8 - links: - - https://czteam.club/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Movies"} - - {id: 2, cat: TV, desc: "TV-Eps"} - - {id: 3, cat: Audio, desc: "Music"} - - {id: 4, cat: PC/Games, desc: "Games"} - - {id: 5, cat: PC/ISO, desc: "Software"} - - {id: 6, cat: XXX, desc: "XxX"} - - {id: 7, cat: Other, desc: "Other"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: 1 - login: "Log in" - error: - - selector: form#loginform > span.warning - test: - path: torrents.php - - search: - path: torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: time - order_way: desc - action: basic - searchsubmit: 1 - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - title: - selector: a.torrent_name - category: - selector: td.cats_col - case: - div.cats_movies: 1 - div.cats_tveps: 2 - div.cats_music: 3 - div.cats_games: 4 - div.cats_software: 5 - div.cats_xxx: 6 - div.cats_other: 7 - details: - selector: a.torrent_name - attribute: href - banner: - selector: a.torrent_name - optional: true - attribute: cover - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(4) - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - "strong.tl_free": "0" - "strong.tl_neutral": "0" - "*": "1" - uploadvolumefactor: - case: - "strong.tl_neutral": "0" - "*": "1" - description: - selector: div.torrent_info +--- + site: czteam + name: CZTeam + language: cs-cz + type: private + encoding: UTF-8 + links: + - https://czteam.club/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Movies"} + - {id: 2, cat: TV, desc: "TV-Eps"} + - {id: 3, cat: Audio, desc: "Music"} + - {id: 4, cat: PC/Games, desc: "Games"} + - {id: 5, cat: PC/ISO, desc: "Software"} + - {id: 6, cat: XXX, desc: "XxX"} + - {id: 7, cat: Other, desc: "Other"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: 1 + login: "Log in" + error: + - selector: form#loginform > span.warning + test: + path: torrents.php + + search: + path: torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: time + order_way: desc + action: basic + searchsubmit: 1 + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + title: + selector: a.torrent_name + category: + selector: td.cats_col + case: + div.cats_movies: 1 + div.cats_tveps: 2 + div.cats_music: 3 + div.cats_games: 4 + div.cats_software: 5 + div.cats_xxx: 6 + div.cats_other: 7 + details: + selector: a.torrent_name + attribute: href + banner: + selector: a.torrent_name + optional: true + attribute: cover + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(4) + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + "strong.tl_free": "0" + "strong.tl_neutral": "0" + "*": "1" + uploadvolumefactor: + case: + "strong.tl_neutral": "0" + "*": "1" + description: + selector: div.torrent_info remove: strong \ No newline at end of file diff --git a/src/Jackett/Definitions/datascene.yml b/src/Jackett/Definitions/datascene.yml index 02e4a805..b08c10c0 100644 --- a/src/Jackett/Definitions/datascene.yml +++ b/src/Jackett/Definitions/datascene.yml @@ -1,119 +1,119 @@ ---- - site: datascene - name: DataScene - language: ro-ro - type: private - encoding: windows-1252 - links: - - http://datascene.net/ - - caps: - categorymappings: - - {id: 3, cat: TV/Anime, desc: "Anime | Cartoon"} - - {id: 15, cat: PC/0day, desc: "Appz | Win"} - - {id: 4, cat: PC/0day, desc: "Appz | Linux"} - - {id: 6, cat: Books, desc: "E-Book"} - - {id: 10, cat: PC/Games, desc: "Games | PC Iso"} - - {id: 9, cat: PC/Games, desc: "Games | PC Rips"} - - {id: 11, cat: Console, desc: "Games | Pack"} - - {id: 43, cat: Console, desc: "Games | Console"} - - {id: 29, cat: Other, desc: "Images"} - - {id: 2, cat: Other, desc: "MiSC"} - - {id: 5, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 27, cat: Movies, desc: "Movies | Pack"} - - {id: 46, cat: Movies/3D, desc: "Movies | 3D"} - - {id: 26, cat: Movies/SD, desc: "Movies | Cam"} - - {id: 25, cat: Movies, desc: "Movies | Documentary"} - - {id: 24, cat: Movies/DVD, desc: "Movies | DVD-R"} - - {id: 32, cat: Movies/DVD, desc: "Movies | DVD-RO"} - - {id: 23, cat: Movies/HD, desc: "Movies | HD"} - - {id: 31, cat: Movies/HD, desc: "Movies | HD-Ro"} - - {id: 34, cat: Movies/Foreign, desc: "Movies | Hindi"} - - {id: 30, cat: Movies/SD, desc: "Movies | Xvid"} - - {id: 36, cat: Movies/SD, desc: "Movies | Xvid-Ro"} - - {id: 21, cat: Audio/Video, desc: "Music | Video"} - - {id: 19, cat: Audio , desc: "Music | Mp3/Flac"} - - {id: 18, cat: Other, desc: "Other"} - - {id: 42, cat: Other, desc: "Premiera | DsT"} - - {id: 14, cat: TV/Sport, desc: "Sport"} - - {id: 47, cat: TV/SD, desc: "Tv | Episodes"} - - {id: 28, cat: TV/HD, desc: "Tv-HD | Episodes"} - - {id: 13, cat: Other, desc: "Tutoriale"} - - {id: 12, cat: XXX, desc: "XxX"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /browse.php - - ratio: - path: /browse.php - selector: font:contains("Ratio:") > span - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: tr:has(a.tname) - fields: - title: - selector: a.tname - attribute: title - details: - selector: a.tname - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="/download.php/"] - attribute: href - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: (\d+) - size: - selector: td:nth-child(6) - date: - selector: td:nth-child(2) > right > div:has(font:contains("Uploaded")) - remove: div > font - filters: - - name: trim - args: ":" - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - banner: - selector: a.tname - attribute: onmouseover - filters: - - name: regexp - args: src=([^\s]+) - downloadvolumefactor: - case: - "img[src=\"pic/free.gif\"]": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(2) > right +--- + site: datascene + name: DataScene + language: ro-ro + type: private + encoding: windows-1252 + links: + - http://datascene.net/ + + caps: + categorymappings: + - {id: 3, cat: TV/Anime, desc: "Anime | Cartoon"} + - {id: 15, cat: PC/0day, desc: "Appz | Win"} + - {id: 4, cat: PC/0day, desc: "Appz | Linux"} + - {id: 6, cat: Books, desc: "E-Book"} + - {id: 10, cat: PC/Games, desc: "Games | PC Iso"} + - {id: 9, cat: PC/Games, desc: "Games | PC Rips"} + - {id: 11, cat: Console, desc: "Games | Pack"} + - {id: 43, cat: Console, desc: "Games | Console"} + - {id: 29, cat: Other, desc: "Images"} + - {id: 2, cat: Other, desc: "MiSC"} + - {id: 5, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 27, cat: Movies, desc: "Movies | Pack"} + - {id: 46, cat: Movies/3D, desc: "Movies | 3D"} + - {id: 26, cat: Movies/SD, desc: "Movies | Cam"} + - {id: 25, cat: Movies, desc: "Movies | Documentary"} + - {id: 24, cat: Movies/DVD, desc: "Movies | DVD-R"} + - {id: 32, cat: Movies/DVD, desc: "Movies | DVD-RO"} + - {id: 23, cat: Movies/HD, desc: "Movies | HD"} + - {id: 31, cat: Movies/HD, desc: "Movies | HD-Ro"} + - {id: 34, cat: Movies/Foreign, desc: "Movies | Hindi"} + - {id: 30, cat: Movies/SD, desc: "Movies | Xvid"} + - {id: 36, cat: Movies/SD, desc: "Movies | Xvid-Ro"} + - {id: 21, cat: Audio/Video, desc: "Music | Video"} + - {id: 19, cat: Audio , desc: "Music | Mp3/Flac"} + - {id: 18, cat: Other, desc: "Other"} + - {id: 42, cat: Other, desc: "Premiera | DsT"} + - {id: 14, cat: TV/Sport, desc: "Sport"} + - {id: 47, cat: TV/SD, desc: "Tv | Episodes"} + - {id: 28, cat: TV/HD, desc: "Tv-HD | Episodes"} + - {id: 13, cat: Other, desc: "Tutoriale"} + - {id: 12, cat: XXX, desc: "XxX"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /browse.php + + ratio: + path: /browse.php + selector: font:contains("Ratio:") > span + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: tr:has(a.tname) + fields: + title: + selector: a.tname + attribute: title + details: + selector: a.tname + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="/download.php/"] + attribute: href + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: (\d+) + size: + selector: td:nth-child(6) + date: + selector: td:nth-child(2) > right > div:has(font:contains("Uploaded")) + remove: div > font + filters: + - name: trim + args: ":" + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + banner: + selector: a.tname + attribute: onmouseover + filters: + - name: regexp + args: src=([^\s]+) + downloadvolumefactor: + case: + "img[src=\"pic/free.gif\"]": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(2) > right remove: div \ No newline at end of file diff --git a/src/Jackett/Definitions/dragonworld.yml b/src/Jackett/Definitions/dragonworld.yml index 3d716cd5..317f3728 100644 --- a/src/Jackett/Definitions/dragonworld.yml +++ b/src/Jackett/Definitions/dragonworld.yml @@ -1,154 +1,154 @@ ---- - site: dragonworld - name: Dragon World (DTW) - language: de-de - type: private - encoding: UTF-8 - links: - - http://dtw.sytes.net/ - - caps: - categorymappings: - # Dokumentation - - {id: 46, cat: TV/Documentary, desc: "Dokumentation"} - - {id: 55, cat: TV/Documentary, desc: "Dokumentation/HD"} - - {id: 56, cat: TV/Documentary, desc: "Dokumentation/SD"} - # Ebooks - - {id: 36, cat: Books, desc: "Ebooks"} - - {id: 37, cat: Books, desc: "Ebooks"} - - {id: 38, cat: Books, desc: "Ebooks/Hoerspiele/Hoerbuecher"} - # Games - - {id: 21, cat: Console, desc: "Games"} - - {id: 24, cat: Console/Other, desc: "Games/Nintendo"} - - {id: 22, cat: PC/Games, desc: "Games/PC"} - - {id: 23, cat: Console/PS4, desc: "Games/Playstation"} - - {id: 25, cat: Console/Xbox, desc: "Games/Xbox"} - # Kinder - - {id: 10, cat: Other, desc: "Kinder"} - - {id: 14, cat: Other, desc: "Kinder/Diverses"} - - {id: 12, cat: Movies, desc: "Kinder/Filme"} - - {id: 11, cat: PC/Games, desc: "Kinder/Games"} - - {id: 13, cat: Audio, desc: "Kinder/Musik"} - # Movies - - {id: 15, cat: Movies, desc: "Movies"} - - {id: 50, cat: Movies/3D, desc: "Movies/3D"} - - {id: 48, cat: Movies/HD, desc: "Movies/HD"} - - {id: 53, cat: Movies/HD, desc: "Movies/HD Pack"} - - {id: 45, cat: Movies/HD, desc: "Movies/Remuxe"} - - {id: 17, cat: Movies/SD, desc: "Movies/SD"} - - {id: 54, cat: Movies/SD, desc: "Movies/SD Pack"} - # Musik - - {id: 4, cat: Audio, desc: "Musik"} - - {id: 57, cat: Audio, desc: "Musik/Album"} - - {id: 8, cat: Audio/Lossless, desc: "Musik/Flac"} - - {id: 7, cat: Audio/MP3, desc: "Musik/Mp3"} - - {id: 9, cat: Audio/Video, desc: "Musik/Video"} - # Serien - - {id: 26, cat: TV, desc: "Serien"} - - {id: 27, cat: TV/HD, desc: "Serien/HD"} - - {id: 28, cat: TV/SD, desc: "Serien/SD"} - # Software - - {id: 29, cat: PC/0day, desc: "Software"} - - {id: 32, cat: PC/0day, desc: "Software/Diverses"} - - {id: 31, cat: PC/Mac, desc: "Software/Mac"} - - {id: 30, cat: PC/0day, desc: "Software/Windows"} - # Sport - - {id: 39, cat: TV/Sport, desc: "Sport"} - - {id: 40, cat: TV/Sport, desc: "Sport HD"} - - {id: 58, cat: TV/Sport, desc: "Sport SD"} - # XXX - - {id: 33, cat: XXX, desc: "XXX"} - - {id: 34, cat: XXX, desc: "XXX/HD"} - - {id: 35, cat: XXX, desc: "XXX/SD"} - - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table:has(td:contains("Ein Fehler ist aufgetreten")) - test: - path: browse.php - selector: a[href*="/logout.php"] - - download: - before: - path: "takethanks.php" - method: "post" - inputs: - torrentid: "{{ .DownloadUri.Query.id }}" - - search: - path: browse.php - keywordsfilters: - - name: re_replace - args: ["[^a-zA-Z0-9]+", "%"] - inputs: - do: "search" - keywords: "{{ .Keywords }}" - search_type: "t_name" - category: "0" # multi cat search not supported - include_dead_torrents: "yes" - rows: - selector: table#sortabletable > tbody > tr:has(a[href*="/details.php?id="]) - filters: - - name: andmatch - args: 66 - fields: - download: - selector: a[href*="/download.php?id="] - attribute: href - magnet: - selector: a[href^="magnet:"] - attribute: href - title: - selector: a[href*="/details.php?id="] - title: - selector: div.tooltip-content > div - optional: true - details: - selector: a[href*="/details.php?id="] - attribute: href - category: - selector: a[href*="/browse.php?category="] - attribute: href - filters: - - name: querystring - args: category - banner: - selector: div.tooltip-content > img - attribute: src - optional: true - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - img[alt^="OnlyUp Torrent"]: "0" - img[alt^="50% "]: "0.5" - "*": "1" - uploadvolumefactor: - case: - img[alt^="multi2 Torrent"]: "2" - "*": "1" - date: - selector: "td:nth-child(2) > div:has(span[style=\"float: right;\"])" - remove: span - filters: - - name: append - args: " +01:00" - - name: dateparse - args: "02-01-2006 15:04 -07:00" +--- + site: dragonworld + name: Dragon World (DTW) + language: de-de + type: private + encoding: UTF-8 + links: + - http://dtw.sytes.net/ + + caps: + categorymappings: + # Dokumentation + - {id: 46, cat: TV/Documentary, desc: "Dokumentation"} + - {id: 55, cat: TV/Documentary, desc: "Dokumentation/HD"} + - {id: 56, cat: TV/Documentary, desc: "Dokumentation/SD"} + # Ebooks + - {id: 36, cat: Books, desc: "Ebooks"} + - {id: 37, cat: Books, desc: "Ebooks"} + - {id: 38, cat: Books, desc: "Ebooks/Hoerspiele/Hoerbuecher"} + # Games + - {id: 21, cat: Console, desc: "Games"} + - {id: 24, cat: Console/Other, desc: "Games/Nintendo"} + - {id: 22, cat: PC/Games, desc: "Games/PC"} + - {id: 23, cat: Console/PS4, desc: "Games/Playstation"} + - {id: 25, cat: Console/Xbox, desc: "Games/Xbox"} + # Kinder + - {id: 10, cat: Other, desc: "Kinder"} + - {id: 14, cat: Other, desc: "Kinder/Diverses"} + - {id: 12, cat: Movies, desc: "Kinder/Filme"} + - {id: 11, cat: PC/Games, desc: "Kinder/Games"} + - {id: 13, cat: Audio, desc: "Kinder/Musik"} + # Movies + - {id: 15, cat: Movies, desc: "Movies"} + - {id: 50, cat: Movies/3D, desc: "Movies/3D"} + - {id: 48, cat: Movies/HD, desc: "Movies/HD"} + - {id: 53, cat: Movies/HD, desc: "Movies/HD Pack"} + - {id: 45, cat: Movies/HD, desc: "Movies/Remuxe"} + - {id: 17, cat: Movies/SD, desc: "Movies/SD"} + - {id: 54, cat: Movies/SD, desc: "Movies/SD Pack"} + # Musik + - {id: 4, cat: Audio, desc: "Musik"} + - {id: 57, cat: Audio, desc: "Musik/Album"} + - {id: 8, cat: Audio/Lossless, desc: "Musik/Flac"} + - {id: 7, cat: Audio/MP3, desc: "Musik/Mp3"} + - {id: 9, cat: Audio/Video, desc: "Musik/Video"} + # Serien + - {id: 26, cat: TV, desc: "Serien"} + - {id: 27, cat: TV/HD, desc: "Serien/HD"} + - {id: 28, cat: TV/SD, desc: "Serien/SD"} + # Software + - {id: 29, cat: PC/0day, desc: "Software"} + - {id: 32, cat: PC/0day, desc: "Software/Diverses"} + - {id: 31, cat: PC/Mac, desc: "Software/Mac"} + - {id: 30, cat: PC/0day, desc: "Software/Windows"} + # Sport + - {id: 39, cat: TV/Sport, desc: "Sport"} + - {id: 40, cat: TV/Sport, desc: "Sport HD"} + - {id: 58, cat: TV/Sport, desc: "Sport SD"} + # XXX + - {id: 33, cat: XXX, desc: "XXX"} + - {id: 34, cat: XXX, desc: "XXX/HD"} + - {id: 35, cat: XXX, desc: "XXX/SD"} + + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table:has(td:contains("Ein Fehler ist aufgetreten")) + test: + path: browse.php + selector: a[href*="/logout.php"] + + download: + before: + path: "takethanks.php" + method: "post" + inputs: + torrentid: "{{ .DownloadUri.Query.id }}" + + search: + path: browse.php + keywordsfilters: + - name: re_replace + args: ["[^a-zA-Z0-9]+", "%"] + inputs: + do: "search" + keywords: "{{ .Keywords }}" + search_type: "t_name" + category: "0" # multi cat search not supported + include_dead_torrents: "yes" + rows: + selector: table#sortabletable > tbody > tr:has(a[href*="/details.php?id="]) + filters: + - name: andmatch + args: 66 + fields: + download: + selector: a[href*="/download.php?id="] + attribute: href + magnet: + selector: a[href^="magnet:"] + attribute: href + title: + selector: a[href*="/details.php?id="] + title: + selector: div.tooltip-content > div + optional: true + details: + selector: a[href*="/details.php?id="] + attribute: href + category: + selector: a[href*="/browse.php?category="] + attribute: href + filters: + - name: querystring + args: category + banner: + selector: div.tooltip-content > img + attribute: src + optional: true + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + img[alt^="OnlyUp Torrent"]: "0" + img[alt^="50% "]: "0.5" + "*": "1" + uploadvolumefactor: + case: + img[alt^="multi2 Torrent"]: "2" + "*": "1" + date: + selector: "td:nth-child(2) > div:has(span[style=\"float: right;\"])" + remove: span + filters: + - name: append + args: " +01:00" + - name: dateparse + args: "02-01-2006 15:04 -07:00" diff --git a/src/Jackett/Definitions/dragonworldreloaded.yml b/src/Jackett/Definitions/dragonworldreloaded.yml index 0c3f8ccf..ee44a4d3 100644 --- a/src/Jackett/Definitions/dragonworldreloaded.yml +++ b/src/Jackett/Definitions/dragonworldreloaded.yml @@ -1,238 +1,238 @@ ---- - site: dragonworldreloaded - name: Dragonworld Reloaded - language: de-de - type: private - encoding: UTF-8 - links: - - https://dragonworld-reloaded.net/ - - caps: - categorymappings: - # Kino - - {id: 118, cat: Movies/HD, desc: "Kino - HD"} - - {id: 4, cat: Movies/SD, desc: "Kino - SD"} - # Movies - - {id: 18, cat: Movies/SD, desc: "Movies - x264/XviD"} - - {id: 2, cat: Movies, desc: "Movies - Pack SD/HD"} - - {id: 22, cat: Movies/DVD, desc: "Movies - DVD/HD2"} - - {id: 52, cat: Movies, desc: "Movies - Kids"} - - {id: 19, cat: Movies/HD, desc: "Movies - HD"} - - {id: 25, cat: Movies/3D, desc: "Movies - 3D"} - - {id: 26, cat: Movies/BluRay, desc: "Movies - Blu-Ray"} - # Serien - - {id: 40, cat: TV/SD, desc: "Serien - SD"} - - {id: 41, cat: TV/HD, desc: "Serien - HD"} - - {id: 42, cat: TV/SD, desc: "Serien - Pack SD"} - - {id: 80, cat: TV/HD, desc: "Serien - Pack HD"} - # Musik - - {id: 119, cat: Audio, desc: "Musik - ALBEN"} - - {id: 5, cat: Audio/MP3, desc: "Musik - Mp3"} - - {id: 6, cat: Audio, desc: "Musik - Mixe"} - - {id: 92, cat: Audio, desc: "Musik - Discography"} - - {id: 114, cat: Audio, desc: "Musik - Musik Pack"} - - {id: 48, cat: Audio/Video, desc: "Musik - Video"} - # Doku - - {id: 37, cat: TV/Documentary, desc: "Doku - SD"} - - {id: 38, cat: TV/Documentary, desc: "Doku - HD"} - - {id: 81, cat: TV/Documentary, desc: "Doku - Pack "} - # Anime - - {id: 73, cat: TV/Anime, desc: "Anime - Movies"} - - {id: 74, cat: TV/Anime, desc: "Anime - Serien"} - # Games - - {id: 16, cat: PC/Games, desc: "Games - PC"} - - {id: 14, cat: Console/Other, desc: "Games - Wimmelbild"} - - {id: 7, cat: Console/PSP, desc: "Games - PSP"} - - {id: 17, cat: Console/PS3, desc: "Games - PS2/PS3"} - - {id: 29, cat: Console/NDS, desc: "Games - NDS/3DS"} - - {id: 15, cat: Console/Wii, desc: "Games - Wii"} - - {id: 8, cat: Console/Xbox, desc: "Games - XboX "} - # Appz - - {id: 30, cat: PC/0day, desc: "Appz - Windows"} - - {id: 31, cat: PC/0day, desc: "Appz - Linux"} - - {id: 32, cat: PC/Mac, desc: "Appz - Mac"} - - {id: 106, cat: PC/Phone-Android, desc: "Appz - Android"} - # Sport - - {id: 43, cat: TV/Sport, desc: "Sport - SD"} - - {id: 50, cat: TV/Sport, desc: "Sport - HD"} - # Sonstiges - - {id: 34, cat: Books, desc: "Sonstiges - E-Books"} - - {id: 35, cat: Audio/Audiobook, desc: "Sonstiges - Audiobook"} - - {id: 36, cat: Other, desc: "Sonstiges - Diverses"} - # XXX - - {id: 46, cat: XXX, desc: "XXX - SD"} - - {id: 47, cat: XXX, desc: "XXX - HD"} - - {id: 45, cat: XXX, desc: "XXX - Pack"} - - {id: 49, cat: XXX, desc: "XXX - Sonstiges"} - - {id: 110, cat: XXX, desc: "XXX - Hentai Serie"} - - {id: 111, cat: XXX, desc: "XXX - Hentai Movie"} - - {id: 116, cat: XXX, desc: "XXX - SexBooks"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: /login.php - method: form - form: form[action="/login.php"] - cookies: ["JAVA=OK"] # avoid jscheck redirect - captcha: - type: image - image: img[src^="cap/captcha_math.php"] - input: stringCaptcha - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - loggiin: "einloggen" - error: - - selector: div#login_error - test: - path: selection.php - - download: - before: - path: "ajax_det_poll.php" - method: "post" - inputs: - set_thanks: "thanks" - det_id: "{{ .DownloadUri.Query.torrent }}" - ajax: "yes" - - search: - path: selection.php - inputs: - search: "{{ .Keywords }}" - blah: "0" - orderby: "added" - sort: "desc" - rows: - selector: div.selection_wrap - fields: - download: - selector: a.selection_a - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?torrent="] - title: - selector: a.selection_a - details: - selector: a.selection_a - attribute: href - category: - selector: div.kat_cat_pic - case: - # Kino - ":has(div.kat_cat_pic_name:contains(\"Kino\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "118" - ":has(div.kat_cat_pic_name:contains(\"Kino\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "4" - # Movies - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"x264/XviD\"))": "18" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Pack SD/HD\"))": "2" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"DVD/HD2\"))": "22" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Kids\"))": "52" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "19" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"3D\"))": "25" - ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Blu-Ray\"))": "26" - # Serien - ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "40" - ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "41" - ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"Pack SD\"))": "42" - ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"Pack HD\"))": "80" - # Musik - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"ALBEN\"))": "119" - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Mp3\"))": "5" - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Mixe\"))": "6" - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Discography\"))": "92" - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Musik Pack\"))": "114" - ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Video\"))": "48" - # Doku - ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "37" - ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "38" - ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"Pack \"))": "81" - # Anime - ":has(div.kat_cat_pic_name:contains(\"Anime\")):has(div.kat_cat_pic_name_b:contains(\"Movies\"))": "73" - ":has(div.kat_cat_pic_name:contains(\"Anime\")):has(div.kat_cat_pic_name_b:contains(\"Serien\"))": "74" - # Games - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PC\"))": "16" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"Wimmelbild\"))": "14" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PSP\"))": "7" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PS2/PS3\"))": "17" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"NDS/3DS\"))": "29" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"Wii\"))": "15" - ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"XboX \"))": "8" - # Appz - ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Windows\"))": "30" - ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Linux\"))": "31" - ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Mac\"))": "32" - ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Android\"))": "106" - # Sport - ":has(div.kat_cat_pic_name:contains(\"Sport\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "43" - ":has(div.kat_cat_pic_name:contains(\"Sport\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "50" - # Sonstiges - ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"E-Books\"))": "34" - ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"Audiobook\"))": "35" - ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"Diverses\"))": "36" - # XXX - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "46" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "47" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Pack\"))": "45" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Sonstiges\"))": "49" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Hentai Serie\"))": "110" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Hentai Movie\"))": "111" - ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"SexBooks\"))": "116" - banner: - selector: div[id^="details"] img - attribute: src - size: - selector: div.selection_unter_ad - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - grabs: - selector: div.selection_unter_ae - filters: - - name: trim - args: "x" - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - seeders: - selector: div.selection_unter_aa - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - leechers: - selector: div.selection_unter_aaa - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - downloadvolumefactor: - case: - ":root:has(div.onlyup)": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - date: - selector: div.selection_unter_ab - filters: - - name: replace - args: ["Heute", "Today"] - - name: replace - args: ["Gestern", "Yesterday"] - - name: replace - args: [" um", ""] - - name: dateparse - args: "02.01.2006 15:04:05" - description: - selector: selection_unter_af - optional: true +--- + site: dragonworldreloaded + name: Dragonworld Reloaded + language: de-de + type: private + encoding: UTF-8 + links: + - https://dragonworld-reloaded.net/ + + caps: + categorymappings: + # Kino + - {id: 118, cat: Movies/HD, desc: "Kino - HD"} + - {id: 4, cat: Movies/SD, desc: "Kino - SD"} + # Movies + - {id: 18, cat: Movies/SD, desc: "Movies - x264/XviD"} + - {id: 2, cat: Movies, desc: "Movies - Pack SD/HD"} + - {id: 22, cat: Movies/DVD, desc: "Movies - DVD/HD2"} + - {id: 52, cat: Movies, desc: "Movies - Kids"} + - {id: 19, cat: Movies/HD, desc: "Movies - HD"} + - {id: 25, cat: Movies/3D, desc: "Movies - 3D"} + - {id: 26, cat: Movies/BluRay, desc: "Movies - Blu-Ray"} + # Serien + - {id: 40, cat: TV/SD, desc: "Serien - SD"} + - {id: 41, cat: TV/HD, desc: "Serien - HD"} + - {id: 42, cat: TV/SD, desc: "Serien - Pack SD"} + - {id: 80, cat: TV/HD, desc: "Serien - Pack HD"} + # Musik + - {id: 119, cat: Audio, desc: "Musik - ALBEN"} + - {id: 5, cat: Audio/MP3, desc: "Musik - Mp3"} + - {id: 6, cat: Audio, desc: "Musik - Mixe"} + - {id: 92, cat: Audio, desc: "Musik - Discography"} + - {id: 114, cat: Audio, desc: "Musik - Musik Pack"} + - {id: 48, cat: Audio/Video, desc: "Musik - Video"} + # Doku + - {id: 37, cat: TV/Documentary, desc: "Doku - SD"} + - {id: 38, cat: TV/Documentary, desc: "Doku - HD"} + - {id: 81, cat: TV/Documentary, desc: "Doku - Pack "} + # Anime + - {id: 73, cat: TV/Anime, desc: "Anime - Movies"} + - {id: 74, cat: TV/Anime, desc: "Anime - Serien"} + # Games + - {id: 16, cat: PC/Games, desc: "Games - PC"} + - {id: 14, cat: Console/Other, desc: "Games - Wimmelbild"} + - {id: 7, cat: Console/PSP, desc: "Games - PSP"} + - {id: 17, cat: Console/PS3, desc: "Games - PS2/PS3"} + - {id: 29, cat: Console/NDS, desc: "Games - NDS/3DS"} + - {id: 15, cat: Console/Wii, desc: "Games - Wii"} + - {id: 8, cat: Console/Xbox, desc: "Games - XboX "} + # Appz + - {id: 30, cat: PC/0day, desc: "Appz - Windows"} + - {id: 31, cat: PC/0day, desc: "Appz - Linux"} + - {id: 32, cat: PC/Mac, desc: "Appz - Mac"} + - {id: 106, cat: PC/Phone-Android, desc: "Appz - Android"} + # Sport + - {id: 43, cat: TV/Sport, desc: "Sport - SD"} + - {id: 50, cat: TV/Sport, desc: "Sport - HD"} + # Sonstiges + - {id: 34, cat: Books, desc: "Sonstiges - E-Books"} + - {id: 35, cat: Audio/Audiobook, desc: "Sonstiges - Audiobook"} + - {id: 36, cat: Other, desc: "Sonstiges - Diverses"} + # XXX + - {id: 46, cat: XXX, desc: "XXX - SD"} + - {id: 47, cat: XXX, desc: "XXX - HD"} + - {id: 45, cat: XXX, desc: "XXX - Pack"} + - {id: 49, cat: XXX, desc: "XXX - Sonstiges"} + - {id: 110, cat: XXX, desc: "XXX - Hentai Serie"} + - {id: 111, cat: XXX, desc: "XXX - Hentai Movie"} + - {id: 116, cat: XXX, desc: "XXX - SexBooks"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: /login.php + method: form + form: form[action="/login.php"] + cookies: ["JAVA=OK"] # avoid jscheck redirect + captcha: + type: image + image: img[src^="cap/captcha_math.php"] + input: stringCaptcha + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + loggiin: "einloggen" + error: + - selector: div#login_error + test: + path: selection.php + + download: + before: + path: "ajax_det_poll.php" + method: "post" + inputs: + set_thanks: "thanks" + det_id: "{{ .DownloadUri.Query.torrent }}" + ajax: "yes" + + search: + path: selection.php + inputs: + search: "{{ .Keywords }}" + blah: "0" + orderby: "added" + sort: "desc" + rows: + selector: div.selection_wrap + fields: + download: + selector: a.selection_a + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?torrent="] + title: + selector: a.selection_a + details: + selector: a.selection_a + attribute: href + category: + selector: div.kat_cat_pic + case: + # Kino + ":has(div.kat_cat_pic_name:contains(\"Kino\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "118" + ":has(div.kat_cat_pic_name:contains(\"Kino\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "4" + # Movies + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"x264/XviD\"))": "18" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Pack SD/HD\"))": "2" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"DVD/HD2\"))": "22" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Kids\"))": "52" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "19" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"3D\"))": "25" + ":has(div.kat_cat_pic_name:contains(\"Movies\")):has(div.kat_cat_pic_name_b:contains(\"Blu-Ray\"))": "26" + # Serien + ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "40" + ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "41" + ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"Pack SD\"))": "42" + ":has(div.kat_cat_pic_name:contains(\"Serien\")):has(div.kat_cat_pic_name_b:contains(\"Pack HD\"))": "80" + # Musik + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"ALBEN\"))": "119" + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Mp3\"))": "5" + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Mixe\"))": "6" + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Discography\"))": "92" + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Musik Pack\"))": "114" + ":has(div.kat_cat_pic_name:contains(\"Musik\")):has(div.kat_cat_pic_name_b:contains(\"Video\"))": "48" + # Doku + ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "37" + ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "38" + ":has(div.kat_cat_pic_name:contains(\"Doku\")):has(div.kat_cat_pic_name_b:contains(\"Pack \"))": "81" + # Anime + ":has(div.kat_cat_pic_name:contains(\"Anime\")):has(div.kat_cat_pic_name_b:contains(\"Movies\"))": "73" + ":has(div.kat_cat_pic_name:contains(\"Anime\")):has(div.kat_cat_pic_name_b:contains(\"Serien\"))": "74" + # Games + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PC\"))": "16" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"Wimmelbild\"))": "14" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PSP\"))": "7" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"PS2/PS3\"))": "17" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"NDS/3DS\"))": "29" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"Wii\"))": "15" + ":has(div.kat_cat_pic_name:contains(\"Games\")):has(div.kat_cat_pic_name_b:contains(\"XboX \"))": "8" + # Appz + ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Windows\"))": "30" + ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Linux\"))": "31" + ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Mac\"))": "32" + ":has(div.kat_cat_pic_name:contains(\"Appz\")):has(div.kat_cat_pic_name_b:contains(\"Android\"))": "106" + # Sport + ":has(div.kat_cat_pic_name:contains(\"Sport\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "43" + ":has(div.kat_cat_pic_name:contains(\"Sport\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "50" + # Sonstiges + ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"E-Books\"))": "34" + ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"Audiobook\"))": "35" + ":has(div.kat_cat_pic_name:contains(\"Sonstiges\")):has(div.kat_cat_pic_name_b:contains(\"Diverses\"))": "36" + # XXX + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"SD\"))": "46" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"HD\"))": "47" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Pack\"))": "45" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Sonstiges\"))": "49" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Hentai Serie\"))": "110" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"Hentai Movie\"))": "111" + ":has(div.kat_cat_pic_name:contains(\"XXX\")):has(div.kat_cat_pic_name_b:contains(\"SexBooks\"))": "116" + banner: + selector: div[id^="details"] img + attribute: src + size: + selector: div.selection_unter_ad + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + grabs: + selector: div.selection_unter_ae + filters: + - name: trim + args: "x" + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + seeders: + selector: div.selection_unter_aa + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + leechers: + selector: div.selection_unter_aaa + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + downloadvolumefactor: + case: + ":root:has(div.onlyup)": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + date: + selector: div.selection_unter_ab + filters: + - name: replace + args: ["Heute", "Today"] + - name: replace + args: ["Gestern", "Yesterday"] + - name: replace + args: [" um", ""] + - name: dateparse + args: "02.01.2006 15:04:05" + description: + selector: selection_unter_af + optional: true diff --git a/src/Jackett/Definitions/dreamteam.yml b/src/Jackett/Definitions/dreamteam.yml index c1c12f72..96fdbe3a 100644 --- a/src/Jackett/Definitions/dreamteam.yml +++ b/src/Jackett/Definitions/dreamteam.yml @@ -1,320 +1,320 @@ ---- - site: dreamteam - name: Dream Team - language: el-gr - type: private - encoding: UTF-8 - links: - - http://dream-team.ml/ - - caps: - categorymappings: -# - {id: 115, cat: , desc: ""} - - {id: 115, cat: Movies, desc: "One foreign films external subtitles"} - - {id: 130, cat: Movies, desc: "CAM / TS / TC"} - - {id: 131, cat: Movies, desc: "DVDSCR / PPVRiP / WebRip / R5"} - - {id: 132, cat: Movies, desc: "DVDRrip"} - - {id: 133, cat: Movies, desc: "BDRip / BRRip / HDRip"} - - {id: 134, cat: Movies, desc: "MicroHD"} - - {id: 135, cat: Movies, desc: "HD - WEB-DL"} - - {id: 136, cat: Movies, desc: "HD - 480p"} - - {id: 137, cat: Movies, desc: "HD - 720p"} - - {id: 138, cat: Movies, desc: "HD - 1080p"} - - {id: 139, cat: Movies, desc: "9.01 3D HD 720p Half SBS & OU"} - - {id: 140, cat: Movies, desc: "9.2 3D HD 1080p Half SBS & OU"} - - {id: 141, cat: Movies, desc: "9.3 3D Bluray Disc HD 720p / 1080p"} - - {id: 142, cat: Movies, desc: "9.4 3D MicroHD 720p / 1080p"} - - {id: 144, cat: Movies, desc: "9.5 packages"} - - {id: 145, cat: Movies, desc: "9.6 filmography"} - - {id: 143, cat: Movies, desc: "9.7 Tv Movies"} -# - {id: 130, cat: , desc: ""} -# - {id: 131, cat: , desc: ""} -# - {id: 132, cat: , desc: ""} -# - {id: 133, cat: , desc: ""} -# - {id: 134, cat: , desc: ""} -# - {id: 135, cat: , desc: ""} -# - {id: 136, cat: , desc: ""} -# - {id: 137, cat: , desc: ""} -# - {id: 138, cat: , desc: ""} -# - {id: 139, cat: , desc: ""} -# - {id: 140, cat: , desc: ""} -# - {id: 141, cat: , desc: ""} -# - {id: 142, cat: , desc: ""} -# - {id: 144, cat: , desc: ""} -# - {id: 145, cat: , desc: ""} -# - {id: 143, cat: , desc: ""} -# - {id: 116, cat: , desc: ""} - - {id: 116, cat: Movies, desc: "Two foreign films integrated subtitles"} - - {id: 146, cat: Movies, desc: "CAM / TS / TC"} - - {id: 147, cat: Movies, desc: "DVDSCR / PPVRiP / WebRip / R5"} - - {id: 148, cat: Movies, desc: "DVDRrip"} - - {id: 149, cat: Movies, desc: "BDRip / BRRip / HDRip"} - - {id: 150, cat: Movies, desc: "MicroHD"} - - {id: 151, cat: Movies, desc: "HD - WEB-DL"} - - {id: 152, cat: Movies, desc: "Tv Movies"} -# - {id: 242, cat: , desc: ""} - - {id: 153, cat: Movies, desc: "Packages"} - - {id: 154, cat: Movies, desc: "filmography"} - - {id: 243, cat: Movies, desc: "HD 1080p"} - - {id: 244, cat: Movies, desc: "HD 480p"} -# - {id: 146, cat: , desc: ""} -# - {id: 147, cat: , desc: ""} -# - {id: 148, cat: , desc: ""} -# - {id: 149, cat: , desc: ""} -# - {id: 150, cat: , desc: ""} -# - {id: 151, cat: , desc: ""} -# - {id: 152, cat: , desc: ""} -# - {id: 242, cat: , desc: ""} -# - {id: 153, cat: , desc: ""} -# - {id: 154, cat: , desc: ""} -# - {id: 243, cat: , desc: ""} -# - {id: 244, cat: , desc: ""} -# - {id: 117, cat: , desc: ""} - - {id: 117, cat: Movies, desc: "???????e? ?a???e?"} - - {id: 155, cat: Movies, desc: "CAM / TS / TC"} - - {id: 156, cat: Movies, desc: "SCR / PPVRiP / Webrip / R5"} - - {id: 157, cat: Movies, desc: "DVDRrip 3"} - - {id: 158, cat: Movies, desc: "BDRip / BRRip / HDRip"} - - {id: 159, cat: Movies, desc: "MicroHD 5"} - - {id: 160, cat: Movies, desc: "HD - 480p"} - - {id: 161, cat: Movies, desc: "6.1 HD - 720p"} - - {id: 162, cat: Movies, desc: "HD 6.2 - 1080"} - - {id: 163, cat: Movies, desc: "TV Movies"} - - {id: 164, cat: Movies, desc: "?a?eta 8"} - - {id: 165, cat: Movies, desc: "F??µ???af?e?"} -# - {id: 155, cat: , desc: ""} -# - {id: 156, cat: , desc: ""} -# - {id: 157, cat: , desc: ""} -# - {id: 158, cat: , desc: ""} -# - {id: 159, cat: , desc: ""} -# - {id: 160, cat: , desc: ""} -# - {id: 161, cat: , desc: ""} -# - {id: 162, cat: , desc: ""} -# - {id: 163, cat: , desc: ""} -# - {id: 164, cat: , desc: ""} -# - {id: 165, cat: , desc: ""} -# - {id: 118, cat: , desc: ""} - - {id: 118, cat: TV, desc: "Foreign Television external subtitles"} - - {id: 166, cat: TV, desc: "SD"} - - {id: 167, cat: TV, desc: "720p"} - - {id: 168, cat: TV, desc: "1080p"} - - {id: 169, cat: TV, desc: "Sport"} - - {id: 170, cat: TV, desc: "documentaries"} - - {id: 171, cat: TV, desc: "Packages"} -# - {id: 166, cat: , desc: ""} -# - {id: 167, cat: , desc: ""} -# - {id: 168, cat: , desc: ""} -# - {id: 169, cat: , desc: ""} -# - {id: 170, cat: , desc: ""} -# - {id: 171, cat: , desc: ""} -# - {id: 119, cat: , desc: ""} - - {id: 119, cat: TV, desc: "foreign Television integrated subtitles"} - - {id: 172, cat: TV, desc: "SD"} - - {id: 173, cat: TV, desc: "720p"} - - {id: 174, cat: TV, desc: "1080p"} - - {id: 175, cat: TV, desc: "Sport"} - - {id: 176, cat: TV, desc: "documentaries"} - - {id: 177, cat: TV, desc: "Tv Rips"} - - {id: 178, cat: TV, desc: "Packages"} -# - {id: 172, cat: , desc: ""} -# - {id: 173, cat: , desc: ""} -# - {id: 174, cat: , desc: ""} -# - {id: 175, cat: , desc: ""} -# - {id: 176, cat: , desc: ""} -# - {id: 177, cat: , desc: ""} -# - {id: 178, cat: , desc: ""} -# - {id: 120, cat: , desc: ""} - - {id: 120, cat: TV, desc: "Greek Television"} - - {id: 179, cat: TV, desc: "SD"} - - {id: 180, cat: TV, desc: "720p"} - - {id: 181, cat: TV, desc: "1080p"} - - {id: 182, cat: TV, desc: "Sport"} - - {id: 183, cat: TV, desc: "five documentaries"} - - {id: 184, cat: TV, desc: "six Tv Rips"} - - {id: 185, cat: TV, desc: "Packages"} -# - {id: 179, cat: , desc: ""} -# - {id: 180, cat: , desc: ""} -# - {id: 181, cat: , desc: ""} -# - {id: 182, cat: , desc: ""} -# - {id: 183, cat: , desc: ""} -# - {id: 184, cat: , desc: ""} -# - {id: 185, cat: , desc: ""} -# - {id: 122, cat: , desc: ""} - - {id: 122, cat: Audio, desc: "?e?? ???s???"} - - {id: 216, cat: Audio, desc: "1. DJs Stuff & Promos"} - - {id: 217, cat: Audio, desc: "2. DJs Stuff & Promos (Flac)"} - - {id: 218, cat: Audio, desc: "3. Singles"} - - {id: 219, cat: Audio, desc: "4. Singles (Flac)"} - - {id: 220, cat: Audio, desc: "5. ??s????af?e?"} - - {id: 221, cat: Audio, desc: "6. ??s????af?e? (Flac)"} - - {id: 222, cat: Audio, desc: "7. ??af??e? S?????e?"} - - {id: 223, cat: Audio, desc: "8. ??af??e? S?????e? (Flac)"} - - {id: 224, cat: Audio, desc: "9. SoundTracks"} - - {id: 225, cat: Audio, desc: "9.1 Varius Artist"} - - {id: 226, cat: Audio, desc: "9.2 Compact Disc Club"} - - {id: 227, cat: Audio, desc: "9.3 ???s??a Video Clips"} -# - {id: 123, cat: , desc: ""} - - {id: 123, cat: Audio, desc: "???????? ???s???"} - - {id: 228, cat: Audio, desc: "1. DJs Stuff & Promos"} - - {id: 229, cat: Audio, desc: "2. DJs Stuff & Promos (Flac)"} - - {id: 230, cat: Audio, desc: "3. Singles"} - - {id: 231, cat: Audio, desc: "4. Singles (Flac)"} - - {id: 232, cat: Audio, desc: "5. ??s????af?e?"} - - {id: 233, cat: Audio, desc: "6. ??s????af?e? (Flac)"} - - {id: 234, cat: Audio, desc: "7. ??af??e? S?????e?"} - - {id: 235, cat: Audio, desc: "8. ??af??e? S?????e? (Flac)"} - - {id: 236, cat: Audio, desc: "9. ?a?d??a"} - - {id: 237, cat: Audio, desc: "9.1 SoundTracks"} - - {id: 238, cat: Audio, desc: "9.2 Varius Artist"} - - {id: 239, cat: Audio, desc: "9.3 Compact Disc Club"} - - {id: 240, cat: Audio, desc: "9.4 ???s??a Video Clips"} -# - {id: 121, cat: , desc: ""} - - {id: 121, cat: Movies, desc: "children"} - - {id: 186, cat: Movies, desc: "children's films external subtitles"} - - {id: 187, cat: Movies, desc: "two children's films integrated subtitles"} - - {id: 188, cat: Movies, desc: "three children's films Metaglotismenes"} - - {id: 189, cat: Movies, desc: "four cartoon series external subtitles"} - - {id: 190, cat: Movies, desc: "five children's series integrated subtitles"} - - {id: 191, cat: Movies, desc: "six children's series Metaglotismenes"} - - {id: 192, cat: Movies, desc: "Anime external subtitles"} - - {id: 193, cat: Movies, desc: "Anime integrated subtitles"} - - {id: 194, cat: Movies, desc: "Anime Metaglotismenes"} -# - {id: 186, cat: , desc: ""} -# - {id: 187, cat: , desc: ""} -# - {id: 188, cat: , desc: ""} -# - {id: 189, cat: , desc: ""} -# - {id: 190, cat: , desc: ""} -# - {id: 191, cat: , desc: ""} -# - {id: 192, cat: , desc: ""} -# - {id: 193, cat: , desc: ""} -# - {id: 194, cat: , desc: ""} -# - {id: 128, cat: , desc: ""} - - {id: 128, cat: Console, desc: "9.1 ?a????d?a"} - - {id: 195, cat: Console, desc: "Windows Games"} - - {id: 196, cat: Console, desc: "Nintendo DS"} - - {id: 197, cat: Console, desc: "Sony PS1"} - - {id: 198, cat: Console, desc: "Sony PS2"} - - {id: 199, cat: Console, desc: "Sony PS3"} - - {id: 200, cat: Console, desc: "Sony PSP"} - - {id: 201, cat: Console, desc: "Wii"} - - {id: 202, cat: Console, desc: "XboX 360"} -# - {id: 124, cat: , desc: ""} - - {id: 124, cat: PC, desc: "9.2 Applications"} - - {id: 203, cat: PC, desc: "Applications Windows"} - - {id: 204, cat: PC, desc: "Applications Mac"} - - {id: 205, cat: PC, desc: "Linux Applications"} -# - {id: 203, cat: , desc: ""} -# - {id: 204, cat: , desc: ""} -# - {id: 205, cat: , desc: ""} -# - {id: 126, cat: , desc: ""} - - {id: 126, cat: Books, desc: "9.3 Electronic Books"} - - {id: 206, cat: Books, desc: "Electronic books"} - - {id: 207, cat: Books, desc: "Magazines"} - - {id: 208, cat: Books, desc: "Comic Books"} -# - {id: 206, cat: , desc: ""} -# - {id: 207, cat: , desc: ""} -# - {id: 208, cat: , desc: ""} -# - {id: 125, cat: , desc: ""} - - {id: 125, cat: Other, desc: "9.4 Gallery"} - - {id: 209, cat: Other, desc: "Gallery"} - - {id: 210, cat: Other, desc: "Gallery HD"} - - {id: 211, cat: Other, desc: "Photos 3D"} - - {id: 212, cat: Other, desc: "Wallpapers"} - - {id: 213, cat: Other, desc: "Screensavers"} -# - {id: 209, cat: , desc: ""} -# - {id: 210, cat: , desc: ""} -# - {id: 211, cat: , desc: ""} -# - {id: 212, cat: , desc: ""} -# - {id: 213, cat: , desc: ""} -# - {id: 127, cat: , desc: ""} - - {id: 127, cat: PC/Phone-Other, desc: "9.5 Mobile / Miscellaneous"} - - {id: 214, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 215, cat: PC/Phone-Other, desc: "Miscellaneous"} -# - {id: 214, cat: , desc: ""} -# - {id: 215, cat: , desc: ""} -# - {id: 129, cat: , desc: ""} - - {id: 129, cat: Other, desc: "9.6 Blocked DREAM TEAM"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td:contains("remaining tries") - test: - path: browse.php - selector: a[href^="http://dream-team.ml/logout.php"] - - download: - before: - path: "takethanks.php" - method: "post" - inputs: - torrentid: "{{ .DownloadUri.Query.id }}" - - search: - path: browse.php - keywordsfilters: - # remove words <= 3 characters and surrounding special characters - - name: re_replace - args: ["(?:^|\\s)[_\\+\\/\\.\\-\\(\\)]*[\\S]{0,3}[_\\+\\/\\.\\-\\(\\)]*(?:\\s|$)", " "] - inputs: - do: "search" - keywords: "{{ .Keywords }}" - search_type: "t_name" - category: "0" # multi cat search not supported - include_dead_torrents: "yes" - rows: - selector: table#sortabletable > tbody > tr:has(a[href^="http://dream-team.ml/details.php?id="]) - filters: - - name: andmatch - args: 66 - fields: - download: - selector: a[href^="http://dream-team.ml/download.php?id="] - attribute: href - title: - selector: a[href^="http://dream-team.ml/details.php?id="] - title|optional: - selector: div.tooltip-content > div - details: - selector: a[href^="http://dream-team.ml/details.php?id="] - attribute: href - category: - selector: a[href^="http://dream-team.ml/browse.php?category="] - attribute: href - filters: - - name: querystring - args: category - banner|optional: - selector: div.tooltip-content > img - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - img[alt^="Free Torrent "]: "0" - img[alt^="Silver Torrent "]: "0.5" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - date: - selector: "td:nth-child(2) > div:has(span[style=\"float: right;\"])" - remove: span - filters: - - name: append - args: " +00:00" - - name: dateparse - args: "02-01-2006 15:04 -07:00" +--- + site: dreamteam + name: Dream Team + language: el-gr + type: private + encoding: UTF-8 + links: + - http://dream-team.ml/ + + caps: + categorymappings: +# - {id: 115, cat: , desc: ""} + - {id: 115, cat: Movies, desc: "One foreign films external subtitles"} + - {id: 130, cat: Movies, desc: "CAM / TS / TC"} + - {id: 131, cat: Movies, desc: "DVDSCR / PPVRiP / WebRip / R5"} + - {id: 132, cat: Movies, desc: "DVDRrip"} + - {id: 133, cat: Movies, desc: "BDRip / BRRip / HDRip"} + - {id: 134, cat: Movies, desc: "MicroHD"} + - {id: 135, cat: Movies, desc: "HD - WEB-DL"} + - {id: 136, cat: Movies, desc: "HD - 480p"} + - {id: 137, cat: Movies, desc: "HD - 720p"} + - {id: 138, cat: Movies, desc: "HD - 1080p"} + - {id: 139, cat: Movies, desc: "9.01 3D HD 720p Half SBS & OU"} + - {id: 140, cat: Movies, desc: "9.2 3D HD 1080p Half SBS & OU"} + - {id: 141, cat: Movies, desc: "9.3 3D Bluray Disc HD 720p / 1080p"} + - {id: 142, cat: Movies, desc: "9.4 3D MicroHD 720p / 1080p"} + - {id: 144, cat: Movies, desc: "9.5 packages"} + - {id: 145, cat: Movies, desc: "9.6 filmography"} + - {id: 143, cat: Movies, desc: "9.7 Tv Movies"} +# - {id: 130, cat: , desc: ""} +# - {id: 131, cat: , desc: ""} +# - {id: 132, cat: , desc: ""} +# - {id: 133, cat: , desc: ""} +# - {id: 134, cat: , desc: ""} +# - {id: 135, cat: , desc: ""} +# - {id: 136, cat: , desc: ""} +# - {id: 137, cat: , desc: ""} +# - {id: 138, cat: , desc: ""} +# - {id: 139, cat: , desc: ""} +# - {id: 140, cat: , desc: ""} +# - {id: 141, cat: , desc: ""} +# - {id: 142, cat: , desc: ""} +# - {id: 144, cat: , desc: ""} +# - {id: 145, cat: , desc: ""} +# - {id: 143, cat: , desc: ""} +# - {id: 116, cat: , desc: ""} + - {id: 116, cat: Movies, desc: "Two foreign films integrated subtitles"} + - {id: 146, cat: Movies, desc: "CAM / TS / TC"} + - {id: 147, cat: Movies, desc: "DVDSCR / PPVRiP / WebRip / R5"} + - {id: 148, cat: Movies, desc: "DVDRrip"} + - {id: 149, cat: Movies, desc: "BDRip / BRRip / HDRip"} + - {id: 150, cat: Movies, desc: "MicroHD"} + - {id: 151, cat: Movies, desc: "HD - WEB-DL"} + - {id: 152, cat: Movies, desc: "Tv Movies"} +# - {id: 242, cat: , desc: ""} + - {id: 153, cat: Movies, desc: "Packages"} + - {id: 154, cat: Movies, desc: "filmography"} + - {id: 243, cat: Movies, desc: "HD 1080p"} + - {id: 244, cat: Movies, desc: "HD 480p"} +# - {id: 146, cat: , desc: ""} +# - {id: 147, cat: , desc: ""} +# - {id: 148, cat: , desc: ""} +# - {id: 149, cat: , desc: ""} +# - {id: 150, cat: , desc: ""} +# - {id: 151, cat: , desc: ""} +# - {id: 152, cat: , desc: ""} +# - {id: 242, cat: , desc: ""} +# - {id: 153, cat: , desc: ""} +# - {id: 154, cat: , desc: ""} +# - {id: 243, cat: , desc: ""} +# - {id: 244, cat: , desc: ""} +# - {id: 117, cat: , desc: ""} + - {id: 117, cat: Movies, desc: "???????e? ?a???e?"} + - {id: 155, cat: Movies, desc: "CAM / TS / TC"} + - {id: 156, cat: Movies, desc: "SCR / PPVRiP / Webrip / R5"} + - {id: 157, cat: Movies, desc: "DVDRrip 3"} + - {id: 158, cat: Movies, desc: "BDRip / BRRip / HDRip"} + - {id: 159, cat: Movies, desc: "MicroHD 5"} + - {id: 160, cat: Movies, desc: "HD - 480p"} + - {id: 161, cat: Movies, desc: "6.1 HD - 720p"} + - {id: 162, cat: Movies, desc: "HD 6.2 - 1080"} + - {id: 163, cat: Movies, desc: "TV Movies"} + - {id: 164, cat: Movies, desc: "?a?eta 8"} + - {id: 165, cat: Movies, desc: "F??µ???af?e?"} +# - {id: 155, cat: , desc: ""} +# - {id: 156, cat: , desc: ""} +# - {id: 157, cat: , desc: ""} +# - {id: 158, cat: , desc: ""} +# - {id: 159, cat: , desc: ""} +# - {id: 160, cat: , desc: ""} +# - {id: 161, cat: , desc: ""} +# - {id: 162, cat: , desc: ""} +# - {id: 163, cat: , desc: ""} +# - {id: 164, cat: , desc: ""} +# - {id: 165, cat: , desc: ""} +# - {id: 118, cat: , desc: ""} + - {id: 118, cat: TV, desc: "Foreign Television external subtitles"} + - {id: 166, cat: TV, desc: "SD"} + - {id: 167, cat: TV, desc: "720p"} + - {id: 168, cat: TV, desc: "1080p"} + - {id: 169, cat: TV, desc: "Sport"} + - {id: 170, cat: TV, desc: "documentaries"} + - {id: 171, cat: TV, desc: "Packages"} +# - {id: 166, cat: , desc: ""} +# - {id: 167, cat: , desc: ""} +# - {id: 168, cat: , desc: ""} +# - {id: 169, cat: , desc: ""} +# - {id: 170, cat: , desc: ""} +# - {id: 171, cat: , desc: ""} +# - {id: 119, cat: , desc: ""} + - {id: 119, cat: TV, desc: "foreign Television integrated subtitles"} + - {id: 172, cat: TV, desc: "SD"} + - {id: 173, cat: TV, desc: "720p"} + - {id: 174, cat: TV, desc: "1080p"} + - {id: 175, cat: TV, desc: "Sport"} + - {id: 176, cat: TV, desc: "documentaries"} + - {id: 177, cat: TV, desc: "Tv Rips"} + - {id: 178, cat: TV, desc: "Packages"} +# - {id: 172, cat: , desc: ""} +# - {id: 173, cat: , desc: ""} +# - {id: 174, cat: , desc: ""} +# - {id: 175, cat: , desc: ""} +# - {id: 176, cat: , desc: ""} +# - {id: 177, cat: , desc: ""} +# - {id: 178, cat: , desc: ""} +# - {id: 120, cat: , desc: ""} + - {id: 120, cat: TV, desc: "Greek Television"} + - {id: 179, cat: TV, desc: "SD"} + - {id: 180, cat: TV, desc: "720p"} + - {id: 181, cat: TV, desc: "1080p"} + - {id: 182, cat: TV, desc: "Sport"} + - {id: 183, cat: TV, desc: "five documentaries"} + - {id: 184, cat: TV, desc: "six Tv Rips"} + - {id: 185, cat: TV, desc: "Packages"} +# - {id: 179, cat: , desc: ""} +# - {id: 180, cat: , desc: ""} +# - {id: 181, cat: , desc: ""} +# - {id: 182, cat: , desc: ""} +# - {id: 183, cat: , desc: ""} +# - {id: 184, cat: , desc: ""} +# - {id: 185, cat: , desc: ""} +# - {id: 122, cat: , desc: ""} + - {id: 122, cat: Audio, desc: "?e?? ???s???"} + - {id: 216, cat: Audio, desc: "1. DJs Stuff & Promos"} + - {id: 217, cat: Audio, desc: "2. DJs Stuff & Promos (Flac)"} + - {id: 218, cat: Audio, desc: "3. Singles"} + - {id: 219, cat: Audio, desc: "4. Singles (Flac)"} + - {id: 220, cat: Audio, desc: "5. ??s????af?e?"} + - {id: 221, cat: Audio, desc: "6. ??s????af?e? (Flac)"} + - {id: 222, cat: Audio, desc: "7. ??af??e? S?????e?"} + - {id: 223, cat: Audio, desc: "8. ??af??e? S?????e? (Flac)"} + - {id: 224, cat: Audio, desc: "9. SoundTracks"} + - {id: 225, cat: Audio, desc: "9.1 Varius Artist"} + - {id: 226, cat: Audio, desc: "9.2 Compact Disc Club"} + - {id: 227, cat: Audio, desc: "9.3 ???s??a Video Clips"} +# - {id: 123, cat: , desc: ""} + - {id: 123, cat: Audio, desc: "???????? ???s???"} + - {id: 228, cat: Audio, desc: "1. DJs Stuff & Promos"} + - {id: 229, cat: Audio, desc: "2. DJs Stuff & Promos (Flac)"} + - {id: 230, cat: Audio, desc: "3. Singles"} + - {id: 231, cat: Audio, desc: "4. Singles (Flac)"} + - {id: 232, cat: Audio, desc: "5. ??s????af?e?"} + - {id: 233, cat: Audio, desc: "6. ??s????af?e? (Flac)"} + - {id: 234, cat: Audio, desc: "7. ??af??e? S?????e?"} + - {id: 235, cat: Audio, desc: "8. ??af??e? S?????e? (Flac)"} + - {id: 236, cat: Audio, desc: "9. ?a?d??a"} + - {id: 237, cat: Audio, desc: "9.1 SoundTracks"} + - {id: 238, cat: Audio, desc: "9.2 Varius Artist"} + - {id: 239, cat: Audio, desc: "9.3 Compact Disc Club"} + - {id: 240, cat: Audio, desc: "9.4 ???s??a Video Clips"} +# - {id: 121, cat: , desc: ""} + - {id: 121, cat: Movies, desc: "children"} + - {id: 186, cat: Movies, desc: "children's films external subtitles"} + - {id: 187, cat: Movies, desc: "two children's films integrated subtitles"} + - {id: 188, cat: Movies, desc: "three children's films Metaglotismenes"} + - {id: 189, cat: Movies, desc: "four cartoon series external subtitles"} + - {id: 190, cat: Movies, desc: "five children's series integrated subtitles"} + - {id: 191, cat: Movies, desc: "six children's series Metaglotismenes"} + - {id: 192, cat: Movies, desc: "Anime external subtitles"} + - {id: 193, cat: Movies, desc: "Anime integrated subtitles"} + - {id: 194, cat: Movies, desc: "Anime Metaglotismenes"} +# - {id: 186, cat: , desc: ""} +# - {id: 187, cat: , desc: ""} +# - {id: 188, cat: , desc: ""} +# - {id: 189, cat: , desc: ""} +# - {id: 190, cat: , desc: ""} +# - {id: 191, cat: , desc: ""} +# - {id: 192, cat: , desc: ""} +# - {id: 193, cat: , desc: ""} +# - {id: 194, cat: , desc: ""} +# - {id: 128, cat: , desc: ""} + - {id: 128, cat: Console, desc: "9.1 ?a????d?a"} + - {id: 195, cat: Console, desc: "Windows Games"} + - {id: 196, cat: Console, desc: "Nintendo DS"} + - {id: 197, cat: Console, desc: "Sony PS1"} + - {id: 198, cat: Console, desc: "Sony PS2"} + - {id: 199, cat: Console, desc: "Sony PS3"} + - {id: 200, cat: Console, desc: "Sony PSP"} + - {id: 201, cat: Console, desc: "Wii"} + - {id: 202, cat: Console, desc: "XboX 360"} +# - {id: 124, cat: , desc: ""} + - {id: 124, cat: PC, desc: "9.2 Applications"} + - {id: 203, cat: PC, desc: "Applications Windows"} + - {id: 204, cat: PC, desc: "Applications Mac"} + - {id: 205, cat: PC, desc: "Linux Applications"} +# - {id: 203, cat: , desc: ""} +# - {id: 204, cat: , desc: ""} +# - {id: 205, cat: , desc: ""} +# - {id: 126, cat: , desc: ""} + - {id: 126, cat: Books, desc: "9.3 Electronic Books"} + - {id: 206, cat: Books, desc: "Electronic books"} + - {id: 207, cat: Books, desc: "Magazines"} + - {id: 208, cat: Books, desc: "Comic Books"} +# - {id: 206, cat: , desc: ""} +# - {id: 207, cat: , desc: ""} +# - {id: 208, cat: , desc: ""} +# - {id: 125, cat: , desc: ""} + - {id: 125, cat: Other, desc: "9.4 Gallery"} + - {id: 209, cat: Other, desc: "Gallery"} + - {id: 210, cat: Other, desc: "Gallery HD"} + - {id: 211, cat: Other, desc: "Photos 3D"} + - {id: 212, cat: Other, desc: "Wallpapers"} + - {id: 213, cat: Other, desc: "Screensavers"} +# - {id: 209, cat: , desc: ""} +# - {id: 210, cat: , desc: ""} +# - {id: 211, cat: , desc: ""} +# - {id: 212, cat: , desc: ""} +# - {id: 213, cat: , desc: ""} +# - {id: 127, cat: , desc: ""} + - {id: 127, cat: PC/Phone-Other, desc: "9.5 Mobile / Miscellaneous"} + - {id: 214, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 215, cat: PC/Phone-Other, desc: "Miscellaneous"} +# - {id: 214, cat: , desc: ""} +# - {id: 215, cat: , desc: ""} +# - {id: 129, cat: , desc: ""} + - {id: 129, cat: Other, desc: "9.6 Blocked DREAM TEAM"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td:contains("remaining tries") + test: + path: browse.php + selector: a[href^="http://dream-team.ml/logout.php"] + + download: + before: + path: "takethanks.php" + method: "post" + inputs: + torrentid: "{{ .DownloadUri.Query.id }}" + + search: + path: browse.php + keywordsfilters: + # remove words <= 3 characters and surrounding special characters + - name: re_replace + args: ["(?:^|\\s)[_\\+\\/\\.\\-\\(\\)]*[\\S]{0,3}[_\\+\\/\\.\\-\\(\\)]*(?:\\s|$)", " "] + inputs: + do: "search" + keywords: "{{ .Keywords }}" + search_type: "t_name" + category: "0" # multi cat search not supported + include_dead_torrents: "yes" + rows: + selector: table#sortabletable > tbody > tr:has(a[href^="http://dream-team.ml/details.php?id="]) + filters: + - name: andmatch + args: 66 + fields: + download: + selector: a[href^="http://dream-team.ml/download.php?id="] + attribute: href + title: + selector: a[href^="http://dream-team.ml/details.php?id="] + title|optional: + selector: div.tooltip-content > div + details: + selector: a[href^="http://dream-team.ml/details.php?id="] + attribute: href + category: + selector: a[href^="http://dream-team.ml/browse.php?category="] + attribute: href + filters: + - name: querystring + args: category + banner|optional: + selector: div.tooltip-content > img + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + img[alt^="Free Torrent "]: "0" + img[alt^="Silver Torrent "]: "0.5" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + date: + selector: "td:nth-child(2) > div:has(span[style=\"float: right;\"])" + remove: span + filters: + - name: append + args: " +00:00" + - name: dateparse + args: "02-01-2006 15:04 -07:00" diff --git a/src/Jackett/Definitions/eotforum.yml b/src/Jackett/Definitions/eotforum.yml index bee3f7f8..61c300a6 100644 --- a/src/Jackett/Definitions/eotforum.yml +++ b/src/Jackett/Definitions/eotforum.yml @@ -1,180 +1,180 @@ ---- - site: eotforum - name: EoT-Forum - description: "A German gerneral tracker" - language: de-de - type: private - encoding: windows-1252 - links: - - http://eot-forum.net - - caps: - categorymappings: - # Filme - - {id: 14, cat: Movies/SD, desc: "SD XviD"} - - {id: 15, cat: Movies/SD, desc: "SD x264"} - - {id: 16, cat: Movies/HD, desc: "HD"} - - {id: 68, cat: Movies/HD, desc: "UHD"} - - {id: 17, cat: Movies/3D, desc: "3D"} - - {id: 18, cat: Movies/DVD, desc: "DVD-R"} - - {id: 19, cat: Movies, desc: "Pack"} - - {id: 20, cat: Movies, desc: "International"} - - {id: 21, cat: XXX, desc: "XXX"} - - # Serien/TV - - {id: 23, cat: TV/SD, desc: "SD XviD"} - - {id: 24, cat: TV/SD, desc: "SD x264"} - - {id: 25, cat: TV/HD, desc: "HD"} - - {id: 26, cat: TV/SD, desc: "DVD-R"} - - {id: 27, cat: TV, desc: "Pack"} - - {id: 28, cat: TV, desc: "International"} - - {id: 29, cat: TV/Sport, desc: "Sport"} - - # Dokus - - {id: 31, cat: TV/Documentary, desc: "SD XviD"} - - {id: 32, cat: TV/Documentary, desc: "SD x264"} - - {id: 33, cat: TV/Documentary, desc: "HD"} - - {id: 34, cat: TV/Documentary, desc: "3D"} - - {id: 35, cat: TV/Documentary, desc: "Pack"} - - {id: 67, cat: TV/Documentary, desc: "DVD-R"} - - {id: 36, cat: TV/Documentary, desc: "International"} - - # Audio - - {id: 38, cat: Audio, desc: "Charts"} - - {id: 39, cat: Audio/MP3, desc: "MP3"} - - {id: 40, cat: Audio/Lossless, desc: "Flac"} - - {id: 41, cat: Audio, desc: "Pack"} - - {id: 42, cat: Audio/Video, desc: "MusikVideo"} - - {id: 43, cat: Audio/Audiobook, desc: "Hörbücher"} - - # Spiele - - {id: 45, cat: PC/Games, desc: "Windows"} - - {id: 46, cat: PC/Mac, desc: "MacOS"} - - {id: 47, cat: Console/PS4, desc: "Sony PS"} - - {id: 48, cat: Console/Xbox , desc: "Microsoft XBox"} - - {id: 49, cat: Console/NDS, desc: "Nintendo"} - - {id: 50, cat: PC/Games, desc: "Linux"} - - {id: 51, cat: Console, desc: "Andere"} - - # Software - - {id: 53, cat: PC, desc: "Windows"} - - {id: 54, cat: PC/Mac, desc: "MacOS"} - - {id: 55, cat: PC, desc: "Linux"} - - {id: 56, cat: PC/Phone-Android, desc: "Android"} - - {id: 57, cat: PC/Phone-IOS, desc: "Apple IOS"} - - {id: 58, cat: PC/Phone-Other, desc: "Andere"} - - # Sonstiges - - {id: 60, cat: Books, desc: "EBooks"} - - {id: 61, cat: Other, desc: "Bilder"} - - {id: 62, cat: TV/Anime, desc: "Anime"} - - {id: 63, cat: Other, desc: "MISC"} - - {id: 64, cat: XXX, desc: "XXX-Bilder/EBooks/Audio"} - - # EOT-Specials - - {id: 66, cat: Other, desc: "Special"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: index.php?page=login - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - rememberme: "forever" - submit: "Login" - error: - - selector: td.lista[align="center"][colspan="2"] > span - test: - path: index.php - selector: img[alt="Ratio"] - - ratio: - path: index.php - selector: img[alt="Ratio"] + font - - search: - path: index.php - inputs: - page: "torrents" - search: "{{ .Query.Keywords }}" - options: "0" - active: "0" - gold: "0" - rows: - selector: table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) - dateheaders: - selector: ":has(td.header > b)" - filters: - - name: replace - args: ["Torrents vom ", ""] - - name: replace - args: ["Januar", "January"] - - name: replace - args: ["Februar", "February"] - - name: replace - args: ["März", "March"] - - name: replace - args: ["Mai", "May"] - - name: replace - args: ["Juni", "June"] - - name: replace - args: ["Juli", "July"] - - name: replace - args: ["Oktober", "October"] - - name: replace - args: ["Dezember", "December"] - - name: dateparse - args: "02.January.2006" - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: a[href^="index.php?page=torrent-details&id="] - attribute: title - filters: - - name: replace - args: ["Details anzeigen: ", ""] - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - comments: - selector: a[href*="#comments"] - attribute: href - size: - selector: td:nth-child(3) - grabs: - selector: td:nth-child(5) - filters: - - name: split - args: ["♦", 2] - - name: replace - args: ["---", "0"] - seeders: - selector: td:nth-child(5) > a:nth-child(1) - leechers: - selector: td:nth-child(5) > a:nth-child(2) - downloadvolumefactor: - case: - img[alt="gold"]: "0" - img[alt="silver"]: "0.5" - "*": "1" - uploadvolumefactor: - case: - img[alt="2x Upload Multiplier"]: "2" - img[alt="3x Upload Multiplier"]: "3" - img[alt="4x Upload Multiplier"]: "4" - img[alt="5x Upload Multiplier"]: "5" - img[alt="6x Upload Multiplier"]: "6" - img[alt="7x Upload Multiplier"]: "7" - img[alt="8x Upload Multiplier"]: "8" - img[alt="9x Upload Multiplier"]: "9" - img[alt="10x Upload Multiplier"]: "10" - "*": "1" +--- + site: eotforum + name: EoT-Forum + description: "A German gerneral tracker" + language: de-de + type: private + encoding: windows-1252 + links: + - http://eot-forum.net + + caps: + categorymappings: + # Filme + - {id: 14, cat: Movies/SD, desc: "SD XviD"} + - {id: 15, cat: Movies/SD, desc: "SD x264"} + - {id: 16, cat: Movies/HD, desc: "HD"} + - {id: 68, cat: Movies/HD, desc: "UHD"} + - {id: 17, cat: Movies/3D, desc: "3D"} + - {id: 18, cat: Movies/DVD, desc: "DVD-R"} + - {id: 19, cat: Movies, desc: "Pack"} + - {id: 20, cat: Movies, desc: "International"} + - {id: 21, cat: XXX, desc: "XXX"} + + # Serien/TV + - {id: 23, cat: TV/SD, desc: "SD XviD"} + - {id: 24, cat: TV/SD, desc: "SD x264"} + - {id: 25, cat: TV/HD, desc: "HD"} + - {id: 26, cat: TV/SD, desc: "DVD-R"} + - {id: 27, cat: TV, desc: "Pack"} + - {id: 28, cat: TV, desc: "International"} + - {id: 29, cat: TV/Sport, desc: "Sport"} + + # Dokus + - {id: 31, cat: TV/Documentary, desc: "SD XviD"} + - {id: 32, cat: TV/Documentary, desc: "SD x264"} + - {id: 33, cat: TV/Documentary, desc: "HD"} + - {id: 34, cat: TV/Documentary, desc: "3D"} + - {id: 35, cat: TV/Documentary, desc: "Pack"} + - {id: 67, cat: TV/Documentary, desc: "DVD-R"} + - {id: 36, cat: TV/Documentary, desc: "International"} + + # Audio + - {id: 38, cat: Audio, desc: "Charts"} + - {id: 39, cat: Audio/MP3, desc: "MP3"} + - {id: 40, cat: Audio/Lossless, desc: "Flac"} + - {id: 41, cat: Audio, desc: "Pack"} + - {id: 42, cat: Audio/Video, desc: "MusikVideo"} + - {id: 43, cat: Audio/Audiobook, desc: "Hörbücher"} + + # Spiele + - {id: 45, cat: PC/Games, desc: "Windows"} + - {id: 46, cat: PC/Mac, desc: "MacOS"} + - {id: 47, cat: Console/PS4, desc: "Sony PS"} + - {id: 48, cat: Console/Xbox , desc: "Microsoft XBox"} + - {id: 49, cat: Console/NDS, desc: "Nintendo"} + - {id: 50, cat: PC/Games, desc: "Linux"} + - {id: 51, cat: Console, desc: "Andere"} + + # Software + - {id: 53, cat: PC, desc: "Windows"} + - {id: 54, cat: PC/Mac, desc: "MacOS"} + - {id: 55, cat: PC, desc: "Linux"} + - {id: 56, cat: PC/Phone-Android, desc: "Android"} + - {id: 57, cat: PC/Phone-IOS, desc: "Apple IOS"} + - {id: 58, cat: PC/Phone-Other, desc: "Andere"} + + # Sonstiges + - {id: 60, cat: Books, desc: "EBooks"} + - {id: 61, cat: Other, desc: "Bilder"} + - {id: 62, cat: TV/Anime, desc: "Anime"} + - {id: 63, cat: Other, desc: "MISC"} + - {id: 64, cat: XXX, desc: "XXX-Bilder/EBooks/Audio"} + + # EOT-Specials + - {id: 66, cat: Other, desc: "Special"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + rememberme: "forever" + submit: "Login" + error: + - selector: td.lista[align="center"][colspan="2"] > span + test: + path: index.php + selector: img[alt="Ratio"] + + ratio: + path: index.php + selector: img[alt="Ratio"] + font + + search: + path: index.php + inputs: + page: "torrents" + search: "{{ .Query.Keywords }}" + options: "0" + active: "0" + gold: "0" + rows: + selector: table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) + dateheaders: + selector: ":has(td.header > b)" + filters: + - name: replace + args: ["Torrents vom ", ""] + - name: replace + args: ["Januar", "January"] + - name: replace + args: ["Februar", "February"] + - name: replace + args: ["März", "March"] + - name: replace + args: ["Mai", "May"] + - name: replace + args: ["Juni", "June"] + - name: replace + args: ["Juli", "July"] + - name: replace + args: ["Oktober", "October"] + - name: replace + args: ["Dezember", "December"] + - name: dateparse + args: "02.January.2006" + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: a[href^="index.php?page=torrent-details&id="] + attribute: title + filters: + - name: replace + args: ["Details anzeigen: ", ""] + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + comments: + selector: a[href*="#comments"] + attribute: href + size: + selector: td:nth-child(3) + grabs: + selector: td:nth-child(5) + filters: + - name: split + args: ["♦", 2] + - name: replace + args: ["---", "0"] + seeders: + selector: td:nth-child(5) > a:nth-child(1) + leechers: + selector: td:nth-child(5) > a:nth-child(2) + downloadvolumefactor: + case: + img[alt="gold"]: "0" + img[alt="silver"]: "0.5" + "*": "1" + uploadvolumefactor: + case: + img[alt="2x Upload Multiplier"]: "2" + img[alt="3x Upload Multiplier"]: "3" + img[alt="4x Upload Multiplier"]: "4" + img[alt="5x Upload Multiplier"]: "5" + img[alt="6x Upload Multiplier"]: "6" + img[alt="7x Upload Multiplier"]: "7" + img[alt="8x Upload Multiplier"]: "8" + img[alt="9x Upload Multiplier"]: "9" + img[alt="10x Upload Multiplier"]: "10" + "*": "1" diff --git a/src/Jackett/Definitions/estone.yml b/src/Jackett/Definitions/estone.yml index a9115bf4..c816bf4d 100644 --- a/src/Jackett/Definitions/estone.yml +++ b/src/Jackett/Definitions/estone.yml @@ -1,119 +1,119 @@ ---- - site: estone - name: eStone - language: hu-hu - type: private - encoding: UTF-8 - links: - - http://estone.cc/ - - caps: - categorymappings: - - {id: 24, cat: Movies/SD, desc: "Film/XviD/Hun"} - - {id: 38, cat: Movies/SD, desc: "Film/XviD/Eng"} - - {id: 51, cat: Movies/SD, desc: "Film/SD/Hun"} - - {id: 52, cat: Movies/SD, desc: "Film/SD/Eng"} - - {id: 25, cat: Movies/DVD, desc: "Film/DVD/Hun"} - - {id: 26, cat: Movies/DVD, desc: "Film/DVD/Eng"} - - {id: 42, cat: Movies/HD, desc: "Film/HD/Hun"} - - {id: 50, cat: Movies/HD, desc: "Film/HD/Eng"} - - {id: 36, cat: TV, desc: "Sorozat/Hun"} - - {id: 47, cat: TV, desc: "Sorozat/Eng"} - - {id: 41, cat: Audio/MP3, desc: "Mp3/Hun"} - - {id: 40, cat: Audio/MP3, desc: "Mp3/Eng"} - - {id: 35, cat: PC/0day, desc: "Program"} - - {id: 28, cat: PC/Games, desc: "Játék/ISO"} - - {id: 30, cat: PC/Games, desc: "Játék/Rip"} - - {id: 32, cat: Console, desc: "Konzol"} - - {id: 34, cat: PC/Phone-Other, desc: "Mobil"} - - {id: 44, cat: Books, desc: "Könyv/Hun"} - - {id: 33, cat: Books, desc: "Könyv/Eng"} - - {id: 31, cat: Other, desc: "Képek"} - - {id: 39, cat: XXX, desc: "XXX/Film"} - - {id: 49, cat: XXX/Imageset, desc: "XXX/Kép"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - login_username: "{{ .Config.username }}" - login_password: "{{ .Config.password }}" - error: - - selector: script:contains("hiba(\"") - message: - selector: script:contains("hiba(\"") - filters: - - name: replace - args: ["hiba(\"", ""] - - name: replace - args: ["\");", ""] - test: - path: /letoltes.php - - search: - path: /letoltes.php - method: get - inputs: - $raw: "{{range .Categories}}kat[]={{.}}&{{end}}" - kereses_nev: "{{ .Query.Keywords }}" - rows: - selector: body > div[id^="torrent_"] - fields: - title: - selector: a[title] - attribute: title - category: - selector: div#kategoria_torrent > a - attribute: href - filters: - - name: querystring - args: cat - details: - attribute: id - filters: - - name: replace - args: ["torrent_", "adatlap.php?id="] - download: - attribute: id - filters: - - name: replace - args: ["torrent_", "download.php?id="] - banner: - selector: img[onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: borito\("(.*?) +?", - size: - selector: input[id^="meret_"] - attribute: value - grabs: - selector: div:nth-child(8) > div - seeders: - selector: div:nth-child(6) > div > a - leechers: - selector: div:nth-child(7) > div > a - date: - selector: div:nth-child(4) - filters: - - name: split - args: ["(", 0] - - name: append - args: "+01:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img[src="pic/free.png"]: "0" - "*": "1" - uploadvolumefactor: - case: - img[src="pic/dupla_up.png"]: "2" - "*": "1" - description: - selector: div:nth-child(2) - remove: a +--- + site: estone + name: eStone + language: hu-hu + type: private + encoding: UTF-8 + links: + - http://estone.cc/ + + caps: + categorymappings: + - {id: 24, cat: Movies/SD, desc: "Film/XviD/Hun"} + - {id: 38, cat: Movies/SD, desc: "Film/XviD/Eng"} + - {id: 51, cat: Movies/SD, desc: "Film/SD/Hun"} + - {id: 52, cat: Movies/SD, desc: "Film/SD/Eng"} + - {id: 25, cat: Movies/DVD, desc: "Film/DVD/Hun"} + - {id: 26, cat: Movies/DVD, desc: "Film/DVD/Eng"} + - {id: 42, cat: Movies/HD, desc: "Film/HD/Hun"} + - {id: 50, cat: Movies/HD, desc: "Film/HD/Eng"} + - {id: 36, cat: TV, desc: "Sorozat/Hun"} + - {id: 47, cat: TV, desc: "Sorozat/Eng"} + - {id: 41, cat: Audio/MP3, desc: "Mp3/Hun"} + - {id: 40, cat: Audio/MP3, desc: "Mp3/Eng"} + - {id: 35, cat: PC/0day, desc: "Program"} + - {id: 28, cat: PC/Games, desc: "Játék/ISO"} + - {id: 30, cat: PC/Games, desc: "Játék/Rip"} + - {id: 32, cat: Console, desc: "Konzol"} + - {id: 34, cat: PC/Phone-Other, desc: "Mobil"} + - {id: 44, cat: Books, desc: "Könyv/Hun"} + - {id: 33, cat: Books, desc: "Könyv/Eng"} + - {id: 31, cat: Other, desc: "Képek"} + - {id: 39, cat: XXX, desc: "XXX/Film"} + - {id: 49, cat: XXX/Imageset, desc: "XXX/Kép"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + login_username: "{{ .Config.username }}" + login_password: "{{ .Config.password }}" + error: + - selector: script:contains("hiba(\"") + message: + selector: script:contains("hiba(\"") + filters: + - name: replace + args: ["hiba(\"", ""] + - name: replace + args: ["\");", ""] + test: + path: /letoltes.php + + search: + path: /letoltes.php + method: get + inputs: + $raw: "{{range .Categories}}kat[]={{.}}&{{end}}" + kereses_nev: "{{ .Query.Keywords }}" + rows: + selector: body > div[id^="torrent_"] + fields: + title: + selector: a[title] + attribute: title + category: + selector: div#kategoria_torrent > a + attribute: href + filters: + - name: querystring + args: cat + details: + attribute: id + filters: + - name: replace + args: ["torrent_", "adatlap.php?id="] + download: + attribute: id + filters: + - name: replace + args: ["torrent_", "download.php?id="] + banner: + selector: img[onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: borito\("(.*?) +?", + size: + selector: input[id^="meret_"] + attribute: value + grabs: + selector: div:nth-child(8) > div + seeders: + selector: div:nth-child(6) > div > a + leechers: + selector: div:nth-child(7) > div > a + date: + selector: div:nth-child(4) + filters: + - name: split + args: ["(", 0] + - name: append + args: "+01:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img[src="pic/free.png"]: "0" + "*": "1" + uploadvolumefactor: + case: + img[src="pic/dupla_up.png"]: "2" + "*": "1" + description: + selector: div:nth-child(2) + remove: a diff --git a/src/Jackett/Definitions/ethor.yml b/src/Jackett/Definitions/ethor.yml index 7663aa03..d34bb64b 100644 --- a/src/Jackett/Definitions/ethor.yml +++ b/src/Jackett/Definitions/ethor.yml @@ -1,119 +1,119 @@ ---- - site: ethor - name: Ethor.net (Thor's Land) - description: "A French gerneral tracker" - language: fr-fr - type: private - encoding: UTF-8 - links: - - https://ethor.net/ - - caps: - categorymappings: - - {id: 22, cat: PC, desc: "Applications/Divers"} - - {id: 1, cat: PC, desc: "Applications/PC ISO"} - - {id: 44, cat: PC, desc: "Applications/Portable"} - - {id: 47, cat: Movies/BluRay, desc: "Films/Bluray"} - - {id: 20, cat: Movies/DVD, desc: "Films/DVDr"} - - {id: 42, cat: Movies/HD, desc: "Films/HD Rip"} - - {id: 19, cat: Movies/SD, desc: "Films/SD Rip"} - - {id: 5, cat: Movies/SD, desc: "Films/VCD"} - - {id: 4, cat: PC/Games, desc: "Jeux/PC"} - - {id: 41, cat: Console, desc: "Jeux/Portable"} - - {id: 34, cat: Console/PS4, desc: "Jeux/PS2-PS3"} - - {id: 38, cat: Console/Wii, desc: "Jeux/Wii-GC"} - - {id: 40, cat: Console/Xbox, desc: "Jeux/Xbox360"} - - {id: 6, cat: Audio, desc: "Musique"} - - {id: 37, cat: Audio/Video, desc: "Musique/Video"} - - {id: 48, cat: TV/HD, desc: "Série-Télé/Bluray"} - - {id: 45, cat: TV/SD, desc: "Série-Télé/DVDr"} - - {id: 43, cat: TV/HD, desc: "Série-Télé/HD Rip"} - - {id: 7, cat: TV/SD, desc: "Série-Télé/SD Rip"} - - {id: 23, cat: Books, desc: "E-Books"} - - {id: 46, cat: Other, desc: "Évé. sportif"} - - {id: 36, cat: Other, desc: "Kidz"} - - {id: 25, cat: Other, desc: "Misc"} - - {id: 9, cat: XXX, desc: "XXX"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q, imdbid] - - login: - path: login3.php - method: form - form: form[action="login3.php?takelogin=1"] - captcha: - type: image - image: img#validationimage - input: validationcode - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - secure_cookie: "0" - test: - path: browse.php - - ratio: - path: browse.php - selector: span#ratioRatio - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" - advcat: "0" - incldead: "1" - stype: "b" - dp: "0" - isUserClick: "0" - rows: - selector: p + table > tbody > tr:has(a[href^="/details.php"]) - fields: - download: - selector: a[href^="/details.php"]:has(b) - attribute: href - filters: - - name: replace - args: ["/details.php", "/download.php"] - title: - selector: a[href^="/details.php"]:has(b) - category: - selector: a[href^="/browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - comments: - selector: a[href^="/details.php"]:has(b) - attribute: href - files: - selector: a[href*="#filelist"] - size: - selector: td:nth-child(6) - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: "(\\d+)" - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - date: - selector: td:nth-child(5) - filters: - - name: append - args: " -05:00" # timezone offset - - name: dateparse - args: "2006-01-0215:04:05 -07:00" - downloadvolumefactor: - case: - "img[title^=\"Freeleech: \"]": "0" - "img[title^=\"Half Freeleech: \"]": "0.5" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: ethor + name: Ethor.net (Thor's Land) + description: "A French gerneral tracker" + language: fr-fr + type: private + encoding: UTF-8 + links: + - https://ethor.net/ + + caps: + categorymappings: + - {id: 22, cat: PC, desc: "Applications/Divers"} + - {id: 1, cat: PC, desc: "Applications/PC ISO"} + - {id: 44, cat: PC, desc: "Applications/Portable"} + - {id: 47, cat: Movies/BluRay, desc: "Films/Bluray"} + - {id: 20, cat: Movies/DVD, desc: "Films/DVDr"} + - {id: 42, cat: Movies/HD, desc: "Films/HD Rip"} + - {id: 19, cat: Movies/SD, desc: "Films/SD Rip"} + - {id: 5, cat: Movies/SD, desc: "Films/VCD"} + - {id: 4, cat: PC/Games, desc: "Jeux/PC"} + - {id: 41, cat: Console, desc: "Jeux/Portable"} + - {id: 34, cat: Console/PS4, desc: "Jeux/PS2-PS3"} + - {id: 38, cat: Console/Wii, desc: "Jeux/Wii-GC"} + - {id: 40, cat: Console/Xbox, desc: "Jeux/Xbox360"} + - {id: 6, cat: Audio, desc: "Musique"} + - {id: 37, cat: Audio/Video, desc: "Musique/Video"} + - {id: 48, cat: TV/HD, desc: "Série-Télé/Bluray"} + - {id: 45, cat: TV/SD, desc: "Série-Télé/DVDr"} + - {id: 43, cat: TV/HD, desc: "Série-Télé/HD Rip"} + - {id: 7, cat: TV/SD, desc: "Série-Télé/SD Rip"} + - {id: 23, cat: Books, desc: "E-Books"} + - {id: 46, cat: Other, desc: "Évé. sportif"} + - {id: 36, cat: Other, desc: "Kidz"} + - {id: 25, cat: Other, desc: "Misc"} + - {id: 9, cat: XXX, desc: "XXX"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q, imdbid] + + login: + path: login3.php + method: form + form: form[action="login3.php?takelogin=1"] + captcha: + type: image + image: img#validationimage + input: validationcode + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + secure_cookie: "0" + test: + path: browse.php + + ratio: + path: browse.php + selector: span#ratioRatio + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" + advcat: "0" + incldead: "1" + stype: "b" + dp: "0" + isUserClick: "0" + rows: + selector: p + table > tbody > tr:has(a[href^="/details.php"]) + fields: + download: + selector: a[href^="/details.php"]:has(b) + attribute: href + filters: + - name: replace + args: ["/details.php", "/download.php"] + title: + selector: a[href^="/details.php"]:has(b) + category: + selector: a[href^="/browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + comments: + selector: a[href^="/details.php"]:has(b) + attribute: href + files: + selector: a[href*="#filelist"] + size: + selector: td:nth-child(6) + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: "(\\d+)" + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + date: + selector: td:nth-child(5) + filters: + - name: append + args: " -05:00" # timezone offset + - name: dateparse + args: "2006-01-0215:04:05 -07:00" + downloadvolumefactor: + case: + "img[title^=\"Freeleech: \"]": "0" + "img[title^=\"Half Freeleech: \"]": "0.5" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/freedomhd.yml b/src/Jackett/Definitions/freedomhd.yml index 02aec14f..19773fcb 100644 --- a/src/Jackett/Definitions/freedomhd.yml +++ b/src/Jackett/Definitions/freedomhd.yml @@ -1,130 +1,130 @@ ---- - site: freedomhd - name: Freedom-HD - language: fr-fr - type: private - encoding: UTF-8 - links: - - http://freedom-paradise.eu/ - - caps: - categorymappings: - # ANIMES - - {id: 105, cat: TV/Anime, desc: "1080p"} - - {id: 104, cat: TV/Anime, desc: "720p"} - - {id: 90, cat: TV/Anime, desc: "HDRIP-720p"} - - {id: 93, cat: TV/Anime, desc: "HDRIP1080p"} - - {id: 131, cat: TV/Anime, desc: "SD"} - - {id: 120, cat: TV/Anime, desc: "X265-1080p"} - - {id: 119, cat: TV/Anime, desc: "X265-720p"} - - {id: 107, cat: TV/Anime, desc: "1080p"} - - {id: 106, cat: TV/Anime, desc: "720p"} - - {id: 94, cat: TV/Anime, desc: "HDRIP1080p"} - - {id: 91, cat: TV/Anime, desc: "HDRIP720p"} - - # EBOOK - - {id: 124, cat: Books, desc: "Livres et Magazines"} - - # FILMS - - {id: 97, cat: Movies/HD, desc: "1080p"} - - {id: 103, cat: Movies/3D, desc: "3D"} - - {id: 111, cat: Movies/HD, desc: "4K"} - - {id: 96, cat: Movies/HD, desc: "720p"} - - {id: 127, cat: Movies/HD, desc: "BDrip"} - - {id: 128, cat: Movies/HD, desc: "BRrip"} - - {id: 126, cat: Movies/SD, desc: "DVDrip"} - - {id: 89, cat: Movies/HD, desc: "HDRIP-720p"} - - {id: 92, cat: Movies/HD, desc: "HDRIP1080p"} - - {id: 112, cat: Movies/SD, desc: "Team-Hush"} - - {id: 129, cat: Movies/HD, desc: "Team-Romkent"} - - {id: 125, cat: Movies/Other, desc: "WEBrip"} - - {id: 110, cat: Movies/HD, desc: "X265-1080p"} - - {id: 109, cat: Movies/HD, desc: "X265-720p"} - - # MUSIQUES - - {id: 114, cat: Audio/Lossless, desc: "Flac"} - - {id: 113, cat: Audio/MP3, desc: "MP3"} - - {id: 132, cat: Audio, desc: "Musiques-HQ"} - - {id: 130, cat: Audio/Video, desc: "video clip"} - - # SERIE-sd - - {id: 121, cat: TV/SD, desc: "SD"} - - # SERIES-HD - - {id: 102, cat: TV/HD, desc: "1080p"} - - {id: 101, cat: TV/HD, desc: "720p"} - - {id: 100, cat: TV/HD, desc: "HDrip1080p"} - - {id: 99, cat: TV/HD, desc: "HDrip720p"} - - # SPECTACLES - - {id: 118, cat: TV/Sport, desc: "HDRIP1080p"} - - {id: 117, cat: TV/Sport, desc: "HDRIP720p"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: account-login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - remember: "yes" - returnto: "/" - error: - - selector: div.myFrame:has(font.error) - test: - path: torrents-search.php - - search: - path: torrents-search.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - - rows: - selector: table.ttable_headinner > tbody > tr[class^="t-row"] - filters: - - name: andmatch - after: 1 - fields: - download: - selector: a[href^="torrents-details.php?id="] - attribute: href - filters: - - name: replace - args: ["torrents-details.php", "download.php"] - title: - selector: a[href^="torrents-details.php?id="] - attribute: title - category: - selector: a[href^="torrents.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="torrents-details.php?id="] - attribute: href - description: - selector: ul - banner: - selector: img.rounded-img - attribute: src - size: - selector: td:nth-child(3) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(4) - leechers: - selector: td:nth-child(5) - downloadvolumefactor: - case: - img[alt="freeleech"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: freedomhd + name: Freedom-HD + language: fr-fr + type: private + encoding: UTF-8 + links: + - http://freedom-paradise.eu/ + + caps: + categorymappings: + # ANIMES + - {id: 105, cat: TV/Anime, desc: "1080p"} + - {id: 104, cat: TV/Anime, desc: "720p"} + - {id: 90, cat: TV/Anime, desc: "HDRIP-720p"} + - {id: 93, cat: TV/Anime, desc: "HDRIP1080p"} + - {id: 131, cat: TV/Anime, desc: "SD"} + - {id: 120, cat: TV/Anime, desc: "X265-1080p"} + - {id: 119, cat: TV/Anime, desc: "X265-720p"} + - {id: 107, cat: TV/Anime, desc: "1080p"} + - {id: 106, cat: TV/Anime, desc: "720p"} + - {id: 94, cat: TV/Anime, desc: "HDRIP1080p"} + - {id: 91, cat: TV/Anime, desc: "HDRIP720p"} + + # EBOOK + - {id: 124, cat: Books, desc: "Livres et Magazines"} + + # FILMS + - {id: 97, cat: Movies/HD, desc: "1080p"} + - {id: 103, cat: Movies/3D, desc: "3D"} + - {id: 111, cat: Movies/HD, desc: "4K"} + - {id: 96, cat: Movies/HD, desc: "720p"} + - {id: 127, cat: Movies/HD, desc: "BDrip"} + - {id: 128, cat: Movies/HD, desc: "BRrip"} + - {id: 126, cat: Movies/SD, desc: "DVDrip"} + - {id: 89, cat: Movies/HD, desc: "HDRIP-720p"} + - {id: 92, cat: Movies/HD, desc: "HDRIP1080p"} + - {id: 112, cat: Movies/SD, desc: "Team-Hush"} + - {id: 129, cat: Movies/HD, desc: "Team-Romkent"} + - {id: 125, cat: Movies/Other, desc: "WEBrip"} + - {id: 110, cat: Movies/HD, desc: "X265-1080p"} + - {id: 109, cat: Movies/HD, desc: "X265-720p"} + + # MUSIQUES + - {id: 114, cat: Audio/Lossless, desc: "Flac"} + - {id: 113, cat: Audio/MP3, desc: "MP3"} + - {id: 132, cat: Audio, desc: "Musiques-HQ"} + - {id: 130, cat: Audio/Video, desc: "video clip"} + + # SERIE-sd + - {id: 121, cat: TV/SD, desc: "SD"} + + # SERIES-HD + - {id: 102, cat: TV/HD, desc: "1080p"} + - {id: 101, cat: TV/HD, desc: "720p"} + - {id: 100, cat: TV/HD, desc: "HDrip1080p"} + - {id: 99, cat: TV/HD, desc: "HDrip720p"} + + # SPECTACLES + - {id: 118, cat: TV/Sport, desc: "HDRIP1080p"} + - {id: 117, cat: TV/Sport, desc: "HDRIP720p"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: account-login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + remember: "yes" + returnto: "/" + error: + - selector: div.myFrame:has(font.error) + test: + path: torrents-search.php + + search: + path: torrents-search.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + + rows: + selector: table.ttable_headinner > tbody > tr[class^="t-row"] + filters: + - name: andmatch + after: 1 + fields: + download: + selector: a[href^="torrents-details.php?id="] + attribute: href + filters: + - name: replace + args: ["torrents-details.php", "download.php"] + title: + selector: a[href^="torrents-details.php?id="] + attribute: title + category: + selector: a[href^="torrents.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="torrents-details.php?id="] + attribute: href + description: + selector: ul + banner: + selector: img.rounded-img + attribute: src + size: + selector: td:nth-child(3) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(4) + leechers: + selector: td:nth-child(5) + downloadvolumefactor: + case: + img[alt="freeleech"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/gfxpeers.yml b/src/Jackett/Definitions/gfxpeers.yml index bd2ac02f..1ad30664 100644 --- a/src/Jackett/Definitions/gfxpeers.yml +++ b/src/Jackett/Definitions/gfxpeers.yml @@ -1,80 +1,80 @@ ---- - site: gfxpeers - name: GFXPeers - language: en-us - type: private - encoding: UTF-8 - links: - - https://gfxpeers.net/ - - caps: - categorymappings: - - {id: 1, cat: PC/0day, desc: "Applications"} - - {id: 2, cat: PC/0day, desc: "Plug-ins"} - - {id: 3, cat: Other, desc: "Tutorials"} - - {id: 4, cat: Other, desc: "Textures"} - - {id: 5, cat: Other, desc: "3D Models"} - - {id: 6, cat: Other, desc: "Game-Dev"} - - {id: 7, cat: Other, desc: "Miscellaneous"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: "1" - error: - - selector: .auth_form > .warning - test: - path: /torrents.php - - search: - path: /torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: "time" - order_way: "desc" - action: "advanced" - searchsubmit: "1" - - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - title: - selector: a[href^="torrents.php?id="] - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" - category: - selector: a[href^="torrents.php?filter_cat"] - attribute: href - filters: - - name: regexp - args: "\\[(\\d+?)\\]" - details: - selector: a[href^="torrents.php?id="] - attribute: href - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - files: - selector: td:nth-child(3) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - date: - selector: td:nth-child(4) +--- + site: gfxpeers + name: GFXPeers + language: en-us + type: private + encoding: UTF-8 + links: + - https://gfxpeers.net/ + + caps: + categorymappings: + - {id: 1, cat: PC/0day, desc: "Applications"} + - {id: 2, cat: PC/0day, desc: "Plug-ins"} + - {id: 3, cat: Other, desc: "Tutorials"} + - {id: 4, cat: Other, desc: "Textures"} + - {id: 5, cat: Other, desc: "3D Models"} + - {id: 6, cat: Other, desc: "Game-Dev"} + - {id: 7, cat: Other, desc: "Miscellaneous"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: "1" + error: + - selector: .auth_form > .warning + test: + path: /torrents.php + + search: + path: /torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: "time" + order_way: "desc" + action: "advanced" + searchsubmit: "1" + + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + title: + selector: a[href^="torrents.php?id="] + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" + category: + selector: a[href^="torrents.php?filter_cat"] + attribute: href + filters: + - name: regexp + args: "\\[(\\d+?)\\]" + details: + selector: a[href^="torrents.php?id="] + attribute: href + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + files: + selector: td:nth-child(3) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + date: + selector: td:nth-child(4) diff --git a/src/Jackett/Definitions/gods.yml b/src/Jackett/Definitions/gods.yml index 6129ab79..c3a68e42 100644 --- a/src/Jackett/Definitions/gods.yml +++ b/src/Jackett/Definitions/gods.yml @@ -1,162 +1,162 @@ ---- - site: gods - name: GODS - language: de-de - type: private - encoding: windows-1252 - links: - - https://gods.lu/ - - caps: - categorymappings: - # Movie - - {id: 132, cat: Movies/BluRay, desc: "BluRay"} - - {id: 146, cat: Movies/HD, desc: "Remux"} - - {id: 186, cat: Movies/HD, desc: "UHD"} - - {id: 189, cat: Movies/HD, desc: "HD"} - - {id: 190, cat: Movies/SD, desc: "SD"} - - {id: 20, cat: Movies/DVD, desc: "DVD"} - - {id: 131, cat: Movies/3D, desc: "3D"} - - {id: 16, cat: Movies, desc: "Packs"} - - # Serien - - {id: 187, cat: TV/HD, desc: "Staffeln UHD"} - - {id: 173, cat: TV/HD, desc: "Staffeln HD"} - - {id: 133, cat: TV/SD, desc: "Staffeln SD"} - - {id: 188, cat: TV/HD, desc: "Folgen UHD"} - - {id: 174, cat: TV/HD, desc: "Folgen HD"} - - {id: 7, cat: TV/SD, desc: "Folgen SD"} - - # Doku - - {id: 152, cat: TV/Documentary, desc: "HD"} - - {id: 153, cat: TV/Documentary, desc: "SD"} - - # Spiele - - {id: 4, cat: PC/Games, desc: "Windows"} - - {id: 29, cat: Console/XBox360, desc: "XBOX 360"} - - {id: 126, cat: Console/Wii, desc: "Wii"} - - {id: 183, cat: Console/Wii, desc: "Wii U"} - - {id: 128, cat: Console/PS3, desc: "PS3"} - - {id: 154, cat: Console/Other, desc: "Andere"} - - # Musik - - {id: 6, cat: Audio, desc: "Alben"} - - {id: 139, cat: Audio/Lossless, desc: "Lossless"} - - {id: 177, cat: Audio, desc: "Singles"} - - {id: 157, cat: Audio, desc: "Charts"} - - {id: 192, cat: Audio, desc: "Packs"} - - {id: 161, cat: Audio/Video, desc: "Video"} - - - {id: 22, cat: PC/0day, desc: "Windows"} - - {id: 129, cat: PC/Mac, desc: "Mac OS"} - - {id: 164, cat: PC/0day, desc: "Linux"} - - {id: 124, cat: PC/Phone-Android, desc: "Android"} - - {id: 165, cat: PC/Phone-IOS, desc: "Apple iOS"} - - {id: 167, cat: PC/Phone-Other, desc: "Andere"} - - # Sport - - {id: 130, cat: TV/Sport, desc: "HD"} - - {id: 135, cat: TV/Sport, desc: "SD"} - - # International - - {id: 170, cat: Movies/Foreign, desc: "Filme HD"} - - {id: 134, cat: Movies/Foreign, desc: "Filme SD"} - - {id: 171, cat: TV/Foreign, desc: "Folgen HD"} - - {id: 172, cat: TV/Foreign, desc: "Folgen SD"} - - # Sonstiges - - {id: 28, cat: TV/Anime, desc: "Anime"} - - {id: 13, cat: Books, desc: "e-Book"} - - {id: 11, cat: Audio/Audiobook, desc: "Hören"} - - {id: 136, cat: Other, desc: "Bilder"} - - {id: 9, cat: Other, desc: "Tutorial"} - - {id: 178, cat: Other, desc: "Anderes"} - - modes: - search: [q] - tv-search: [q, season, ep] - - settings: - - name: pin - type: text - label: Pin - - name: username - type: text - label: Username - - name: password - type: password - label: Password - - login: - path: /login/ - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - pin: "{{ .Config.pin }}" - test: - path: browse.php - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - intitle: "1" - incldead: "1" - team: "0" - orderby: "added" - sort: desc - rows: - selector: table.tableinborder > tbody > tr:has(a[href^="details.php"]) - fields: - title: - selector: a[href^="details.php"] - banner: - selector: a[href^="details.php"] > span > img - attribute: src - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php"] - attribute: href - comments: - selector: a[href*="&tocomm="] - attribute: href - download: - selector: a[href^="download.php"] - attribute: href - files: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) - grabs: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) - size: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - seeders: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) - leechers: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(3) - date: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(6) - filters: - - name: replace - args: ["\xA0", " "] - - name: dateparse - args: "02.01.2006 15:04:05" - downloadvolumefactor: - case: - img[alt="onlyupload"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: gods + name: GODS + language: de-de + type: private + encoding: windows-1252 + links: + - https://gods.lu/ + + caps: + categorymappings: + # Movie + - {id: 132, cat: Movies/BluRay, desc: "BluRay"} + - {id: 146, cat: Movies/HD, desc: "Remux"} + - {id: 186, cat: Movies/HD, desc: "UHD"} + - {id: 189, cat: Movies/HD, desc: "HD"} + - {id: 190, cat: Movies/SD, desc: "SD"} + - {id: 20, cat: Movies/DVD, desc: "DVD"} + - {id: 131, cat: Movies/3D, desc: "3D"} + - {id: 16, cat: Movies, desc: "Packs"} + + # Serien + - {id: 187, cat: TV/HD, desc: "Staffeln UHD"} + - {id: 173, cat: TV/HD, desc: "Staffeln HD"} + - {id: 133, cat: TV/SD, desc: "Staffeln SD"} + - {id: 188, cat: TV/HD, desc: "Folgen UHD"} + - {id: 174, cat: TV/HD, desc: "Folgen HD"} + - {id: 7, cat: TV/SD, desc: "Folgen SD"} + + # Doku + - {id: 152, cat: TV/Documentary, desc: "HD"} + - {id: 153, cat: TV/Documentary, desc: "SD"} + + # Spiele + - {id: 4, cat: PC/Games, desc: "Windows"} + - {id: 29, cat: Console/XBox360, desc: "XBOX 360"} + - {id: 126, cat: Console/Wii, desc: "Wii"} + - {id: 183, cat: Console/Wii, desc: "Wii U"} + - {id: 128, cat: Console/PS3, desc: "PS3"} + - {id: 154, cat: Console/Other, desc: "Andere"} + + # Musik + - {id: 6, cat: Audio, desc: "Alben"} + - {id: 139, cat: Audio/Lossless, desc: "Lossless"} + - {id: 177, cat: Audio, desc: "Singles"} + - {id: 157, cat: Audio, desc: "Charts"} + - {id: 192, cat: Audio, desc: "Packs"} + - {id: 161, cat: Audio/Video, desc: "Video"} + + - {id: 22, cat: PC/0day, desc: "Windows"} + - {id: 129, cat: PC/Mac, desc: "Mac OS"} + - {id: 164, cat: PC/0day, desc: "Linux"} + - {id: 124, cat: PC/Phone-Android, desc: "Android"} + - {id: 165, cat: PC/Phone-IOS, desc: "Apple iOS"} + - {id: 167, cat: PC/Phone-Other, desc: "Andere"} + + # Sport + - {id: 130, cat: TV/Sport, desc: "HD"} + - {id: 135, cat: TV/Sport, desc: "SD"} + + # International + - {id: 170, cat: Movies/Foreign, desc: "Filme HD"} + - {id: 134, cat: Movies/Foreign, desc: "Filme SD"} + - {id: 171, cat: TV/Foreign, desc: "Folgen HD"} + - {id: 172, cat: TV/Foreign, desc: "Folgen SD"} + + # Sonstiges + - {id: 28, cat: TV/Anime, desc: "Anime"} + - {id: 13, cat: Books, desc: "e-Book"} + - {id: 11, cat: Audio/Audiobook, desc: "Hören"} + - {id: 136, cat: Other, desc: "Bilder"} + - {id: 9, cat: Other, desc: "Tutorial"} + - {id: 178, cat: Other, desc: "Anderes"} + + modes: + search: [q] + tv-search: [q, season, ep] + + settings: + - name: pin + type: text + label: Pin + - name: username + type: text + label: Username + - name: password + type: password + label: Password + + login: + path: /login/ + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + pin: "{{ .Config.pin }}" + test: + path: browse.php + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + intitle: "1" + incldead: "1" + team: "0" + orderby: "added" + sort: desc + rows: + selector: table.tableinborder > tbody > tr:has(a[href^="details.php"]) + fields: + title: + selector: a[href^="details.php"] + banner: + selector: a[href^="details.php"] > span > img + attribute: src + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php"] + attribute: href + comments: + selector: a[href*="&tocomm="] + attribute: href + download: + selector: a[href^="download.php"] + attribute: href + files: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) + grabs: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) + size: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + seeders: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) + leechers: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(3) + date: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(6) + filters: + - name: replace + args: ["\xA0", " "] + - name: dateparse + args: "02.01.2006 15:04:05" + downloadvolumefactor: + case: + img[alt="onlyupload"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/gormogon.yml b/src/Jackett/Definitions/gormogon.yml index 98f9f691..b8ca5ead 100644 --- a/src/Jackett/Definitions/gormogon.yml +++ b/src/Jackett/Definitions/gormogon.yml @@ -1,193 +1,193 @@ ---- - site: gormogon - name: Gormogon - language: en-us - type: private - encoding: UTF-8 - links: - - http://www.gormogon.com - - caps: - categorymappings: - # Movies: - - {id: 1, cat: Movies/DVD, desc: "DVD-R"} - - {id: 2, cat: Movies, desc: "Action"} - - {id: 14, cat: Movies, desc: "Adventure"} - - {id: 15, cat: Movies, desc: "Animation"} - - {id: 16, cat: Movies, desc: "Biography"} - - {id: 17, cat: Movies, desc: "Comedy"} - - {id: 18, cat: Movies, desc: "Crime"} - - {id: 19, cat: Movies, desc: "Disney"} - - {id: 92, cat: Movies, desc: "Documentary"} - - {id: 20, cat: Movies, desc: "Drama"} - - {id: 21, cat: Movies, desc: "Family"} - - {id: 22, cat: Movies, desc: "Fantasy"} - - {id: 23, cat: Movies, desc: "Film Noir"} - - {id: 97, cat: Movies, desc: "History"} - - {id: 24, cat: Movies, desc: "Horror"} - - {id: 25, cat: Movies, desc: "Martial Arts"} - - {id: 26, cat: Movies, desc: "Musicals"} - - {id: 27, cat: Movies, desc: "Mystery"} - - {id: 28, cat: Movies, desc: "Romance"} - - {id: 29, cat: Movies, desc: "Sci-Fi"} - - {id: 30, cat: Movies, desc: "Thriller"} - - {id: 31, cat: Movies, desc: "War"} - - {id: 32, cat: Movies, desc: "Western"} - - {id: 33, cat: Movies, desc: "Other"} - - # Classic TV: - - {id: 34, cat: TV, desc: "Action"} - - {id: 35, cat: TV, desc: "Adventure"} - - {id: 36, cat: TV, desc: "Animation"} - - {id: 37, cat: TV, desc: "Biography"} - - {id: 38, cat: TV, desc: "Comedy"} - - {id: 39, cat: TV, desc: "Crime"} - - {id: 40, cat: TV, desc: "Disney"} - - {id: 41, cat: TV, desc: "Documentary"} - - {id: 42, cat: TV, desc: "Drama"} - - {id: 43, cat: TV, desc: "Family"} - - {id: 44, cat: TV, desc: "Fantasy"} - - {id: 45, cat: TV, desc: "TV Noir"} - - {id: 46, cat: TV, desc: "Horror"} - - {id: 47, cat: TV, desc: "Martial Arts"} - - {id: 49, cat: TV, desc: "Musicals"} - - {id: 50, cat: TV, desc: "Mystery"} - - {id: 51, cat: TV, desc: "Romance"} - - {id: 52, cat: TV, desc: "Sci-Fi"} - - {id: 48, cat: TV, desc: "Shows"} - - {id: 53, cat: TV, desc: "Thriller"} - - {id: 54, cat: TV, desc: "War"} - - {id: 55, cat: TV, desc: "Western"} - - {id: 56, cat: TV, desc: "Other"} - - {id: 90, cat: TV, desc: "TV Movies"} - - # Old Time Radio - - {id: 57, cat: Audio, desc: "Action"} - - {id: 58, cat: Audio, desc: "Adventure"} - - {id: 59, cat: Audio, desc: "Biography"} - - {id: 60, cat: Audio, desc: "Comedy"} - - {id: 61, cat: Audio, desc: "Crime"} - - {id: 62, cat: Audio, desc: "Documentary"} - - {id: 63, cat: Audio, desc: "Drama"} - - {id: 64, cat: Audio, desc: "Family"} - - {id: 65, cat: Audio, desc: "Fantasy"} - - {id: 66, cat: Audio, desc: "Radio Noir"} - - {id: 67, cat: Audio, desc: "Horror"} - - {id: 68, cat: Audio, desc: "Musicals"} - - {id: 69, cat: Audio, desc: "Mystery"} - - {id: 70, cat: Audio, desc: "Romance"} - - {id: 71, cat: Audio, desc: "Sci-Fi"} - - {id: 72, cat: Audio, desc: "Shows"} - - {id: 73, cat: Audio, desc: "Thriller"} - - {id: 74, cat: Audio, desc: "War"} - - {id: 75, cat: Audio, desc: "Western"} - - {id: 76, cat: Audio, desc: "Other"} - - # Music: - - {id: 77, cat: Audio, desc: "Official Sountracks"} - - {id: 78, cat: Audio, desc: "Theme Tunes"} - - {id: 79, cat: Audio, desc: "Music 30s"} - - {id: 80, cat: Audio, desc: "Music 40s"} - - {id: 81, cat: Audio, desc: "Music 50s"} - - {id: 85, cat: Audio, desc: "Music 60s"} - - {id: 86, cat: Audio, desc: "Music 70s"} - - {id: 87, cat: Audio, desc: "Music '80 - '84"} - - # Printed: - - {id: 82, cat: Books, desc: "Books"} - - {id: 91, cat: Books, desc: "Newspaper"} - - {id: 83, cat: Books, desc: "Scripts"} - - {id: 84, cat: Books, desc: "Posters"} - - {id: 88, cat: Books, desc: "Comics"} - - {id: 89, cat: Books, desc: "Magazines"} - - # Software: - - {id: 94, cat: Other, desc: "Screensavers"} - - {id: 95, cat: PC, desc: "Programs"} - - {id: 96, cat: Other, desc: "Other"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: index.php?page=login&returnto=index.php - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - error: - - selector: td.lista > span[style="color:#FF0000;"] - test: - path: index.php - selector: form[name="jump1"] - - ratio: - path: index.php - selector: form[name="jump1"] > table > tbody > tr > td:contains("SR ") - filters: - - name: trim - args: ")" - - name: split - args: [" ", 1] - - download: - selector: a[href^="download.php?id="] - - search: - path: index.php - inputs: - search: "{{ .Query.Keywords }}" - category: "{{range .Categories}}{{.}};{{end}}" - page: torrents - active: 0 - rows: - selector: table.lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) - fields: - download: - selector: a[href^="index.php?page=downloadcheck&id="] - attribute: href - title: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - details: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: td:nth-child(10) - date: - selector: td:nth-child(5) - filters: - - name: dateparse - args: "02/01/2006" - grabs: - selector: td:nth-child(8) - filters: - - name: replace - args: ["---", "0"] - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - downloadvolumefactor: - case: - img[alt="gold"]: "0" - img[alt="silver"]: "0.5" - "*": "1" - uploadvolumefactor: - case: - img[alt="2x Upload Multiplier"]: "2" - img[alt="3x Upload Multiplier"]: "3" - img[alt="4x Upload Multiplier"]: "4" - img[alt="5x Upload Multiplier"]: "5" - img[alt="6x Upload Multiplier"]: "6" - img[alt="7x Upload Multiplier"]: "7" - img[alt="8x Upload Multiplier"]: "8" - img[alt="9x Upload Multiplier"]: "9" - img[alt="10x Upload Multiplier"]: "10" +--- + site: gormogon + name: Gormogon + language: en-us + type: private + encoding: UTF-8 + links: + - http://www.gormogon.com + + caps: + categorymappings: + # Movies: + - {id: 1, cat: Movies/DVD, desc: "DVD-R"} + - {id: 2, cat: Movies, desc: "Action"} + - {id: 14, cat: Movies, desc: "Adventure"} + - {id: 15, cat: Movies, desc: "Animation"} + - {id: 16, cat: Movies, desc: "Biography"} + - {id: 17, cat: Movies, desc: "Comedy"} + - {id: 18, cat: Movies, desc: "Crime"} + - {id: 19, cat: Movies, desc: "Disney"} + - {id: 92, cat: Movies, desc: "Documentary"} + - {id: 20, cat: Movies, desc: "Drama"} + - {id: 21, cat: Movies, desc: "Family"} + - {id: 22, cat: Movies, desc: "Fantasy"} + - {id: 23, cat: Movies, desc: "Film Noir"} + - {id: 97, cat: Movies, desc: "History"} + - {id: 24, cat: Movies, desc: "Horror"} + - {id: 25, cat: Movies, desc: "Martial Arts"} + - {id: 26, cat: Movies, desc: "Musicals"} + - {id: 27, cat: Movies, desc: "Mystery"} + - {id: 28, cat: Movies, desc: "Romance"} + - {id: 29, cat: Movies, desc: "Sci-Fi"} + - {id: 30, cat: Movies, desc: "Thriller"} + - {id: 31, cat: Movies, desc: "War"} + - {id: 32, cat: Movies, desc: "Western"} + - {id: 33, cat: Movies, desc: "Other"} + + # Classic TV: + - {id: 34, cat: TV, desc: "Action"} + - {id: 35, cat: TV, desc: "Adventure"} + - {id: 36, cat: TV, desc: "Animation"} + - {id: 37, cat: TV, desc: "Biography"} + - {id: 38, cat: TV, desc: "Comedy"} + - {id: 39, cat: TV, desc: "Crime"} + - {id: 40, cat: TV, desc: "Disney"} + - {id: 41, cat: TV, desc: "Documentary"} + - {id: 42, cat: TV, desc: "Drama"} + - {id: 43, cat: TV, desc: "Family"} + - {id: 44, cat: TV, desc: "Fantasy"} + - {id: 45, cat: TV, desc: "TV Noir"} + - {id: 46, cat: TV, desc: "Horror"} + - {id: 47, cat: TV, desc: "Martial Arts"} + - {id: 49, cat: TV, desc: "Musicals"} + - {id: 50, cat: TV, desc: "Mystery"} + - {id: 51, cat: TV, desc: "Romance"} + - {id: 52, cat: TV, desc: "Sci-Fi"} + - {id: 48, cat: TV, desc: "Shows"} + - {id: 53, cat: TV, desc: "Thriller"} + - {id: 54, cat: TV, desc: "War"} + - {id: 55, cat: TV, desc: "Western"} + - {id: 56, cat: TV, desc: "Other"} + - {id: 90, cat: TV, desc: "TV Movies"} + + # Old Time Radio + - {id: 57, cat: Audio, desc: "Action"} + - {id: 58, cat: Audio, desc: "Adventure"} + - {id: 59, cat: Audio, desc: "Biography"} + - {id: 60, cat: Audio, desc: "Comedy"} + - {id: 61, cat: Audio, desc: "Crime"} + - {id: 62, cat: Audio, desc: "Documentary"} + - {id: 63, cat: Audio, desc: "Drama"} + - {id: 64, cat: Audio, desc: "Family"} + - {id: 65, cat: Audio, desc: "Fantasy"} + - {id: 66, cat: Audio, desc: "Radio Noir"} + - {id: 67, cat: Audio, desc: "Horror"} + - {id: 68, cat: Audio, desc: "Musicals"} + - {id: 69, cat: Audio, desc: "Mystery"} + - {id: 70, cat: Audio, desc: "Romance"} + - {id: 71, cat: Audio, desc: "Sci-Fi"} + - {id: 72, cat: Audio, desc: "Shows"} + - {id: 73, cat: Audio, desc: "Thriller"} + - {id: 74, cat: Audio, desc: "War"} + - {id: 75, cat: Audio, desc: "Western"} + - {id: 76, cat: Audio, desc: "Other"} + + # Music: + - {id: 77, cat: Audio, desc: "Official Sountracks"} + - {id: 78, cat: Audio, desc: "Theme Tunes"} + - {id: 79, cat: Audio, desc: "Music 30s"} + - {id: 80, cat: Audio, desc: "Music 40s"} + - {id: 81, cat: Audio, desc: "Music 50s"} + - {id: 85, cat: Audio, desc: "Music 60s"} + - {id: 86, cat: Audio, desc: "Music 70s"} + - {id: 87, cat: Audio, desc: "Music '80 - '84"} + + # Printed: + - {id: 82, cat: Books, desc: "Books"} + - {id: 91, cat: Books, desc: "Newspaper"} + - {id: 83, cat: Books, desc: "Scripts"} + - {id: 84, cat: Books, desc: "Posters"} + - {id: 88, cat: Books, desc: "Comics"} + - {id: 89, cat: Books, desc: "Magazines"} + + # Software: + - {id: 94, cat: Other, desc: "Screensavers"} + - {id: 95, cat: PC, desc: "Programs"} + - {id: 96, cat: Other, desc: "Other"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: index.php?page=login&returnto=index.php + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + error: + - selector: td.lista > span[style="color:#FF0000;"] + test: + path: index.php + selector: form[name="jump1"] + + ratio: + path: index.php + selector: form[name="jump1"] > table > tbody > tr > td:contains("SR ") + filters: + - name: trim + args: ")" + - name: split + args: [" ", 1] + + download: + selector: a[href^="download.php?id="] + + search: + path: index.php + inputs: + search: "{{ .Query.Keywords }}" + category: "{{range .Categories}}{{.}};{{end}}" + page: torrents + active: 0 + rows: + selector: table.lista > tbody > tr:has(a[href^="index.php?page=torrents&category="]) + fields: + download: + selector: a[href^="index.php?page=downloadcheck&id="] + attribute: href + title: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + details: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: td:nth-child(10) + date: + selector: td:nth-child(5) + filters: + - name: dateparse + args: "02/01/2006" + grabs: + selector: td:nth-child(8) + filters: + - name: replace + args: ["---", "0"] + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + downloadvolumefactor: + case: + img[alt="gold"]: "0" + img[alt="silver"]: "0.5" + "*": "1" + uploadvolumefactor: + case: + img[alt="2x Upload Multiplier"]: "2" + img[alt="3x Upload Multiplier"]: "3" + img[alt="4x Upload Multiplier"]: "4" + img[alt="5x Upload Multiplier"]: "5" + img[alt="6x Upload Multiplier"]: "6" + img[alt="7x Upload Multiplier"]: "7" + img[alt="8x Upload Multiplier"]: "8" + img[alt="9x Upload Multiplier"]: "9" + img[alt="10x Upload Multiplier"]: "10" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/hdbits.yml b/src/Jackett/Definitions/hdbits.yml index 7503cef9..cc196a4a 100644 --- a/src/Jackett/Definitions/hdbits.yml +++ b/src/Jackett/Definitions/hdbits.yml @@ -1,83 +1,83 @@ ---- - site: hdbits - name: HDBits - description: "Best HD Tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://hdbits.org - - caps: - categorymappings: - - {id: 1, cat: "Movies", desc: "Movie"} - - {id: 2, cat: "TV", desc: "TV"} - - {id: 3, cat: "TV/Documentary", desc: "Documentary"} - - {id: 4, cat: "Audio", desc: "Music"} - - {id: 5, cat: "TV/Sport", desc: "Sport"} - - {id: 6, cat: "Audio", desc: "Audio Track"} - - {id: 7, cat: "XXX", desc: "XXX"} - - {id: 8, cat: "Other", desc: "Misc/Demo"} - - modes: - search: [q] - - login: - path: /login - method: form - form: form - inputs: - uname: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table.main:contains("Login Failed!") - test: - path: my.php - - download: - selector: a[href^="/download.php"] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table#torrent-list > tbody > tr:has(a[href^="/details.php?id="]) - fields: - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - title: - selector: td:nth-child(3) a - download: - selector: a[href^="/download.php"] - attribute: href - details: - selector: a[href^="/details.php?id="] - attribute: href - grabs: - selector: td:nth-child(7) a - size: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - date: - selector: td:nth-child(5) - filters: - - name: append - args: " ago" - downloadvolumefactor: - case: - "a[title=\"25% Free Leech: only 75% of the download is counted.\"]": "0.25" - "a[title=\"50% Free Leech: only half the download is counted.\"]": "0.5" - "a[title=\"100% FL: no download is counted.\"]": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: hdbits + name: HDBits + description: "Best HD Tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://hdbits.org + + caps: + categorymappings: + - {id: 1, cat: "Movies", desc: "Movie"} + - {id: 2, cat: "TV", desc: "TV"} + - {id: 3, cat: "TV/Documentary", desc: "Documentary"} + - {id: 4, cat: "Audio", desc: "Music"} + - {id: 5, cat: "TV/Sport", desc: "Sport"} + - {id: 6, cat: "Audio", desc: "Audio Track"} + - {id: 7, cat: "XXX", desc: "XXX"} + - {id: 8, cat: "Other", desc: "Misc/Demo"} + + modes: + search: [q] + + login: + path: /login + method: form + form: form + inputs: + uname: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table.main:contains("Login Failed!") + test: + path: my.php + + download: + selector: a[href^="/download.php"] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table#torrent-list > tbody > tr:has(a[href^="/details.php?id="]) + fields: + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + title: + selector: td:nth-child(3) a + download: + selector: a[href^="/download.php"] + attribute: href + details: + selector: a[href^="/details.php?id="] + attribute: href + grabs: + selector: td:nth-child(7) a + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + date: + selector: td:nth-child(5) + filters: + - name: append + args: " ago" + downloadvolumefactor: + case: + "a[title=\"25% Free Leech: only 75% of the download is counted.\"]": "0.25" + "a[title=\"50% Free Leech: only half the download is counted.\"]": "0.5" + "a[title=\"100% FL: no download is counted.\"]": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/hdbitscom.yml b/src/Jackett/Definitions/hdbitscom.yml index 96894cc4..87eb7407 100644 --- a/src/Jackett/Definitions/hdbitscom.yml +++ b/src/Jackett/Definitions/hdbitscom.yml @@ -1,97 +1,97 @@ ---- - site: hdbitscom - name: HD-Bits.com - description: "HD tracker" - language: en-us - encoding: UTF-8 - type: private - links: - - https://www.hd-bits.com - - caps: - categorymappings: - - {id: 1, cat: Audio, desc: "Music"} - - {id: 2, cat: Movies, desc: "Movies"} - - {id: 3, cat: TV, desc: "TV-Series"} - - {id: 4, cat: PC, desc: "Applications"} - - {id: 5, cat: XXX, desc: "Adult"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: 1 - login: "Log in" - error: - - selector: form#loginform > span.warning - test: - path: torrents.php - - ratio: - path: torrents.php - selector: li#stats_ratio > span - - search: - path: torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: time - order_way: desc - action: basic - searchsubmit: 1 - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - description: - selector: div.group_info div.tags - title: - selector: div.group_info a[href^="torrents.php?id="] - category: - selector: td.cats_col - case: - div.cats_music: 1 - div.cats_movies: 2 - div.cats_tvseries: 3 - div.cats_applications: 4 - div.cats_xxx: 5 - comments: - selector: a[href^="torrents.php?id="] - attribute: href - imdb: - selector: a[href*="http://www.imdb.com/title/"] - optional: true - attribute: href - banner: - selector: img[alt="Cover"] - optional: true - attribute: src - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(4) - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - "div.freeleech:contains('Freeleech!')": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: hdbitscom + name: HD-Bits.com + description: "HD tracker" + language: en-us + encoding: UTF-8 + type: private + links: + - https://www.hd-bits.com + + caps: + categorymappings: + - {id: 1, cat: Audio, desc: "Music"} + - {id: 2, cat: Movies, desc: "Movies"} + - {id: 3, cat: TV, desc: "TV-Series"} + - {id: 4, cat: PC, desc: "Applications"} + - {id: 5, cat: XXX, desc: "Adult"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: 1 + login: "Log in" + error: + - selector: form#loginform > span.warning + test: + path: torrents.php + + ratio: + path: torrents.php + selector: li#stats_ratio > span + + search: + path: torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: time + order_way: desc + action: basic + searchsubmit: 1 + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + description: + selector: div.group_info div.tags + title: + selector: div.group_info a[href^="torrents.php?id="] + category: + selector: td.cats_col + case: + div.cats_music: 1 + div.cats_movies: 2 + div.cats_tvseries: 3 + div.cats_applications: 4 + div.cats_xxx: 5 + comments: + selector: a[href^="torrents.php?id="] + attribute: href + imdb: + selector: a[href*="http://www.imdb.com/title/"] + optional: true + attribute: href + banner: + selector: img[alt="Cover"] + optional: true + attribute: src + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(4) + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + "div.freeleech:contains('Freeleech!')": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/hdchina.yml b/src/Jackett/Definitions/hdchina.yml index 372de77d..f96878bc 100755 --- a/src/Jackett/Definitions/hdchina.yml +++ b/src/Jackett/Definitions/hdchina.yml @@ -1,121 +1,121 @@ ---- - site: hdchina - name: HDChina - description: "A chinese tracker" - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://hdchina.club/ - - caps: - categorymappings: - - {id: 20, cat: Movies/BluRay, desc: "Movie Full BD"} - - {id: 17, cat: Movies/HD, desc: "Movie 1080p"} - - {id: 16, cat: Movies/HD, desc: "Movie 1080i"} - - {id: 9, cat: Movies/HD, desc: "Movie 720p"} - - {id: 13, cat: TV, desc: "EU/US TV series"} - - {id: 25, cat: TV, desc: "Chinese TV series"} - - {id: 26, cat: TV, desc: "Kor Drama"} - - {id: 24, cat: TV, desc: "Jpn Drama"} - - {id: 21, cat: TV, desc: "EU/US TV series pack"} - - {id: 22, cat: TV, desc: "Chinese TV series pack"} - - {id: 23, cat: TV, desc: "JPN/KOR drama pack"} - - {id: 27, cat: Movies/SD, desc: "iPad Video"} - - {id: 5, cat: TV/Documentary, desc: "Documentary"} - - {id: 15, cat: TV/Sport, desc: "Sports"} - - {id: 14, cat: TV/Anime, desc: "Animation"} - - {id: 401, cat: TV, desc: "TV Shows"} - - {id: 402, cat: Audio, desc: "Vocal Concert"} - - {id: 406, cat: Audio, desc: "Music Video"} - - {id: 408, cat: Audio, desc: "Music"} - - {id: 19, cat: Audio, desc: "Audio Track"} - - {id: 405, cat: Audio, desc: "Drama"} - - {id: 404, cat: Books, desc: "Book"} - - {id: 409, cat: Other, desc: "Other"} - - {id: 410, cat: Movies/HD, desc: "4K UltraHD"} - - {id: 411, cat: TV, desc: "Travel"} - - {id: 412, cat: TV, desc: "Food"} - - modes: - search: [q] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - captcha: - type: image - image: img[alt="CAPTCHA"] - input: imagestring - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "0" - spstate: "0" - inclbookmarked: "0" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: "0" - rows: - selector: table.torrent_list > tbody > tr:has(a[href^="?cat="]) - fields: - title: - selector: td:nth-child(2) a - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php", "download.php"] - size: - selector: td.t_size - grabs: - selector: td.t_completed - seeders: - selector: td.t_torrents - leechers: - selector: td.t_leech - date: - selector: td.t_time - filters: - - name: replace - args: ["时", " hours"] - - name: replace - args: ["分", " minutes"] - - name: replace - args: ["天", " days"] - - name: replace - args: ["年", " year"] - - name: replace - args: ["月", " months"] - - name: append - args: " ago" - downloadvolumefactor: - case: - img.pro_50pctdown: ".5" - img.pro_30pctdown: ".3" - img.pro_free: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: hdchina + name: HDChina + description: "A chinese tracker" + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://hdchina.club/ + + caps: + categorymappings: + - {id: 20, cat: Movies/BluRay, desc: "Movie Full BD"} + - {id: 17, cat: Movies/HD, desc: "Movie 1080p"} + - {id: 16, cat: Movies/HD, desc: "Movie 1080i"} + - {id: 9, cat: Movies/HD, desc: "Movie 720p"} + - {id: 13, cat: TV, desc: "EU/US TV series"} + - {id: 25, cat: TV, desc: "Chinese TV series"} + - {id: 26, cat: TV, desc: "Kor Drama"} + - {id: 24, cat: TV, desc: "Jpn Drama"} + - {id: 21, cat: TV, desc: "EU/US TV series pack"} + - {id: 22, cat: TV, desc: "Chinese TV series pack"} + - {id: 23, cat: TV, desc: "JPN/KOR drama pack"} + - {id: 27, cat: Movies/SD, desc: "iPad Video"} + - {id: 5, cat: TV/Documentary, desc: "Documentary"} + - {id: 15, cat: TV/Sport, desc: "Sports"} + - {id: 14, cat: TV/Anime, desc: "Animation"} + - {id: 401, cat: TV, desc: "TV Shows"} + - {id: 402, cat: Audio, desc: "Vocal Concert"} + - {id: 406, cat: Audio, desc: "Music Video"} + - {id: 408, cat: Audio, desc: "Music"} + - {id: 19, cat: Audio, desc: "Audio Track"} + - {id: 405, cat: Audio, desc: "Drama"} + - {id: 404, cat: Books, desc: "Book"} + - {id: 409, cat: Other, desc: "Other"} + - {id: 410, cat: Movies/HD, desc: "4K UltraHD"} + - {id: 411, cat: TV, desc: "Travel"} + - {id: 412, cat: TV, desc: "Food"} + + modes: + search: [q] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + captcha: + type: image + image: img[alt="CAPTCHA"] + input: imagestring + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "0" + spstate: "0" + inclbookmarked: "0" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: "0" + rows: + selector: table.torrent_list > tbody > tr:has(a[href^="?cat="]) + fields: + title: + selector: td:nth-child(2) a + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php", "download.php"] + size: + selector: td.t_size + grabs: + selector: td.t_completed + seeders: + selector: td.t_torrents + leechers: + selector: td.t_leech + date: + selector: td.t_time + filters: + - name: replace + args: ["时", " hours"] + - name: replace + args: ["分", " minutes"] + - name: replace + args: ["天", " days"] + - name: replace + args: ["年", " year"] + - name: replace + args: ["月", " months"] + - name: append + args: " ago" + downloadvolumefactor: + case: + img.pro_50pctdown: ".5" + img.pro_30pctdown: ".3" + img.pro_free: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/hdhome.yml b/src/Jackett/Definitions/hdhome.yml index d411aacc..79400ee3 100644 --- a/src/Jackett/Definitions/hdhome.yml +++ b/src/Jackett/Definitions/hdhome.yml @@ -1,142 +1,142 @@ ---- - site: hdhome - name: HDHome - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://hdhome.org - - caps: - categorymappings: - - {id: 411, cat: Movies/SD, desc: "Movies SD"} - - {id: 412, cat: Movies/SD, desc: "Movies IPad"} - - {id: 413, cat: Movies/HD, desc: "Movies 720p"} - - {id: 414, cat: Movies/HD, desc: "Movies 1080p"} - - {id: 415, cat: Movies/HD, desc: "Movies REMUX"} - - {id: 450, cat: Movies/BluRay, desc: "Movies Bluray"} - - {id: 416, cat: Movies/HD, desc: "Movies 2160p"} - - {id: 417, cat: TV/Documentary, desc: "Doc SD"} - - {id: 418, cat: TV/Documentary, desc: "Doc IPad"} - - {id: 419, cat: TV/Documentary, desc: "Doc 720p"} - - {id: 420, cat: TV/Documentary, desc: "Doc 1080p"} - - {id: 421, cat: TV/Documentary, desc: "Doc REMUX"} - - {id: 451, cat: TV/Documentary, desc: "Doc Bluray"} - - {id: 422, cat: TV/Documentary, desc: "Doc 2160p"} - - {id: 423, cat: TV/HD, desc: "TVMusic 720p"} - - {id: 424, cat: TV/HD, desc: "TVMusic 1080i"} - - {id: 425, cat: TV/SD, desc: "TVShow SD"} - - {id: 426, cat: TV/SD, desc: "TVShow IPad"} - - {id: 427, cat: TV/HD, desc: "TVShow 720p"} - - {id: 428, cat: TV/HD, desc: "TVShow 1080i"} - - {id: 429, cat: TV/HD, desc: "TVShow 1080p"} - - {id: 430, cat: TV/HD, desc: "TVShow REMUX"} - - {id: 452, cat: TV/HD, desc: "TVShows Bluray"} - - {id: 431, cat: TV/HD, desc: "TVShow 2160p"} - - {id: 432, cat: TV/SD, desc: "TVSeries SD"} - - {id: 433, cat: TV/SD, desc: "TVSeries IPad"} - - {id: 434, cat: TV/HD, desc: "TVSeries 720p"} - - {id: 435, cat: TV/HD, desc: "TVSeries 1080i"} - - {id: 436, cat: TV/HD, desc: "TVSeries 1080p"} - - {id: 437, cat: TV/HD, desc: "TVSeries REMUX"} - - {id: 453, cat: TV/HD, desc: "TVSereis Bluray"} - - {id: 438, cat: TV/HD, desc: "TVSeries 2160p"} - - {id: 439, cat: Audio/Other, desc: "Musics APE"} - - {id: 440, cat: Audio/Lossless, desc: "Musics FLAC"} - - {id: 441, cat: Audio/Video, desc: "Musics MV"} - - {id: 442, cat: TV/Sport, desc: "Sports 720p"} - - {id: 443, cat: TV/Sport, desc: "Sports 1080i"} - - {id: 444, cat: TV/Anime, desc: "Anime SD"} - - {id: 445, cat: TV/Anime, desc: "Anime IPad"} - - {id: 446, cat: TV/Anime, desc: "Anime 720p"} - - {id: 447, cat: TV/Anime, desc: "Anime 1080p"} - - {id: 448, cat: TV/Anime, desc: "Anime REMUX"} - - {id: 454, cat: TV/Anime, desc: "Anime Bluray"} - - {id: 409, cat: Other, desc: "Misc"} - - {id: 449, cat: TV/Anime, desc: "Anime 2160p"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - captcha: - type: image - image: img[alt="CAPTCHA"] - input: imagestring - inputs: - logintype: "username" - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("姿势不正确")) - - selector: td.embedded:has(h2:contains("失败")) - test: - path: /torrents.php - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "1" - spstate: "0" - inclbookmarked: "0" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: "0" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[title][href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - size: - selector: td.rowfollow:nth-child(5) - grabs: - selector: td.rowfollow:nth-child(8) - seeders: - selector: td.rowfollow:nth-child(6) - leechers: - selector: td.rowfollow:nth-child(7) - date: - selector: td.rowfollow:nth-child(4) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) +--- + site: hdhome + name: HDHome + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://hdhome.org + + caps: + categorymappings: + - {id: 411, cat: Movies/SD, desc: "Movies SD"} + - {id: 412, cat: Movies/SD, desc: "Movies IPad"} + - {id: 413, cat: Movies/HD, desc: "Movies 720p"} + - {id: 414, cat: Movies/HD, desc: "Movies 1080p"} + - {id: 415, cat: Movies/HD, desc: "Movies REMUX"} + - {id: 450, cat: Movies/BluRay, desc: "Movies Bluray"} + - {id: 416, cat: Movies/HD, desc: "Movies 2160p"} + - {id: 417, cat: TV/Documentary, desc: "Doc SD"} + - {id: 418, cat: TV/Documentary, desc: "Doc IPad"} + - {id: 419, cat: TV/Documentary, desc: "Doc 720p"} + - {id: 420, cat: TV/Documentary, desc: "Doc 1080p"} + - {id: 421, cat: TV/Documentary, desc: "Doc REMUX"} + - {id: 451, cat: TV/Documentary, desc: "Doc Bluray"} + - {id: 422, cat: TV/Documentary, desc: "Doc 2160p"} + - {id: 423, cat: TV/HD, desc: "TVMusic 720p"} + - {id: 424, cat: TV/HD, desc: "TVMusic 1080i"} + - {id: 425, cat: TV/SD, desc: "TVShow SD"} + - {id: 426, cat: TV/SD, desc: "TVShow IPad"} + - {id: 427, cat: TV/HD, desc: "TVShow 720p"} + - {id: 428, cat: TV/HD, desc: "TVShow 1080i"} + - {id: 429, cat: TV/HD, desc: "TVShow 1080p"} + - {id: 430, cat: TV/HD, desc: "TVShow REMUX"} + - {id: 452, cat: TV/HD, desc: "TVShows Bluray"} + - {id: 431, cat: TV/HD, desc: "TVShow 2160p"} + - {id: 432, cat: TV/SD, desc: "TVSeries SD"} + - {id: 433, cat: TV/SD, desc: "TVSeries IPad"} + - {id: 434, cat: TV/HD, desc: "TVSeries 720p"} + - {id: 435, cat: TV/HD, desc: "TVSeries 1080i"} + - {id: 436, cat: TV/HD, desc: "TVSeries 1080p"} + - {id: 437, cat: TV/HD, desc: "TVSeries REMUX"} + - {id: 453, cat: TV/HD, desc: "TVSereis Bluray"} + - {id: 438, cat: TV/HD, desc: "TVSeries 2160p"} + - {id: 439, cat: Audio/Other, desc: "Musics APE"} + - {id: 440, cat: Audio/Lossless, desc: "Musics FLAC"} + - {id: 441, cat: Audio/Video, desc: "Musics MV"} + - {id: 442, cat: TV/Sport, desc: "Sports 720p"} + - {id: 443, cat: TV/Sport, desc: "Sports 1080i"} + - {id: 444, cat: TV/Anime, desc: "Anime SD"} + - {id: 445, cat: TV/Anime, desc: "Anime IPad"} + - {id: 446, cat: TV/Anime, desc: "Anime 720p"} + - {id: 447, cat: TV/Anime, desc: "Anime 1080p"} + - {id: 448, cat: TV/Anime, desc: "Anime REMUX"} + - {id: 454, cat: TV/Anime, desc: "Anime Bluray"} + - {id: 409, cat: Other, desc: "Misc"} + - {id: 449, cat: TV/Anime, desc: "Anime 2160p"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + captcha: + type: image + image: img[alt="CAPTCHA"] + input: imagestring + inputs: + logintype: "username" + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("姿势不正确")) + - selector: td.embedded:has(h2:contains("失败")) + test: + path: /torrents.php + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "1" + spstate: "0" + inclbookmarked: "0" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: "0" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[title][href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + size: + selector: td.rowfollow:nth-child(5) + grabs: + selector: td.rowfollow:nth-child(8) + seeders: + selector: td.rowfollow:nth-child(6) + leechers: + selector: td.rowfollow:nth-child(7) + date: + selector: td.rowfollow:nth-child(4) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) remove: a, img \ No newline at end of file diff --git a/src/Jackett/Definitions/hdsky.yml b/src/Jackett/Definitions/hdsky.yml index aebefef4..fffd54c4 100644 --- a/src/Jackett/Definitions/hdsky.yml +++ b/src/Jackett/Definitions/hdsky.yml @@ -1,119 +1,119 @@ ---- - site: hdsky - name: HDSky - description: "A chinese tracker" - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://hdsky.me - - caps: - categorymappings: - - {id: 401, cat: Movies, desc: "Movies/电影"} - - {id: 404, cat: TV/Documentary, desc: "Documentaries/纪录片"} - - {id: 410, cat: Movies, desc: "iPad/iPad影视"} - - {id: 405, cat: TV/Anime, desc: "Animations/动漫"} - - {id: 402, cat: TV, desc: "TV Series/剧集"} - - {id: 403, cat: TV, desc: "TV Shows/综艺"} - - {id: 406, cat: Audio/Video, desc: "Music Videos/音乐MV"} - - {id: 407, cat: TV/Sport, desc: "Sports/体育"} - - {id: 408, cat: Audio, desc: "HQ Audio/无损音乐"} - - {id: 409, cat: Other, desc: "Misc/其他"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - captcha: - type: image - image: img[alt="CAPTCHA"] - input: imagestring - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - ratio: - path: /torrents.php - selector: table#info_block - filters: - - name: regexp - args: "Ratio:\\s(.*?)\\s\\s" - - download: - method: post - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "1" - spstate: "0" - inclbookmarked: "0" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: "0" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[title][href^="details.php?id="] - attribute: href - download: - selector: form[action^="download.php?id="] - attribute: action - imdb: - selector: a[href^="http://www.imdb.com/title/tt"] - attribute: href - size: - selector: td.rowfollow:nth-child(5) - grabs: - selector: td.rowfollow:nth-child(8) - seeders: - selector: td.rowfollow:nth-child(6) - leechers: - selector: td.rowfollow:nth-child(7) - date: - selector: td.rowfollow:nth-child(4) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) +--- + site: hdsky + name: HDSky + description: "A chinese tracker" + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://hdsky.me + + caps: + categorymappings: + - {id: 401, cat: Movies, desc: "Movies/电影"} + - {id: 404, cat: TV/Documentary, desc: "Documentaries/纪录片"} + - {id: 410, cat: Movies, desc: "iPad/iPad影视"} + - {id: 405, cat: TV/Anime, desc: "Animations/动漫"} + - {id: 402, cat: TV, desc: "TV Series/剧集"} + - {id: 403, cat: TV, desc: "TV Shows/综艺"} + - {id: 406, cat: Audio/Video, desc: "Music Videos/音乐MV"} + - {id: 407, cat: TV/Sport, desc: "Sports/体育"} + - {id: 408, cat: Audio, desc: "HQ Audio/无损音乐"} + - {id: 409, cat: Other, desc: "Misc/其他"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + captcha: + type: image + image: img[alt="CAPTCHA"] + input: imagestring + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + ratio: + path: /torrents.php + selector: table#info_block + filters: + - name: regexp + args: "Ratio:\\s(.*?)\\s\\s" + + download: + method: post + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "1" + spstate: "0" + inclbookmarked: "0" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: "0" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[title][href^="details.php?id="] + attribute: href + download: + selector: form[action^="download.php?id="] + attribute: action + imdb: + selector: a[href^="http://www.imdb.com/title/tt"] + attribute: href + size: + selector: td.rowfollow:nth-child(5) + grabs: + selector: td.rowfollow:nth-child(8) + seeders: + selector: td.rowfollow:nth-child(6) + leechers: + selector: td.rowfollow:nth-child(7) + date: + selector: td.rowfollow:nth-child(4) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) remove: a, img \ No newline at end of file diff --git a/src/Jackett/Definitions/hyperay.yml b/src/Jackett/Definitions/hyperay.yml index e40d66e9..dff64c7e 100644 --- a/src/Jackett/Definitions/hyperay.yml +++ b/src/Jackett/Definitions/hyperay.yml @@ -1,107 +1,107 @@ ---- - site: hyperay - name: Hyperay - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://www.hyperay.cc - - caps: - categorymappings: - - {id: 410, cat: Movies/HD, desc: "Movies 1080p"} - - {id: 411, cat: Movies/HD, desc: "Movies 720p"} - - {id: 401, cat: Movies/BluRay, desc: "Movies Blu-ray"} - - {id: 415, cat: Movies, desc: "Movies REMUX"} - - {id: 416, cat: Movies/3D, desc: "Movies 3D"} - - {id: 414, cat: Movies/DVD, desc: "Movies DVD"} - - {id: 412, cat: Movies/WEBDL, desc: "Movies WEB-DL"} - - {id: 413, cat: Movies/SD, desc: "Movies HDTV"} - - {id: 417, cat: Movies/Other, desc: "Movies iPad"} - - {id: 402, cat: TV, desc: "TV Series"} - - {id: 403, cat: TV, desc: "TV Shows"} - - {id: 404, cat: TV/Documentary, desc: "Documentaries"} - - {id: 405, cat: TV/Anime, desc: "Animations"} - - {id: 406, cat: Audio/Video, desc: "Music Videos"} - - {id: 407, cat: TV/Sport, desc: "Sports"} - - {id: 408, cat: Audio, desc: "HQ Audio"} - - {id: 418, cat: Books, desc: "Book"} - - {id: 409, cat: Other, desc: "Misc"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - authcode: "" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "1" - spstate: "0" - inclbookmarked: "0" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: "0" - rows: - selector: table.torrents > tbody > tr[class] - fields: - title: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[title][href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - imdb: - selector: a[href^="http://www.imdb.com/title/"] - attribute: href - banner: - selector: a[title][onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: "showmenu\\(this,'.*','(.*)'\\);" - size: - selector: td.rowfollow:nth-child(6) - grabs: - selector: td.rowfollow:nth-child(9) - seeders: - selector: td.rowfollow:nth-child(7) - leechers: - selector: td.rowfollow:nth-child(8) - date: - selector: td.rowfollow:nth-child(5) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: hyperay + name: Hyperay + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://www.hyperay.cc + + caps: + categorymappings: + - {id: 410, cat: Movies/HD, desc: "Movies 1080p"} + - {id: 411, cat: Movies/HD, desc: "Movies 720p"} + - {id: 401, cat: Movies/BluRay, desc: "Movies Blu-ray"} + - {id: 415, cat: Movies, desc: "Movies REMUX"} + - {id: 416, cat: Movies/3D, desc: "Movies 3D"} + - {id: 414, cat: Movies/DVD, desc: "Movies DVD"} + - {id: 412, cat: Movies/WEBDL, desc: "Movies WEB-DL"} + - {id: 413, cat: Movies/SD, desc: "Movies HDTV"} + - {id: 417, cat: Movies/Other, desc: "Movies iPad"} + - {id: 402, cat: TV, desc: "TV Series"} + - {id: 403, cat: TV, desc: "TV Shows"} + - {id: 404, cat: TV/Documentary, desc: "Documentaries"} + - {id: 405, cat: TV/Anime, desc: "Animations"} + - {id: 406, cat: Audio/Video, desc: "Music Videos"} + - {id: 407, cat: TV/Sport, desc: "Sports"} + - {id: 408, cat: Audio, desc: "HQ Audio"} + - {id: 418, cat: Books, desc: "Book"} + - {id: 409, cat: Other, desc: "Misc"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + authcode: "" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "1" + spstate: "0" + inclbookmarked: "0" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: "0" + rows: + selector: table.torrents > tbody > tr[class] + fields: + title: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[title][href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + imdb: + selector: a[href^="http://www.imdb.com/title/"] + attribute: href + banner: + selector: a[title][onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: "showmenu\\(this,'.*','(.*)'\\);" + size: + selector: td.rowfollow:nth-child(6) + grabs: + selector: td.rowfollow:nth-child(9) + seeders: + selector: td.rowfollow:nth-child(7) + leechers: + selector: td.rowfollow:nth-child(8) + date: + selector: td.rowfollow:nth-child(5) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/icetorrent.yml b/src/Jackett/Definitions/icetorrent.yml index 037ec269..309ffdd7 100755 --- a/src/Jackett/Definitions/icetorrent.yml +++ b/src/Jackett/Definitions/icetorrent.yml @@ -1,151 +1,151 @@ ---- - site: icetorrent - name: ICE Torrent - language: ro-ro - type: private - encoding: UTF-8 - links: - - https://www.icetorrent.org - - caps: - categorymappings: - - {id: 1, cat: PC/0day , desc: "Appz"} - - {id: 85, cat: Audio/Audiobook, desc: "AudioBooks"} - - {id: 68, cat: Books, desc: "Carti/Reviste"} - - {id: 23, cat: Books, desc: "Cartoons"} - - {id: 73, cat: Audio/Video, desc: "Concert/Videoclip"} - - {id: 75, cat: Other, desc: "Diverse"} - - {id: 69, cat: Books, desc: "Documentare"} - - {id: 51, cat: TV/Documentary, desc: "Documentaries"} - - {id: 43, cat: Books, desc: "eBooks"} - - {id: 63, cat: Movies/DVD, desc: "Filme DVD"} - - {id: 65, cat: Movies/HD, desc: "Filme HD"} - - {id: 64, cat: Movies/SD, desc: "Filme Xvid"} - - {id: 40, cat: Console, desc: "Games/Console"} - - {id: 26, cat: PC/Games, desc: "Games/PC"} - - {id: 38, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 59, cat: Movies/3D, desc: "Movies/3D"} - - {id: 92, cat: Movies/HD, desc: "Movies/4K-UHD"} - - {id: 32, cat: Movies/BluRay, desc: "Movies/Blu-Ray"} - - {id: 28, cat: Movies/DVD, desc: "Movies/DVD"} - - {id: 42, cat: Movies/HD, desc: "Movies/HD-x264"} - - {id: 91, cat: Movies/HD, desc: "Movies/HEVC-x265"} - - {id: 79, cat: Movies/HD, desc: "Movies/microHD"} - - {id: 29, cat: Movies/SD, desc: "Movies/SD"} - - {id: 72, cat: Audio/Lossless, desc: "Music/FLAC"} - - {id: 6, cat: Audio/MP3, desc: "Music/MP3"} - - {id: 37, cat: Audio/Video, desc: "Music/Video"} - - {id: 70, cat: Audio/Lossless, desc: "Muzica FLAC"} - - {id: 71, cat: Audio/MP3, desc: "Muzica MP3"} - - {id: 74, cat: Other, desc: "Other"} - - {id: 41, cat: Other, desc: "Pictures"} - - {id: 67, cat: TV, desc: "Seriale TV"} - - {id: 48, cat: TV/Sport, desc: "Sports"} - - {id: 87, cat: Other, desc: "TUTS"} - - {id: 33, cat: TV/SD, desc: "TV Episodes"} - - {id: 34, cat: TV/HD, desc: "TVHD Episodes"} - - {id: 9, cat: XXX, desc: "XXX"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: /login.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: font:contains("failed") + table - test: - path: /browse.php - - ratio: - text: -1 - - search: - paths: - - path: browse.php - categorymappings: ["!", 9] - - path: browseadult.php - categorymappings: [9] - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" - incldead: 1 - search_by: "{{ if .Query.IMDBID }}imdb{{else}}name{{end}}" - rows: - selector: table.torrenttable > tbody > tr:has(a[title][href^="details.php?id="]) - fields: - title: - selector: a[title][href^="details.php?id="] - attribute: title - details: - selector: a[title][href^="details.php?id="] - attribute: href - category: - selector: a[href*=".php?cat="] - attribute: href - filters: - - name: querystring - args: cat - imdb: - selector: a[title="IMDB"] - attribute: href - banner: - attribute: rel - imdb: - selector: a[href^="http://www.imdb.com/title/"] - optional: true - attribute: href - download: - selector: a[href^="download.php"] - attribute: href - files: - selector: td:nth-child(5) > a - filters: - - name: regexp - args: (\d+) - size: - selector: td:nth-child(5) - remove: a - date: - selector: td:nth-child(2) > div - remove: b - filters: - - name: replace - args: ["\xA0", " "] - - name: replace - args: ["Added on ", ""] - - name: replace - args: ["st ", " "] - - name: replace - args: ["nd ", " "] - - name: replace - args: ["rd ", " "] - - name: replace - args: ["th ", " "] - - name: replace - args: [" by", ""] - - name: append - args: " +02:00" - - name: dateparse - args: "2 Jan 2006 15:04:05 -07:00" - grabs: - selector: td:nth-child(6) - downloadvolumefactor: - case: - "*": "0" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(2) - remove: a[title][href^="details.php?id="], div - seeders: - text: "9999" - leechers: - text: "9999" +--- + site: icetorrent + name: ICE Torrent + language: ro-ro + type: private + encoding: UTF-8 + links: + - https://www.icetorrent.org + + caps: + categorymappings: + - {id: 1, cat: PC/0day , desc: "Appz"} + - {id: 85, cat: Audio/Audiobook, desc: "AudioBooks"} + - {id: 68, cat: Books, desc: "Carti/Reviste"} + - {id: 23, cat: Books, desc: "Cartoons"} + - {id: 73, cat: Audio/Video, desc: "Concert/Videoclip"} + - {id: 75, cat: Other, desc: "Diverse"} + - {id: 69, cat: Books, desc: "Documentare"} + - {id: 51, cat: TV/Documentary, desc: "Documentaries"} + - {id: 43, cat: Books, desc: "eBooks"} + - {id: 63, cat: Movies/DVD, desc: "Filme DVD"} + - {id: 65, cat: Movies/HD, desc: "Filme HD"} + - {id: 64, cat: Movies/SD, desc: "Filme Xvid"} + - {id: 40, cat: Console, desc: "Games/Console"} + - {id: 26, cat: PC/Games, desc: "Games/PC"} + - {id: 38, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 59, cat: Movies/3D, desc: "Movies/3D"} + - {id: 92, cat: Movies/HD, desc: "Movies/4K-UHD"} + - {id: 32, cat: Movies/BluRay, desc: "Movies/Blu-Ray"} + - {id: 28, cat: Movies/DVD, desc: "Movies/DVD"} + - {id: 42, cat: Movies/HD, desc: "Movies/HD-x264"} + - {id: 91, cat: Movies/HD, desc: "Movies/HEVC-x265"} + - {id: 79, cat: Movies/HD, desc: "Movies/microHD"} + - {id: 29, cat: Movies/SD, desc: "Movies/SD"} + - {id: 72, cat: Audio/Lossless, desc: "Music/FLAC"} + - {id: 6, cat: Audio/MP3, desc: "Music/MP3"} + - {id: 37, cat: Audio/Video, desc: "Music/Video"} + - {id: 70, cat: Audio/Lossless, desc: "Muzica FLAC"} + - {id: 71, cat: Audio/MP3, desc: "Muzica MP3"} + - {id: 74, cat: Other, desc: "Other"} + - {id: 41, cat: Other, desc: "Pictures"} + - {id: 67, cat: TV, desc: "Seriale TV"} + - {id: 48, cat: TV/Sport, desc: "Sports"} + - {id: 87, cat: Other, desc: "TUTS"} + - {id: 33, cat: TV/SD, desc: "TV Episodes"} + - {id: 34, cat: TV/HD, desc: "TVHD Episodes"} + - {id: 9, cat: XXX, desc: "XXX"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: /login.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: font:contains("failed") + table + test: + path: /browse.php + + ratio: + text: -1 + + search: + paths: + - path: browse.php + categorymappings: ["!", 9] + - path: browseadult.php + categorymappings: [9] + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" + incldead: 1 + search_by: "{{ if .Query.IMDBID }}imdb{{else}}name{{end}}" + rows: + selector: table.torrenttable > tbody > tr:has(a[title][href^="details.php?id="]) + fields: + title: + selector: a[title][href^="details.php?id="] + attribute: title + details: + selector: a[title][href^="details.php?id="] + attribute: href + category: + selector: a[href*=".php?cat="] + attribute: href + filters: + - name: querystring + args: cat + imdb: + selector: a[title="IMDB"] + attribute: href + banner: + attribute: rel + imdb: + selector: a[href^="http://www.imdb.com/title/"] + optional: true + attribute: href + download: + selector: a[href^="download.php"] + attribute: href + files: + selector: td:nth-child(5) > a + filters: + - name: regexp + args: (\d+) + size: + selector: td:nth-child(5) + remove: a + date: + selector: td:nth-child(2) > div + remove: b + filters: + - name: replace + args: ["\xA0", " "] + - name: replace + args: ["Added on ", ""] + - name: replace + args: ["st ", " "] + - name: replace + args: ["nd ", " "] + - name: replace + args: ["rd ", " "] + - name: replace + args: ["th ", " "] + - name: replace + args: [" by", ""] + - name: append + args: " +02:00" + - name: dateparse + args: "2 Jan 2006 15:04:05 -07:00" + grabs: + selector: td:nth-child(6) + downloadvolumefactor: + case: + "*": "0" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(2) + remove: a[title][href^="details.php?id="], div + seeders: + text: "9999" + leechers: + text: "9999" diff --git a/src/Jackett/Definitions/iloveclassics.yml b/src/Jackett/Definitions/iloveclassics.yml index b29a4836..78a945c1 100644 --- a/src/Jackett/Definitions/iloveclassics.yml +++ b/src/Jackett/Definitions/iloveclassics.yml @@ -1,106 +1,106 @@ ---- - site: iloveclassics - name: I Love Classics - description: "Classics movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://www.iloveclassics.com/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Action/Adventure"} - - {id: 22, cat: Movies, desc: "Animation"} - - {id: 18, cat: Movies, desc: "Audio"} - - {id: 2, cat: Movies, desc: "Comedy"} - - {id: 12, cat: Movies, desc: "Crime/Mystery"} - - {id: 4, cat: Movies, desc: "Documentary"} - - {id: 3, cat: Movies, desc: "Drama"} - - {id: 24, cat: Movies, desc: "E-Book"} - - {id: 9, cat: Movies, desc: "Family"} - - {id: 23, cat: Movies, desc: "Fantasy"} - - {id: 6, cat: Movies, desc: "Film Noir"} - - {id: 7, cat: Movies, desc: "Film Short"} - - {id: 8, cat: Movies, desc: "Horror"} - - {id: 10, cat: Movies, desc: "Martial Arts"} - - {id: 11, cat: Movies, desc: "Musical"} - - {id: 20, cat: Movies, desc: "Other"} - - {id: 13, cat: Movies, desc: "Romance"} - - {id: 5, cat: Movies, desc: "Sci-Fi"} - - {id: 14, cat: Movies, desc: "Silent"} - - {id: 15, cat: Movies, desc: "Thriller"} - - {id: 19, cat: Movies, desc: "TV Shows"} - - {id: 16, cat: Movies, desc: "War"} - - {id: 17, cat: Movies, desc: "Western"} - - modes: - search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table:contains("Login failed!") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table#hover-over > tbody > tr.table_col1 - filters: - - name: andmatch - fields: - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - title: - selector: td:nth-child(2) a - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - grabs: - selector: td:nth-child(9) - filters: - - name: regexp - args: (\d+\s+)(?=x) - files: - selector: td:nth-child(4) - size: - selector: td:nth-child(9) - filters: - - name: regexp - args: (\d+.*(MB|GB)+) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - date: - selector: td:nth-child(2) - downloadvolumefactor: - case: - "img[title=\"This Torrent is on Free Leech. Download amounts do not count to your ratio\"]": "0" - "img[title=\"This Torrent is Free Leech because it has 5 or more seeders. Download amounts do not count to your ratio while 5 seeders remain\"]": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: iloveclassics + name: I Love Classics + description: "Classics movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://www.iloveclassics.com/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Action/Adventure"} + - {id: 22, cat: Movies, desc: "Animation"} + - {id: 18, cat: Movies, desc: "Audio"} + - {id: 2, cat: Movies, desc: "Comedy"} + - {id: 12, cat: Movies, desc: "Crime/Mystery"} + - {id: 4, cat: Movies, desc: "Documentary"} + - {id: 3, cat: Movies, desc: "Drama"} + - {id: 24, cat: Movies, desc: "E-Book"} + - {id: 9, cat: Movies, desc: "Family"} + - {id: 23, cat: Movies, desc: "Fantasy"} + - {id: 6, cat: Movies, desc: "Film Noir"} + - {id: 7, cat: Movies, desc: "Film Short"} + - {id: 8, cat: Movies, desc: "Horror"} + - {id: 10, cat: Movies, desc: "Martial Arts"} + - {id: 11, cat: Movies, desc: "Musical"} + - {id: 20, cat: Movies, desc: "Other"} + - {id: 13, cat: Movies, desc: "Romance"} + - {id: 5, cat: Movies, desc: "Sci-Fi"} + - {id: 14, cat: Movies, desc: "Silent"} + - {id: 15, cat: Movies, desc: "Thriller"} + - {id: 19, cat: Movies, desc: "TV Shows"} + - {id: 16, cat: Movies, desc: "War"} + - {id: 17, cat: Movies, desc: "Western"} + + modes: + search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table:contains("Login failed!") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table#hover-over > tbody > tr.table_col1 + filters: + - name: andmatch + fields: + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + title: + selector: td:nth-child(2) a + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + grabs: + selector: td:nth-child(9) + filters: + - name: regexp + args: (\d+\s+)(?=x) + files: + selector: td:nth-child(4) + size: + selector: td:nth-child(9) + filters: + - name: regexp + args: (\d+.*(MB|GB)+) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + date: + selector: td:nth-child(2) + downloadvolumefactor: + case: + "img[title=\"This Torrent is on Free Leech. Download amounts do not count to your ratio\"]": "0" + "img[title=\"This Torrent is Free Leech because it has 5 or more seeders. Download amounts do not count to your ratio while 5 seeders remain\"]": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/infinityt.yml b/src/Jackett/Definitions/infinityt.yml index 06275298..af9e4d0a 100644 --- a/src/Jackett/Definitions/infinityt.yml +++ b/src/Jackett/Definitions/infinityt.yml @@ -1,106 +1,106 @@ ---- - site: infinityt - name: Infinity-T - language: da-dk - type: private - encoding: UTF-8 - links: - - https://infinity-t.org/ - - caps: - categorymappings: - - {id: 22, cat: Audio/Audiobook, desc: "aBook"} - - {id: 13, cat: PC/Phone-Android, desc: "Appz/Android"} - - {id: 14, cat: PC/Phone-IOS, desc: "Appz/iPhone"} - - {id: 12, cat: PC/Mac, desc: "Appz/Mac"} - - {id: 11, cat: PC/0day, desc: "Appz/Win"} - - {id: 19, cat: Movies, desc: "AU/NEED"} - - {id: 20, cat: Books, desc: "eBook"} - - {id: 17, cat: Console, desc: "Games/Console"} - - {id: 16, cat: PC/Mac, desc: "Games/Mac"} - - {id: 15, cat: PC/Games, desc: "Games/PC"} - - {id: 8, cat: Movies, desc: "Movie/Boxset"} - - {id: 7, cat: Movies/DVD, desc: "Movie/DVD"} - - {id: 5, cat: Movies/HD, desc: "Movie/HD"} - - {id: 6, cat: Movies/SD, desc: "Movie/SD"} - - {id: 10, cat: Audio/Lossless, desc: "Music/FLAC"} - - {id: 9, cat: Audio/MP3, desc: "Music/MP3"} - - {id: 21, cat: Movies/Bluray, desc: "REMUX/Bluray"} - - {id: 4, cat: TV, desc: "TV/Boxset"} - - {id: 3, cat: TV, desc: "TV/DVD"} - - {id: 1, cat: TV/HD, desc: "TV/HD"} - - {id: 2, cat: TV/SD, desc: "TV/SD"} - - {id: 18, cat: XXX, desc: "XXX"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: td.outer > table > tbody > tr[id] - fields: - imdb: - selector: a[href^="https://www.nullrefer.com/?http://imdb.com/title/"] - attribute: href - banner: - selector: a[rel] - attribute: rel - filters: - - name: replace - args: ["pic/noposter.jpg", ""] - title: - selector: a[href^="details.php?id="] - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php"] - attribute: href - files: - selector: td:nth-child(3) - size: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - date: - selector: td:nth-child(5) - filters: - - name: replace - args: ["I Dag", "Today"] - - name: replace - args: ["I Går", "Yesterday"] - - grabs: - selector: td:nth-child(8) - downloadvolumefactor: - case: - td[style*="/pic/free.png"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: infinityt + name: Infinity-T + language: da-dk + type: private + encoding: UTF-8 + links: + - https://infinity-t.org/ + + caps: + categorymappings: + - {id: 22, cat: Audio/Audiobook, desc: "aBook"} + - {id: 13, cat: PC/Phone-Android, desc: "Appz/Android"} + - {id: 14, cat: PC/Phone-IOS, desc: "Appz/iPhone"} + - {id: 12, cat: PC/Mac, desc: "Appz/Mac"} + - {id: 11, cat: PC/0day, desc: "Appz/Win"} + - {id: 19, cat: Movies, desc: "AU/NEED"} + - {id: 20, cat: Books, desc: "eBook"} + - {id: 17, cat: Console, desc: "Games/Console"} + - {id: 16, cat: PC/Mac, desc: "Games/Mac"} + - {id: 15, cat: PC/Games, desc: "Games/PC"} + - {id: 8, cat: Movies, desc: "Movie/Boxset"} + - {id: 7, cat: Movies/DVD, desc: "Movie/DVD"} + - {id: 5, cat: Movies/HD, desc: "Movie/HD"} + - {id: 6, cat: Movies/SD, desc: "Movie/SD"} + - {id: 10, cat: Audio/Lossless, desc: "Music/FLAC"} + - {id: 9, cat: Audio/MP3, desc: "Music/MP3"} + - {id: 21, cat: Movies/Bluray, desc: "REMUX/Bluray"} + - {id: 4, cat: TV, desc: "TV/Boxset"} + - {id: 3, cat: TV, desc: "TV/DVD"} + - {id: 1, cat: TV/HD, desc: "TV/HD"} + - {id: 2, cat: TV/SD, desc: "TV/SD"} + - {id: 18, cat: XXX, desc: "XXX"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: td.outer > table > tbody > tr[id] + fields: + imdb: + selector: a[href^="https://www.nullrefer.com/?http://imdb.com/title/"] + attribute: href + banner: + selector: a[rel] + attribute: rel + filters: + - name: replace + args: ["pic/noposter.jpg", ""] + title: + selector: a[href^="details.php?id="] + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php"] + attribute: href + files: + selector: td:nth-child(3) + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + date: + selector: td:nth-child(5) + filters: + - name: replace + args: ["I Dag", "Today"] + - name: replace + args: ["I Går", "Yesterday"] + + grabs: + selector: td:nth-child(8) + downloadvolumefactor: + case: + td[style*="/pic/free.png"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/inperil.yml b/src/Jackett/Definitions/inperil.yml index 089d2b2f..aff82ecb 100644 --- a/src/Jackett/Definitions/inperil.yml +++ b/src/Jackett/Definitions/inperil.yml @@ -1,104 +1,104 @@ ---- - site: inperil - name: inPeril - type: private - language: lv-lv - type: private - encoding: UTF-8 - links: - - http://www.inperil.net/ - - caps: - categorymappings: - - {id: 34, cat: TV/Anime, desc: "Animation"} - - {id: 22, cat: PC/0day, desc: "Appz"} - - {id: 25, cat: PC/Games, desc: "Games/Console"} - - {id: 4, cat: PC/Games, desc: "Games/PC"} - - {id: 27, cat: Other/Misc, desc: "Misc"} - - {id: 35, cat: Movies/HD, desc: "Movies/HD"} - - {id: 37, cat: Movies/Foreign, desc: "Movies/LAT"} - - {id: 42, cat: Movies, desc: "Movies/Pack"} - - {id: 38, cat: Movies, desc: "Movies/Retro"} - - {id: 36, cat: Movies/Foreign, desc: "Movies/RUS"} - - {id: 19, cat: Movies/SD, desc: "Movies/SD"} - - {id: 6, cat: Audio, desc: "Music"} - - {id: 26, cat: Audio/Video, desc: "Music Videos"} - - {id: 31, cat: Audio/Lossless, desc: "Music/FLAC"} - - {id: 39, cat: TV/HD, desc: "TV/HD"} - - {id: 43, cat: TV, desc: "TV/Pack"} - - {id: 7, cat: TV/SD, desc: "TV/SD"} - - {id: 40, cat: XXX, desc: "XXX/HD"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: font.logintext - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: table > tbody > tr:has(a[href^="details.php?id="]) - fields: - title: - selector: a[href^="details.php?id="][title] - attribute: title - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="download.php/"] - attribute: href - files: - selector: td:nth-child(3) - size: - selector: td:nth-child(6) - date: - selector: td:nth-child(5) - filters: - - name: append - args: " +02:00" - - name: dateparse - args: "2006-01-0215:04:05 -07:00" - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: ([,\d]+) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - banner: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: src=([^\s]+) - downloadvolumefactor: - case: - "img[alt=\"Zelta Torrents\"]": "0" - "img[alt=\"Sudraba Torrents\"]": "0.5" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: inperil + name: inPeril + type: private + language: lv-lv + type: private + encoding: UTF-8 + links: + - http://www.inperil.net/ + + caps: + categorymappings: + - {id: 34, cat: TV/Anime, desc: "Animation"} + - {id: 22, cat: PC/0day, desc: "Appz"} + - {id: 25, cat: PC/Games, desc: "Games/Console"} + - {id: 4, cat: PC/Games, desc: "Games/PC"} + - {id: 27, cat: Other/Misc, desc: "Misc"} + - {id: 35, cat: Movies/HD, desc: "Movies/HD"} + - {id: 37, cat: Movies/Foreign, desc: "Movies/LAT"} + - {id: 42, cat: Movies, desc: "Movies/Pack"} + - {id: 38, cat: Movies, desc: "Movies/Retro"} + - {id: 36, cat: Movies/Foreign, desc: "Movies/RUS"} + - {id: 19, cat: Movies/SD, desc: "Movies/SD"} + - {id: 6, cat: Audio, desc: "Music"} + - {id: 26, cat: Audio/Video, desc: "Music Videos"} + - {id: 31, cat: Audio/Lossless, desc: "Music/FLAC"} + - {id: 39, cat: TV/HD, desc: "TV/HD"} + - {id: 43, cat: TV, desc: "TV/Pack"} + - {id: 7, cat: TV/SD, desc: "TV/SD"} + - {id: 40, cat: XXX, desc: "XXX/HD"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: font.logintext + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: table > tbody > tr:has(a[href^="details.php?id="]) + fields: + title: + selector: a[href^="details.php?id="][title] + attribute: title + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="download.php/"] + attribute: href + files: + selector: td:nth-child(3) + size: + selector: td:nth-child(6) + date: + selector: td:nth-child(5) + filters: + - name: append + args: " +02:00" + - name: dateparse + args: "2006-01-0215:04:05 -07:00" + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: ([,\d]+) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + banner: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: src=([^\s]+) + downloadvolumefactor: + case: + "img[alt=\"Zelta Torrents\"]": "0" + "img[alt=\"Sudraba Torrents\"]": "0.5" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/insanetracker.yml b/src/Jackett/Definitions/insanetracker.yml index 10576252..947820bc 100644 --- a/src/Jackett/Definitions/insanetracker.yml +++ b/src/Jackett/Definitions/insanetracker.yml @@ -1,140 +1,140 @@ ---- - site: insanetracker - name: Insane Tracker - language: hu-hu - type: private - encoding: UTF-8 - links: - - https://newinsane.info/ - - caps: - categorymappings: - - {id: 8, cat: TV/SD, desc: "Sorozat/Hun"} - - {id: 40, cat: TV/HD, desc: "Sorozat/Hun/HD"} - - {id: 41, cat: Movies/SD, desc: "Film/Hun/SD"} - - {id: 15, cat: Movies/DVD, desc: "Film/Hun/DVD-R"} - - {id: 27, cat: Movies/HD, desc: "Film/Hun/HD"} - - {id: 44, cat: Movies/HD, desc: "Film/Hun/UHD"} - - {id: 2, cat: Books, desc: "eBook/Hun"} - - {id: 7, cat: TV/SD, desc: "Sorozat/Eng"} - - {id: 39, cat: TV/HD, desc: "Sorozat/Eng/HD"} - - {id: 42, cat: Movies/SD, desc: "Film/Eng/SD"} - - {id: 14, cat: Movies/DVD, desc: "Film/Eng/DVD-R"} - - {id: 25, cat: Movies/HD, desc: "Film/Eng/HD"} - - {id: 45, cat: Movies/HD, desc: "Film/Eng/UHD"} - - {id: 1, cat: Books, desc: "eBook/Eng"} - - {id: 38, cat: Audio/Audiobook, desc: "Hangoskönyv"} - - {id: 21, cat: XXX, desc: "XXX"} - - {id: 4, cat: PC/ISO, desc: "Program/ISO"} - - {id: 19, cat: Audio/Other, desc: "Zene/Hun"} - - {id: 37, cat: Audio/Lossless, desc: "Lossless/Hun"} - - {id: 9, cat: PC/Games, desc: "Játék/ISO"} - - {id: 43, cat: Console, desc: "Játék/Konzol"} - - {id: 29, cat: Other, desc: "Képek"} - - {id: 28, cat: XXX/Imageset, desc: "XXX Képek"} - - {id: 3, cat: PC/0day, desc: "Program/Egyéb"} - - {id: 18, cat: Audio/Other, desc: "Zene/Eng"} - - {id: 26, cat: Audio/Lossless, desc: "Lossless/Eng"} - - {id: 11, cat: PC/Games, desc: "Játék/Rip"} - - {id: 13, cat: PC/Phone-Other, desc: "Mobil"} - - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q, imdbid] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - notsecure: "1" - error: - - selector: div.login_error_content - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" - t: "all" - rows: - selector: table.torrentable > tbody > tr:has(td.maintd) - fields: - title: - selector: div.tortitle > a - attribute: title - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: div.tortitle > a - attribute: href - download: - selector: a[href^="download.php/"] - attribute: href - imdb|optional: - selector: a[title="IMDb link"] - attribute: href - banner|optional|1: - selector: img[alt="offer"] - attribute: src - banner|optional|2: - selector: a.cover - attribute: href - files: - selector: td:nth-child(6) - filters: - - name: replace - args: [".", ""] - size: - selector: td:nth-child(8) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - grabs: - selector: td:nth-child(9) > div:first-child - filters: - - name: replace - args: [".", ""] - - name: regexp - args: "^([\\d]+)" - seeders: - selector: td:nth-child(9) > div:first-child - filters: - - name: replace - args: [".", ""] - - name: regexp - args: "\\|\\s*([\\d]+)\\s*\\|" - leechers: - selector: td:nth-child(9) > div:first-child - filters: - - name: replace - args: [".", ""] - - name: regexp - args: "([\\d]+)$" - date: - selector: td.date - filters: - - name: dateparse - args: "2006.01.02 15:04:05" - downloadvolumefactor: - text: "0" - uploadvolumefactor: - case: - img[src^="pic/4x.gif"]: "4" - img[src^="pic/3x.gif"]: "3" - img[src^="pic/2x.gif"]: "2" - "*": "1" - description: - selector: td.maintd - remove: div.tortitle, div.markcont, div.tablebuttons, div.tablebigbuttons +--- + site: insanetracker + name: Insane Tracker + language: hu-hu + type: private + encoding: UTF-8 + links: + - https://newinsane.info/ + + caps: + categorymappings: + - {id: 8, cat: TV/SD, desc: "Sorozat/Hun"} + - {id: 40, cat: TV/HD, desc: "Sorozat/Hun/HD"} + - {id: 41, cat: Movies/SD, desc: "Film/Hun/SD"} + - {id: 15, cat: Movies/DVD, desc: "Film/Hun/DVD-R"} + - {id: 27, cat: Movies/HD, desc: "Film/Hun/HD"} + - {id: 44, cat: Movies/HD, desc: "Film/Hun/UHD"} + - {id: 2, cat: Books, desc: "eBook/Hun"} + - {id: 7, cat: TV/SD, desc: "Sorozat/Eng"} + - {id: 39, cat: TV/HD, desc: "Sorozat/Eng/HD"} + - {id: 42, cat: Movies/SD, desc: "Film/Eng/SD"} + - {id: 14, cat: Movies/DVD, desc: "Film/Eng/DVD-R"} + - {id: 25, cat: Movies/HD, desc: "Film/Eng/HD"} + - {id: 45, cat: Movies/HD, desc: "Film/Eng/UHD"} + - {id: 1, cat: Books, desc: "eBook/Eng"} + - {id: 38, cat: Audio/Audiobook, desc: "Hangoskönyv"} + - {id: 21, cat: XXX, desc: "XXX"} + - {id: 4, cat: PC/ISO, desc: "Program/ISO"} + - {id: 19, cat: Audio/Other, desc: "Zene/Hun"} + - {id: 37, cat: Audio/Lossless, desc: "Lossless/Hun"} + - {id: 9, cat: PC/Games, desc: "Játék/ISO"} + - {id: 43, cat: Console, desc: "Játék/Konzol"} + - {id: 29, cat: Other, desc: "Képek"} + - {id: 28, cat: XXX/Imageset, desc: "XXX Képek"} + - {id: 3, cat: PC/0day, desc: "Program/Egyéb"} + - {id: 18, cat: Audio/Other, desc: "Zene/Eng"} + - {id: 26, cat: Audio/Lossless, desc: "Lossless/Eng"} + - {id: 11, cat: PC/Games, desc: "Játék/Rip"} + - {id: 13, cat: PC/Phone-Other, desc: "Mobil"} + + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q, imdbid] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + notsecure: "1" + error: + - selector: div.login_error_content + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" + t: "all" + rows: + selector: table.torrentable > tbody > tr:has(td.maintd) + fields: + title: + selector: div.tortitle > a + attribute: title + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: div.tortitle > a + attribute: href + download: + selector: a[href^="download.php/"] + attribute: href + imdb|optional: + selector: a[title="IMDb link"] + attribute: href + banner|optional|1: + selector: img[alt="offer"] + attribute: src + banner|optional|2: + selector: a.cover + attribute: href + files: + selector: td:nth-child(6) + filters: + - name: replace + args: [".", ""] + size: + selector: td:nth-child(8) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + grabs: + selector: td:nth-child(9) > div:first-child + filters: + - name: replace + args: [".", ""] + - name: regexp + args: "^([\\d]+)" + seeders: + selector: td:nth-child(9) > div:first-child + filters: + - name: replace + args: [".", ""] + - name: regexp + args: "\\|\\s*([\\d]+)\\s*\\|" + leechers: + selector: td:nth-child(9) > div:first-child + filters: + - name: replace + args: [".", ""] + - name: regexp + args: "([\\d]+)$" + date: + selector: td.date + filters: + - name: dateparse + args: "2006.01.02 15:04:05" + downloadvolumefactor: + text: "0" + uploadvolumefactor: + case: + img[src^="pic/4x.gif"]: "4" + img[src^="pic/3x.gif"]: "3" + img[src^="pic/2x.gif"]: "2" + "*": "1" + description: + selector: td.maintd + remove: div.tortitle, div.markcont, div.tablebuttons, div.tablebigbuttons diff --git a/src/Jackett/Definitions/jpopsuki.yml b/src/Jackett/Definitions/jpopsuki.yml index 543f5c86..1c273504 100644 --- a/src/Jackett/Definitions/jpopsuki.yml +++ b/src/Jackett/Definitions/jpopsuki.yml @@ -1,105 +1,105 @@ ---- - site: jpopsuki - name: JPopsuki - language: en-us - type: private - encoding: UTF-8 - links: - - https://jpopsuki.eu/ - - caps: - categorymappings: - - {id: 1, cat: Audio, desc: "Album"} - - {id: 2, cat: Audio, desc: "Single"} - - {id: 3, cat: Movies, desc: "PV"} - - {id: 4, cat: Movies/DVD, desc: "DVD"} - - {id: 5, cat: TV, desc: "TV-Music"} - - {id: 6, cat: TV, desc: "TV-Variety"} - - {id: 7, cat: TV, desc: "TV-Drama"} - - {id: 8, cat: Other, desc: "Fansubs"} - - {id: 9, cat: Other, desc: "Pictures"} - - {id: 10, cat: Other/Misc, desc: "Misc"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: 1 - login: "Log in" - error: - - selector: form#loginform > span.warning - test: - path: torrents.php - - ratio: - path: torrents.php - selector: li#stats_ratio > span - - search: - path: torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: time - order_way: desc - action: basic - searchsubmit: 1 - rows: - selector: table#torrent_table > tbody > tr[class^="torrent"] - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - description: - selector: div.tags - title: - selector: td:nth-child(4) - remove: span, div.tags, a[title="View Comments"] - filters: - - name: replace - args: [" ()", ""] - - name: replace - args: [" / Freeleech!", ""] - category: - selector: a[href*="filter_cat"] - attribute: href - filters: - - name: regexp - args: "%5B(\\d+?)%5D" - details: - selector: a[href^="torrents.php?id="] - attribute: href - banner: - selector: td:nth-child(3) img - attribute: src - files: - selector: td:nth-child(5) - date: - selector: td:nth-child(6) - attribute: title - filters: - - name: append - args: " +00:00" - - name: dateparse - args: "Jan 02 2006, 15:04 -07:00" - size: - selector: td:nth-child(7) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - downloadvolumefactor: - case: - "strong:contains(\"Freeleech!\")": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: jpopsuki + name: JPopsuki + language: en-us + type: private + encoding: UTF-8 + links: + - https://jpopsuki.eu/ + + caps: + categorymappings: + - {id: 1, cat: Audio, desc: "Album"} + - {id: 2, cat: Audio, desc: "Single"} + - {id: 3, cat: Movies, desc: "PV"} + - {id: 4, cat: Movies/DVD, desc: "DVD"} + - {id: 5, cat: TV, desc: "TV-Music"} + - {id: 6, cat: TV, desc: "TV-Variety"} + - {id: 7, cat: TV, desc: "TV-Drama"} + - {id: 8, cat: Other, desc: "Fansubs"} + - {id: 9, cat: Other, desc: "Pictures"} + - {id: 10, cat: Other/Misc, desc: "Misc"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: 1 + login: "Log in" + error: + - selector: form#loginform > span.warning + test: + path: torrents.php + + ratio: + path: torrents.php + selector: li#stats_ratio > span + + search: + path: torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: time + order_way: desc + action: basic + searchsubmit: 1 + rows: + selector: table#torrent_table > tbody > tr[class^="torrent"] + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + description: + selector: div.tags + title: + selector: td:nth-child(4) + remove: span, div.tags, a[title="View Comments"] + filters: + - name: replace + args: [" ()", ""] + - name: replace + args: [" / Freeleech!", ""] + category: + selector: a[href*="filter_cat"] + attribute: href + filters: + - name: regexp + args: "%5B(\\d+?)%5D" + details: + selector: a[href^="torrents.php?id="] + attribute: href + banner: + selector: td:nth-child(3) img + attribute: src + files: + selector: td:nth-child(5) + date: + selector: td:nth-child(6) + attribute: title + filters: + - name: append + args: " +00:00" + - name: dateparse + args: "Jan 02 2006, 15:04 -07:00" + size: + selector: td:nth-child(7) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + downloadvolumefactor: + case: + "strong:contains(\"Freeleech!\")": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/karagarga.yml b/src/Jackett/Definitions/karagarga.yml index 03c8c49b..c0807530 100644 --- a/src/Jackett/Definitions/karagarga.yml +++ b/src/Jackett/Definitions/karagarga.yml @@ -1,83 +1,83 @@ ---- - site: karagarga - name: Karagarga - description: "Rare and obscure movie tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://karagarga.in/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Movies"} - - modes: - search: [q] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - captcha: - type: image - image: img#captcha_img - input: imagestring - error: - - selector: table:contains("Login failed!") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "\"{{ .Query.Keywords }}\"" - search_type: "title" - rows: - selector: table#browse > tbody > tr:has(a[href^="browse.php?genre="]) - fields: - category: - text: 1 - title: - selector: td:nth-child(2) span - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - grabs: - selector: td:nth-child(12) - filters: - - name: regexp - args: ([\d,]+) - files: - selector: td:nth-child(10) - size: - selector: td:nth-child(11) - seeders: - selector: td:nth-child(13) - leechers: - selector: td:nth-child(14) - date: - selector: td:nth-child(9) - filters: - - name: replace - args: ["'", ""] - - name: dateparse - args: "Jan 02 06" - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: karagarga + name: Karagarga + description: "Rare and obscure movie tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://karagarga.in/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Movies"} + + modes: + search: [q] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + captcha: + type: image + image: img#captcha_img + input: imagestring + error: + - selector: table:contains("Login failed!") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "\"{{ .Query.Keywords }}\"" + search_type: "title" + rows: + selector: table#browse > tbody > tr:has(a[href^="browse.php?genre="]) + fields: + category: + text: 1 + title: + selector: td:nth-child(2) span + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + grabs: + selector: td:nth-child(12) + filters: + - name: regexp + args: ([\d,]+) + files: + selector: td:nth-child(10) + size: + selector: td:nth-child(11) + seeders: + selector: td:nth-child(13) + leechers: + selector: td:nth-child(14) + date: + selector: td:nth-child(9) + filters: + - name: replace + args: ["'", ""] + - name: dateparse + args: "Jan 02 06" + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/leparadisdunet.yml b/src/Jackett/Definitions/leparadisdunet.yml index ef5ffe0c..aa9f9600 100644 --- a/src/Jackett/Definitions/leparadisdunet.yml +++ b/src/Jackett/Definitions/leparadisdunet.yml @@ -1,163 +1,163 @@ ---- - site: leparadisdunet - name: Le Paradis Du Net - language: fr-fr - type: semi-private - encoding: UTF-8 - links: - - https://le-paradis-du-net.com/ - - caps: - categorymappings: - - {id: 10, cat: Movies/3D, desc: "3D"} - - {id: 9, cat: XXX, desc: "Adultes"} - - {id: 1, cat: PC, desc: "APPLICATION"} - - {id: 33, cat: PC/Phone-Other, desc: " Iphone/Ipod/Android"} - - {id: 3, cat: PC/0day, desc: " Linux"} - - {id: 32, cat: PC/Mac, desc: " Mac"} - - {id: 4, cat: PC/0day, desc: " Windows"} - - {id: 70, cat: Movies/HD, desc: "BDRIP"} - - {id: 69, cat: Movies/BluRay, desc: "Blueray"} - - {id: 73, cat: Movies/HD, desc: "BRRIP"} - - {id: 22, cat: Movies/SD, desc: "CAM TS SCREENER"} - - {id: 39, cat: Movies/DVD, desc: " R5"} - - {id: 13, cat: TV/Anime, desc: "DESSINS ANIMES"} - - {id: 48, cat: TV/Anime, desc: " Animations"} - - {id: 47, cat: TV/Anime, desc: " Mangas"} - - {id: 14, cat: TV/Documentary, desc: "DOCUMENTAIRE"} - - {id: 52, cat: TV/Documentary, desc: " EmissionsTV"} - - {id: 49, cat: TV/Documentary, desc: " Tv docs"} - - {id: 15, cat: Movies/DVD, desc: "DVDR"} - - {id: 16, cat: Movies/SD, desc: "DVDRIP"} - - {id: 35, cat: Movies, desc: " Action"} - - {id: 64, cat: Movies, desc: " Autres"} - - {id: 36, cat: Movies, desc: " Aventure"} - - {id: 55, cat: Movies, desc: " Comédie"} - - {id: 37, cat: Movies, desc: " Drame"} - - {id: 38, cat: Movies, desc: " Fantastique"} - - {id: 63, cat: Movies, desc: " Guerre"} - - {id: 72, cat: Movies, desc: " Historique/Biopic"} - - {id: 67, cat: Movies, desc: " Horreur"} - - {id: 65, cat: Movies, desc: " Thriller"} - - {id: 71, cat: Movies, desc: " Werstern"} - - {id: 17, cat: Movies/SD, desc: "DVDRIP VOSTFR"} - - {id: 19, cat: Books, desc: "EBOOK"} - - {id: 54, cat: Books, desc: " Journaux"} - - {id: 81, cat: Books, desc: " Magazines"} - - {id: 82, cat: Books, desc: " People"} - - {id: 40, cat: Movies/HD, desc: "HD"} - - {id: 41, cat: Movies/HD, desc: " 1080p"} - - {id: 42, cat: Movies/HD, desc: " 720P"} - - {id: 77, cat: Movies/HD, desc: " HD LIGHT"} - - {id: 86, cat: TV/SD, desc: " HDTV"} - - {id: 20, cat: Console/Other, desc: "JEUX"} - - {id: 56, cat: Console/NDS, desc: " DS"} - - {id: 57, cat: PC/Games, desc: " Pc"} - - {id: 26, cat: Console/PS3, desc: " PS3"} - - {id: 58, cat: Console/PSP, desc: " PSP"} - - {id: 25, cat: Console/Wii, desc: " Wii"} - - {id: 24, cat: Console/Xbox360, desc: " Xbox360"} - - {id: 21, cat: Audio, desc: "MUSIQUES"} - - {id: 29, cat: Audio/Video, desc: " Clip"} - - {id: 68, cat: Audio/Video, desc: " Concert"} - - {id: 31, cat: Audio/Lossless, desc: " FLAC"} - - {id: 30, cat: Audio/MP3, desc: " mp3"} - - {id: 28, cat: Audio/Lossless, desc: " wave"} - - {id: 27, cat: Audio/Other, desc: " wma"} - - {id: 5, cat: TV, desc: "SERIES"} - - {id: 79, cat: TV/HD, desc: " SERIES HD 1080P"} - - {id: 80, cat: TV/HD, desc: " SERIES HD 720p"} - - {id: 75, cat: TV, desc: " TV pack"} - - {id: 8, cat: TV, desc: " vf"} - - {id: 6, cat: TV, desc: " vo"} - - {id: 7, cat: TV, desc: " vost"} - - {id: 12, cat: TV/Sport, desc: "SPORTS"} - - {id: 61, cat: TV/Sport, desc: " Autres "} - - {id: 45, cat: TV/Sport, desc: " Catch VF"} - - {id: 59, cat: TV/Sport, desc: " Catch VO"} - - {id: 44, cat: TV/Sport, desc: " Football"} - - {id: 60, cat: TV/Sport, desc: " UFC/MMA"} - - {id: 76, cat: TV, desc: "Télévision"} - - {id: 78, cat: Movies/WEBDL, desc: "WEBRIP"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: table:has(td:contains("Une erreur est survenue")) - test: - path: browse.php - - download: - before: - path: "/takethanks.php" - method: "post" - inputs: - torrentid: "{{ re_replace .DownloadUri.AbsolutePath \"^.*download-torrent-(\\d+)/.*$\" \"$1\" }}" - - search: - path: browse.php - inputs: - do: "chercher" - keywords: "{{ .Query.Keywords }}" - search_type: "t_name" - category: "0" # multi cat search not supported - include_dead_torrents: "yes" - rows: - selector: table#sortabletable > tbody > tr:has(a[href*="/torrent-details-"]) - fields: - download: - selector: a[href*="/torrent-details-"] - attribute: href - filters: - - name: replace - args: ["torrent-details-", "download-torrent-"] - title: - selector: a[href*="/torrent-details-"] - details: - selector: a[href*="/torrent-details-"] - attribute: href - category: - selector: a[href*="/torrent-category-"] - attribute: href - filters: - - name: regexp - args: torrent-category-(\d+) - size: - selector: td:nth-child(4) - date: - selector: td:nth-child(2) > div > font[color="white"] - filters: - - name: replace - args: ["le ", ""] - - name: replace - args: [" à ", " "] - - name: trim - args: "\t" - - name: trim - args: "\n" - - name: append - args: " +01:00" - - name: dateparse - args: "02-01-2006 15:04 -07:00" - grabs: - selector: td:nth-child(5) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - downloadvolumefactor: - case: - img[alt^="Free Torrent "]: "0" - img[alt^="Silver Torrent "]: "0.5" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: leparadisdunet + name: Le Paradis Du Net + language: fr-fr + type: semi-private + encoding: UTF-8 + links: + - https://le-paradis-du-net.com/ + + caps: + categorymappings: + - {id: 10, cat: Movies/3D, desc: "3D"} + - {id: 9, cat: XXX, desc: "Adultes"} + - {id: 1, cat: PC, desc: "APPLICATION"} + - {id: 33, cat: PC/Phone-Other, desc: " Iphone/Ipod/Android"} + - {id: 3, cat: PC/0day, desc: " Linux"} + - {id: 32, cat: PC/Mac, desc: " Mac"} + - {id: 4, cat: PC/0day, desc: " Windows"} + - {id: 70, cat: Movies/HD, desc: "BDRIP"} + - {id: 69, cat: Movies/BluRay, desc: "Blueray"} + - {id: 73, cat: Movies/HD, desc: "BRRIP"} + - {id: 22, cat: Movies/SD, desc: "CAM TS SCREENER"} + - {id: 39, cat: Movies/DVD, desc: " R5"} + - {id: 13, cat: TV/Anime, desc: "DESSINS ANIMES"} + - {id: 48, cat: TV/Anime, desc: " Animations"} + - {id: 47, cat: TV/Anime, desc: " Mangas"} + - {id: 14, cat: TV/Documentary, desc: "DOCUMENTAIRE"} + - {id: 52, cat: TV/Documentary, desc: " EmissionsTV"} + - {id: 49, cat: TV/Documentary, desc: " Tv docs"} + - {id: 15, cat: Movies/DVD, desc: "DVDR"} + - {id: 16, cat: Movies/SD, desc: "DVDRIP"} + - {id: 35, cat: Movies, desc: " Action"} + - {id: 64, cat: Movies, desc: " Autres"} + - {id: 36, cat: Movies, desc: " Aventure"} + - {id: 55, cat: Movies, desc: " Comédie"} + - {id: 37, cat: Movies, desc: " Drame"} + - {id: 38, cat: Movies, desc: " Fantastique"} + - {id: 63, cat: Movies, desc: " Guerre"} + - {id: 72, cat: Movies, desc: " Historique/Biopic"} + - {id: 67, cat: Movies, desc: " Horreur"} + - {id: 65, cat: Movies, desc: " Thriller"} + - {id: 71, cat: Movies, desc: " Werstern"} + - {id: 17, cat: Movies/SD, desc: "DVDRIP VOSTFR"} + - {id: 19, cat: Books, desc: "EBOOK"} + - {id: 54, cat: Books, desc: " Journaux"} + - {id: 81, cat: Books, desc: " Magazines"} + - {id: 82, cat: Books, desc: " People"} + - {id: 40, cat: Movies/HD, desc: "HD"} + - {id: 41, cat: Movies/HD, desc: " 1080p"} + - {id: 42, cat: Movies/HD, desc: " 720P"} + - {id: 77, cat: Movies/HD, desc: " HD LIGHT"} + - {id: 86, cat: TV/SD, desc: " HDTV"} + - {id: 20, cat: Console/Other, desc: "JEUX"} + - {id: 56, cat: Console/NDS, desc: " DS"} + - {id: 57, cat: PC/Games, desc: " Pc"} + - {id: 26, cat: Console/PS3, desc: " PS3"} + - {id: 58, cat: Console/PSP, desc: " PSP"} + - {id: 25, cat: Console/Wii, desc: " Wii"} + - {id: 24, cat: Console/Xbox360, desc: " Xbox360"} + - {id: 21, cat: Audio, desc: "MUSIQUES"} + - {id: 29, cat: Audio/Video, desc: " Clip"} + - {id: 68, cat: Audio/Video, desc: " Concert"} + - {id: 31, cat: Audio/Lossless, desc: " FLAC"} + - {id: 30, cat: Audio/MP3, desc: " mp3"} + - {id: 28, cat: Audio/Lossless, desc: " wave"} + - {id: 27, cat: Audio/Other, desc: " wma"} + - {id: 5, cat: TV, desc: "SERIES"} + - {id: 79, cat: TV/HD, desc: " SERIES HD 1080P"} + - {id: 80, cat: TV/HD, desc: " SERIES HD 720p"} + - {id: 75, cat: TV, desc: " TV pack"} + - {id: 8, cat: TV, desc: " vf"} + - {id: 6, cat: TV, desc: " vo"} + - {id: 7, cat: TV, desc: " vost"} + - {id: 12, cat: TV/Sport, desc: "SPORTS"} + - {id: 61, cat: TV/Sport, desc: " Autres "} + - {id: 45, cat: TV/Sport, desc: " Catch VF"} + - {id: 59, cat: TV/Sport, desc: " Catch VO"} + - {id: 44, cat: TV/Sport, desc: " Football"} + - {id: 60, cat: TV/Sport, desc: " UFC/MMA"} + - {id: 76, cat: TV, desc: "Télévision"} + - {id: 78, cat: Movies/WEBDL, desc: "WEBRIP"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: table:has(td:contains("Une erreur est survenue")) + test: + path: browse.php + + download: + before: + path: "/takethanks.php" + method: "post" + inputs: + torrentid: "{{ re_replace .DownloadUri.AbsolutePath \"^.*download-torrent-(\\d+)/.*$\" \"$1\" }}" + + search: + path: browse.php + inputs: + do: "chercher" + keywords: "{{ .Query.Keywords }}" + search_type: "t_name" + category: "0" # multi cat search not supported + include_dead_torrents: "yes" + rows: + selector: table#sortabletable > tbody > tr:has(a[href*="/torrent-details-"]) + fields: + download: + selector: a[href*="/torrent-details-"] + attribute: href + filters: + - name: replace + args: ["torrent-details-", "download-torrent-"] + title: + selector: a[href*="/torrent-details-"] + details: + selector: a[href*="/torrent-details-"] + attribute: href + category: + selector: a[href*="/torrent-category-"] + attribute: href + filters: + - name: regexp + args: torrent-category-(\d+) + size: + selector: td:nth-child(4) + date: + selector: td:nth-child(2) > div > font[color="white"] + filters: + - name: replace + args: ["le ", ""] + - name: replace + args: [" à ", " "] + - name: trim + args: "\t" + - name: trim + args: "\n" + - name: append + args: " +01:00" + - name: dateparse + args: "02-01-2006 15:04 -07:00" + grabs: + selector: td:nth-child(5) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + downloadvolumefactor: + case: + img[alt^="Free Torrent "]: "0" + img[alt^="Silver Torrent "]: "0.5" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/losslessclub.yml b/src/Jackett/Definitions/losslessclub.yml index 87721c8e..a4709505 100644 --- a/src/Jackett/Definitions/losslessclub.yml +++ b/src/Jackett/Definitions/losslessclub.yml @@ -1,82 +1,82 @@ ---- - site: losslessclub - name: LosslessClub - language: ru-ru - type: private - encoding: windows-1251 - links: - - https://losslessclub.com/ - - caps: - categories: - 1: Audio/Lossless - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded > div.error - test: - path: /browse.php - selector: span.bar_user_welcome - - search: - path: /browse.php - inputs: - search: "{{ .Query.Keywords }}" - t: "all" - rows: - selector: div#releases-table > table > tbody > tr:has(a.browselink) - fields: - title: - selector: a.browselink - category: - text: "1" - details: - selector: a.browselink - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - banner|optional: - selector: img.thumbnail - attribute: src - size: - selector: td:nth-child(5) - grabs|optional: - selector: td:nth-child(6) br + span - seeders: - selector: td:nth-child(6) - remove: br + span - filters: - - name: regexp - args: "([\\.\\d]+)\\s+\\|" - leechers: - selector: td:nth-child(6) - remove: br + span - filters: - - name: regexp - args: "\\|\\s*([\\.\\d]+)" - date: - selector: td:nth-child(7) - remove: a, i - filters: - - name: replace - args: ["by", ""] - - name: dateparse - args: "2/01/06" - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: div.tag_list_browse +--- + site: losslessclub + name: LosslessClub + language: ru-ru + type: private + encoding: windows-1251 + links: + - https://losslessclub.com/ + + caps: + categories: + 1: Audio/Lossless + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded > div.error + test: + path: /browse.php + selector: span.bar_user_welcome + + search: + path: /browse.php + inputs: + search: "{{ .Query.Keywords }}" + t: "all" + rows: + selector: div#releases-table > table > tbody > tr:has(a.browselink) + fields: + title: + selector: a.browselink + category: + text: "1" + details: + selector: a.browselink + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + banner|optional: + selector: img.thumbnail + attribute: src + size: + selector: td:nth-child(5) + grabs|optional: + selector: td:nth-child(6) br + span + seeders: + selector: td:nth-child(6) + remove: br + span + filters: + - name: regexp + args: "([\\.\\d]+)\\s+\\|" + leechers: + selector: td:nth-child(6) + remove: br + span + filters: + - name: regexp + args: "\\|\\s*([\\.\\d]+)" + date: + selector: td:nth-child(7) + remove: a, i + filters: + - name: replace + args: ["by", ""] + - name: dateparse + args: "2/01/06" + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: div.tag_list_browse diff --git a/src/Jackett/Definitions/mteamtp.yml b/src/Jackett/Definitions/mteamtp.yml index 4d87d4ab..a34b63c0 100644 --- a/src/Jackett/Definitions/mteamtp.yml +++ b/src/Jackett/Definitions/mteamtp.yml @@ -1,132 +1,132 @@ ---- - site: mteamtp - name: M-Team - TP - description: "A chinese tracker" - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://tp.m-team.cc - - caps: - categorymappings: - - {id: 401, cat: Movies/SD, desc: "Movie(電影)/SD"} - - {id: 419, cat: Movies/HD, desc: "Movie(電影)/HD"} - - {id: 420, cat: Movies/DVD, desc: "Movie(電影)/DVDiSo"} - - {id: 421, cat: Movies/BluRay, desc: "Movie(電影)/Blu-Ray"} - - {id: 439, cat: Movies/Other, desc: "Movie(電影)/Remux"} - - {id: 403, cat: TV/SD, desc: "TV Series(影劇/綜藝)/SD"} - - {id: 402, cat: TV/HD, desc: "TV Series(影劇/綜藝)/HD"} - - {id: 435, cat: TV/SD, desc: "TV Series(影劇/綜藝)/DVDiSo"} - - {id: 438, cat: TV/HD, desc: "TV Series(影劇/綜藝)/BD"} - - {id: 404, cat: TV/Documentary, desc: "紀錄教育"} - - {id: 405, cat: TV/Anime, desc: "Anime(動畫)"} - - {id: 406, cat: Audio/Video, desc: "MV(演唱)"} - - {id: 408, cat: Audio/Other, desc: "Music(AAC/ALAC)"} - - {id: 434, cat: Audio, desc: "Music(無損)"} - - {id: 407, cat: TV/Sport, desc: "Sports(運動)"} - - {id: 422, cat: PC/0day, desc: "Software(軟體)"} - - {id: 423, cat: PC/Games, desc: "PCGame(PC遊戲)"} - - {id: 427, cat: Books, desc: "eBook(電子書)"} - - {id: 409, cat: Other, desc: "Misc(其他)"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - ratio: - path: /torrents.php - selector: table#info_block - filters: - - name: regexp - args: "Ratio:\\s(.*?)\\s\\s" - - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "0" - spstate: "0" - inclbookmarked: "0" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: "0" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[title][href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - banner: - selector: img[alt="torrent thumbnail"] - attribute: src - filters: - - name: replace - args: ["pic/nopic.jpg", ""] - size: - selector: td.rowfollow:nth-child(5) - grabs: - selector: td.rowfollow:nth-child(8) - seeders: - selector: td.rowfollow:nth-child(6) - leechers: - selector: td.rowfollow:nth-child(7) - date: - selector: td.rowfollow:nth-child(4):not(:has(span)) - optional: true - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-0215:04:05 -07:00" - date: - selector: td.rowfollow:nth-child(4) > span[title] - optional: true - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) +--- + site: mteamtp + name: M-Team - TP + description: "A chinese tracker" + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://tp.m-team.cc + + caps: + categorymappings: + - {id: 401, cat: Movies/SD, desc: "Movie(電影)/SD"} + - {id: 419, cat: Movies/HD, desc: "Movie(電影)/HD"} + - {id: 420, cat: Movies/DVD, desc: "Movie(電影)/DVDiSo"} + - {id: 421, cat: Movies/BluRay, desc: "Movie(電影)/Blu-Ray"} + - {id: 439, cat: Movies/Other, desc: "Movie(電影)/Remux"} + - {id: 403, cat: TV/SD, desc: "TV Series(影劇/綜藝)/SD"} + - {id: 402, cat: TV/HD, desc: "TV Series(影劇/綜藝)/HD"} + - {id: 435, cat: TV/SD, desc: "TV Series(影劇/綜藝)/DVDiSo"} + - {id: 438, cat: TV/HD, desc: "TV Series(影劇/綜藝)/BD"} + - {id: 404, cat: TV/Documentary, desc: "紀錄教育"} + - {id: 405, cat: TV/Anime, desc: "Anime(動畫)"} + - {id: 406, cat: Audio/Video, desc: "MV(演唱)"} + - {id: 408, cat: Audio/Other, desc: "Music(AAC/ALAC)"} + - {id: 434, cat: Audio, desc: "Music(無損)"} + - {id: 407, cat: TV/Sport, desc: "Sports(運動)"} + - {id: 422, cat: PC/0day, desc: "Software(軟體)"} + - {id: 423, cat: PC/Games, desc: "PCGame(PC遊戲)"} + - {id: 427, cat: Books, desc: "eBook(電子書)"} + - {id: 409, cat: Other, desc: "Misc(其他)"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + ratio: + path: /torrents.php + selector: table#info_block + filters: + - name: regexp + args: "Ratio:\\s(.*?)\\s\\s" + + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "0" + spstate: "0" + inclbookmarked: "0" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: "0" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[title][href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + banner: + selector: img[alt="torrent thumbnail"] + attribute: src + filters: + - name: replace + args: ["pic/nopic.jpg", ""] + size: + selector: td.rowfollow:nth-child(5) + grabs: + selector: td.rowfollow:nth-child(8) + seeders: + selector: td.rowfollow:nth-child(6) + leechers: + selector: td.rowfollow:nth-child(7) + date: + selector: td.rowfollow:nth-child(4):not(:has(span)) + optional: true + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-0215:04:05 -07:00" + date: + selector: td.rowfollow:nth-child(4) > span[title] + optional: true + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) remove: a, img \ No newline at end of file diff --git a/src/Jackett/Definitions/myspleen.yml b/src/Jackett/Definitions/myspleen.yml index dd842036..60fa4a90 100644 --- a/src/Jackett/Definitions/myspleen.yml +++ b/src/Jackett/Definitions/myspleen.yml @@ -1,99 +1,99 @@ ---- - site: myspleen - name: MySpleen - language: en-us - type: private - encoding: UTF-8 - links: - - https://www.myspleen.org - - caps: - categorymappings: - - {id: 31, cat: TV, desc: "Adult Swim"} - - {id: 30, cat: TV, desc: "Animation"} - - {id: 25, cat: TV, desc: "Cartoon Network"} - - {id: 3, cat: TV, desc: "Comedy"} - - {id: 26, cat: TV, desc: "Comedy Central"} - - {id: 24, cat: TV, desc: "MST3K"} - - {id: 28, cat: TV, desc: "MTV"} - - {id: 29, cat: TV, desc: "Nick"} - - {id: 20, cat: Other, desc: "Other"} - - {id: 32, cat: TV, desc: "Star Wars"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - returnto: "/" - error: - - selector: div#content:has(h2:contains("Login Failed")) - test: - path: /browse.php - selector: span.key:contains("Ratio") + span.value - - ratio: - path: /browse.php - selector: span.key:contains("Ratio") + span.value - - search: - path: /browse.php - method: post - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - title: "0" - rows: - selector: table#main-torrents > tbody > tr - fields: - title: - selector: td.tor-name > a - attribute: title - category: - selector: td[class^="cat-"] > a - attribute: href - filters: - - name: querystring - args: cat - details: - selector: td.tor-name > a - attribute: href - download: - selector: td.tor-down > a - attribute: href - files: - selector: td:nth-child(5) - size: - selector: td:nth-child(8) - grabs: - selector: td:nth-child(9) - filters: - - name: regexp - args: "(\\d+)" - seeders: - selector: td:nth-child(10) - filters: - - name: regexp - args: "^(\\d+)" - leechers: - selector: td:nth-child(11) - filters: - - name: regexp - args: "^(\\d+)" - date: - selector: td:nth-child(7) - downloadvolumefactor: - case: - span.star: "0" - span.fltime: "0" - ":root li[id=\"alert-fl\"][class=\"alert\"]:contains(\"Freeleech ends in \")": 0 - "*": "1" - uploadvolumefactor: - case: +--- + site: myspleen + name: MySpleen + language: en-us + type: private + encoding: UTF-8 + links: + - https://www.myspleen.org + + caps: + categorymappings: + - {id: 31, cat: TV, desc: "Adult Swim"} + - {id: 30, cat: TV, desc: "Animation"} + - {id: 25, cat: TV, desc: "Cartoon Network"} + - {id: 3, cat: TV, desc: "Comedy"} + - {id: 26, cat: TV, desc: "Comedy Central"} + - {id: 24, cat: TV, desc: "MST3K"} + - {id: 28, cat: TV, desc: "MTV"} + - {id: 29, cat: TV, desc: "Nick"} + - {id: 20, cat: Other, desc: "Other"} + - {id: 32, cat: TV, desc: "Star Wars"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + returnto: "/" + error: + - selector: div#content:has(h2:contains("Login Failed")) + test: + path: /browse.php + selector: span.key:contains("Ratio") + span.value + + ratio: + path: /browse.php + selector: span.key:contains("Ratio") + span.value + + search: + path: /browse.php + method: post + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + title: "0" + rows: + selector: table#main-torrents > tbody > tr + fields: + title: + selector: td.tor-name > a + attribute: title + category: + selector: td[class^="cat-"] > a + attribute: href + filters: + - name: querystring + args: cat + details: + selector: td.tor-name > a + attribute: href + download: + selector: td.tor-down > a + attribute: href + files: + selector: td:nth-child(5) + size: + selector: td:nth-child(8) + grabs: + selector: td:nth-child(9) + filters: + - name: regexp + args: "(\\d+)" + seeders: + selector: td:nth-child(10) + filters: + - name: regexp + args: "^(\\d+)" + leechers: + selector: td:nth-child(11) + filters: + - name: regexp + args: "^(\\d+)" + date: + selector: td:nth-child(7) + downloadvolumefactor: + case: + span.star: "0" + span.fltime: "0" + ":root li[id=\"alert-fl\"][class=\"alert\"]:contains(\"Freeleech ends in \")": 0 + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/nachtwerk.yml b/src/Jackett/Definitions/nachtwerk.yml index 5b090ee7..7552d7c3 100644 --- a/src/Jackett/Definitions/nachtwerk.yml +++ b/src/Jackett/Definitions/nachtwerk.yml @@ -1,152 +1,152 @@ ---- - site: nachtwerk - name: Nachtwerk - language: de-de - type: private - encoding: ISO-8859-15 - links: - - https://nwtracker.com/ - - caps: - categorymappings: - - {id: 75, cat: Movies/3D, desc: "Filme - 3D"} - - {id: 34, cat: Movies, desc: "Filme - Xvid / x264"} - - {id: 55, cat: Movies/BluRay, desc: "Filme - Blu-Ray"} - - {id: 20, cat: Movies/DVD, desc: "Filme - DVD-R"} - - {id: 71, cat: Movies/HD, desc: "Filme - HD 1080p"} - - {id: 70, cat: Movies/HD, desc: "Filme - HD 720p"} - - {id: 35, cat: Movies/Foreign, desc: "Filme - Inter"} - - {id: 104, cat: Movies/HD, desc: "Filme - UHD"} - - {id: 107, cat: Movies/Other, desc: "Filme - Remux"} - - {id: 7, cat: TV/SD, desc: "Serien - Xvid / x264"} - - {id: 72, cat: TV/HD, desc: "Serien - HD"} - - {id: 82, cat: TV/Foreign, desc: "Serien - Inter"} - - {id: 69, cat: TV, desc: "Serien - Pack's"} - - {id: 42, cat: TV, desc: "Serien - TV Show"} - - {id: 105, cat: TV/HD, desc: "Serien - UHD"} - - {id: 51, cat: XXX, desc: "XXX - Xvid / x264"} - - {id: 73, cat: XXX, desc: "XXX - HD"} - - {id: 84, cat: XXX, desc: "XXX - Pack's"} - - {id: 85, cat: XXX, desc: "XXX - Sonstiges"} - - {id: 102, cat: XXX, desc: "XXX - Hentai"} - - {id: 103, cat: XXX, desc: "XXX - UHD"} - - {id: 6, cat: Audio/MP3, desc: "Audio - MP3"} - - {id: 74, cat: Audio/Lossless, desc: "Audio - Flac"} - - {id: 86, cat: Audio/Video, desc: "Audio - Videos"} - - {id: 24, cat: Audio/Audiobook, desc: "Audio - Hörspiel/Hörbuch"} - - {id: 93, cat: PC/Mac, desc: "Appz - Mac"} - - {id: 67, cat: PC/0day, desc: "Appz - Windows"} - - {id: 31, cat: PC/Phone-Other, desc: "Appz - Handy"} - - {id: 81, cat: PC, desc: "Appz - Sonstiges"} - - {id: 25, cat: TV/Documentary, desc: "Dokus - Xvid / x264"} - - {id: 76, cat: TV/Documentary, desc: "Dokus - HD"} - - {id: 99, cat: TV/Documentary, desc: "Dokus - Pack's"} - - {id: 100, cat: TV/Documentary, desc: "Dokus - 3D"} - - {id: 106, cat: TV/Documentary, desc: "Dokus - UHD"} - - {id: 90, cat: Console/PS3, desc: "Games - PSX"} - - {id: 56, cat: Console/Wii, desc: "Games - WII"} - - {id: 43, cat: Console/Xbox, desc: "Games - XboX"} - - {id: 4, cat: PC/Games, desc: "Games - PC"} - - {id: 88, cat: Console/NDS, desc: "Games - xDS"} - - {id: 91, cat: PC/Mac, desc: "Games - Mac"} - - {id: 92, cat: Console, desc: "Games - Sonstiges"} - - {id: 23, cat: TV/Anime, desc: "Anime - Xvid / x264"} - - {id: 80, cat: TV/Anime, desc: "Anime - HD"} - - {id: 98, cat: TV/Anime, desc: "Anime - Serien"} - - {id: 94, cat: Books/Magazines, desc: "eBooks - Magazine/Zeitungen"} - - {id: 95, cat: Books/Comics, desc: "eBooks - Comics"} - - {id: 30, cat: Books, desc: "eBooks - Bücher"} - - {id: 96, cat: TV/Sport, desc: "Sport - Wrestling"} - - {id: 97, cat: TV/Sport, desc: "Sport - Fussball"} - - {id: 45, cat: TV/Sport, desc: "Sport - Sonstiges"} - - {id: 9, cat: Other, desc: "Diverses - Sonstiges"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /browse.php - - download: - selector: a[href^="download.php?torrent="] - - search: - path: /browse.php - method: post - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - spstate: "0" - inclbookmarked: "0" - search_area: "0" - search_mode: "0" - rows: - selector: table.tableinborder[cellspacing="1"][cellpadding="0"] > tbody > tr - fields: - title: - selector: a[href^="details.php?id="] - filters: - - name: replace - args: ["[NW] ", ""] - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "thanks1.php?torrentid="] - banner: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: "src=.*'\\);" - size: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - files: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) - grabs: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) - seeders: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(1) - leechers: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(3) - date: - selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(5) - filters: - - name: replace - args: ["\xA0", " "] - - name: append - args: " +01:00" - - name: dateparse - args: "02.01.2006 15:04:05 -07:00" - downloadvolumefactor: - case: - img[src="pic/onlyuploadd.gif"]: "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: nachtwerk + name: Nachtwerk + language: de-de + type: private + encoding: ISO-8859-15 + links: + - https://nwtracker.com/ + + caps: + categorymappings: + - {id: 75, cat: Movies/3D, desc: "Filme - 3D"} + - {id: 34, cat: Movies, desc: "Filme - Xvid / x264"} + - {id: 55, cat: Movies/BluRay, desc: "Filme - Blu-Ray"} + - {id: 20, cat: Movies/DVD, desc: "Filme - DVD-R"} + - {id: 71, cat: Movies/HD, desc: "Filme - HD 1080p"} + - {id: 70, cat: Movies/HD, desc: "Filme - HD 720p"} + - {id: 35, cat: Movies/Foreign, desc: "Filme - Inter"} + - {id: 104, cat: Movies/HD, desc: "Filme - UHD"} + - {id: 107, cat: Movies/Other, desc: "Filme - Remux"} + - {id: 7, cat: TV/SD, desc: "Serien - Xvid / x264"} + - {id: 72, cat: TV/HD, desc: "Serien - HD"} + - {id: 82, cat: TV/Foreign, desc: "Serien - Inter"} + - {id: 69, cat: TV, desc: "Serien - Pack's"} + - {id: 42, cat: TV, desc: "Serien - TV Show"} + - {id: 105, cat: TV/HD, desc: "Serien - UHD"} + - {id: 51, cat: XXX, desc: "XXX - Xvid / x264"} + - {id: 73, cat: XXX, desc: "XXX - HD"} + - {id: 84, cat: XXX, desc: "XXX - Pack's"} + - {id: 85, cat: XXX, desc: "XXX - Sonstiges"} + - {id: 102, cat: XXX, desc: "XXX - Hentai"} + - {id: 103, cat: XXX, desc: "XXX - UHD"} + - {id: 6, cat: Audio/MP3, desc: "Audio - MP3"} + - {id: 74, cat: Audio/Lossless, desc: "Audio - Flac"} + - {id: 86, cat: Audio/Video, desc: "Audio - Videos"} + - {id: 24, cat: Audio/Audiobook, desc: "Audio - Hörspiel/Hörbuch"} + - {id: 93, cat: PC/Mac, desc: "Appz - Mac"} + - {id: 67, cat: PC/0day, desc: "Appz - Windows"} + - {id: 31, cat: PC/Phone-Other, desc: "Appz - Handy"} + - {id: 81, cat: PC, desc: "Appz - Sonstiges"} + - {id: 25, cat: TV/Documentary, desc: "Dokus - Xvid / x264"} + - {id: 76, cat: TV/Documentary, desc: "Dokus - HD"} + - {id: 99, cat: TV/Documentary, desc: "Dokus - Pack's"} + - {id: 100, cat: TV/Documentary, desc: "Dokus - 3D"} + - {id: 106, cat: TV/Documentary, desc: "Dokus - UHD"} + - {id: 90, cat: Console/PS3, desc: "Games - PSX"} + - {id: 56, cat: Console/Wii, desc: "Games - WII"} + - {id: 43, cat: Console/Xbox, desc: "Games - XboX"} + - {id: 4, cat: PC/Games, desc: "Games - PC"} + - {id: 88, cat: Console/NDS, desc: "Games - xDS"} + - {id: 91, cat: PC/Mac, desc: "Games - Mac"} + - {id: 92, cat: Console, desc: "Games - Sonstiges"} + - {id: 23, cat: TV/Anime, desc: "Anime - Xvid / x264"} + - {id: 80, cat: TV/Anime, desc: "Anime - HD"} + - {id: 98, cat: TV/Anime, desc: "Anime - Serien"} + - {id: 94, cat: Books/Magazines, desc: "eBooks - Magazine/Zeitungen"} + - {id: 95, cat: Books/Comics, desc: "eBooks - Comics"} + - {id: 30, cat: Books, desc: "eBooks - Bücher"} + - {id: 96, cat: TV/Sport, desc: "Sport - Wrestling"} + - {id: 97, cat: TV/Sport, desc: "Sport - Fussball"} + - {id: 45, cat: TV/Sport, desc: "Sport - Sonstiges"} + - {id: 9, cat: Other, desc: "Diverses - Sonstiges"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /browse.php + + download: + selector: a[href^="download.php?torrent="] + + search: + path: /browse.php + method: post + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + spstate: "0" + inclbookmarked: "0" + search_area: "0" + search_mode: "0" + rows: + selector: table.tableinborder[cellspacing="1"][cellpadding="0"] > tbody > tr + fields: + title: + selector: a[href^="details.php?id="] + filters: + - name: replace + args: ["[NW] ", ""] + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "thanks1.php?torrentid="] + banner: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: "src=.*'\\);" + size: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + files: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) + grabs: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(3) > b:nth-child(1) + seeders: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(1) + leechers: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(3) + date: + selector: td:nth-child(2) > table > tbody > tr:nth-child(2) > td:nth-child(5) + filters: + - name: replace + args: ["\xA0", " "] + - name: append + args: " +01:00" + - name: dateparse + args: "02.01.2006 15:04:05 -07:00" + downloadvolumefactor: + case: + img[src="pic/onlyuploadd.gif"]: "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/nethd.yml b/src/Jackett/Definitions/nethd.yml index ad4b7159..ccfcba77 100644 --- a/src/Jackett/Definitions/nethd.yml +++ b/src/Jackett/Definitions/nethd.yml @@ -1,99 +1,99 @@ ---- - site: nethd - name: NetHD - description: "A vietnamese tracker" - language: vi-vn - type: semi-private - encoding: UTF-8 - links: - - http://nethd.org/ - - caps: - categorymappings: - - {id: 401, cat: Movies, desc: "Movies"} - - {id: 402, cat: Audio, desc: "Music"} - - {id: 403, cat: PC/Games, desc: "Game"} - - {id: 404, cat: PC, desc: "Software"} - - {id: 405, cat: Other, desc: "Image"} - - {id: 406, cat: Books, desc: "Book"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: form#loginform > span.warning - test: - path: /torrents.php - - ratio: - path: /torrents.php - selector: div.user-info-extend > dl > dt:contains("Ratio:") + dd - search: - path: /torrents.php - method: post - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: 0 - spstate: 0 - inclbookmarked: 0 - incldead: 1 - rows: - selector: tr:has(td.name) - fields: - title: - selector: td.name > div > a.poster-preview[title] - attribute: title - category: - selector: td.category > a - attribute: href - filters: - - name: querystring - args: cat - details: - selector: td.name > div > a.poster-preview[title] - attribute: href - comments: - selector: a[href*="#comments"] - attribute: href - download: - selector: a.bookmark[onclick] - attribute: onclick - filters: - - name: replace - args: [",false)", ""] - - name: replace - args: ["return bookmark(", "download.php?id="] - size: - selector: td:nth-child(5) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - grabs: - selector: td:nth-child(8) - date: - selector: td:nth-child(4) - filters: - - name: append - args: " +0700" - - name: dateparse - args: "2006-01-0215:04:05 -0700" - downloadvolumefactor: - case: - "span.label:contains(\"Free\")": "0" - "span.label:contains(\"50%\")": "0.5" - "*": "1" - uploadvolumefactor: - case: - "span.label:contains(\"2X\")": "2" +--- + site: nethd + name: NetHD + description: "A vietnamese tracker" + language: vi-vn + type: semi-private + encoding: UTF-8 + links: + - http://nethd.org/ + + caps: + categorymappings: + - {id: 401, cat: Movies, desc: "Movies"} + - {id: 402, cat: Audio, desc: "Music"} + - {id: 403, cat: PC/Games, desc: "Game"} + - {id: 404, cat: PC, desc: "Software"} + - {id: 405, cat: Other, desc: "Image"} + - {id: 406, cat: Books, desc: "Book"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: form#loginform > span.warning + test: + path: /torrents.php + + ratio: + path: /torrents.php + selector: div.user-info-extend > dl > dt:contains("Ratio:") + dd + search: + path: /torrents.php + method: post + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: 0 + spstate: 0 + inclbookmarked: 0 + incldead: 1 + rows: + selector: tr:has(td.name) + fields: + title: + selector: td.name > div > a.poster-preview[title] + attribute: title + category: + selector: td.category > a + attribute: href + filters: + - name: querystring + args: cat + details: + selector: td.name > div > a.poster-preview[title] + attribute: href + comments: + selector: a[href*="#comments"] + attribute: href + download: + selector: a.bookmark[onclick] + attribute: onclick + filters: + - name: replace + args: [",false)", ""] + - name: replace + args: ["return bookmark(", "download.php?id="] + size: + selector: td:nth-child(5) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + grabs: + selector: td:nth-child(8) + date: + selector: td:nth-child(4) + filters: + - name: append + args: " +0700" + - name: dateparse + args: "2006-01-0215:04:05 -0700" + downloadvolumefactor: + case: + "span.label:contains(\"Free\")": "0" + "span.label:contains(\"50%\")": "0.5" + "*": "1" + uploadvolumefactor: + case: + "span.label:contains(\"2X\")": "2" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/newretro.yml b/src/Jackett/Definitions/newretro.yml index a0c67110..16e08898 100644 --- a/src/Jackett/Definitions/newretro.yml +++ b/src/Jackett/Definitions/newretro.yml @@ -1,121 +1,121 @@ ---- - site: newretro - name: The New Retro - description: "A German gerneral tracker" - language: de-de - type: private - encoding: windows-1252 - links: - - http://new-retro.eu/ - - caps: - categorymappings: - - {id: 101, cat: TV/Anime, desc: "Filme - Animie"} - - {id: 102, cat: Movies/BluRay, desc: "Filme - Bluray"} - - {id: 131, cat: Movies/Other, desc: "Filme - Bollywood"} - - {id: 103, cat: Movies/DVD, desc: "Filme - DVD"} - - {id: 104, cat: Movies/DVD, desc: "Filme - DVD-R"} - - {id: 132, cat: Movies/DVD, desc: "Filme - HD2DVD"} - - {id: 130, cat: Movies, desc: "Filme - Klassiker"} - - {id: 105, cat: Movies, desc: "Filme - x264"} - - {id: 106, cat: Movies, desc: "Filme - XviD / DivX"} - - {id: 69, cat: XXX, desc: " XXX"} - - {id: 124, cat: Audio, desc: "Musik - Alben"} - - {id: 122, cat: Audio/Audiobook, desc: "Musik - Hörbuch"} - - {id: 123, cat: Audio, desc: "Musik - Mixe"} - - {id: 133, cat: Audio/MP3, desc: "Musik - MP3"} - - {id: 125, cat: Audio/Video, desc: "Musik - Video"} - - {id: 113, cat: PC, desc: "Programme - Linux"} - - {id: 114, cat: PC/Mac, desc: "Programme - Mac"} - - {id: 115, cat: PC, desc: "Programme - Windows"} - - {id: 117, cat: TV, desc: "Allgemein - Serien"} - - {id: 116, cat: TV/Documentary, desc: "Serien - Dokus"} - - {id: 118, cat: TV/Sport, desc: "Serien - Sport"} - - {id: 119, cat: Other, desc: "Bilder"} - - {id: 120, cat: Books, desc: "Ebook"} - - {id: 127, cat: Other, desc: "Für Unsere kleinsten"} - - {id: 121, cat: Other, desc: "Handy Stuff"} - - {id: 129, cat: Other, desc: "Sonstiges"} - - {id: 109, cat: Other, desc: "Spiele - Handy"} - - {id: 112, cat: Console, desc: "Spiele - Konsolen"} - - {id: 111, cat: PC/Games, desc: "Spiele - Mac / Linux"} - - {id: 110, cat: PC/Games, desc: "Spiele - PC"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - returnto: "/" - error: - - selector: table.tableinborder:contains("Anmeldung Gescheitert!") > tbody > tr > td.tablea - test: - path: /usercp.php - - ratio: - path: /usercp.php - selector: div#lmtd table > tbody > tr:contains("Ratio:") > td:nth-child(2) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - showsearch: "1" - orderby: "added" - sort: "desc" - incldead: "1" - - rows: - selector: table.tableinborder[summary] > tbody > tr - filters: - - name: andmatch - fields: - download: - selector: a[href^="download.php?torrent="] - attribute: href - title: - selector: a[href^="details.php?id="]:has(b) - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - comments: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(4) > a - attribute: href - size: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) - grabs: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(3) > b - files: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) - seeders: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(1) - leechers: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(3) - date: - selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(5) - filters: - - name: replace - args: ["\u00a0", " "] - - name: dateparse - args: "02.01.2006 15:04:05" - downloadvolumefactor: - case: - "font[color=\"red\"]:contains(\"Only Upload\")": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: newretro + name: The New Retro + description: "A German gerneral tracker" + language: de-de + type: private + encoding: windows-1252 + links: + - http://new-retro.eu/ + + caps: + categorymappings: + - {id: 101, cat: TV/Anime, desc: "Filme - Animie"} + - {id: 102, cat: Movies/BluRay, desc: "Filme - Bluray"} + - {id: 131, cat: Movies/Other, desc: "Filme - Bollywood"} + - {id: 103, cat: Movies/DVD, desc: "Filme - DVD"} + - {id: 104, cat: Movies/DVD, desc: "Filme - DVD-R"} + - {id: 132, cat: Movies/DVD, desc: "Filme - HD2DVD"} + - {id: 130, cat: Movies, desc: "Filme - Klassiker"} + - {id: 105, cat: Movies, desc: "Filme - x264"} + - {id: 106, cat: Movies, desc: "Filme - XviD / DivX"} + - {id: 69, cat: XXX, desc: " XXX"} + - {id: 124, cat: Audio, desc: "Musik - Alben"} + - {id: 122, cat: Audio/Audiobook, desc: "Musik - Hörbuch"} + - {id: 123, cat: Audio, desc: "Musik - Mixe"} + - {id: 133, cat: Audio/MP3, desc: "Musik - MP3"} + - {id: 125, cat: Audio/Video, desc: "Musik - Video"} + - {id: 113, cat: PC, desc: "Programme - Linux"} + - {id: 114, cat: PC/Mac, desc: "Programme - Mac"} + - {id: 115, cat: PC, desc: "Programme - Windows"} + - {id: 117, cat: TV, desc: "Allgemein - Serien"} + - {id: 116, cat: TV/Documentary, desc: "Serien - Dokus"} + - {id: 118, cat: TV/Sport, desc: "Serien - Sport"} + - {id: 119, cat: Other, desc: "Bilder"} + - {id: 120, cat: Books, desc: "Ebook"} + - {id: 127, cat: Other, desc: "Für Unsere kleinsten"} + - {id: 121, cat: Other, desc: "Handy Stuff"} + - {id: 129, cat: Other, desc: "Sonstiges"} + - {id: 109, cat: Other, desc: "Spiele - Handy"} + - {id: 112, cat: Console, desc: "Spiele - Konsolen"} + - {id: 111, cat: PC/Games, desc: "Spiele - Mac / Linux"} + - {id: 110, cat: PC/Games, desc: "Spiele - PC"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + returnto: "/" + error: + - selector: table.tableinborder:contains("Anmeldung Gescheitert!") > tbody > tr > td.tablea + test: + path: /usercp.php + + ratio: + path: /usercp.php + selector: div#lmtd table > tbody > tr:contains("Ratio:") > td:nth-child(2) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + showsearch: "1" + orderby: "added" + sort: "desc" + incldead: "1" + + rows: + selector: table.tableinborder[summary] > tbody > tr + filters: + - name: andmatch + fields: + download: + selector: a[href^="download.php?torrent="] + attribute: href + title: + selector: a[href^="details.php?id="]:has(b) + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + comments: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(4) > a + attribute: href + size: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(1) + grabs: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(3) > b + files: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(1) > b:nth-child(2) + seeders: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(1) + leechers: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(2) > b:nth-child(3) + date: + selector: td.tablea > table > tbody > tr:nth-child(2) > td:nth-child(5) + filters: + - name: replace + args: ["\u00a0", " "] + - name: dateparse + args: "02.01.2006 15:04:05" + downloadvolumefactor: + case: + "font[color=\"red\"]:contains(\"Only Upload\")": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/ourbits.yml b/src/Jackett/Definitions/ourbits.yml index 8c70b9cb..16b5345d 100644 --- a/src/Jackett/Definitions/ourbits.yml +++ b/src/Jackett/Definitions/ourbits.yml @@ -1,109 +1,109 @@ ---- - site: ourbits - name: Ourbits - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://ourbits.club/ - - caps: - categorymappings: - - {id: 401, cat: Movies/BluRay, desc: "Movies Blu-ray"} - - {id: 402, cat: Movies/HD, desc: "Movies REMUX"} - - {id: 419, cat: Movies/HD, desc: "Movies 1080p"} - - {id: 404, cat: Movies/HD, desc: "Movies 720p"} - - {id: 405, cat: Movies/3D, desc: "Movies 3D"} - - {id: 406, cat: Movies/DVD, desc: "Movies DVD"} - - {id: 407, cat: Movies/WEBDL, desc: "Movies WEB-DL"} - - {id: 408, cat: Movies/SD, desc: "Movies HDTV"} - - {id: 409, cat: Movies/Other, desc: "Movies iPad"} - - {id: 410, cat: TV/Documentary, desc: "Documentaries"} - - {id: 411, cat: TV/Anime, desc: "Animations"} - - {id: 412, cat: TV, desc: "TV Series"} - - {id: 413, cat: TV, desc: "TV Shows"} - - {id: 414, cat: Audio/Video, desc: "Music Videos"} - - {id: 415, cat: TV/Sport, desc: "Sports"} - - {id: 416, cat: Audio, desc: "Music"} - - {id: 420, cat: Other, desc: "Other"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [imdbid] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("登录失败")) - test: - path: /torrents.php - - search: - path: /torrents.php - method: get - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "1" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[href^="details.php?id="] - title|optional: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - imdb|optional: - selector: div.imdb_100 > a - attribute: href - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - date: - selector: td:nth-child(4) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) - remove: a, img +--- + site: ourbits + name: Ourbits + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://ourbits.club/ + + caps: + categorymappings: + - {id: 401, cat: Movies/BluRay, desc: "Movies Blu-ray"} + - {id: 402, cat: Movies/HD, desc: "Movies REMUX"} + - {id: 419, cat: Movies/HD, desc: "Movies 1080p"} + - {id: 404, cat: Movies/HD, desc: "Movies 720p"} + - {id: 405, cat: Movies/3D, desc: "Movies 3D"} + - {id: 406, cat: Movies/DVD, desc: "Movies DVD"} + - {id: 407, cat: Movies/WEBDL, desc: "Movies WEB-DL"} + - {id: 408, cat: Movies/SD, desc: "Movies HDTV"} + - {id: 409, cat: Movies/Other, desc: "Movies iPad"} + - {id: 410, cat: TV/Documentary, desc: "Documentaries"} + - {id: 411, cat: TV/Anime, desc: "Animations"} + - {id: 412, cat: TV, desc: "TV Series"} + - {id: 413, cat: TV, desc: "TV Shows"} + - {id: 414, cat: Audio/Video, desc: "Music Videos"} + - {id: 415, cat: TV/Sport, desc: "Sports"} + - {id: 416, cat: Audio, desc: "Music"} + - {id: 420, cat: Other, desc: "Other"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [imdbid] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("登录失败")) + test: + path: /torrents.php + + search: + path: /torrents.php + method: get + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "1" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[href^="details.php?id="] + title|optional: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + imdb|optional: + selector: div.imdb_100 > a + attribute: href + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + date: + selector: td:nth-child(4) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) + remove: a, img diff --git a/src/Jackett/Definitions/passionetorrent.yml b/src/Jackett/Definitions/passionetorrent.yml index 212fbe78..0d1da6c9 100644 --- a/src/Jackett/Definitions/passionetorrent.yml +++ b/src/Jackett/Definitions/passionetorrent.yml @@ -1,158 +1,158 @@ ---- - site: passionetorrent - name: Passione Torrent - language: it-it - type: private - encoding: UTF-8 - links: - - http://www.passionetorrent.info/ - - caps: - categorymappings: - # VIDEO - - {id: 1, cat: Movies, desc: "News Cinema"} - - {id: 2, cat: Movies/SD, desc: "BDRip"} - - {id: 17, cat: Movies/SD, desc: "DVDRip"} - - {id: 21, cat: TV, desc: "TV"} - - {id: 22, cat: Movies/HD, desc: "720p/1080p"} - - {id: 23, cat: Movies/HD, desc: "1080p HRS x265 HEVC"} - - {id: 42, cat: Movies/HD, desc: "2160p 4k UltraHD HRS"} - - {id: 30, cat: TV/Anime, desc: "Cartoons"} - - {id: 38, cat: Movies/SD, desc: "BD-BR-DvdRip sub ita"} - - {id: 39, cat: Movies/SD, desc: "Introvabili"} - - {id: 40, cat: TV/Documentary, desc: "documentaries"} - - {id: 24, cat: Movies/SD, desc: "Filmografie"} - - # MUSICA - - {id: 32, cat: Audio, desc: "Italian music"} - - {id: 41, cat: Audio, desc: "Discography"} - - {id: 33, cat: Audio, desc: "MusicaInternazionale"} - - {id: 34, cat: Audio, desc: "Compilation"} - - # PDF - - {id: 28, cat: Books, desc: "Ebook"} - - # GAMES - - {id: 14, cat: PC/Games, desc: "PC Games"} - - # SOFTWARE - - {id: 7, cat: PC/ISO, desc: "Sistemi operativi"} - - {id: 36, cat: PC/ISO, desc: "Windows APP"} - - {id: 9, cat: PC/Phone-IOS, desc: "Apple APP"} - - {id: 37, cat: PC/Phone-Android, desc: "Android APP"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: index.php?page=login - method: post - inputs: - uid: "{{ .Config.username }}" - pwd: "{{ .Config.password }}" - error: - - selector: body[onLoad^="makeAlert('"] - message: - selector: body[onLoad^="makeAlert('"] - attribute: onLoad - filters: - - name: replace - args: ["makeAlert('Error' , '", ""] - - name: replace - args: ["');", ""] - test: - path: index.php - - download: - before: - path: "thanks.php" - method: "post" - inputs: - infohash: "{{ .DownloadUri.Query.id }}" - thanks: "1" - rndval: "1487013827343" - selector: a[href^="download.php?id="] - - search: - path: index.php - keywordsfilters: - # most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later - - name: re_replace - args: ["S0?(\\d{1,2})", " $1 "] - - name: re_replace - args: ["E(\\d{2,3})", " $1 "] - - name: replace - args: ["-", ""] - inputs: - search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" - page: "torrents" - category: "{{range .Categories}}{{.}};{{end}}" - options: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - active: "0" - rows: - selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) - fields: - download: - selector: a[href^="index.php?page=downloadcheck&id="] - attribute: href - title: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - filters: - # normalize to SXXEYY format - - name: re_replace - args: ["(\\d{2})x(\\d{2})", "S$1E$2"] - - name: re_replace - args: ["(\\d{1})x(\\d{2})", "S0$1E$2"] - banner: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: onmouseover - filters: - - name: regexp - args: "src=(.*?) " - category: - selector: a[href^="index.php?page=torrents&category="] - attribute: href - filters: - - name: querystring - args: category - details: - selector: a[onmouseover][href^="index.php?page=torrent-details&id="] - attribute: href - size: - selector: td:nth-last-child(4) - date: - selector: td:nth-last-child(8) - filters: - - name: append - args: " +01:00" - - name: dateparse - args: "02/01/2006 -07:00" - grabs: - selector: td:nth-last-child(7) - filters: - - name: replace - args: ["---", "0"] - seeders: - selector: td:nth-last-child(5) - leechers: - selector: td:nth-last-child(6) - downloadvolumefactor: - case: - img[alt="Gold 100% Free"]: "0" - img[alt="Silver 50% Free"]: "0.5" - img[alt="Bronze 25% Free"]: "0.75" - "*": "1" - uploadvolumefactor: - case: - img[alt="2x Upload Multiplier"]: "2" - img[alt="3x Upload Multiplier"]: "3" - img[alt="4x Upload Multiplier"]: "4" - img[alt="5x Upload Multiplier"]: "5" - img[alt="6x Upload Multiplier"]: "6" - img[alt="7x Upload Multiplier"]: "7" - img[alt="8x Upload Multiplier"]: "8" - img[alt="9x Upload Multiplier"]: "9" - img[alt="10x Upload Multiplier"]: "10" +--- + site: passionetorrent + name: Passione Torrent + language: it-it + type: private + encoding: UTF-8 + links: + - http://www.passionetorrent.info/ + + caps: + categorymappings: + # VIDEO + - {id: 1, cat: Movies, desc: "News Cinema"} + - {id: 2, cat: Movies/SD, desc: "BDRip"} + - {id: 17, cat: Movies/SD, desc: "DVDRip"} + - {id: 21, cat: TV, desc: "TV"} + - {id: 22, cat: Movies/HD, desc: "720p/1080p"} + - {id: 23, cat: Movies/HD, desc: "1080p HRS x265 HEVC"} + - {id: 42, cat: Movies/HD, desc: "2160p 4k UltraHD HRS"} + - {id: 30, cat: TV/Anime, desc: "Cartoons"} + - {id: 38, cat: Movies/SD, desc: "BD-BR-DvdRip sub ita"} + - {id: 39, cat: Movies/SD, desc: "Introvabili"} + - {id: 40, cat: TV/Documentary, desc: "documentaries"} + - {id: 24, cat: Movies/SD, desc: "Filmografie"} + + # MUSICA + - {id: 32, cat: Audio, desc: "Italian music"} + - {id: 41, cat: Audio, desc: "Discography"} + - {id: 33, cat: Audio, desc: "MusicaInternazionale"} + - {id: 34, cat: Audio, desc: "Compilation"} + + # PDF + - {id: 28, cat: Books, desc: "Ebook"} + + # GAMES + - {id: 14, cat: PC/Games, desc: "PC Games"} + + # SOFTWARE + - {id: 7, cat: PC/ISO, desc: "Sistemi operativi"} + - {id: 36, cat: PC/ISO, desc: "Windows APP"} + - {id: 9, cat: PC/Phone-IOS, desc: "Apple APP"} + - {id: 37, cat: PC/Phone-Android, desc: "Android APP"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: index.php?page=login + method: post + inputs: + uid: "{{ .Config.username }}" + pwd: "{{ .Config.password }}" + error: + - selector: body[onLoad^="makeAlert('"] + message: + selector: body[onLoad^="makeAlert('"] + attribute: onLoad + filters: + - name: replace + args: ["makeAlert('Error' , '", ""] + - name: replace + args: ["');", ""] + test: + path: index.php + + download: + before: + path: "thanks.php" + method: "post" + inputs: + infohash: "{{ .DownloadUri.Query.id }}" + thanks: "1" + rndval: "1487013827343" + selector: a[href^="download.php?id="] + + search: + path: index.php + keywordsfilters: + # most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later + - name: re_replace + args: ["S0?(\\d{1,2})", " $1 "] + - name: re_replace + args: ["E(\\d{2,3})", " $1 "] + - name: replace + args: ["-", ""] + inputs: + search: "{{if .Query.IMDBID}}{{ .Query.IMDBIDShort }}{{else}}{{ .Keywords }}{{end}}" + page: "torrents" + category: "{{range .Categories}}{{.}};{{end}}" + options: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + active: "0" + rows: + selector: table > tbody > tr > td > table.lista > tbody > tr:has(a[href^="index.php?page=torrent-details&id="]) + fields: + download: + selector: a[href^="index.php?page=downloadcheck&id="] + attribute: href + title: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + filters: + # normalize to SXXEYY format + - name: re_replace + args: ["(\\d{2})x(\\d{2})", "S$1E$2"] + - name: re_replace + args: ["(\\d{1})x(\\d{2})", "S0$1E$2"] + banner: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: onmouseover + filters: + - name: regexp + args: "src=(.*?) " + category: + selector: a[href^="index.php?page=torrents&category="] + attribute: href + filters: + - name: querystring + args: category + details: + selector: a[onmouseover][href^="index.php?page=torrent-details&id="] + attribute: href + size: + selector: td:nth-last-child(4) + date: + selector: td:nth-last-child(8) + filters: + - name: append + args: " +01:00" + - name: dateparse + args: "02/01/2006 -07:00" + grabs: + selector: td:nth-last-child(7) + filters: + - name: replace + args: ["---", "0"] + seeders: + selector: td:nth-last-child(5) + leechers: + selector: td:nth-last-child(6) + downloadvolumefactor: + case: + img[alt="Gold 100% Free"]: "0" + img[alt="Silver 50% Free"]: "0.5" + img[alt="Bronze 25% Free"]: "0.75" + "*": "1" + uploadvolumefactor: + case: + img[alt="2x Upload Multiplier"]: "2" + img[alt="3x Upload Multiplier"]: "3" + img[alt="4x Upload Multiplier"]: "4" + img[alt="5x Upload Multiplier"]: "5" + img[alt="6x Upload Multiplier"]: "6" + img[alt="7x Upload Multiplier"]: "7" + img[alt="8x Upload Multiplier"]: "8" + img[alt="9x Upload Multiplier"]: "9" + img[alt="10x Upload Multiplier"]: "10" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/polishsource.yml b/src/Jackett/Definitions/polishsource.yml index dbe0ad40..8c682470 100644 --- a/src/Jackett/Definitions/polishsource.yml +++ b/src/Jackett/Definitions/polishsource.yml @@ -1,115 +1,115 @@ ---- - site: polishsource - name: PolishSource - language: pl-pl - type: private - encoding: ISO-8859-2 - links: - - https://polishsource.cz/ - - caps: - categorymappings: - - {id: 12, cat: Movies/SD, desc: "Movies/SD"} - - {id: 11, cat: Movies/HD, desc: "Movies/HD"} - - {id: 45, cat: Movies/3D, desc: "Movies/3D"} - - {id: 4, cat: Movies/DVD, desc: "Movies/DVD"} - - {id: 43, cat: Movies/BluRay, desc: "Movies/BD"} - - {id: 10, cat: TV/SD, desc: "TV/SD"} - - {id: 39, cat: TV/HD, desc: "TV/HD"} - - {id: 8, cat: PC/Games, desc: "Games/PC"} - - {id: 3, cat: Console, desc: "Games/Consoles"} - - {id: 5, cat: Books, desc: "E-Books"} - - {id: 42, cat: Audio, desc: "Music"} - - {id: 18, cat: PC/0day, desc: "Apps"} - - {id: 13, cat: XXX, desc: "XXX"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - captcha: - type: image - image: img[src="img.php"] - input: vImageCodP - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - - selector: td.embedded:has(h2:contains("Error")) - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - scene: "0" - pl: "0" - sub: "" - search_in: "title" - rows: - selector: table#restable > tbody > tr:has(a[href^="details.php?id="]) - fields: - title: - selector: a[href^="details.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="downloadssl.php?id="] - attribute: href - description|optional: - selector: td:nth-child(2) > small - filters: - - name: prepend - args: "Genre: " - - name: append - args: "\n<br>" - description|optional|append|1: - selector: img[src="pic/pl.png"] - filters: - - name: append - args: "Language: polish\n<br>" - description|optional|append|2: - selector: img[src="pic/napisy.png"] - filters: - - name: append - args: "Subbed\n<br>" - imdb|optional: - selector: a[href^="http://www.imdb.com/title/tt"] - grabs: - selector: td:nth-child(6) - filters: - - name: regexp - args: (\d+) - size: - selector: td:nth-child(5) - date: - selector: td:nth-child(4) - filters: - - name: append - args: " +00:00" - - name: dateparse - args: "2006-01-0215:04:05 -07:00" - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - text: "0" - uploadvolumefactor: - text: "1" +--- + site: polishsource + name: PolishSource + language: pl-pl + type: private + encoding: ISO-8859-2 + links: + - https://polishsource.cz/ + + caps: + categorymappings: + - {id: 12, cat: Movies/SD, desc: "Movies/SD"} + - {id: 11, cat: Movies/HD, desc: "Movies/HD"} + - {id: 45, cat: Movies/3D, desc: "Movies/3D"} + - {id: 4, cat: Movies/DVD, desc: "Movies/DVD"} + - {id: 43, cat: Movies/BluRay, desc: "Movies/BD"} + - {id: 10, cat: TV/SD, desc: "TV/SD"} + - {id: 39, cat: TV/HD, desc: "TV/HD"} + - {id: 8, cat: PC/Games, desc: "Games/PC"} + - {id: 3, cat: Console, desc: "Games/Consoles"} + - {id: 5, cat: Books, desc: "E-Books"} + - {id: 42, cat: Audio, desc: "Music"} + - {id: 18, cat: PC/0day, desc: "Apps"} + - {id: 13, cat: XXX, desc: "XXX"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + captcha: + type: image + image: img[src="img.php"] + input: vImageCodP + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + - selector: td.embedded:has(h2:contains("Error")) + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + scene: "0" + pl: "0" + sub: "" + search_in: "title" + rows: + selector: table#restable > tbody > tr:has(a[href^="details.php?id="]) + fields: + title: + selector: a[href^="details.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="downloadssl.php?id="] + attribute: href + description|optional: + selector: td:nth-child(2) > small + filters: + - name: prepend + args: "Genre: " + - name: append + args: "\n<br>" + description|optional|append|1: + selector: img[src="pic/pl.png"] + filters: + - name: append + args: "Language: polish\n<br>" + description|optional|append|2: + selector: img[src="pic/napisy.png"] + filters: + - name: append + args: "Subbed\n<br>" + imdb|optional: + selector: a[href^="http://www.imdb.com/title/tt"] + grabs: + selector: td:nth-child(6) + filters: + - name: regexp + args: (\d+) + size: + selector: td:nth-child(5) + date: + selector: td:nth-child(4) + filters: + - name: append + args: " +00:00" + - name: dateparse + args: "2006-01-0215:04:05 -07:00" + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + text: "0" + uploadvolumefactor: + text: "1" diff --git a/src/Jackett/Definitions/qctorrent.yml b/src/Jackett/Definitions/qctorrent.yml index 130ddfc2..0f99ae43 100644 --- a/src/Jackett/Definitions/qctorrent.yml +++ b/src/Jackett/Definitions/qctorrent.yml @@ -1,107 +1,107 @@ ---- - site: qctorrent - name: QcTorrent - description: "A French gerneral tracker" - language: fr-fr - type: private - encoding: UTF-8 - links: - - http://www.qctorrent.net/ - - caps: - categorymappings: - - {id: 30, cat: PC, desc: "++ Applications"} - - {id: 1, cat: PC, desc: "Applications/Divers"} - - {id: 2, cat: PC, desc: "Applications/PC ISO"} - - {id: 3, cat: PC, desc: "Applications/Portable"} - - {id: 31, cat: Movies, desc: "++ Films"} - - {id: 4, cat: Movies/BluRay, desc: "Films/Bluray"} - - {id: 5, cat: Movies/DVD, desc: "Films/DVDr"} - - {id: 6, cat: Movies/HD, desc: "Films/HD Rip"} - - {id: 7, cat: Movies/SD, desc: "Films/SD Rip"} - - {id: 8, cat: Movies/SD, desc: "Films/VCD"} - - {id: 32, cat: Console, desc: "++ Jeux"} - - {id: 9, cat: PC/Games, desc: "Jeux/PC"} - - {id: 10, cat: Console, desc: "Jeux/Portable"} - - {id: 11, cat: Console/PS4, desc: "Jeux/PS"} - - {id: 12, cat: Console/Wii, desc: "Jeux/Wii"} - - {id: 13, cat: Console/Xbox, desc: "Jeux/Xbox"} - - {id: 33, cat: Audio, desc: "++ Musique"} - - {id: 14, cat: Audio, desc: "Musique"} - - {id: 15, cat: Audio/Video, desc: "Musique/Video"} - - {id: 34, cat: TV, desc: "++ Série-Télé"} - - {id: 16, cat: TV/HD, desc: "Série-Télé/Bluray"} - - {id: 17, cat: TV/SD, desc: "Série-Télé/DVDr"} - - {id: 18, cat: TV/HD, desc: "Série-Télé/HD Rip"} - - {id: 19, cat: TV/SD, desc: "Série-Télé/SD Rip"} - - {id: 20, cat: Books, desc: "E-Books"} - - {id: 21, cat: XXX, desc: "XXX"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - login-username: "{{ .Config.username }}" - login-password: "{{ .Config.password }}" - login-remember-me: "on" - login: "" - error: - - selector: "script[type=\"text/javascript\"]:contains(\"$.ambiance({message: \")" - test: - path: search.php - selector: div.top-bar > div.container > div.textleft > div.hidden-sm > font:contains("Ratio:") > font - - ratio: - path: search.php - selector: div.top-bar > div.container > div.textleft > div.hidden-sm > font:contains("Ratio:") > font - - search: - path: search.php - inputs: - category: "{{range .Categories}}{{.}};{{end}}" - title: "{{ .Query.Keywords }}" - search: "Recherche" - rows: - selector: tr[data-snatches] - fields: - download: - selector: td.name > a - attribute: href - filters: - - name: replace - args: ["/torrent/", "/dl/"] - title: - selector: td.name > a - category: - selector: td.coll-0 > a - attribute: href - filters: - - name: querystring - args: category - details: - selector: td.name > a - attribute: href - grabs: - attribute: data-snatches - seeders: - selector: td.seeds - leechers: - selector: td.leeches - date: - selector: td[data-date] - attribute: data-date - downloadvolumefactor: - case: - span[title^="Freeleech:"]: "0" - span[title^="Half Freeleech:"]: "0.5" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - size: - selector: td.size +--- + site: qctorrent + name: QcTorrent + description: "A French gerneral tracker" + language: fr-fr + type: private + encoding: UTF-8 + links: + - http://www.qctorrent.net/ + + caps: + categorymappings: + - {id: 30, cat: PC, desc: "++ Applications"} + - {id: 1, cat: PC, desc: "Applications/Divers"} + - {id: 2, cat: PC, desc: "Applications/PC ISO"} + - {id: 3, cat: PC, desc: "Applications/Portable"} + - {id: 31, cat: Movies, desc: "++ Films"} + - {id: 4, cat: Movies/BluRay, desc: "Films/Bluray"} + - {id: 5, cat: Movies/DVD, desc: "Films/DVDr"} + - {id: 6, cat: Movies/HD, desc: "Films/HD Rip"} + - {id: 7, cat: Movies/SD, desc: "Films/SD Rip"} + - {id: 8, cat: Movies/SD, desc: "Films/VCD"} + - {id: 32, cat: Console, desc: "++ Jeux"} + - {id: 9, cat: PC/Games, desc: "Jeux/PC"} + - {id: 10, cat: Console, desc: "Jeux/Portable"} + - {id: 11, cat: Console/PS4, desc: "Jeux/PS"} + - {id: 12, cat: Console/Wii, desc: "Jeux/Wii"} + - {id: 13, cat: Console/Xbox, desc: "Jeux/Xbox"} + - {id: 33, cat: Audio, desc: "++ Musique"} + - {id: 14, cat: Audio, desc: "Musique"} + - {id: 15, cat: Audio/Video, desc: "Musique/Video"} + - {id: 34, cat: TV, desc: "++ Série-Télé"} + - {id: 16, cat: TV/HD, desc: "Série-Télé/Bluray"} + - {id: 17, cat: TV/SD, desc: "Série-Télé/DVDr"} + - {id: 18, cat: TV/HD, desc: "Série-Télé/HD Rip"} + - {id: 19, cat: TV/SD, desc: "Série-Télé/SD Rip"} + - {id: 20, cat: Books, desc: "E-Books"} + - {id: 21, cat: XXX, desc: "XXX"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + login-username: "{{ .Config.username }}" + login-password: "{{ .Config.password }}" + login-remember-me: "on" + login: "" + error: + - selector: "script[type=\"text/javascript\"]:contains(\"$.ambiance({message: \")" + test: + path: search.php + selector: div.top-bar > div.container > div.textleft > div.hidden-sm > font:contains("Ratio:") > font + + ratio: + path: search.php + selector: div.top-bar > div.container > div.textleft > div.hidden-sm > font:contains("Ratio:") > font + + search: + path: search.php + inputs: + category: "{{range .Categories}}{{.}};{{end}}" + title: "{{ .Query.Keywords }}" + search: "Recherche" + rows: + selector: tr[data-snatches] + fields: + download: + selector: td.name > a + attribute: href + filters: + - name: replace + args: ["/torrent/", "/dl/"] + title: + selector: td.name > a + category: + selector: td.coll-0 > a + attribute: href + filters: + - name: querystring + args: category + details: + selector: td.name > a + attribute: href + grabs: + attribute: data-snatches + seeders: + selector: td.seeds + leechers: + selector: td.leeches + date: + selector: td[data-date] + attribute: data-date + downloadvolumefactor: + case: + span[title^="Freeleech:"]: "0" + span[title^="Half Freeleech:"]: "0.5" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + size: + selector: td.size remove: span \ No newline at end of file diff --git a/src/Jackett/Definitions/redacted-scrape.yml b/src/Jackett/Definitions/redacted-scrape.yml index 448ff591..166d0d22 100644 --- a/src/Jackett/Definitions/redacted-scrape.yml +++ b/src/Jackett/Definitions/redacted-scrape.yml @@ -1,103 +1,103 @@ ---- - site: redacted-scrape - name: Redacted (scrape) - description: "A music tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://redacted.ch/ - - caps: - categorymappings: - - {id: 1, cat: Audio, desc: "Music"} - - {id: 2, cat: PC, desc: "Applications"} - - {id: 3, cat: Books, desc: "E-Books"} - - {id: 4, cat: Audio/Audiobook, desc: "Audiobooks"} - - {id: 5, cat: Movies, desc: "E-Learning Videos"} - - {id: 6, cat: TV, desc: "Comedy"} - - {id: 7, cat: Books/Comics, desc: "Comics"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: 1 - login: "Log in" - error: - - selector: form#loginform > span.warning - test: - path: torrents.php - - ratio: - path: torrents.php - selector: li#stats_ratio > span - - search: - path: torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{ .Query.Keywords }}" - order_by: time - order_way: desc - action: basic - searchsubmit: 1 - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - download: - selector: a[href^="torrents.php?action=download&id="] - attribute: href - description: - selector: div.group_info - remove: span - title: - selector: div.group_info - remove: span, div.tags - filters: - - name: replace - args: [" / Neutral Leech!", ""] - - name: replace - args: [" / Freeleech!", ""] - category: - selector: td.cats_col - case: - div.cats_music: 1 - div.cats_applications: 2 - div.cats_ebooks: 3 - div.cats_audiobooks: 4 - div.cats_elearningvideos: 5 - div.cats_comedy: 6 - div.cats_comics: 7 - comments: - selector: a[href^="torrents.php?id="] - attribute: href - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(4) - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - "strong.tl_free": "0" - "strong.tl_neutral": "0" - ":root div.alertbar:contains(\"freeleech\")": "0" - ":root div.alertbar:contains(\"FREELEECH\")": "0" - "*": "1" - uploadvolumefactor: - case: - "strong.tl_neutral": "0" +--- + site: redacted-scrape + name: Redacted (scrape) + description: "A music tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://redacted.ch/ + + caps: + categorymappings: + - {id: 1, cat: Audio, desc: "Music"} + - {id: 2, cat: PC, desc: "Applications"} + - {id: 3, cat: Books, desc: "E-Books"} + - {id: 4, cat: Audio/Audiobook, desc: "Audiobooks"} + - {id: 5, cat: Movies, desc: "E-Learning Videos"} + - {id: 6, cat: TV, desc: "Comedy"} + - {id: 7, cat: Books/Comics, desc: "Comics"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: 1 + login: "Log in" + error: + - selector: form#loginform > span.warning + test: + path: torrents.php + + ratio: + path: torrents.php + selector: li#stats_ratio > span + + search: + path: torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{ .Query.Keywords }}" + order_by: time + order_way: desc + action: basic + searchsubmit: 1 + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + download: + selector: a[href^="torrents.php?action=download&id="] + attribute: href + description: + selector: div.group_info + remove: span + title: + selector: div.group_info + remove: span, div.tags + filters: + - name: replace + args: [" / Neutral Leech!", ""] + - name: replace + args: [" / Freeleech!", ""] + category: + selector: td.cats_col + case: + div.cats_music: 1 + div.cats_applications: 2 + div.cats_ebooks: 3 + div.cats_audiobooks: 4 + div.cats_elearningvideos: 5 + div.cats_comedy: 6 + div.cats_comics: 7 + comments: + selector: a[href^="torrents.php?id="] + attribute: href + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(4) + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + "strong.tl_free": "0" + "strong.tl_neutral": "0" + ":root div.alertbar:contains(\"freeleech\")": "0" + ":root div.alertbar:contains(\"FREELEECH\")": "0" + "*": "1" + uploadvolumefactor: + case: + "strong.tl_neutral": "0" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/rockhardlossless.yml b/src/Jackett/Definitions/rockhardlossless.yml index 51ecee8a..2420eb1c 100644 --- a/src/Jackett/Definitions/rockhardlossless.yml +++ b/src/Jackett/Definitions/rockhardlossless.yml @@ -1,80 +1,80 @@ ---- - site: rockhardlossless - name: Rockhard Lossless - language: en-us - type: private - encoding: UTF-8 - links: - - https://rockhard-lossless.org - - caps: - categories: - 1: Audio - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: tbody:has(td.colhead > span:contains("Error")) - - selector: tbody:has(td.colhead > span:contains("failed")) - test: - path: /browse.php - - search: - path: /browse.php - method: post - inputs: - search: "{{ .Query.Keywords }}" - incldead: "1" - searchin: "title" - rows: - selector: table > tbody tr.tt - filters: - - name: andmatch - fields: - title: - selector: a[href^="details.php?id="] - category: - text: "1" - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?torrent="] - attribute: href - banner: - selector: td:nth-child(2) > img - attribute: src - size: - selector: td:nth-child(8) - files: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(9) - filters: - - name: regexp - args: ([\d\.]+) - seeders: - selector: td:nth-child(10) - leechers: - selector: td:nth-child(11) - date: - selector: td:nth-child(7) - downloadvolumefactor: - case: - "a.info > b:contains(\"Free\")": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(3) - remove: a, div, font:contains("NEW!") +--- + site: rockhardlossless + name: Rockhard Lossless + language: en-us + type: private + encoding: UTF-8 + links: + - https://rockhard-lossless.org + + caps: + categories: + 1: Audio + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: tbody:has(td.colhead > span:contains("Error")) + - selector: tbody:has(td.colhead > span:contains("failed")) + test: + path: /browse.php + + search: + path: /browse.php + method: post + inputs: + search: "{{ .Query.Keywords }}" + incldead: "1" + searchin: "title" + rows: + selector: table > tbody tr.tt + filters: + - name: andmatch + fields: + title: + selector: a[href^="details.php?id="] + category: + text: "1" + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?torrent="] + attribute: href + banner: + selector: td:nth-child(2) > img + attribute: src + size: + selector: td:nth-child(8) + files: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(9) + filters: + - name: regexp + args: ([\d\.]+) + seeders: + selector: td:nth-child(10) + leechers: + selector: td:nth-child(11) + date: + selector: td:nth-child(7) + downloadvolumefactor: + case: + "a.info > b:contains(\"Free\")": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(3) + remove: a, div, font:contains("NEW!") diff --git a/src/Jackett/Definitions/rodvd.yml b/src/Jackett/Definitions/rodvd.yml index ce01ea86..526b314c 100644 --- a/src/Jackett/Definitions/rodvd.yml +++ b/src/Jackett/Definitions/rodvd.yml @@ -1,125 +1,125 @@ ---- - site: rodvd - name: RoDVD - language: ro-ro - type: private - encoding: windows-1252 - links: - - http://rodvd.net/ - - caps: - categorymappings: - - {id: 48, cat: Movies/3D, desc: "3D"} - - {id: 1, cat: PC/0day, desc: "Appz"} - - {id: 3, cat: Other, desc: "Cartoons"} - - {id: 42, cat: TV/Documentary, desc: "Documentaries"} - - {id: 6, cat: Books, desc: "eBooks"} - - {id: 11, cat: PC/Games, desc: "Games | PC"} - - {id: 12, cat: Console/PS3, desc: "Games | PS2"} - - {id: 36, cat: Console/PS3, desc: "Games | PS3"} - - {id: 40, cat: Console/PSP, desc: "Games | PSP"} - - {id: 25, cat: Console/Wii, desc: "Games | Wii"} - - {id: 16, cat: Console/Xbox, desc: "Games | XBOX"} - - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 43, cat: Movies/BluRay, desc: "Movies | Blu-Ray"} - - {id: 49, cat: Movies/BluRay, desc: "Movies | Blu-Ray-RO"} - - {id: 7, cat: Movies/DVD, desc: "Movies | DVD-R"} - - {id: 2, cat: Movies/DVD, desc: "Movies | DVD-RO"} - - {id: 17, cat: Movies/HD, desc: "Movies | HD"} - - {id: 45, cat: Movies/HD, desc: "Movies | HD-RO"} - - {id: 21, cat: Movies, desc: "Movies | Oldies"} - - {id: 38, cat: Movies, desc: "Movies | Packs"} - - {id: 8, cat: Movies/SD, desc: "Movies | x264"} - - {id: 4, cat: Movies/SD, desc: "Movies | x264-RO"} - - {id: 10, cat: Movies/SD, desc: "Movies | XviD"} - - {id: 44, cat: Movies/SD, desc: "Movies | XviD-RO"} - - {id: 5, cat: Audio/MP3, desc: "Music | Mp3"} - - {id: 39, cat: Audio, desc: "Music | Packs"} - - {id: 23, cat: Audio/Video, desc: "Music | Videos"} - - {id: 18, cat: Other, desc: "Pictures"} - - {id: 46, cat: XXX/Imageset, desc: "Pictures | xxx"} - - {id: 22, cat: TV/Sport, desc: "Sport"} - - {id: 50, cat: TV, desc: "STAR"} - - {id: 20, cat: TV/SD, desc: "TV | Episodes"} - - {id: 47, cat: TV/HD, desc: "TV | Episodes HD"} - - {id: 41, cat: TV, desc: "TV | Packs"} - - {id: 15, cat: XXX, desc: "xXx"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q, imdbid] - - login: - path: login.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.loginerr - test: - path: browse.php - - ratio: - path: browse.php - selector: a#link14 - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" - key: 9 - rows: - selector: table.torrents > tbody > tr:has(a[href^="details.php?id="]) - filters: - - name: andmatch - dateheaders: - selector: "td.days > font > b" - filters: - - name: replace - args: ["Torrents Added: ", ""] - - name: dateparse - args: "2.1.2006" - fields: - title: - selector: a[href^="details.php?id="] font - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="download.php"] - attribute: href - imdb|optional: - selector: a[href*="http://www.imdb.com/title/tt"] - attribute: href - size: - selector: td:nth-child(6) - seeders: - text: 9999 - leechers: - text: 0 - banner: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: "src=\"([^\"]+)" - downloadvolumefactor: - case: - "font.small[color]:contains(\"Free\")": "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(2) - remove: a[href^="details.php?id="] +--- + site: rodvd + name: RoDVD + language: ro-ro + type: private + encoding: windows-1252 + links: + - http://rodvd.net/ + + caps: + categorymappings: + - {id: 48, cat: Movies/3D, desc: "3D"} + - {id: 1, cat: PC/0day, desc: "Appz"} + - {id: 3, cat: Other, desc: "Cartoons"} + - {id: 42, cat: TV/Documentary, desc: "Documentaries"} + - {id: 6, cat: Books, desc: "eBooks"} + - {id: 11, cat: PC/Games, desc: "Games | PC"} + - {id: 12, cat: Console/PS3, desc: "Games | PS2"} + - {id: 36, cat: Console/PS3, desc: "Games | PS3"} + - {id: 40, cat: Console/PSP, desc: "Games | PSP"} + - {id: 25, cat: Console/Wii, desc: "Games | Wii"} + - {id: 16, cat: Console/Xbox, desc: "Games | XBOX"} + - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 43, cat: Movies/BluRay, desc: "Movies | Blu-Ray"} + - {id: 49, cat: Movies/BluRay, desc: "Movies | Blu-Ray-RO"} + - {id: 7, cat: Movies/DVD, desc: "Movies | DVD-R"} + - {id: 2, cat: Movies/DVD, desc: "Movies | DVD-RO"} + - {id: 17, cat: Movies/HD, desc: "Movies | HD"} + - {id: 45, cat: Movies/HD, desc: "Movies | HD-RO"} + - {id: 21, cat: Movies, desc: "Movies | Oldies"} + - {id: 38, cat: Movies, desc: "Movies | Packs"} + - {id: 8, cat: Movies/SD, desc: "Movies | x264"} + - {id: 4, cat: Movies/SD, desc: "Movies | x264-RO"} + - {id: 10, cat: Movies/SD, desc: "Movies | XviD"} + - {id: 44, cat: Movies/SD, desc: "Movies | XviD-RO"} + - {id: 5, cat: Audio/MP3, desc: "Music | Mp3"} + - {id: 39, cat: Audio, desc: "Music | Packs"} + - {id: 23, cat: Audio/Video, desc: "Music | Videos"} + - {id: 18, cat: Other, desc: "Pictures"} + - {id: 46, cat: XXX/Imageset, desc: "Pictures | xxx"} + - {id: 22, cat: TV/Sport, desc: "Sport"} + - {id: 50, cat: TV, desc: "STAR"} + - {id: 20, cat: TV/SD, desc: "TV | Episodes"} + - {id: 47, cat: TV/HD, desc: "TV | Episodes HD"} + - {id: 41, cat: TV, desc: "TV | Packs"} + - {id: 15, cat: XXX, desc: "xXx"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q, imdbid] + + login: + path: login.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.loginerr + test: + path: browse.php + + ratio: + path: browse.php + selector: a#link14 + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Query.Keywords }}{{end}}" + key: 9 + rows: + selector: table.torrents > tbody > tr:has(a[href^="details.php?id="]) + filters: + - name: andmatch + dateheaders: + selector: "td.days > font > b" + filters: + - name: replace + args: ["Torrents Added: ", ""] + - name: dateparse + args: "2.1.2006" + fields: + title: + selector: a[href^="details.php?id="] font + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="download.php"] + attribute: href + imdb|optional: + selector: a[href*="http://www.imdb.com/title/tt"] + attribute: href + size: + selector: td:nth-child(6) + seeders: + text: 9999 + leechers: + text: 0 + banner: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: "src=\"([^\"]+)" + downloadvolumefactor: + case: + "font.small[color]:contains(\"Free\")": "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(2) + remove: a[href^="details.php?id="] diff --git a/src/Jackett/Definitions/sdbits.yml b/src/Jackett/Definitions/sdbits.yml index c7c39228..150f9d39 100644 --- a/src/Jackett/Definitions/sdbits.yml +++ b/src/Jackett/Definitions/sdbits.yml @@ -1,94 +1,94 @@ ---- - site: sdbits - name: SDBits - description: "SDBits is a small tracker that focuses on SD movies and tv." - language: en-us - type: private - encoding: UTF-8 - links: - - http://sdbits.org - - caps: - categorymappings: - - {id: 6, cat: Audio, desc: "Audio"} - - {id: 3, cat: TV/Documentary, desc: "Documentary"} - - {id: 1, cat: Movies, desc: "Movies"} - - {id: 4, cat: Audio, desc: "Music"} - - {id: 5, cat: TV/Sport, desc: "Sports"} - - {id: 2, cat: TV, desc: "TV"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takeloginn3.php - method: post - inputs: - uname: "{{ .Config.username }}" - password: "{{ .Config.password }}" - returnto: "/" - error: - - selector: td.embedded:has(h2:contains("failed")+table) - test: - path: /browse.php - selector: span.smallfont:has(a[href="logout.php"]) - - ratio: - path: /browse.php - selector: span.smallfont:has(a[href="logout.php"]) - filters: - - name: regexp - args: "Ratio:[ \u00a0](.*?)\u00a0" - - search: - path: /browse.php - method: post - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - descriptions: "0" - rows: - selector: table#torrent-list > tbody > tr[id] - fields: - title: - selector: td:nth-child(3) > b > a - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: td:nth-child(3) > b > a - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - size: - selector: td:nth-child(6) - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: "(\\d+)" - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - date: - selector: td:nth-child(5) - filters: - - name: append - args: " ago" - imdb: - selector: a[href^="http://www.imdb.com/"] - attribute: href - downloadvolumefactor: - case: - "a[style=\"color:#000099\"][href^=\"details.php?\"]": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: sdbits + name: SDBits + description: "SDBits is a small tracker that focuses on SD movies and tv." + language: en-us + type: private + encoding: UTF-8 + links: + - http://sdbits.org + + caps: + categorymappings: + - {id: 6, cat: Audio, desc: "Audio"} + - {id: 3, cat: TV/Documentary, desc: "Documentary"} + - {id: 1, cat: Movies, desc: "Movies"} + - {id: 4, cat: Audio, desc: "Music"} + - {id: 5, cat: TV/Sport, desc: "Sports"} + - {id: 2, cat: TV, desc: "TV"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takeloginn3.php + method: post + inputs: + uname: "{{ .Config.username }}" + password: "{{ .Config.password }}" + returnto: "/" + error: + - selector: td.embedded:has(h2:contains("failed")+table) + test: + path: /browse.php + selector: span.smallfont:has(a[href="logout.php"]) + + ratio: + path: /browse.php + selector: span.smallfont:has(a[href="logout.php"]) + filters: + - name: regexp + args: "Ratio:[ \u00a0](.*?)\u00a0" + + search: + path: /browse.php + method: post + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + descriptions: "0" + rows: + selector: table#torrent-list > tbody > tr[id] + fields: + title: + selector: td:nth-child(3) > b > a + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: td:nth-child(3) > b > a + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + size: + selector: td:nth-child(6) + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: "(\\d+)" + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + date: + selector: td:nth-child(5) + filters: + - name: append + args: " ago" + imdb: + selector: a[href^="http://www.imdb.com/"] + attribute: href + downloadvolumefactor: + case: + "a[style=\"color:#000099\"][href^=\"details.php?\"]": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/secretcinema.yml b/src/Jackett/Definitions/secretcinema.yml index cfd546bd..be750a89 100644 --- a/src/Jackett/Definitions/secretcinema.yml +++ b/src/Jackett/Definitions/secretcinema.yml @@ -1,130 +1,130 @@ ---- - site: secretcinema - name: Secret Cinema - description: "A tracker for rare movies." - language: en-us - type: private - encoding: "UTF-8" - links: - - http://www.secret-cinema.net - - caps: - categorymappings: - - {id: 1, cat: TV/Anime, desc: "Animation"} - - {id: 2, cat: Movies, desc: "Arthouse"} - - {id: 3, cat: Movies, desc: "Asian"} - - {id: 19, cat: Audio/Audiobook, desc: "Audiobooks"} - - {id: 29, cat: Movies, desc: "Badfilm"} - - {id: 18, cat: Books, desc: "Books"} - - {id: 4, cat: Movies, desc: "Classics"} - - {id: 5, cat: Movies, desc: "Comedy"} - - {id: 20, cat: Books/Comics, desc: "Comix"} - - {id: 6, cat: Movies, desc: "Cult"} - - {id: 7, cat: TV/Documentary, desc: "Documentary"} - - {id: 8, cat: Movies, desc: "Fantasy & SF"} - - {id: 9, cat: Movies, desc: "Horror"} - - {id: 22, cat: Movies, desc: "Noir"} - - {id: 17, cat: Audio, desc: "OST"} - - {id: 10, cat: Other, desc: "Other"} - - {id: 15, cat: TV, desc: "Other TV"} - - {id: 16, cat: Audio, desc: "Radio"} - - {id: 11, cat: Movies, desc: "Silent"} - - {id: 12, cat: TV, desc: "Talent Show!"} - - {id: 14, cat: Movies, desc: "TV Movies"} - - {id: 13, cat: TV, desc: "TV Series"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - returnto: "index.php" - test: - path: /browse.php - selector: div.Userstats - - ratio: - path: /browse.php - selector: div.Userstats - filters: - - name: regexp - args: "\n\u00a0(.*) \u00a0" - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}cat{{.}}=on&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - tpp: "100" - dirty: "1" - rows: - selector: td > table[id="large"] > tbody > tr:has(div.browsing) - filters: - - name: andmatch - dateheaders: - selector: ":has(td.colhead[title] > b)" - filters: - - name: dateparse - args: "Mon 02 Jan" - fields: - title: - selector: a[href^="viewtopic.php?id="] - description: - selector: table > tbody > tr:nth-child(2) > td:nth-child(2) - category: - selector: a[href^="browse.php?cat"] - attribute: href - filters: - - name: replace - args: ["browse.php?cat", ""] - - name: replace - args: ["=on", ""] - details: - selector: a[href^="viewtopic.php?id="] - attribute: href - download: - selector: a[href^="download.php/"] - attribute: href - size: - selector: table > tbody > tr:nth-child(2) > td:nth-child(4) - files: - selector: table > tbody > tr:nth-child(2) > td:nth-child(3) - filters: - - name: regexp - args: "(\\d+)" - grabs: - selector: table > tbody > tr:nth-child(2) > td:nth-child(5) - filters: - - name: regexp - args: "(\\d+)" - seeders: - selector: table > tbody > tr:nth-child(2) > td:nth-child(6) - filters: - - name: regexp - args: "(\\d+)" - leechers: - selector: table > tbody > tr:nth-child(2) > td:nth-child(7) - filters: - - name: regexp - args: "(\\d+)" - date: - selector: td:nth-child(1) > div > table > tbody > tr:nth-child(2) > td:nth-child(1) - filters: - - name: replace - args: ["'", ""] - - name: replace - args: ["\xA0", ""] - - name: dateparse - args: "02 Jan 0615:04" - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: secretcinema + name: Secret Cinema + description: "A tracker for rare movies." + language: en-us + type: private + encoding: "UTF-8" + links: + - http://www.secret-cinema.net + + caps: + categorymappings: + - {id: 1, cat: TV/Anime, desc: "Animation"} + - {id: 2, cat: Movies, desc: "Arthouse"} + - {id: 3, cat: Movies, desc: "Asian"} + - {id: 19, cat: Audio/Audiobook, desc: "Audiobooks"} + - {id: 29, cat: Movies, desc: "Badfilm"} + - {id: 18, cat: Books, desc: "Books"} + - {id: 4, cat: Movies, desc: "Classics"} + - {id: 5, cat: Movies, desc: "Comedy"} + - {id: 20, cat: Books/Comics, desc: "Comix"} + - {id: 6, cat: Movies, desc: "Cult"} + - {id: 7, cat: TV/Documentary, desc: "Documentary"} + - {id: 8, cat: Movies, desc: "Fantasy & SF"} + - {id: 9, cat: Movies, desc: "Horror"} + - {id: 22, cat: Movies, desc: "Noir"} + - {id: 17, cat: Audio, desc: "OST"} + - {id: 10, cat: Other, desc: "Other"} + - {id: 15, cat: TV, desc: "Other TV"} + - {id: 16, cat: Audio, desc: "Radio"} + - {id: 11, cat: Movies, desc: "Silent"} + - {id: 12, cat: TV, desc: "Talent Show!"} + - {id: 14, cat: Movies, desc: "TV Movies"} + - {id: 13, cat: TV, desc: "TV Series"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + returnto: "index.php" + test: + path: /browse.php + selector: div.Userstats + + ratio: + path: /browse.php + selector: div.Userstats + filters: + - name: regexp + args: "\n\u00a0(.*) \u00a0" + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}cat{{.}}=on&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + tpp: "100" + dirty: "1" + rows: + selector: td > table[id="large"] > tbody > tr:has(div.browsing) + filters: + - name: andmatch + dateheaders: + selector: ":has(td.colhead[title] > b)" + filters: + - name: dateparse + args: "Mon 02 Jan" + fields: + title: + selector: a[href^="viewtopic.php?id="] + description: + selector: table > tbody > tr:nth-child(2) > td:nth-child(2) + category: + selector: a[href^="browse.php?cat"] + attribute: href + filters: + - name: replace + args: ["browse.php?cat", ""] + - name: replace + args: ["=on", ""] + details: + selector: a[href^="viewtopic.php?id="] + attribute: href + download: + selector: a[href^="download.php/"] + attribute: href + size: + selector: table > tbody > tr:nth-child(2) > td:nth-child(4) + files: + selector: table > tbody > tr:nth-child(2) > td:nth-child(3) + filters: + - name: regexp + args: "(\\d+)" + grabs: + selector: table > tbody > tr:nth-child(2) > td:nth-child(5) + filters: + - name: regexp + args: "(\\d+)" + seeders: + selector: table > tbody > tr:nth-child(2) > td:nth-child(6) + filters: + - name: regexp + args: "(\\d+)" + leechers: + selector: table > tbody > tr:nth-child(2) > td:nth-child(7) + filters: + - name: regexp + args: "(\\d+)" + date: + selector: td:nth-child(1) > div > table > tbody > tr:nth-child(2) > td:nth-child(1) + filters: + - name: replace + args: ["'", ""] + - name: replace + args: ["\xA0", ""] + - name: dateparse + args: "02 Jan 0615:04" + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/shareisland.yml b/src/Jackett/Definitions/shareisland.yml index c251b16c..8f79bbcd 100644 --- a/src/Jackett/Definitions/shareisland.yml +++ b/src/Jackett/Definitions/shareisland.yml @@ -1,170 +1,170 @@ ---- - site: shareisland - name: Shareisland - description: "A general italian tracker" - language: it-it - type: private - encoding: UTF-8 - links: - - http://shareisland.org - - caps: - categorymappings: - - {id: 32, cat: Other, desc: "Vip"} - - {id: 45, cat: XXX, desc: "Vip XXX"} - - {id: 33, cat: Other, desc: "ex Vip"} - - {id: 1, cat: Movies, desc: "Movies"} - - {id: 49, cat: Movies/HD, desc: "H-264"} - - {id: 51, cat: Movies/HD, desc: "H-265"} - - {id: 41, cat: Movies/Other, desc: "Cartoons"} - - {id: 14, cat: Movies/SD, desc: "DivX"} - - {id: 16, cat: Movies/Other, desc: "Cine News"} - - {id: 39, cat: Movies/HD, desc: "720p"} - - {id: 40, cat: Movies/HD, desc: "1080p"} - - {id: 46, cat: Movies/BluRay, desc: "Blu Ray Disk"} - - {id: 31, cat: Movies/HD, desc: "BDRip"} - - {id: 17, cat: Movies/DVD, desc: "DVD"} - - {id: 43, cat: Movies/SD, desc: "DVDRip"} - - {id: 6, cat: PC, desc: "Applications"} - - {id: 18, cat: PC/0day, desc: "PC Applications"} - - {id: 19, cat: PC/Mac, desc: "Macintosh Applications"} - - {id: 44, cat: PC/Phone-Android, desc: "Android applications"} - - {id: 7, cat: Audio, desc: "Music"} - - {id: 20, cat: Audio/Video, desc: "Video"} - - {id: 21, cat: Audio/MP3, desc: "Mp3"} - - {id: 2, cat: Console, desc: "Games"} - - {id: 3, cat: Console/PS4, desc: "Sony PS"} - - {id: 4, cat: Console/Wii, desc: "Wii"} - - {id: 26, cat: Console/Xbox, desc: "XboX"} - - {id: 27, cat: PC/Games, desc: "PC"} - - {id: 28, cat: Console/NDS, desc: "Nintendo"} - - {id: 34, cat: Books, desc: "Edicola"} - - {id: 52, cat: Books, desc: "Quotidiani"} - - {id: 53, cat: Books, desc: "Libreria"} - - {id: 35, cat: TV, desc: "SerieTV"} - - {id: 55, cat: TV/HD, desc: "Serie Tv HD"} - - {id: 36, cat: Other, desc: "Rip By ShareIsland"} - - {id: 47, cat: Other, desc: "Disclaimer"} - - {id: 48, cat: Other, desc: "P2P network "} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /ajax/login.php - method: post - form: form - inputs: - loginbox_membername: "{{ .Config.username }}" - loginbox_password: "{{ .Config.password }}" - action: "login" - loginbox_remember: "true" - error: - - selector: div.error - test: - path: /?p=home&pid=1 - selector: div#member_info_bar - - ratio: - path: /?p=home&pid=1 - selector: img[title="Ratio"] + span - - search: - path: / - keywordsfilters: - # most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later - - name: re_replace - args: ["S0?(\\d{1,2})", " $1 "] - - name: re_replace - args: ["E(\\d{2,3})", " $1 "] - - name: re_replace - args: ["[^a-zA-Z0-9]+", "%25"] - inputs: - p: "torrents" - pid: "32" - $raw: "{{range .Categories}}cid[]={{.}}&{{end}}" - keywords: "{{ .Keywords }}" - search_type: "name" - searchin: "title" - - rows: - selector: table#torrents_table_classic > tbody > tr:not([id="torrents_table_classic_head"]) - filters: - - name: andmatch - fields: - title: - selector: td.torrent_name > a - filters: - # normalize to SXXEYY format - - name: re_replace - args: ["(\\d{2})x(\\d{2})", "S$1E$2"] - - name: re_replace - args: ["(\\d{1})x(\\d{2})", "S0$1E$2"] - category: - selector: div.category_image > a - attribute: href - filters: - - name: querystring - args: cid - comments: - selector: td.torrent_name > a - attribute: href - download: - selector: a:has(img[title="Download Torrent"]) - attribute: href - size: - selector: td.size - seeders: - selector: td.seeders - leechers: - selector: td.leechers - grabs: - selector: td.completed - downloadvolumefactor: - case: - "img[title=\"FREE!\"]": "0" - "img[title=\"Download Multiplier: 0.5\"]": "0.5" - "img[title=\"Moltiplicatore Download: 0.5\"]": "0.5" - "*": "1" - uploadvolumefactor: - case: - "img[title=\"Upload Multiplier: 3\"]": "3" - "img[title=\"Upload Multiplier: 2\"]": "2" - "img[title=\"Upload Multiplier: 1.5\"]": "1.5" - "img[title=\"Moltiplicatore Upload: 3\"]": "3" - "img[title=\"Moltiplicatore Upload: 2\"]": "2" - "img[title=\"Moltiplicatore Upload: 1.5\"]": "1.5" - "*": "1" - date: - selector: td.torrent_name - remove: a, span, div, br - filters: - - name: replace - args: ["Uploaded ", ""] - - name: replace - args: [" by", ""] - - name: replace - args: [" at", ""] - - name: replace - args: ["Oggi", "Today"] - - name: replace - args: ["Ieri", "Yesterday"] - - name: replace - args: ["lunedì", "Monday"] - - name: replace - args: ["martedì", "Tuesday"] - - name: replace - args: ["Mercoledì", "Wednesday"] - - name: replace - args: ["Giovedì", "Thursday"] - - name: replace - args: ["Venerdì", "Friday"] - - name: replace - args: ["Sabato", "Saturday"] - - name: replace - args: ["Domenica", "Sunday"] - - name: replace - args: [" alle", ""] - - name: dateparse - args: "02-01-2006 15:04" +--- + site: shareisland + name: Shareisland + description: "A general italian tracker" + language: it-it + type: private + encoding: UTF-8 + links: + - http://shareisland.org + + caps: + categorymappings: + - {id: 32, cat: Other, desc: "Vip"} + - {id: 45, cat: XXX, desc: "Vip XXX"} + - {id: 33, cat: Other, desc: "ex Vip"} + - {id: 1, cat: Movies, desc: "Movies"} + - {id: 49, cat: Movies/HD, desc: "H-264"} + - {id: 51, cat: Movies/HD, desc: "H-265"} + - {id: 41, cat: Movies/Other, desc: "Cartoons"} + - {id: 14, cat: Movies/SD, desc: "DivX"} + - {id: 16, cat: Movies/Other, desc: "Cine News"} + - {id: 39, cat: Movies/HD, desc: "720p"} + - {id: 40, cat: Movies/HD, desc: "1080p"} + - {id: 46, cat: Movies/BluRay, desc: "Blu Ray Disk"} + - {id: 31, cat: Movies/HD, desc: "BDRip"} + - {id: 17, cat: Movies/DVD, desc: "DVD"} + - {id: 43, cat: Movies/SD, desc: "DVDRip"} + - {id: 6, cat: PC, desc: "Applications"} + - {id: 18, cat: PC/0day, desc: "PC Applications"} + - {id: 19, cat: PC/Mac, desc: "Macintosh Applications"} + - {id: 44, cat: PC/Phone-Android, desc: "Android applications"} + - {id: 7, cat: Audio, desc: "Music"} + - {id: 20, cat: Audio/Video, desc: "Video"} + - {id: 21, cat: Audio/MP3, desc: "Mp3"} + - {id: 2, cat: Console, desc: "Games"} + - {id: 3, cat: Console/PS4, desc: "Sony PS"} + - {id: 4, cat: Console/Wii, desc: "Wii"} + - {id: 26, cat: Console/Xbox, desc: "XboX"} + - {id: 27, cat: PC/Games, desc: "PC"} + - {id: 28, cat: Console/NDS, desc: "Nintendo"} + - {id: 34, cat: Books, desc: "Edicola"} + - {id: 52, cat: Books, desc: "Quotidiani"} + - {id: 53, cat: Books, desc: "Libreria"} + - {id: 35, cat: TV, desc: "SerieTV"} + - {id: 55, cat: TV/HD, desc: "Serie Tv HD"} + - {id: 36, cat: Other, desc: "Rip By ShareIsland"} + - {id: 47, cat: Other, desc: "Disclaimer"} + - {id: 48, cat: Other, desc: "P2P network "} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /ajax/login.php + method: post + form: form + inputs: + loginbox_membername: "{{ .Config.username }}" + loginbox_password: "{{ .Config.password }}" + action: "login" + loginbox_remember: "true" + error: + - selector: div.error + test: + path: /?p=home&pid=1 + selector: div#member_info_bar + + ratio: + path: /?p=home&pid=1 + selector: img[title="Ratio"] + span + + search: + path: / + keywordsfilters: + # most ITA TV torrents are in XXxYY format, so we search without S/E prefixes and filter later + - name: re_replace + args: ["S0?(\\d{1,2})", " $1 "] + - name: re_replace + args: ["E(\\d{2,3})", " $1 "] + - name: re_replace + args: ["[^a-zA-Z0-9]+", "%25"] + inputs: + p: "torrents" + pid: "32" + $raw: "{{range .Categories}}cid[]={{.}}&{{end}}" + keywords: "{{ .Keywords }}" + search_type: "name" + searchin: "title" + + rows: + selector: table#torrents_table_classic > tbody > tr:not([id="torrents_table_classic_head"]) + filters: + - name: andmatch + fields: + title: + selector: td.torrent_name > a + filters: + # normalize to SXXEYY format + - name: re_replace + args: ["(\\d{2})x(\\d{2})", "S$1E$2"] + - name: re_replace + args: ["(\\d{1})x(\\d{2})", "S0$1E$2"] + category: + selector: div.category_image > a + attribute: href + filters: + - name: querystring + args: cid + comments: + selector: td.torrent_name > a + attribute: href + download: + selector: a:has(img[title="Download Torrent"]) + attribute: href + size: + selector: td.size + seeders: + selector: td.seeders + leechers: + selector: td.leechers + grabs: + selector: td.completed + downloadvolumefactor: + case: + "img[title=\"FREE!\"]": "0" + "img[title=\"Download Multiplier: 0.5\"]": "0.5" + "img[title=\"Moltiplicatore Download: 0.5\"]": "0.5" + "*": "1" + uploadvolumefactor: + case: + "img[title=\"Upload Multiplier: 3\"]": "3" + "img[title=\"Upload Multiplier: 2\"]": "2" + "img[title=\"Upload Multiplier: 1.5\"]": "1.5" + "img[title=\"Moltiplicatore Upload: 3\"]": "3" + "img[title=\"Moltiplicatore Upload: 2\"]": "2" + "img[title=\"Moltiplicatore Upload: 1.5\"]": "1.5" + "*": "1" + date: + selector: td.torrent_name + remove: a, span, div, br + filters: + - name: replace + args: ["Uploaded ", ""] + - name: replace + args: [" by", ""] + - name: replace + args: [" at", ""] + - name: replace + args: ["Oggi", "Today"] + - name: replace + args: ["Ieri", "Yesterday"] + - name: replace + args: ["lunedì", "Monday"] + - name: replace + args: ["martedì", "Tuesday"] + - name: replace + args: ["Mercoledì", "Wednesday"] + - name: replace + args: ["Giovedì", "Thursday"] + - name: replace + args: ["Venerdì", "Friday"] + - name: replace + args: ["Sabato", "Saturday"] + - name: replace + args: ["Domenica", "Sunday"] + - name: replace + args: [" alle", ""] + - name: dateparse + args: "02-01-2006 15:04" diff --git a/src/Jackett/Definitions/sharespacedb.yml b/src/Jackett/Definitions/sharespacedb.yml index c86af3f0..5039424b 100644 --- a/src/Jackett/Definitions/sharespacedb.yml +++ b/src/Jackett/Definitions/sharespacedb.yml @@ -1,156 +1,156 @@ ---- - site: sharespacedb - name: ShareSpaceDB - description: "A French gerneral tracker" - language: fr-fr - type: private - encoding: UTF-8 - links: - - https://ssdb.me/ - - caps: - categorymappings: - - {id: 50, cat: TV/Anime, desc: "Anime: Tout"} - - {id: 40, cat: PC, desc: "Apps: Windows"} - - {id: 41, cat: PC/Mac, desc: "Apps: Mac"} - - {id: 42, cat: PC/Phone-Android, desc: "Apps: Android"} - - {id: 43, cat: PC/Phone-IOS, desc: "Apps: Ipod/Iphone"} - - {id: 44, cat: PC, desc: "Apps: Autres"} - - {id: 45, cat: PC, desc: "Apps: Linux"} - - {id: 27, cat: Books, desc: "E-Books: Livres"} - - {id: 28, cat: Books, desc: "E-Books: Audio"} - - {id: 29, cat: Books/Comics, desc: "E-Books: Comics"} - - {id: 30, cat: Books, desc: "E-Books: Mangas"} - - {id: 32, cat: Books, desc: "E-Books: Bds"} - - {id: 31, cat: Books, desc: "E-Books: Presse"} - - {id: 63, cat: Books, desc: "E-Books: ePUB"} - - {id: 1, cat: Movies/SD, desc: "Films: DVDRip"} - - {id: 2, cat: Movies/SD, desc: "Films: DVDRip VOSTFR"} - - {id: 3, cat: Movies/DVD, desc: "Films: DVD-R"} - - {id: 4, cat: Movies/HD, desc: "Films: 720p"} - - {id: 5, cat: Movies/HD, desc: "Films: 1080p"} - - {id: 6, cat: Movies/BluRay, desc: "Films: BluRay x264 et x265"} - - {id: 7, cat: Movies/3D, desc: "Films: BluRay-3D"} - - {id: 11, cat: Movies/HD, desc: "Films: BDRip"} - - {id: 9, cat: Movies/DVD, desc: "Films: R5"} - - {id: 10, cat: Movies/SD, desc: "Films: DVDSCR"} - - {id: 56, cat: Movies/HD, desc: "Films: mHD"} - - {id: 12, cat: Movies/HD, desc: "Films: BRRip"} - - {id: 13, cat: Movies/HD, desc: "Films: WEBRip"} - - {id: 58, cat: Movies/HD, desc: "Films: WEBRip 720p"} - - {id: 59, cat: Movies/HD, desc: "Films: WEBRip 1080p"} - - {id: 8, cat: Movies/SD, desc: "Films: Cam / TS"} - - {id: 62, cat: Movies/HD, desc: "Films: Uhd4k"} - - {id: 35, cat: Console/Xbox, desc: "Jeux: XBOX"} - - {id: 36, cat: Console/Wii, desc: "Jeux: WII"} - - {id: 37, cat: Console/PSP, desc: "Jeux: PSP"} - - {id: 38, cat: Console/NDS, desc: "Jeux: DS"} - - {id: 39, cat: PC/Phone-Android, desc: "Jeux: Android"} - - {id: 34, cat: Console/PS3, desc: "Jeux: PS3"} - - {id: 55, cat: PC/Mac, desc: "Jeux: Mac"} - - {id: 33, cat: PC/Games, desc: "Jeux: PC"} - - {id: 46, cat: Audio/MP3, desc: "Musiques: MP3"} - - {id: 47, cat: Audio/Lossless, desc: "Musiques: FLAC"} - - {id: 48, cat: Audio, desc: "Musiques: WMA"} - - {id: 49, cat: Audio, desc: "Musiques: Autres"} - - {id: 14, cat: TV/SD, desc: "Series: HDTV"} - - {id: 15, cat: TV, desc: "Series: TV VOSTFR"} - - {id: 16, cat: TV, desc: "Series: TV VOSTA"} - - {id: 17, cat: TV, desc: "Series: TV PACK"} - - {id: 18, cat: TV/HD, desc: "Series: HDTV 1080p"} - - {id: 57, cat: TV/HD, desc: "Series: TVHD VOSTFR"} - - {id: 20, cat: TV, desc: "Series: TV VO"} - - {id: 19, cat: TV/HD, desc: "Series: HDTV 720p"} - - {id: 64, cat: TV/SD, desc: "Series: WEBRip"} - - {id: 60, cat: TV/HD, desc: "Series: WEBRip 720p"} - - {id: 61, cat: TV/HD, desc: "Series: WEBRip 1080p"} - - {id: 21, cat: TV/SD, desc: "Series: DVD-R TV"} - - {id: 26, cat: TV, desc: "Television: Television"} - - {id: 24, cat: TV, desc: "Television: Spectacles"} - - {id: 23, cat: TV/Sport, desc: "Television: Sports"} - - {id: 25, cat: TV/Anime, desc: "Television: Animes"} - - {id: 22, cat: TV/Documentary, desc: "Television: Documentaires"} - - {id: 51, cat: XXX, desc: "XXX: Tous"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: account-login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - remember: "yes" - returnto: "/" - error: - - selector: div#nfobar > p#msgError - test: - path: torrents-search.php - - ratio: - path: torrents-search.php - selector: div#infobar0 > ul > li:nth-child(1) > font:last-child - - search: - path: torrents-search.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - - rows: - selector: table.ttable_headinner > tbody > tr.t-row - filters: - - name: andmatch - after: 1 - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: a[href^="torrents-details.php?id="] - attribute: title - category: - selector: a[href^="torrents.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="torrents-details.php?id="] - attribute: href - comments: - selector: a[href^="comments.php"] - attribute: href - banner: - selector: a[onmouseover][href^="torrents-details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: <td align=left><img src=(.*?) width - size: - selector: td:nth-child(7) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - date: - selector: small > i - filters: - - name: replace - args: ["Date: ", ""] - - name: replace - args: ["le ", ""] - - name: dateparse - args: "15:04:05 02-01-2006" - downloadvolumefactor: - case: - img[src="images/free.gif"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: sharespacedb + name: ShareSpaceDB + description: "A French gerneral tracker" + language: fr-fr + type: private + encoding: UTF-8 + links: + - https://ssdb.me/ + + caps: + categorymappings: + - {id: 50, cat: TV/Anime, desc: "Anime: Tout"} + - {id: 40, cat: PC, desc: "Apps: Windows"} + - {id: 41, cat: PC/Mac, desc: "Apps: Mac"} + - {id: 42, cat: PC/Phone-Android, desc: "Apps: Android"} + - {id: 43, cat: PC/Phone-IOS, desc: "Apps: Ipod/Iphone"} + - {id: 44, cat: PC, desc: "Apps: Autres"} + - {id: 45, cat: PC, desc: "Apps: Linux"} + - {id: 27, cat: Books, desc: "E-Books: Livres"} + - {id: 28, cat: Books, desc: "E-Books: Audio"} + - {id: 29, cat: Books/Comics, desc: "E-Books: Comics"} + - {id: 30, cat: Books, desc: "E-Books: Mangas"} + - {id: 32, cat: Books, desc: "E-Books: Bds"} + - {id: 31, cat: Books, desc: "E-Books: Presse"} + - {id: 63, cat: Books, desc: "E-Books: ePUB"} + - {id: 1, cat: Movies/SD, desc: "Films: DVDRip"} + - {id: 2, cat: Movies/SD, desc: "Films: DVDRip VOSTFR"} + - {id: 3, cat: Movies/DVD, desc: "Films: DVD-R"} + - {id: 4, cat: Movies/HD, desc: "Films: 720p"} + - {id: 5, cat: Movies/HD, desc: "Films: 1080p"} + - {id: 6, cat: Movies/BluRay, desc: "Films: BluRay x264 et x265"} + - {id: 7, cat: Movies/3D, desc: "Films: BluRay-3D"} + - {id: 11, cat: Movies/HD, desc: "Films: BDRip"} + - {id: 9, cat: Movies/DVD, desc: "Films: R5"} + - {id: 10, cat: Movies/SD, desc: "Films: DVDSCR"} + - {id: 56, cat: Movies/HD, desc: "Films: mHD"} + - {id: 12, cat: Movies/HD, desc: "Films: BRRip"} + - {id: 13, cat: Movies/HD, desc: "Films: WEBRip"} + - {id: 58, cat: Movies/HD, desc: "Films: WEBRip 720p"} + - {id: 59, cat: Movies/HD, desc: "Films: WEBRip 1080p"} + - {id: 8, cat: Movies/SD, desc: "Films: Cam / TS"} + - {id: 62, cat: Movies/HD, desc: "Films: Uhd4k"} + - {id: 35, cat: Console/Xbox, desc: "Jeux: XBOX"} + - {id: 36, cat: Console/Wii, desc: "Jeux: WII"} + - {id: 37, cat: Console/PSP, desc: "Jeux: PSP"} + - {id: 38, cat: Console/NDS, desc: "Jeux: DS"} + - {id: 39, cat: PC/Phone-Android, desc: "Jeux: Android"} + - {id: 34, cat: Console/PS3, desc: "Jeux: PS3"} + - {id: 55, cat: PC/Mac, desc: "Jeux: Mac"} + - {id: 33, cat: PC/Games, desc: "Jeux: PC"} + - {id: 46, cat: Audio/MP3, desc: "Musiques: MP3"} + - {id: 47, cat: Audio/Lossless, desc: "Musiques: FLAC"} + - {id: 48, cat: Audio, desc: "Musiques: WMA"} + - {id: 49, cat: Audio, desc: "Musiques: Autres"} + - {id: 14, cat: TV/SD, desc: "Series: HDTV"} + - {id: 15, cat: TV, desc: "Series: TV VOSTFR"} + - {id: 16, cat: TV, desc: "Series: TV VOSTA"} + - {id: 17, cat: TV, desc: "Series: TV PACK"} + - {id: 18, cat: TV/HD, desc: "Series: HDTV 1080p"} + - {id: 57, cat: TV/HD, desc: "Series: TVHD VOSTFR"} + - {id: 20, cat: TV, desc: "Series: TV VO"} + - {id: 19, cat: TV/HD, desc: "Series: HDTV 720p"} + - {id: 64, cat: TV/SD, desc: "Series: WEBRip"} + - {id: 60, cat: TV/HD, desc: "Series: WEBRip 720p"} + - {id: 61, cat: TV/HD, desc: "Series: WEBRip 1080p"} + - {id: 21, cat: TV/SD, desc: "Series: DVD-R TV"} + - {id: 26, cat: TV, desc: "Television: Television"} + - {id: 24, cat: TV, desc: "Television: Spectacles"} + - {id: 23, cat: TV/Sport, desc: "Television: Sports"} + - {id: 25, cat: TV/Anime, desc: "Television: Animes"} + - {id: 22, cat: TV/Documentary, desc: "Television: Documentaires"} + - {id: 51, cat: XXX, desc: "XXX: Tous"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: account-login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + remember: "yes" + returnto: "/" + error: + - selector: div#nfobar > p#msgError + test: + path: torrents-search.php + + ratio: + path: torrents-search.php + selector: div#infobar0 > ul > li:nth-child(1) > font:last-child + + search: + path: torrents-search.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + + rows: + selector: table.ttable_headinner > tbody > tr.t-row + filters: + - name: andmatch + after: 1 + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: a[href^="torrents-details.php?id="] + attribute: title + category: + selector: a[href^="torrents.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="torrents-details.php?id="] + attribute: href + comments: + selector: a[href^="comments.php"] + attribute: href + banner: + selector: a[onmouseover][href^="torrents-details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: <td align=left><img src=(.*?) width + size: + selector: td:nth-child(7) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + date: + selector: small > i + filters: + - name: replace + args: ["Date: ", ""] + - name: replace + args: ["le ", ""] + - name: dateparse + args: "15:04:05 02-01-2006" + downloadvolumefactor: + case: + img[src="images/free.gif"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/shellife.yml b/src/Jackett/Definitions/shellife.yml index 4f49e7fa..0b091e93 100644 --- a/src/Jackett/Definitions/shellife.yml +++ b/src/Jackett/Definitions/shellife.yml @@ -1,81 +1,81 @@ ---- - site: shellife - name: Shellife - language: en-us - type: private - encoding: UTF-8 - links: - - https://shellife.eu/ - - caps: - categories: - 1: Audio - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td:has(h2:contains("failed")) - test: - path: browse.php - - search: - path: browse.php - inputs: - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: table#ct > tbody > tr.torrent_row - filters: - - name: andmatch - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: a.altlink - title|append|1: - text: " - " - title|append|2: - selector: a[name] - details: - selector: a[name] - attribute: href - filters: - - name: replace - args: ["#", "/details.php?id="] - category: - text: 1 - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - grabs: - selector: td:nth-child(6) - size: - selector: td:nth-child(5) - downloadvolumefactor: - case: - img[alt="Freeleech"]: "0" - img[alt="Free"]: "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" - description: - selector: td:nth-child(2) - remove: a.altlink, a[name], div[id^="news"] - filters: - - name: trim - args: "-" - - name: trim - args: " " - +--- + site: shellife + name: Shellife + language: en-us + type: private + encoding: UTF-8 + links: + - https://shellife.eu/ + + caps: + categories: + 1: Audio + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td:has(h2:contains("failed")) + test: + path: browse.php + + search: + path: browse.php + inputs: + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: table#ct > tbody > tr.torrent_row + filters: + - name: andmatch + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: a.altlink + title|append|1: + text: " - " + title|append|2: + selector: a[name] + details: + selector: a[name] + attribute: href + filters: + - name: replace + args: ["#", "/details.php?id="] + category: + text: 1 + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + grabs: + selector: td:nth-child(6) + size: + selector: td:nth-child(5) + downloadvolumefactor: + case: + img[alt="Freeleech"]: "0" + img[alt="Free"]: "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" + description: + selector: td:nth-child(2) + remove: a.altlink, a[name], div[id^="news"] + filters: + - name: trim + args: "-" + - name: trim + args: " " + \ No newline at end of file diff --git a/src/Jackett/Definitions/skytorrents.yml b/src/Jackett/Definitions/skytorrents.yml index d038155d..c422dd4e 100644 --- a/src/Jackett/Definitions/skytorrents.yml +++ b/src/Jackett/Definitions/skytorrents.yml @@ -1,58 +1,58 @@ ---- - site: skytorrents - name: Sky torrents - language: en-us - type: public - encoding: UTF-8 - links: - - https://www.skytorrents.in/ - - caps: - categories: - TV: TV - Movies: Movies - - modes: - search: [q] - tv-search: [q, season, ep] - - settings: [] - - search: - path: "search/all/{{if .Query.Keywords}}ed{{else}}ad{{end}}/1/{{ .Query.Keywords}}" - rows: - selector: "table > tbody > tr" - filters: - - name: andmatch - fields: - title: - selector: td:nth-child(1) > a:first-child[title] - attribute: title - details: - selector: td:nth-child(1) > a:first-child - attribute: href - size: - selector: td:nth-child(2) - files: - selector: td:nth-child(3) - seeders: - selector: td:nth-child(5) - leechers: - selector: td:nth-child(6) - description: - selector: td:nth-child(1) - case: - img[title="Verified and marked"]: "Verified and marked" - "*": "" - date: - selector: td:nth-child(4) - filters: - - name: dateparse - args: "01-02-2006" - download: - selector: td > a[href^="/file"] - attribute: href - downloadvolumefactor: - text: "0" - uploadvolumefactor: +--- + site: skytorrents + name: Sky torrents + language: en-us + type: public + encoding: UTF-8 + links: + - https://www.skytorrents.in/ + + caps: + categories: + TV: TV + Movies: Movies + + modes: + search: [q] + tv-search: [q, season, ep] + + settings: [] + + search: + path: "search/all/{{if .Query.Keywords}}ed{{else}}ad{{end}}/1/{{ .Query.Keywords}}" + rows: + selector: "table > tbody > tr" + filters: + - name: andmatch + fields: + title: + selector: td:nth-child(1) > a:first-child[title] + attribute: title + details: + selector: td:nth-child(1) > a:first-child + attribute: href + size: + selector: td:nth-child(2) + files: + selector: td:nth-child(3) + seeders: + selector: td:nth-child(5) + leechers: + selector: td:nth-child(6) + description: + selector: td:nth-child(1) + case: + img[title="Verified and marked"]: "Verified and marked" + "*": "" + date: + selector: td:nth-child(4) + filters: + - name: dateparse + args: "01-02-2006" + download: + selector: td > a[href^="/file"] + attribute: href + downloadvolumefactor: + text: "0" + uploadvolumefactor: text: "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/tasmanit.yml b/src/Jackett/Definitions/tasmanit.yml index 3f615056..87e7df86 100755 --- a/src/Jackett/Definitions/tasmanit.yml +++ b/src/Jackett/Definitions/tasmanit.yml @@ -1,109 +1,109 @@ ---- - site: tasmanit - name: Tasmanit - language: en-us - type: private - encoding: UTF-8 - links: - - https://tasmanit.es - - caps: - categorymappings: - - {id: 72, cat: TV, desc: "All Australian TV"} - - {id: 23, cat: TV, desc: "AU-AUTOGEN"} - - {id: 8, cat: TV, desc: "Australian Comedy"} - - {id: 18, cat: TV, desc: "Australian Crime Shows"} - - {id: 14, cat: TV, desc: "Australian Documentaries"} - - {id: 9, cat: TV, desc: "Australian Dramas"} - - {id: 10, cat: TV, desc: "Australian Game/Quiz Shows"} - - {id: 12, cat: TV, desc: "Australian Kids Shows"} - - {id: 21, cat: TV, desc: "Australian Lifestyle TV"} - - {id: 11, cat: TV, desc: "Aussie News and Current Affairs"} - - {id: 76, cat: TV/Other, desc: "Australian TV Other"} - - {id: 15, cat: TV, desc: "Australian Real Crime"} - - {id: 13, cat: TV, desc: "Australian Reality TV"} - - {id: 17, cat: TV, desc: "Australian Science Shows"} - - {id: 80, cat: TV, desc: "Australian Soaps"} - - {id: 16, cat: TV, desc: "Australian Talkshows"} - - {id: 22, cat: TV, desc: "Australian Movies"} - - {id: 73, cat: TV, desc: "New Zealand TV"} - - {id: 61, cat: TV, desc: "NZ-AUTOGEN"} - - {id: 47, cat: TV, desc: "New Zealand Comedy"} - - {id: 58, cat: TV, desc: "New Zealand Crime Shows"} - - {id: 53, cat: TV, desc: "New Zealand Documentaries"} - - {id: 48, cat: TV, desc: "New Zealand Dramas"} - - {id: 49, cat: TV, desc: "New Zealand Game/Quiz Shows"} - - {id: 51, cat: TV, desc: "New Zealand Kids Shows"} - - {id: 56, cat: TV, desc: "New Zealand Lifestyle TV"} - - {id: 50, cat: TV, desc: "New Zealand News and Current Affairs"} - - {id: 60, cat: TV, desc: "New Zealand Real Crime"} - - {id: 52, cat: TV, desc: "New Zealand Reality TV"} - - {id: 54, cat: TV, desc: "New Zealand Science Shows"} - - {id: 81, cat: TV, desc: "New Zealand Soaps"} - - {id: 57, cat: TV, desc: "New Zealand Talkshows"} - - {id: 59, cat: TV, desc: "New Zealand Movies"} - - {id: 36, cat: TV, desc: "New Zealand TV"} - - {id: 55, cat: TV, desc: "SATV - All"} - - {id: 55, cat: TV, desc: "South African TV"} - - {id: 7, cat: TV/Other, desc: "New Zealand TV Other"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: form - form: form[action="takelogin.php"] - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div#content:has(h2:contains("Login Failed")) - test: - path: browse.php - - search: - path: browse.php - method: post - inputs: - do: "search" - keywords: "{{ .Keywords }}" - search_type: "t_name" - include_dead_torrents: "yes" - rows: - selector: table#sortabletable > tbody > tr:has(a[href]) - fields: - title: - selector: td:nth-child(2) a - category: - selector: a[href^="https://tasmanit.es/browse.php?category="] - attribute: href - filters: - - name: querystring - args: category - details: - selector: a[href^="https://tasmanit.es/details.php?id="] - attribute: href - download: - selector: a[href^="https://tasmanit.es/details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php", "download.php"] - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - date: - selector: td:nth-child(2) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: tasmanit + name: Tasmanit + language: en-us + type: private + encoding: UTF-8 + links: + - https://tasmanit.es + + caps: + categorymappings: + - {id: 72, cat: TV, desc: "All Australian TV"} + - {id: 23, cat: TV, desc: "AU-AUTOGEN"} + - {id: 8, cat: TV, desc: "Australian Comedy"} + - {id: 18, cat: TV, desc: "Australian Crime Shows"} + - {id: 14, cat: TV, desc: "Australian Documentaries"} + - {id: 9, cat: TV, desc: "Australian Dramas"} + - {id: 10, cat: TV, desc: "Australian Game/Quiz Shows"} + - {id: 12, cat: TV, desc: "Australian Kids Shows"} + - {id: 21, cat: TV, desc: "Australian Lifestyle TV"} + - {id: 11, cat: TV, desc: "Aussie News and Current Affairs"} + - {id: 76, cat: TV/Other, desc: "Australian TV Other"} + - {id: 15, cat: TV, desc: "Australian Real Crime"} + - {id: 13, cat: TV, desc: "Australian Reality TV"} + - {id: 17, cat: TV, desc: "Australian Science Shows"} + - {id: 80, cat: TV, desc: "Australian Soaps"} + - {id: 16, cat: TV, desc: "Australian Talkshows"} + - {id: 22, cat: TV, desc: "Australian Movies"} + - {id: 73, cat: TV, desc: "New Zealand TV"} + - {id: 61, cat: TV, desc: "NZ-AUTOGEN"} + - {id: 47, cat: TV, desc: "New Zealand Comedy"} + - {id: 58, cat: TV, desc: "New Zealand Crime Shows"} + - {id: 53, cat: TV, desc: "New Zealand Documentaries"} + - {id: 48, cat: TV, desc: "New Zealand Dramas"} + - {id: 49, cat: TV, desc: "New Zealand Game/Quiz Shows"} + - {id: 51, cat: TV, desc: "New Zealand Kids Shows"} + - {id: 56, cat: TV, desc: "New Zealand Lifestyle TV"} + - {id: 50, cat: TV, desc: "New Zealand News and Current Affairs"} + - {id: 60, cat: TV, desc: "New Zealand Real Crime"} + - {id: 52, cat: TV, desc: "New Zealand Reality TV"} + - {id: 54, cat: TV, desc: "New Zealand Science Shows"} + - {id: 81, cat: TV, desc: "New Zealand Soaps"} + - {id: 57, cat: TV, desc: "New Zealand Talkshows"} + - {id: 59, cat: TV, desc: "New Zealand Movies"} + - {id: 36, cat: TV, desc: "New Zealand TV"} + - {id: 55, cat: TV, desc: "SATV - All"} + - {id: 55, cat: TV, desc: "South African TV"} + - {id: 7, cat: TV/Other, desc: "New Zealand TV Other"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: form + form: form[action="takelogin.php"] + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div#content:has(h2:contains("Login Failed")) + test: + path: browse.php + + search: + path: browse.php + method: post + inputs: + do: "search" + keywords: "{{ .Keywords }}" + search_type: "t_name" + include_dead_torrents: "yes" + rows: + selector: table#sortabletable > tbody > tr:has(a[href]) + fields: + title: + selector: td:nth-child(2) a + category: + selector: a[href^="https://tasmanit.es/browse.php?category="] + attribute: href + filters: + - name: querystring + args: category + details: + selector: a[href^="https://tasmanit.es/details.php?id="] + attribute: href + download: + selector: a[href^="https://tasmanit.es/details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php", "download.php"] + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + date: + selector: td:nth-child(2) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/tenyardtracker.yml b/src/Jackett/Definitions/tenyardtracker.yml index 07ff6f71..ebbdcd3a 100644 --- a/src/Jackett/Definitions/tenyardtracker.yml +++ b/src/Jackett/Definitions/tenyardtracker.yml @@ -1,74 +1,74 @@ ---- - site: tenyardtracker - name: TenYardTracker - description: "An American football tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://tenyardtracker.com/ - - caps: - categories: - 1: TV # Sports - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: members.php?action=takelogin - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div:contains("Login Failed") - test: - path: my.php - #error: - #- path: members.php?action=takelogin - test: - path: my.php - #selector: a[href="members.php?action=logout"] - - ratio: - path: browse.php - selector: #status_bar - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table[border="1"] tr:not(:first-child) - fields: - category: - text: 1 - title: - selector: td:nth-child(2) - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?torrent="] - details: - selector: a[href^="details.php?id="] - attribute: href - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(5) - size: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: +--- + site: tenyardtracker + name: TenYardTracker + description: "An American football tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://tenyardtracker.com/ + + caps: + categories: + 1: TV # Sports + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: members.php?action=takelogin + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div:contains("Login Failed") + test: + path: my.php + #error: + #- path: members.php?action=takelogin + test: + path: my.php + #selector: a[href="members.php?action=logout"] + + ratio: + path: browse.php + selector: #status_bar + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table[border="1"] tr:not(:first-child) + fields: + category: + text: 1 + title: + selector: td:nth-child(2) + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?torrent="] + details: + selector: a[href^="details.php?id="] + attribute: href + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(5) + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/theempire.yml b/src/Jackett/Definitions/theempire.yml index 35310c0c..2dbc5c2c 100644 --- a/src/Jackett/Definitions/theempire.yml +++ b/src/Jackett/Definitions/theempire.yml @@ -1,121 +1,121 @@ ---- - site: theempire - name: The Empire - description: "Commonwealth television" - language: en-us - type: private - encoding: UTF-8 - links: - - http://www.theempire.bz/ - - caps: - categorymappings: - - {id: 55, cat: TV, desc: "Adverts"} - - {id: 60, cat: TV, desc: "Educational"} - - {id: 63, cat: TV, desc: "Game Shows"} - - {id: 67, cat: TV, desc: "Music"} - - {id: 72, cat: TV, desc: "QuizComedy"} - - {id: 77, cat: TV, desc: "Special Events"} - - {id: 81, cat: TV, desc: "Trains & Planes"} - - {id: 54, cat: TV, desc: "Arts & Culture"} - - {id: 61, cat: TV, desc: "Entertainment"} - - {id: 53, cat: TV, desc: "Gardening"} - - {id: 68, cat: TV, desc: "Mystery & Crime Fiction"} - - {id: 73, cat: TV, desc: "Radio"} - - {id: 78, cat: TV, desc: "Special Interest"} - - {id: 82, cat: TV, desc: "Travel"} - - {id: 56, cat: TV, desc: "Comedy"} - - {id: 85, cat: TV, desc: "Euro-Noir"} - - {id: 64, cat: TV, desc: "Kids"} - - {id: 69, cat: TV, desc: "News"} - - {id: 74, cat: TV, desc: "Reality"} - - {id: 79, cat: TV, desc: "Sport"} - - {id: 83, cat: TV, desc: "Wildlife & Nature"} - - {id: 58, cat: TV, desc: "Documentary"} - - {id: 57, cat: TV, desc: "Fly on the Wall/Lifestyle"} - - {id: 65, cat: TV, desc: "Magazine"} - - {id: 70, cat: TV, desc: "Occult & Horror"} - - {id: 75, cat: TV, desc: "Sci-Fi"} - - {id: 84, cat: TV, desc: "Style & Fashion"} - - {id: 62, cat: TV, desc: "Food Drink & Cooking"} - - {id: 66, cat: TV, desc: "Motoring"} - - {id: 71, cat: TV, desc: "Property"} - - {id: 76, cat: TV, desc: "Soaps"} - - {id: 80, cat: TV, desc: "Talkshow"} - - {id: 59, cat: TV, desc: "Drama"} - - modes: - search: [q] - - login: - path: /login.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - captcha: - type: image - image: img#freecap - input: word - error: - - selector: table:contains("Login failed!") - test: - path: main.php - - download: - selector: a[href^="download.php"] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - search: "{{ .Query.Keywords }}" - rows: - selector: table[border="0"] > tbody > tr.ttable:has(a[href^="browse.php?cat="]) - fields: - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - title: - filters: - selector: td:nth-child(2) b - download: - selector: a[href^="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php?id=", "download.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - grabs: - selector: td:nth-child(8) - filters: - - name: regexp - args: ([\d,]+) - files: - selector: td:nth-child(4) - size: - selector: td:nth-child(7) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - date: - selector: td:nth-child(6) - filters: - - name: regexp - args: (\d{4}-\d{2}-\d{2}) - downloadvolumefactor: - case: - "font[color=\"green\"]": "0" - "font[color=\"blue\"]": "0" - "*": "1" - uploadvolumefactor: - case: - "font[color=\"green\"]": "0" +--- + site: theempire + name: The Empire + description: "Commonwealth television" + language: en-us + type: private + encoding: UTF-8 + links: + - http://www.theempire.bz/ + + caps: + categorymappings: + - {id: 55, cat: TV, desc: "Adverts"} + - {id: 60, cat: TV, desc: "Educational"} + - {id: 63, cat: TV, desc: "Game Shows"} + - {id: 67, cat: TV, desc: "Music"} + - {id: 72, cat: TV, desc: "QuizComedy"} + - {id: 77, cat: TV, desc: "Special Events"} + - {id: 81, cat: TV, desc: "Trains & Planes"} + - {id: 54, cat: TV, desc: "Arts & Culture"} + - {id: 61, cat: TV, desc: "Entertainment"} + - {id: 53, cat: TV, desc: "Gardening"} + - {id: 68, cat: TV, desc: "Mystery & Crime Fiction"} + - {id: 73, cat: TV, desc: "Radio"} + - {id: 78, cat: TV, desc: "Special Interest"} + - {id: 82, cat: TV, desc: "Travel"} + - {id: 56, cat: TV, desc: "Comedy"} + - {id: 85, cat: TV, desc: "Euro-Noir"} + - {id: 64, cat: TV, desc: "Kids"} + - {id: 69, cat: TV, desc: "News"} + - {id: 74, cat: TV, desc: "Reality"} + - {id: 79, cat: TV, desc: "Sport"} + - {id: 83, cat: TV, desc: "Wildlife & Nature"} + - {id: 58, cat: TV, desc: "Documentary"} + - {id: 57, cat: TV, desc: "Fly on the Wall/Lifestyle"} + - {id: 65, cat: TV, desc: "Magazine"} + - {id: 70, cat: TV, desc: "Occult & Horror"} + - {id: 75, cat: TV, desc: "Sci-Fi"} + - {id: 84, cat: TV, desc: "Style & Fashion"} + - {id: 62, cat: TV, desc: "Food Drink & Cooking"} + - {id: 66, cat: TV, desc: "Motoring"} + - {id: 71, cat: TV, desc: "Property"} + - {id: 76, cat: TV, desc: "Soaps"} + - {id: 80, cat: TV, desc: "Talkshow"} + - {id: 59, cat: TV, desc: "Drama"} + + modes: + search: [q] + + login: + path: /login.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + captcha: + type: image + image: img#freecap + input: word + error: + - selector: table:contains("Login failed!") + test: + path: main.php + + download: + selector: a[href^="download.php"] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + search: "{{ .Query.Keywords }}" + rows: + selector: table[border="0"] > tbody > tr.ttable:has(a[href^="browse.php?cat="]) + fields: + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + title: + filters: + selector: td:nth-child(2) b + download: + selector: a[href^="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php?id=", "download.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + grabs: + selector: td:nth-child(8) + filters: + - name: regexp + args: ([\d,]+) + files: + selector: td:nth-child(4) + size: + selector: td:nth-child(7) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + date: + selector: td:nth-child(6) + filters: + - name: regexp + args: (\d{4}-\d{2}-\d{2}) + downloadvolumefactor: + case: + "font[color=\"green\"]": "0" + "font[color=\"blue\"]": "0" + "*": "1" + uploadvolumefactor: + case: + "font[color=\"green\"]": "0" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/thehorrorcharnel.yml b/src/Jackett/Definitions/thehorrorcharnel.yml index 42257409..d59bded6 100644 --- a/src/Jackett/Definitions/thehorrorcharnel.yml +++ b/src/Jackett/Definitions/thehorrorcharnel.yml @@ -1,105 +1,105 @@ ---- - site: thehorrorcharnel - name: The Horror Charnel - description: "A Horror, Cult, Sleaze, Sci-Fi & more tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://horrorcharnel.org - - caps: - categories: - 1: Movies - 2: TV - - modes: - search: [q] - tv-search: [q, season, ep] - - settings: - - name: username - type: text - label: Username - - name: password - type: password - label: Password - - login: - path: loginto.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - use_sslvalue=: "on" - perm_ssl: "1" - returnto: "/" - error: - - selector: "div#base_content > table.mainouter > tbody > tr > td.outer > table.main > tbody > tr > td:has(h2)" - test: - path: usercp.php - - ratio: - path: /my.php - selector: td.navi_top:contains("Deine Ratio:") - filters: - - name: replace - args: ["Deine Ratio: ", ""] - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - - search: - path: /browse.php - inputs: - #$raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - - rows: - selector: p + table > tbody > tr:has(a[href^="details.php?id="]), p + table > tbody > tr[id^="kdescr"] - filters: - - name: andmatch - after: 1 - fields: - title: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: <b>(.*?)</b> - description: - selector: td[colspan="13"] - remove: a - category: - text: 1 - comments: - selector: a[onmouseover][href^="details.php"] - attribute: href - download: - selector: a[href^="download.php"] - attribute: href - files: - selector: td:nth-child(6) - size: - selector: td:nth-child(9) - seeders: - selector: td:nth-child(11) - leechers: - selector: td:nth-child(12) - date: - selector: td:nth-child(8) - grabs: - selector: td:nth-child(10) - filters: - - name: regexp - args: (\d+) - downloadvolumefactor: - case: - img[src="free.gif"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: thehorrorcharnel + name: The Horror Charnel + description: "A Horror, Cult, Sleaze, Sci-Fi & more tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://horrorcharnel.org + + caps: + categories: + 1: Movies + 2: TV + + modes: + search: [q] + tv-search: [q, season, ep] + + settings: + - name: username + type: text + label: Username + - name: password + type: password + label: Password + + login: + path: loginto.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + use_sslvalue=: "on" + perm_ssl: "1" + returnto: "/" + error: + - selector: "div#base_content > table.mainouter > tbody > tr > td.outer > table.main > tbody > tr > td:has(h2)" + test: + path: usercp.php + + ratio: + path: /my.php + selector: td.navi_top:contains("Deine Ratio:") + filters: + - name: replace + args: ["Deine Ratio: ", ""] + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + + search: + path: /browse.php + inputs: + #$raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + + rows: + selector: p + table > tbody > tr:has(a[href^="details.php?id="]), p + table > tbody > tr[id^="kdescr"] + filters: + - name: andmatch + after: 1 + fields: + title: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: <b>(.*?)</b> + description: + selector: td[colspan="13"] + remove: a + category: + text: 1 + comments: + selector: a[onmouseover][href^="details.php"] + attribute: href + download: + selector: a[href^="download.php"] + attribute: href + files: + selector: td:nth-child(6) + size: + selector: td:nth-child(9) + seeders: + selector: td:nth-child(11) + leechers: + selector: td:nth-child(12) + date: + selector: td:nth-child(8) + grabs: + selector: td:nth-child(10) + filters: + - name: regexp + args: (\d+) + downloadvolumefactor: + case: + img[src="free.gif"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/theshinning.yml b/src/Jackett/Definitions/theshinning.yml index 1843c9fa..57bd3f83 100644 --- a/src/Jackett/Definitions/theshinning.yml +++ b/src/Jackett/Definitions/theshinning.yml @@ -1,157 +1,157 @@ ---- - site: theshinning - name: The Shinning - description: "A German gerneral tracker" - language: de-de - type: private - encoding: windows-1252 - links: - - https://theshinning.org - - caps: - categorymappings: - # Filme - - {id: 28, cat: Movies/SD, desc: "HORROR"} - - {id: 25, cat: Movies/DVD, desc: "SD|DVD"} - - {id: 99, cat: Movies/SD, desc: "SD|SPORT"} - - {id: 24, cat: Movies/SD, desc: "SD|x264"} - - {id: 22, cat: Movies/SD, desc: "SD|XVID"} - - {id: 26, cat: XXX, desc: "SD|XxX"} - - # High Definition - - {id: 29, cat: Movies/BluRay, desc: "BLURAY"} - - {id: 19, cat: Movies/HD, desc: "HD|1080p"} - - {id: 21, cat: Movies/3D, desc: "HD|3D"} - - {id: 107, cat: Movies/HD, desc: "HD|4K"} - - {id: 20, cat: Movies/HD, desc: "HD|720p"} - - {id: 101, cat: Movies/HD, desc: "HD|REMUX"} - - {id: 100, cat: Movies/HD, desc: "HD|SPORT"} - - {id: 27, cat: XXX, desc: "HD|XxX"} - - {id: 102, cat: Movies/HD, desc: "SMALL|HD"} - - # Musik - - {id: 13, cat: Audio, desc: "CHARTS"} - - {id: 31, cat: Audio/Lossless, desc: "FLAC"} - - {id: 97, cat: Audio/Audiobook, desc: "HOERSPIELE"} - - {id: 30, cat: Audio/MP3, desc: "MP3"} - - {id: 106, cat: Audio, desc: "SAMPLER"} - - # Releaser - - {id: 18, cat: Movies, desc: "CR3WHD"} - - {id: 16, cat: Movies, desc: "ONKEL JENS"} - - {id: 17, cat: Movies, desc: "xTM|XviD"} - - # Serie - - {id: 11, cat: TV/SD, desc: "DVD|SERIEN"} - - {id: 9, cat: TV/HD, desc: "HD|SERIEN"} - - {id: 32, cat: TV, desc: "MIXED|SERIEN"} - - {id: 10, cat: TV, desc: "PACK|SERIEN"} - - {id: 8, cat: TV/SD, desc: "SD|SERIEN"} - - {id: 105, cat: TV, desc: "SMALL|SERIE"} - - {id: 12, cat: TV, desc: "US|SERIEN"} - - # Sonstige - - {id: 98, cat: PC, desc: "APPS"} - - {id: 90, cat: TV/Documentary, desc: "DOKUS"} - - {id: 91, cat: Books, desc: "EBOOKS"} - - {id: 14, cat: Movies, desc: "KINOHITS"} - - {id: 15, cat: Other, desc: "REQUEST"} - - {id: 23, cat: Other , desc: "SONSTIGES"} - - {id: 104, cat: XXX/Imageset, desc: "XXX|IMAGE"} - - # Spiele - - {id: 96, cat: Console/NDS, desc: "GAMES|NDS"} - - {id: 92, cat: PC/Games, desc: "GAMES|PC"} - - {id: 94, cat: Console/PS4, desc: "GAMES|PS"} - - {id: 95, cat: Console/Wii, desc: "GAMES|WII"} - - {id: 93, cat: Console/Xbox, desc: "GAMES|XBOX"} - - # Wrestling - - {id: 3, cat: TV/Sport, desc: "HD|RAW"} - - {id: 1, cat: TV/Sport, desc: "HD|SMACKD"} - - {id: 6, cat: TV/Sport, desc: "NXT"} - - {id: 7, cat: TV/Sport, desc: "PPV"} - - {id: 4, cat: TV/Sport, desc: "SD|RAW"} - - {id: 2, cat: TV/Sport, desc: "SD|SMACKD"} - - {id: 5, cat: TV/Sport, desc: "TNA"} - - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /login.php - method: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.stderr_info_wrap - test: - path: /browse.php - selector: img[title="Ratio"] + i - - ratio: - path: /browse.php - selector: img[title="Ratio"] + i - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - showsearch: "1" - incldead: "1" - orderby: "added" - sort: "desc" - rows: - selector: table.main > tbody > tr:contains("Alle Torrents") + tr > td > table.tableinborder > tbody > tr - filters: - - name: andmatch - fields: - download: - selector: a[href^="download-ssl.php?torrent="] - attribute: href - title: - selector: div.title_wrap - attribute: title - filters: - - name: replace - args: ["[TsH]", ""] - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: div.title_wrap > a - attribute: href - size: - selector: div.bro_right_ad > b - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - grabs: - selector: div.bro_right_ae > b - seeders: - selector: div.bro_box1_aa > b - leechers: - selector: div.bro_box_aaa > b - date: - selector: div.bro_box_date > span - filters: - - name: replace - args: ["\u00a0", " "] - - name: dateparse - args: "02.01.2006 15:04:05" - downloadvolumefactor: - case: - span[title="OnlyUp"]: "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: theshinning + name: The Shinning + description: "A German gerneral tracker" + language: de-de + type: private + encoding: windows-1252 + links: + - https://theshinning.org + + caps: + categorymappings: + # Filme + - {id: 28, cat: Movies/SD, desc: "HORROR"} + - {id: 25, cat: Movies/DVD, desc: "SD|DVD"} + - {id: 99, cat: Movies/SD, desc: "SD|SPORT"} + - {id: 24, cat: Movies/SD, desc: "SD|x264"} + - {id: 22, cat: Movies/SD, desc: "SD|XVID"} + - {id: 26, cat: XXX, desc: "SD|XxX"} + + # High Definition + - {id: 29, cat: Movies/BluRay, desc: "BLURAY"} + - {id: 19, cat: Movies/HD, desc: "HD|1080p"} + - {id: 21, cat: Movies/3D, desc: "HD|3D"} + - {id: 107, cat: Movies/HD, desc: "HD|4K"} + - {id: 20, cat: Movies/HD, desc: "HD|720p"} + - {id: 101, cat: Movies/HD, desc: "HD|REMUX"} + - {id: 100, cat: Movies/HD, desc: "HD|SPORT"} + - {id: 27, cat: XXX, desc: "HD|XxX"} + - {id: 102, cat: Movies/HD, desc: "SMALL|HD"} + + # Musik + - {id: 13, cat: Audio, desc: "CHARTS"} + - {id: 31, cat: Audio/Lossless, desc: "FLAC"} + - {id: 97, cat: Audio/Audiobook, desc: "HOERSPIELE"} + - {id: 30, cat: Audio/MP3, desc: "MP3"} + - {id: 106, cat: Audio, desc: "SAMPLER"} + + # Releaser + - {id: 18, cat: Movies, desc: "CR3WHD"} + - {id: 16, cat: Movies, desc: "ONKEL JENS"} + - {id: 17, cat: Movies, desc: "xTM|XviD"} + + # Serie + - {id: 11, cat: TV/SD, desc: "DVD|SERIEN"} + - {id: 9, cat: TV/HD, desc: "HD|SERIEN"} + - {id: 32, cat: TV, desc: "MIXED|SERIEN"} + - {id: 10, cat: TV, desc: "PACK|SERIEN"} + - {id: 8, cat: TV/SD, desc: "SD|SERIEN"} + - {id: 105, cat: TV, desc: "SMALL|SERIE"} + - {id: 12, cat: TV, desc: "US|SERIEN"} + + # Sonstige + - {id: 98, cat: PC, desc: "APPS"} + - {id: 90, cat: TV/Documentary, desc: "DOKUS"} + - {id: 91, cat: Books, desc: "EBOOKS"} + - {id: 14, cat: Movies, desc: "KINOHITS"} + - {id: 15, cat: Other, desc: "REQUEST"} + - {id: 23, cat: Other , desc: "SONSTIGES"} + - {id: 104, cat: XXX/Imageset, desc: "XXX|IMAGE"} + + # Spiele + - {id: 96, cat: Console/NDS, desc: "GAMES|NDS"} + - {id: 92, cat: PC/Games, desc: "GAMES|PC"} + - {id: 94, cat: Console/PS4, desc: "GAMES|PS"} + - {id: 95, cat: Console/Wii, desc: "GAMES|WII"} + - {id: 93, cat: Console/Xbox, desc: "GAMES|XBOX"} + + # Wrestling + - {id: 3, cat: TV/Sport, desc: "HD|RAW"} + - {id: 1, cat: TV/Sport, desc: "HD|SMACKD"} + - {id: 6, cat: TV/Sport, desc: "NXT"} + - {id: 7, cat: TV/Sport, desc: "PPV"} + - {id: 4, cat: TV/Sport, desc: "SD|RAW"} + - {id: 2, cat: TV/Sport, desc: "SD|SMACKD"} + - {id: 5, cat: TV/Sport, desc: "TNA"} + + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /login.php + method: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.stderr_info_wrap + test: + path: /browse.php + selector: img[title="Ratio"] + i + + ratio: + path: /browse.php + selector: img[title="Ratio"] + i + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + showsearch: "1" + incldead: "1" + orderby: "added" + sort: "desc" + rows: + selector: table.main > tbody > tr:contains("Alle Torrents") + tr > td > table.tableinborder > tbody > tr + filters: + - name: andmatch + fields: + download: + selector: a[href^="download-ssl.php?torrent="] + attribute: href + title: + selector: div.title_wrap + attribute: title + filters: + - name: replace + args: ["[TsH]", ""] + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: div.title_wrap > a + attribute: href + size: + selector: div.bro_right_ad > b + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + grabs: + selector: div.bro_right_ae > b + seeders: + selector: div.bro_box1_aa > b + leechers: + selector: div.bro_box_aaa > b + date: + selector: div.bro_box_date > span + filters: + - name: replace + args: ["\u00a0", " "] + - name: dateparse + args: "02.01.2006 15:04:05" + downloadvolumefactor: + case: + span[title="OnlyUp"]: "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/tntvillage.yml b/src/Jackett/Definitions/tntvillage.yml index 1dde5014..d4101961 100644 --- a/src/Jackett/Definitions/tntvillage.yml +++ b/src/Jackett/Definitions/tntvillage.yml @@ -1,69 +1,69 @@ ---- - site: tntvillage - name: TNTVillage - language: it-it - type: public - encoding: UTF-8 - links: - - http://www.tntvillage.scambioetico.org/ - - caps: - categorymappings: - - {id: 4, cat: Movies, desc: "Movies category"} - - {id: 2, cat: Audio, desc: "Music videos"} - - {id: 29, cat: TV, desc: "TV Series"} - - {id: 7, cat: TV/Anime, desc: "Animes"} - - {id: 8, cat: TV/Anime, desc: "Cartoons"} - - {id: 14, cat: TV/Documentary, desc: "Documentaries"} - - {id: 30, cat: Books/Comics, desc: "Comics"} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - settings: [] - - search: - paths: - - path: /src/releaselist.php - method: post - inputs: - cat: 0 - page: 1 - srcrel: "{{ .Keywords }}" - rows: - selector: div.showrelease_tb table tbody tr:not(tr:nth-child(1)) - fields: - title: - selector: td:nth-child(7) - category: - selector: td:nth-child(3) a - attribute: href - filters: - - name: split - args: ["=", "-1"] - details: - selector: td:nth-child(7) a - attribute: href - download: - selector: td:nth-child(1) a - attribute: href - magnet: - selector: td:nth-child(2) a - attribute: href - seeders: - selector: td:nth-child(5) - leechers: - selector: td:nth-child(4) - downloadvolumefactor: - text: "0" - uploadvolumefactor: - text: "1" - size: - selector: td:nth-child(3) a - case: - a[href*="&cat=4"]: "5GB" - a[href*="&cat=2"]: "100MB" - a[href*="&cat=30"]: "100MB" - "*": "2GB" +--- + site: tntvillage + name: TNTVillage + language: it-it + type: public + encoding: UTF-8 + links: + - http://www.tntvillage.scambioetico.org/ + + caps: + categorymappings: + - {id: 4, cat: Movies, desc: "Movies category"} + - {id: 2, cat: Audio, desc: "Music videos"} + - {id: 29, cat: TV, desc: "TV Series"} + - {id: 7, cat: TV/Anime, desc: "Animes"} + - {id: 8, cat: TV/Anime, desc: "Cartoons"} + - {id: 14, cat: TV/Documentary, desc: "Documentaries"} + - {id: 30, cat: Books/Comics, desc: "Comics"} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + settings: [] + + search: + paths: + - path: /src/releaselist.php + method: post + inputs: + cat: 0 + page: 1 + srcrel: "{{ .Keywords }}" + rows: + selector: div.showrelease_tb table tbody tr:not(tr:nth-child(1)) + fields: + title: + selector: td:nth-child(7) + category: + selector: td:nth-child(3) a + attribute: href + filters: + - name: split + args: ["=", "-1"] + details: + selector: td:nth-child(7) a + attribute: href + download: + selector: td:nth-child(1) a + attribute: href + magnet: + selector: td:nth-child(2) a + attribute: href + seeders: + selector: td:nth-child(5) + leechers: + selector: td:nth-child(4) + downloadvolumefactor: + text: "0" + uploadvolumefactor: + text: "1" + size: + selector: td:nth-child(3) a + case: + a[href*="&cat=4"]: "5GB" + a[href*="&cat=2"]: "100MB" + a[href*="&cat=30"]: "100MB" + "*": "2GB" diff --git a/src/Jackett/Definitions/torrent9.yml b/src/Jackett/Definitions/torrent9.yml index 98f0c083..ba1a1a00 100644 --- a/src/Jackett/Definitions/torrent9.yml +++ b/src/Jackett/Definitions/torrent9.yml @@ -1,76 +1,76 @@ ---- - site: torrent9 - name: Torrent9 - language: fr-fr - type: public - encoding: UTF-8 - links: - - http://www.torrent9.biz/ - - caps: - categorymappings: - - {id: films, cat: Movies, desc: "Movies"} - - {id: series, cat: TV, desc: "TV"} - - {id: musique, cat: Audio, desc: "Music"} - - {id: ebook, cat: Books, desc: "Books"} - - {id: logiciels, cat: PC, desc: "Software"} - - {id: jeux-pc, cat: PC/Games, desc: "PC Games"} - - {id: jeux-consoles, cat: Console/Xbox360, desc: "Console Games"} - - modes: - search: [q] - tv-search: [q, season, ep] - - search: - path: "{{if .Query.Keywords}}/search_torrent/{{range .Categories }}{{.}}/{{end}}{{ .Query.Keywords }}/page-0,trie-seeds-d{{else}}/top_torrent.php{{end}}" - rows: - selector: div.table-responsive > table tbody tr - fields: - title: - selector: td:nth-child(1) a - details: - selector: td:nth-child(1) a - attribute: href - download: - selector: td:nth-child(1) a - attribute: href - filters: - - name: replace - args: [ "/torrent", "/get_torrent"] - - name: append - args: ".torrent" - size: - selector: td:nth-child(2) - filters: - - name: re_replace - args: [ "\\.(\\d) Ko", "$1X00"] - - name: re_replace - args: [ " Ko", "000"] - - name: re_replace - args: [ "\\.(\\d) Mo", "$1X00000"] - - name: re_replace - args: [ " Mo", "000000"] - - name: re_replace - args: [ "\\.(\\d) Go", "$1X00000000"] - - name: re_replace - args: [ " Go", "000000000"] - - name: re_replace - args: [ "\\.(\\d) To", "$1X00000000000"] - - name: re_replace - args: [ " To", "000000000000"] - - name: replace - args: [ "X", "" ] - seeders: - text: 0 - seeders: - selector: td:nth-child(3) span.seed_ok - optional: true - leechers: - text: 0 - leechers: - selector: td:nth-child(4) - optional: true - downloadvolumefactor: - text: "0" - uploadvolumefactor: +--- + site: torrent9 + name: Torrent9 + language: fr-fr + type: public + encoding: UTF-8 + links: + - http://www.torrent9.biz/ + + caps: + categorymappings: + - {id: films, cat: Movies, desc: "Movies"} + - {id: series, cat: TV, desc: "TV"} + - {id: musique, cat: Audio, desc: "Music"} + - {id: ebook, cat: Books, desc: "Books"} + - {id: logiciels, cat: PC, desc: "Software"} + - {id: jeux-pc, cat: PC/Games, desc: "PC Games"} + - {id: jeux-consoles, cat: Console/Xbox360, desc: "Console Games"} + + modes: + search: [q] + tv-search: [q, season, ep] + + search: + path: "{{if .Query.Keywords}}/search_torrent/{{range .Categories }}{{.}}/{{end}}{{ .Query.Keywords }}/page-0,trie-seeds-d{{else}}/top_torrent.php{{end}}" + rows: + selector: div.table-responsive > table tbody tr + fields: + title: + selector: td:nth-child(1) a + details: + selector: td:nth-child(1) a + attribute: href + download: + selector: td:nth-child(1) a + attribute: href + filters: + - name: replace + args: [ "/torrent", "/get_torrent"] + - name: append + args: ".torrent" + size: + selector: td:nth-child(2) + filters: + - name: re_replace + args: [ "\\.(\\d) Ko", "$1X00"] + - name: re_replace + args: [ " Ko", "000"] + - name: re_replace + args: [ "\\.(\\d) Mo", "$1X00000"] + - name: re_replace + args: [ " Mo", "000000"] + - name: re_replace + args: [ "\\.(\\d) Go", "$1X00000000"] + - name: re_replace + args: [ " Go", "000000000"] + - name: re_replace + args: [ "\\.(\\d) To", "$1X00000000000"] + - name: re_replace + args: [ " To", "000000000000"] + - name: replace + args: [ "X", "" ] + seeders: + text: 0 + seeders: + selector: td:nth-child(3) span.seed_ok + optional: true + leechers: + text: 0 + leechers: + selector: td:nth-child(4) + optional: true + downloadvolumefactor: + text: "0" + uploadvolumefactor: text: "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/torrentbd.yml b/src/Jackett/Definitions/torrentbd.yml index 9d788872..1e3fbb2e 100644 --- a/src/Jackett/Definitions/torrentbd.yml +++ b/src/Jackett/Definitions/torrentbd.yml @@ -1,151 +1,151 @@ ---- - site: torrentbd - name: TorrentBD - description: "A general tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - http://www.torrentbd.com/torrent - - caps: - categorymappings: - - {id: 28, cat: TV/Anime, desc: "Anime - All"} - - {id: 65, cat: PC/Phone-Android, desc: "Apps - Android"} - - {id: 20, cat: PC, desc: "Apps - Linux"} - - {id: 19, cat: PC/Mac, desc: "Apps - Mac"} - - {id: 18, cat: PC, desc: "Apps - PC"} - - {id: 21, cat: Audio, desc: "Bangla - Audio"} - - {id: 7, cat: Movies, desc: "Bangla - Movies | Natok"} - - {id: 49, cat: TV, desc: "Cartoons - All"} - - {id: 9, cat: TV/Documentary, desc: "Documentaries - All"} - - {id: 73, cat: Books/Comics, desc: "E-Books - Comics"} - - {id: 77, cat: Books, desc: "E-Books - Manga"} - - {id: 60, cat: PC/Games, desc: "Games - Cracks | Patches"} - - {id: 17, cat: Console, desc: "Games - Other"} - - {id: 10, cat: PC, desc: "Games - PC"} - - {id: 11, cat: Console/PS3, desc: "Games - PS2"} - - {id: 43, cat: Console/PS3, desc: "Games - PS3"} - - {id: 12, cat: Console/PSP, desc: "Games - PSP"} - - {id: 52, cat: PC/Games, desc: "Games - Updates | DLC"} - - {id: 13, cat: Console/Xbox, desc: "Games - Xbox"} - - {id: 14, cat: Console/Xbox360, desc: "Games - Xbox360"} - - {id: 23, cat: Movies/BluRay, desc: "Hindi - Blu-ray"} - - {id: 51, cat: Movies/SD, desc: "Hindi - CAM | TS | TC"} - - {id: 27, cat: Movies/DVD, desc: "Hindi - DVDRip"} - - {id: 58, cat: Movies/SD, desc: "Hindi - DVDScr | Pre-DVD"} - - {id: 68, cat: Movies/SD, desc: "Hindi - HD-Rip"} - - {id: 59, cat: Movies, desc: "Hindi - Web-Rip"} - - {id: 47, cat: Movies/HD, desc: "Movies - 1080p BluRay"} - - {id: 67, cat: Movies/3D, desc: "Movies - 3D"} - - {id: 42, cat: Movies/BluRay, desc: "Movies - 720p BluRay"} - - {id: 57, cat: Movies, desc: "Movies - Animation"} - - {id: 4, cat: Movies/SD, desc: "Movies - CAM | TS | TC"} - - {id: 69, cat: Movies, desc: "Movies - Dual Audio"} - - {id: 1, cat: Movies/SD, desc: "Movies - DVDRip"} - - {id: 56, cat: Movies/SD, desc: "Movies - DVDSCR | R5 | R6"} - - {id: 46, cat: Movies/SD, desc: "Movies - HD-Rip"} - - {id: 76, cat: Movies/BluRay, desc: "Movies - Lossless BluRay"} - - {id: 2, cat: Movies, desc: "Movies - Packs"} - - {id: 24, cat: Movies/SD, desc: "Movies - SD BluRay"} - - {id: 34, cat: Movies, desc: "Movies - Tamil"} - - {id: 3, cat: Movies, desc: "Movies - Unrated"} - - {id: 72, cat: Movies, desc: "Movies - WEB Rip"} - - {id: 55, cat: Movies, desc: "Movies - WEB-DL"} - - {id: 22, cat: Audio, desc: "Music - Audio"} - - {id: 64, cat: Audio, desc: "Music - Concerts | Live Shows"} - - {id: 71, cat: Audio/Lossless, desc: "Music - FLAC"} - - {id: 50, cat: Audio, desc: "Music - OST"} - - {id: 26, cat: Audio, desc: "Music - Radio"} - - {id: 25, cat: Audio, desc: "Music - Video"} - - {id: 78, cat: Audio, desc: "Music - Video 4K"} - - {id: 36, cat: Books, desc: "Other - E-Books"} - - {id: 37, cat: Other, desc: "Other - Images"} - - {id: 38, cat: PC/Phone-Other, desc: "Other - Mobile Phone"} - - {id: 40, cat: Other, desc: "Other - Other | Misc"} - - {id: 39, cat: Other, desc: "Other - Tutorial"} - - {id: 44, cat: Other, desc: "Religious - Islam"} - - {id: 48, cat: TV/Sport, desc: "Sports - All"} - - {id: 70, cat: TV/Sport, desc: "Sports - Football"} - - {id: 6, cat: TV/Sport, desc: "Sports - Pro Wrestling"} - - {id: 33, cat: Other, desc: "Trailers - Movie | Games"} - - {id: 66, cat: TV, desc: "TV - Awards | Ceremonies"} - - {id: 5, cat: TV/SD, desc: "TV - Episodes"} - - {id: 61, cat: TV/HD, desc: "TV - Episodes - 720p | 1080p"} - - {id: 41, cat: TV/SD, desc: "TV - Packs"} - - {id: 62, cat: TV/HD, desc: "TV - Packs - HD | BRRip"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: account-login.php - method: form - form: form[action="account-login.php"] - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.myFrame:has(div.myF-caption > font.error) - test: - path: torrents-search.php - selector: div.myB-content:contains("Ratio:") - - ratio: - path: torrents-search.php - selector: div.myB-content:contains("Ratio:") - filters: - - name: regexp - args: "Ratio: (.*?)$" - - search: - path: torrents-search.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - rows: - selector: tr.t-row - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: span.torrname - attribute: title - category: - selector: a[href^="torrents.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[onmouseover][href^="torrents-details.php?id="] - attribute: href - comments: - selector: a[href*="#comments"] - attribute: href - size: - selector: td:nth-child(6) - grabs: - selector: td:nth-child(9) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - date: - selector: a[onmouseover][href^="torrents-details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: "Date Added: </b>(\\d+-\\d+-\\d+)<br />" - - name: dateparse - args: "02-01-2006" - downloadvolumefactor: - case: - img[title^="FreeLeech "]: "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: torrentbd + name: TorrentBD + description: "A general tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - http://www.torrentbd.com/torrent + + caps: + categorymappings: + - {id: 28, cat: TV/Anime, desc: "Anime - All"} + - {id: 65, cat: PC/Phone-Android, desc: "Apps - Android"} + - {id: 20, cat: PC, desc: "Apps - Linux"} + - {id: 19, cat: PC/Mac, desc: "Apps - Mac"} + - {id: 18, cat: PC, desc: "Apps - PC"} + - {id: 21, cat: Audio, desc: "Bangla - Audio"} + - {id: 7, cat: Movies, desc: "Bangla - Movies | Natok"} + - {id: 49, cat: TV, desc: "Cartoons - All"} + - {id: 9, cat: TV/Documentary, desc: "Documentaries - All"} + - {id: 73, cat: Books/Comics, desc: "E-Books - Comics"} + - {id: 77, cat: Books, desc: "E-Books - Manga"} + - {id: 60, cat: PC/Games, desc: "Games - Cracks | Patches"} + - {id: 17, cat: Console, desc: "Games - Other"} + - {id: 10, cat: PC, desc: "Games - PC"} + - {id: 11, cat: Console/PS3, desc: "Games - PS2"} + - {id: 43, cat: Console/PS3, desc: "Games - PS3"} + - {id: 12, cat: Console/PSP, desc: "Games - PSP"} + - {id: 52, cat: PC/Games, desc: "Games - Updates | DLC"} + - {id: 13, cat: Console/Xbox, desc: "Games - Xbox"} + - {id: 14, cat: Console/Xbox360, desc: "Games - Xbox360"} + - {id: 23, cat: Movies/BluRay, desc: "Hindi - Blu-ray"} + - {id: 51, cat: Movies/SD, desc: "Hindi - CAM | TS | TC"} + - {id: 27, cat: Movies/DVD, desc: "Hindi - DVDRip"} + - {id: 58, cat: Movies/SD, desc: "Hindi - DVDScr | Pre-DVD"} + - {id: 68, cat: Movies/SD, desc: "Hindi - HD-Rip"} + - {id: 59, cat: Movies, desc: "Hindi - Web-Rip"} + - {id: 47, cat: Movies/HD, desc: "Movies - 1080p BluRay"} + - {id: 67, cat: Movies/3D, desc: "Movies - 3D"} + - {id: 42, cat: Movies/BluRay, desc: "Movies - 720p BluRay"} + - {id: 57, cat: Movies, desc: "Movies - Animation"} + - {id: 4, cat: Movies/SD, desc: "Movies - CAM | TS | TC"} + - {id: 69, cat: Movies, desc: "Movies - Dual Audio"} + - {id: 1, cat: Movies/SD, desc: "Movies - DVDRip"} + - {id: 56, cat: Movies/SD, desc: "Movies - DVDSCR | R5 | R6"} + - {id: 46, cat: Movies/SD, desc: "Movies - HD-Rip"} + - {id: 76, cat: Movies/BluRay, desc: "Movies - Lossless BluRay"} + - {id: 2, cat: Movies, desc: "Movies - Packs"} + - {id: 24, cat: Movies/SD, desc: "Movies - SD BluRay"} + - {id: 34, cat: Movies, desc: "Movies - Tamil"} + - {id: 3, cat: Movies, desc: "Movies - Unrated"} + - {id: 72, cat: Movies, desc: "Movies - WEB Rip"} + - {id: 55, cat: Movies, desc: "Movies - WEB-DL"} + - {id: 22, cat: Audio, desc: "Music - Audio"} + - {id: 64, cat: Audio, desc: "Music - Concerts | Live Shows"} + - {id: 71, cat: Audio/Lossless, desc: "Music - FLAC"} + - {id: 50, cat: Audio, desc: "Music - OST"} + - {id: 26, cat: Audio, desc: "Music - Radio"} + - {id: 25, cat: Audio, desc: "Music - Video"} + - {id: 78, cat: Audio, desc: "Music - Video 4K"} + - {id: 36, cat: Books, desc: "Other - E-Books"} + - {id: 37, cat: Other, desc: "Other - Images"} + - {id: 38, cat: PC/Phone-Other, desc: "Other - Mobile Phone"} + - {id: 40, cat: Other, desc: "Other - Other | Misc"} + - {id: 39, cat: Other, desc: "Other - Tutorial"} + - {id: 44, cat: Other, desc: "Religious - Islam"} + - {id: 48, cat: TV/Sport, desc: "Sports - All"} + - {id: 70, cat: TV/Sport, desc: "Sports - Football"} + - {id: 6, cat: TV/Sport, desc: "Sports - Pro Wrestling"} + - {id: 33, cat: Other, desc: "Trailers - Movie | Games"} + - {id: 66, cat: TV, desc: "TV - Awards | Ceremonies"} + - {id: 5, cat: TV/SD, desc: "TV - Episodes"} + - {id: 61, cat: TV/HD, desc: "TV - Episodes - 720p | 1080p"} + - {id: 41, cat: TV/SD, desc: "TV - Packs"} + - {id: 62, cat: TV/HD, desc: "TV - Packs - HD | BRRip"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: account-login.php + method: form + form: form[action="account-login.php"] + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.myFrame:has(div.myF-caption > font.error) + test: + path: torrents-search.php + selector: div.myB-content:contains("Ratio:") + + ratio: + path: torrents-search.php + selector: div.myB-content:contains("Ratio:") + filters: + - name: regexp + args: "Ratio: (.*?)$" + + search: + path: torrents-search.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + rows: + selector: tr.t-row + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: span.torrname + attribute: title + category: + selector: a[href^="torrents.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[onmouseover][href^="torrents-details.php?id="] + attribute: href + comments: + selector: a[href*="#comments"] + attribute: href + size: + selector: td:nth-child(6) + grabs: + selector: td:nth-child(9) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + date: + selector: a[onmouseover][href^="torrents-details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: "Date Added: </b>(\\d+-\\d+-\\d+)<br />" + - name: dateparse + args: "02-01-2006" + downloadvolumefactor: + case: + img[title^="FreeLeech "]: "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/torrentccf.yml b/src/Jackett/Definitions/torrentccf.yml index f7bb3c25..dce38c89 100644 --- a/src/Jackett/Definitions/torrentccf.yml +++ b/src/Jackett/Definitions/torrentccf.yml @@ -1,118 +1,118 @@ ---- - site: torrentccf - name: TorrentCCF - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://et8.org/ - - caps: - categorymappings: - - {id: 601, cat: Movies, desc: "Movies"} - - {id: 602, cat: TV/Anime, desc: "Animations"} - - {id: 603, cat: TV/Sport, desc: "Sports"} - - {id: 604, cat: TV/Documentary, desc: "Documentaries"} - - {id: 605, cat: Books, desc: "EDU"} - - {id: 606, cat: TV, desc: "TV/Cn"} - - {id: 607, cat: TV, desc: "TV/Western"} - - {id: 608, cat: TV, desc: "TV/hk_tw"} - - {id: 609, cat: TV, desc: "TV/Japan_korea"} - - {id: 610, cat: TV, desc: "TV Shows"} - - {id: 611, cat: Audio, desc: "Music/Cn"} - - {id: 612, cat: Audio, desc: "Music/Western"} - - {id: 613, cat: Audio, desc: "Music/Asia"} - - {id: 614, cat: Audio, desc: "Music/Classic"} - - {id: 615, cat: Audio/Video, desc: "MusicVideo"} - - {id: 616, cat: PC, desc: "Appz"} - - {id: 617, cat: PC/Games, desc: "PC Games"} - - {id: 618, cat: Console/PS4, desc: "Playstation"} - - {id: 619, cat: Console/Xbox, desc: "Xbox"} - - {id: 620, cat: Console/Wii, desc: "Wii"} - - {id: 621, cat: Other, desc: "Others"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [imdbid] - - login: - path: /login.php - method: form - form: form[action="takelogin.php"] - captcha: - type: image - image: img[alt="CAPTCHA"] - input: imagestring - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("登录失败")) - test: - path: /torrents.php - - search: - path: /torrents.php - method: get - inputs: - $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - incldead: "1" - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - rows: - selector: table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[href^="details.php?id="] - title|optional: - selector: a[title][href^="details.php?id="] - attribute: title - category: - selector: a[href^="?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?id="] - attribute: href - imdb|optional: - selector: div.imdb_100 > a - attribute: href - size: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - date: - selector: td:nth-child(4) > span[title] - attribute: title - filters: - - name: append - args: " +08:00" - - name: dateparse - args: "2006-01-02 15:04:05 -07:00" - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" - "*": "1" - description: - selector: td:nth-child(2) - remove: a, img +--- + site: torrentccf + name: TorrentCCF + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://et8.org/ + + caps: + categorymappings: + - {id: 601, cat: Movies, desc: "Movies"} + - {id: 602, cat: TV/Anime, desc: "Animations"} + - {id: 603, cat: TV/Sport, desc: "Sports"} + - {id: 604, cat: TV/Documentary, desc: "Documentaries"} + - {id: 605, cat: Books, desc: "EDU"} + - {id: 606, cat: TV, desc: "TV/Cn"} + - {id: 607, cat: TV, desc: "TV/Western"} + - {id: 608, cat: TV, desc: "TV/hk_tw"} + - {id: 609, cat: TV, desc: "TV/Japan_korea"} + - {id: 610, cat: TV, desc: "TV Shows"} + - {id: 611, cat: Audio, desc: "Music/Cn"} + - {id: 612, cat: Audio, desc: "Music/Western"} + - {id: 613, cat: Audio, desc: "Music/Asia"} + - {id: 614, cat: Audio, desc: "Music/Classic"} + - {id: 615, cat: Audio/Video, desc: "MusicVideo"} + - {id: 616, cat: PC, desc: "Appz"} + - {id: 617, cat: PC/Games, desc: "PC Games"} + - {id: 618, cat: Console/PS4, desc: "Playstation"} + - {id: 619, cat: Console/Xbox, desc: "Xbox"} + - {id: 620, cat: Console/Wii, desc: "Wii"} + - {id: 621, cat: Other, desc: "Others"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [imdbid] + + login: + path: /login.php + method: form + form: form[action="takelogin.php"] + captcha: + type: image + image: img[alt="CAPTCHA"] + input: imagestring + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("登录失败")) + test: + path: /torrents.php + + search: + path: /torrents.php + method: get + inputs: + $raw: "{{range .Categories}}cat{{.}}=1&{{end}}" + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + incldead: "1" + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + rows: + selector: table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[href^="details.php?id="] + title|optional: + selector: a[title][href^="details.php?id="] + attribute: title + category: + selector: a[href^="?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?id="] + attribute: href + imdb|optional: + selector: div.imdb_100 > a + attribute: href + size: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + date: + selector: td:nth-child(4) > span[title] + attribute: title + filters: + - name: append + args: " +08:00" + - name: dateparse + args: "2006-01-02 15:04:05 -07:00" + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" + "*": "1" + description: + selector: td:nth-child(2) + remove: a, img diff --git a/src/Jackett/Definitions/torrenthr.yml b/src/Jackett/Definitions/torrenthr.yml index 3b722ece..7134d2f2 100644 --- a/src/Jackett/Definitions/torrenthr.yml +++ b/src/Jackett/Definitions/torrenthr.yml @@ -1,129 +1,129 @@ ---- - site: torrenthr - name: TorrentHR - language: hr-hr - type: private - encoding: windows-1250 - links: - - https://www.torrenthr.org/ - - caps: - categorymappings: - - {id: 31, cat: TV/Anime, desc: "Anime"} - - {id: 4, cat: Movies/SD, desc: "Filmovi/SD"} - - {id: 18, cat: Movies/Foreign, desc: "Crtani Filmovi"} - - {id: 5, cat: PC/Games, desc: "Igre/PC"} - - {id: 7, cat: TV/SD, desc: "Serije/SD"} - - {id: 1, cat: PC/0day, desc: "Aplikacije"} - - {id: 14, cat: Movies/DVD, desc: "Filmovi/DVD"} - - {id: 12, cat: TV/Documentary, desc: "Dokumentarni Filmovi"} - - {id: 27, cat: Console/PS4, desc: "Igre/PS"} - - {id: 34, cat: TV/HD, desc: "Serije/HD"} - - {id: 25, cat: Books, desc: "E-books"} - - {id: 17, cat: Movies/HD, desc: "Filmovi/HD"} - - {id: 11, cat: Audio, desc: "Koncerti/Spotovi"} - - {id: 28, cat: Console/Wii, desc: "Igre/Wii"} - - {id: 30, cat: Books/Comics, desc: "Stripovi"} - - {id: 38, cat: PC/Phone-Other, desc: "Smartphone"} - - {id: 40, cat: Movies/BluRay, desc: "Filmovi/BD"} - - {id: 3, cat: Audio/MP3, desc: "Glazba/MP3"} - - {id: 26, cat: Console/Xbox, desc: "Igre/Xbox"} - - {id: 10, cat: XXX, desc: "XXX/SD"} - - {id: 16, cat: TV, desc: "THR Packs"} - - {id: 15, cat: TV/Sport, desc: "Sport"} - - {id: 29, cat: Audio/Lossless, desc: "Glazba/FLAC"} - - {id: 13, cat: Other, desc: "Ostalo"} - - {id: 36, cat: XXX, desc: "XXX/HD"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - ssl: "yes" - error: - - selector: div.glavni:has(div.glavni_naslov:contains("Greška")) - test: - path: /browse.php - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - sort: "4" - type: "desc" - rows: - selector: div.glavni_txt > table > tbody > tr[id^="record-"] - fields: - title: - selector: a[href^="details.php?id="] - title|optional|1: - selector: a[href^="details.php?id="][title] - attribute: title - title|optional|2: - selector: a[href^="details.php?id="][onmousemove] - attribute: onmousemove - filters: - - name: regexp - args: "return overlibImage\\('(.*)','.*'\\);" - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: td.kategorije > a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="download.php?id="] - attribute: href - files: - selector: td:nth-child(5) - size: - selector: td:nth-child(7) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: ([\d,]+) - - name: replace - args: [",", ""] - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - banner|optional: - selector: a[href^="details.php?id="][onmousemove] - attribute: onmousemove - filters: - - name: regexp - args: "return overlibImage\\('.*','(.*)'\\);" - downloadvolumefactor: - text: "0" - uploadvolumefactor: - text: "1" - date: - selector: td:nth-child(2) > small - filters: - - name: replace - args: [" u ", " "] - - name: append - args: " +00:00" - - name: dateparse - args: "02.01.2006 15:04:05 -07:00" - description|optional: - selector: td:nth-child(2) +--- + site: torrenthr + name: TorrentHR + language: hr-hr + type: private + encoding: windows-1250 + links: + - https://www.torrenthr.org/ + + caps: + categorymappings: + - {id: 31, cat: TV/Anime, desc: "Anime"} + - {id: 4, cat: Movies/SD, desc: "Filmovi/SD"} + - {id: 18, cat: Movies/Foreign, desc: "Crtani Filmovi"} + - {id: 5, cat: PC/Games, desc: "Igre/PC"} + - {id: 7, cat: TV/SD, desc: "Serije/SD"} + - {id: 1, cat: PC/0day, desc: "Aplikacije"} + - {id: 14, cat: Movies/DVD, desc: "Filmovi/DVD"} + - {id: 12, cat: TV/Documentary, desc: "Dokumentarni Filmovi"} + - {id: 27, cat: Console/PS4, desc: "Igre/PS"} + - {id: 34, cat: TV/HD, desc: "Serije/HD"} + - {id: 25, cat: Books, desc: "E-books"} + - {id: 17, cat: Movies/HD, desc: "Filmovi/HD"} + - {id: 11, cat: Audio, desc: "Koncerti/Spotovi"} + - {id: 28, cat: Console/Wii, desc: "Igre/Wii"} + - {id: 30, cat: Books/Comics, desc: "Stripovi"} + - {id: 38, cat: PC/Phone-Other, desc: "Smartphone"} + - {id: 40, cat: Movies/BluRay, desc: "Filmovi/BD"} + - {id: 3, cat: Audio/MP3, desc: "Glazba/MP3"} + - {id: 26, cat: Console/Xbox, desc: "Igre/Xbox"} + - {id: 10, cat: XXX, desc: "XXX/SD"} + - {id: 16, cat: TV, desc: "THR Packs"} + - {id: 15, cat: TV/Sport, desc: "Sport"} + - {id: 29, cat: Audio/Lossless, desc: "Glazba/FLAC"} + - {id: 13, cat: Other, desc: "Ostalo"} + - {id: 36, cat: XXX, desc: "XXX/HD"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + ssl: "yes" + error: + - selector: div.glavni:has(div.glavni_naslov:contains("Greška")) + test: + path: /browse.php + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + sort: "4" + type: "desc" + rows: + selector: div.glavni_txt > table > tbody > tr[id^="record-"] + fields: + title: + selector: a[href^="details.php?id="] + title|optional|1: + selector: a[href^="details.php?id="][title] + attribute: title + title|optional|2: + selector: a[href^="details.php?id="][onmousemove] + attribute: onmousemove + filters: + - name: regexp + args: "return overlibImage\\('(.*)','.*'\\);" + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: td.kategorije > a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="download.php?id="] + attribute: href + files: + selector: td:nth-child(5) + size: + selector: td:nth-child(7) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: ([\d,]+) + - name: replace + args: [",", ""] + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + banner|optional: + selector: a[href^="details.php?id="][onmousemove] + attribute: onmousemove + filters: + - name: regexp + args: "return overlibImage\\('.*','(.*)'\\);" + downloadvolumefactor: + text: "0" + uploadvolumefactor: + text: "1" + date: + selector: td:nth-child(2) > small + filters: + - name: replace + args: [" u ", " "] + - name: append + args: " +00:00" + - name: dateparse + args: "02.01.2006 15:04:05 -07:00" + description|optional: + selector: td:nth-child(2) remove: a, br, small \ No newline at end of file diff --git a/src/Jackett/Definitions/torrentsectorcrew.yml b/src/Jackett/Definitions/torrentsectorcrew.yml index bda41cb6..f7eb896e 100644 --- a/src/Jackett/Definitions/torrentsectorcrew.yml +++ b/src/Jackett/Definitions/torrentsectorcrew.yml @@ -1,177 +1,177 @@ ---- - site: torrentsectorcrew - name: Torrent Sector Crew - description: "A German general tracker" - language: de-de - type: private - encoding: windows-1252 - links: - - https://tsctracker.net/ - - caps: - categorymappings: - # Apps - - {id: 65, cat: PC/Phone-Android, desc: "Android"} - - {id: 83, cat: PC/Phone-IOS, desc: "iOS"} - - {id: 107, cat: PC/0day, desc: "Linux"} - - {id: 48, cat: PC/Mac, desc: "MAC"} - - {id: 109, cat: PC, desc: "Sonstige"} - - {id: 22, cat: PC/0day, desc: "Win"} - - # Audio - - {id: 24, cat: Audio/Audiobook, desc: "aBooks"} - - {id: 104, cat: Audio, desc: "Disco's"} - - {id: 38, cat: Audio/Audiobook, desc: "Hörspiel"} - - {id: 6, cat: Audio, desc: "Musik"} - - {id: 82, cat: Audio, desc: "Tracks"} - - {id: 29, cat: Audio/Video, desc: "Videos"} - - # Doku - - {id: 113, cat: TV/Documentary, desc: "3D"} - - {id: 76, cat: TV/Documentary, desc: "HD"} - - {id: 78, cat: TV/Documentary, desc: "Packs"} - - {id: 75, cat: TV/Documentary, desc: "SD"} - - {id: 114, cat: TV/Documentary, desc: "Sonstige"} - - {id: 77, cat: TV/Documentary, desc: "Untouched"} - - # Filme - - {id: 54, cat: Movies/HD, desc: "1080p"} - - {id: 5, cat: Movies/3D, desc: "3D"} - - {id: 55, cat: Movies/HD, desc: "720p"} - - {id: 111, cat: Movies, desc: "Anime"} - - {id: 43, cat: Movies/BluRay, desc: "BluRay"} - - {id: 20, cat: Movies/DVD, desc: "DVDR"} - - {id: 120, cat: Movies/Foreign, desc: "Int."} - - {id: 119, cat: Movies, desc: "Remux"} - - {id: 121, cat: Movies/HD, desc: "UHD"} - - {id: 36, cat: Movies/HD, desc: "x264"} - - {id: 19, cat: Movies/SD, desc: "XviD"} - - # Serien - - {id: 112, cat: TV/Anime, desc: "Anime"} - - {id: 69, cat: TV/HD, desc: "HD"} - - {id: 72, cat: TV/Foreign, desc: "Int."} - - {id: 68, cat: TV, desc: "Packs"} - - {id: 66, cat: TV/SD, desc: "SD"} - - {id: 108, cat: TV, desc: "TV-Shows"} - - # Sonstige - - {id: 117, cat: Other, desc: "Diverses"} - - {id: 28, cat: Books, desc: "eBooks"} - - {id: 42, cat: TV/Sport, desc: "Sport"} - - {id: 103, cat: Other, desc: "Tutorials"} - - {id: 9, cat: Other, desc: "Wallpaper"} - - {id: 64, cat: XXX, desc: "XXX"} - - # Spiele - - {id: 115, cat: PC/Mac, desc: "MAC"} - - {id: 37, cat: Console/NDS, desc: "Nintendo"} - - {id: 4, cat: PC/Games, desc: "PC"} - - {id: 58, cat: Console/PS4, desc: "PSX"} - - {id: 116, cat: Other, desc: "Sonstige"} - - {id: 50, cat: Console/Xbox, desc: "XBOX"} - - - modes: - search: [q] - tv-search: [q, season, ep] - - settings: - - name: pin - type: text - label: Pin - - name: username - type: text - label: Username - - name: password - type: password - label: Password - - login: - path: landing.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - pin: "{{ .Config.pin }}" - error: - - selector: "#login_box_desc" - test: - path: my.php - - ratio: - path: /my.php - selector: td.navi_top:contains("Deine Ratio:") - filters: - - name: replace - args: ["Deine Ratio: ", ""] - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - orderby: "added" - sort: desc - rows: - selector: "h2 +p + br + table.tablebrowse > tbody > tr[style=\"height: 45px;\"], tr:contains(\"Weiter\") > td > table.tablebrowse > tbody > tr[style=\"height: 45px;\"]" - fields: - title: - selector: a[title][href^="details.php"] - attribute: title - category: - selector: a[href*="cat="] - attribute: href - filters: - - name: querystring - args: cat - comments: - selector: a[href*="&tocomm="] - attribute: href - download: - selector: a[href^="download_ssl.php"] - attribute: href - files: - selector: td:nth-child(3) - grabs: - selector: td:nth-child(9) - filters: - - name: replace - args: ["-mal", ""] - size: - selector: td:nth-child(6) - filters: - - name: replace - args: [".", ""] - - name: replace - args: [",", "."] - seeders: - selector: td:nth-child(7) - filters: - - name: regexp - args: "(\\d+)" - leechers: - selector: td:nth-child(8) - filters: - - name: regexp - args: "(\\d+)" - date: - selector: td:nth-child(5) - remove: br - filters: - - name: dateparse - args: "02.01.200615:04:05" - downloadvolumefactor: - case: - "font:contains(\"[OnlyUpload]\")": "0" - "font:contains(\"[-40 Download]\")": "0.6" - "*": "1" - uploadvolumefactor: - case: +--- + site: torrentsectorcrew + name: Torrent Sector Crew + description: "A German general tracker" + language: de-de + type: private + encoding: windows-1252 + links: + - https://tsctracker.net/ + + caps: + categorymappings: + # Apps + - {id: 65, cat: PC/Phone-Android, desc: "Android"} + - {id: 83, cat: PC/Phone-IOS, desc: "iOS"} + - {id: 107, cat: PC/0day, desc: "Linux"} + - {id: 48, cat: PC/Mac, desc: "MAC"} + - {id: 109, cat: PC, desc: "Sonstige"} + - {id: 22, cat: PC/0day, desc: "Win"} + + # Audio + - {id: 24, cat: Audio/Audiobook, desc: "aBooks"} + - {id: 104, cat: Audio, desc: "Disco's"} + - {id: 38, cat: Audio/Audiobook, desc: "Hörspiel"} + - {id: 6, cat: Audio, desc: "Musik"} + - {id: 82, cat: Audio, desc: "Tracks"} + - {id: 29, cat: Audio/Video, desc: "Videos"} + + # Doku + - {id: 113, cat: TV/Documentary, desc: "3D"} + - {id: 76, cat: TV/Documentary, desc: "HD"} + - {id: 78, cat: TV/Documentary, desc: "Packs"} + - {id: 75, cat: TV/Documentary, desc: "SD"} + - {id: 114, cat: TV/Documentary, desc: "Sonstige"} + - {id: 77, cat: TV/Documentary, desc: "Untouched"} + + # Filme + - {id: 54, cat: Movies/HD, desc: "1080p"} + - {id: 5, cat: Movies/3D, desc: "3D"} + - {id: 55, cat: Movies/HD, desc: "720p"} + - {id: 111, cat: Movies, desc: "Anime"} + - {id: 43, cat: Movies/BluRay, desc: "BluRay"} + - {id: 20, cat: Movies/DVD, desc: "DVDR"} + - {id: 120, cat: Movies/Foreign, desc: "Int."} + - {id: 119, cat: Movies, desc: "Remux"} + - {id: 121, cat: Movies/HD, desc: "UHD"} + - {id: 36, cat: Movies/HD, desc: "x264"} + - {id: 19, cat: Movies/SD, desc: "XviD"} + + # Serien + - {id: 112, cat: TV/Anime, desc: "Anime"} + - {id: 69, cat: TV/HD, desc: "HD"} + - {id: 72, cat: TV/Foreign, desc: "Int."} + - {id: 68, cat: TV, desc: "Packs"} + - {id: 66, cat: TV/SD, desc: "SD"} + - {id: 108, cat: TV, desc: "TV-Shows"} + + # Sonstige + - {id: 117, cat: Other, desc: "Diverses"} + - {id: 28, cat: Books, desc: "eBooks"} + - {id: 42, cat: TV/Sport, desc: "Sport"} + - {id: 103, cat: Other, desc: "Tutorials"} + - {id: 9, cat: Other, desc: "Wallpaper"} + - {id: 64, cat: XXX, desc: "XXX"} + + # Spiele + - {id: 115, cat: PC/Mac, desc: "MAC"} + - {id: 37, cat: Console/NDS, desc: "Nintendo"} + - {id: 4, cat: PC/Games, desc: "PC"} + - {id: 58, cat: Console/PS4, desc: "PSX"} + - {id: 116, cat: Other, desc: "Sonstige"} + - {id: 50, cat: Console/Xbox, desc: "XBOX"} + + + modes: + search: [q] + tv-search: [q, season, ep] + + settings: + - name: pin + type: text + label: Pin + - name: username + type: text + label: Username + - name: password + type: password + label: Password + + login: + path: landing.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + pin: "{{ .Config.pin }}" + error: + - selector: "#login_box_desc" + test: + path: my.php + + ratio: + path: /my.php + selector: td.navi_top:contains("Deine Ratio:") + filters: + - name: replace + args: ["Deine Ratio: ", ""] + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + orderby: "added" + sort: desc + rows: + selector: "h2 +p + br + table.tablebrowse > tbody > tr[style=\"height: 45px;\"], tr:contains(\"Weiter\") > td > table.tablebrowse > tbody > tr[style=\"height: 45px;\"]" + fields: + title: + selector: a[title][href^="details.php"] + attribute: title + category: + selector: a[href*="cat="] + attribute: href + filters: + - name: querystring + args: cat + comments: + selector: a[href*="&tocomm="] + attribute: href + download: + selector: a[href^="download_ssl.php"] + attribute: href + files: + selector: td:nth-child(3) + grabs: + selector: td:nth-child(9) + filters: + - name: replace + args: ["-mal", ""] + size: + selector: td:nth-child(6) + filters: + - name: replace + args: [".", ""] + - name: replace + args: [",", "."] + seeders: + selector: td:nth-child(7) + filters: + - name: regexp + args: "(\\d+)" + leechers: + selector: td:nth-child(8) + filters: + - name: regexp + args: "(\\d+)" + date: + selector: td:nth-child(5) + remove: br + filters: + - name: dateparse + args: "02.01.200615:04:05" + downloadvolumefactor: + case: + "font:contains(\"[OnlyUpload]\")": "0" + "font:contains(\"[-40 Download]\")": "0.6" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/torrentsmd.yml b/src/Jackett/Definitions/torrentsmd.yml index ad175c4d..4d93772a 100644 --- a/src/Jackett/Definitions/torrentsmd.yml +++ b/src/Jackett/Definitions/torrentsmd.yml @@ -1,94 +1,94 @@ ---- - site: torrentsmd - name: Torrents.Md - language: ru-mo - type: private - encoding: UTF-8 - links: - - https://torrentsmd.com/ - - caps: - categorymappings: - - {id: 1, cat: Movies, desc: "Filme"} - - {id: 2, cat: Audio, desc: "Muzică"} - - {id: 3, cat: PC, desc: "Software"} - - {id: 4, cat: Console, desc: "Jocuri"} - - {id: 5, cat: TV, desc: "Tv"} - - {id: 7, cat: Other, desc: "Alte"} - - {id: 8, cat: Books, desc: "Cărţi"} - - {id: 9, cat: Audio/Video, desc: "Muzică video"} - - {id: 10, cat: TV/Anime, desc: "Anime"} - - {id: 11, cat: Movies, desc: "Filme animate"} - - {id: 12, cat: Movies/DVD, desc: "DVD"} - - {id: 13, cat: Movies, desc: "Filme documentare"} - - {id: 14, cat: Audio/Audiobook, desc: "Cărţi audio"} - - {id: 15, cat: Other, desc: "Lecţii video"} - - {id: 16, cat: Other, desc: "Fotografii"} - - {id: 17, cat: TV/Sport, desc: "Sport"} - - {id: 18, cat: TV/HD, desc: "HDTV"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: login.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("eşuată")) - test: - path: browse.php - - search: - path: "{{if .Query.Keywords}}search.php{{else}}browse.php{{end}}" - inputs: - search_str: "{{ .Query.Keywords }}" - rows: - selector: table.tableTorrents > tbody > tr:has(a[href^="/details.php?id="]) - fields: - title: - selector: a[href^="/details.php?id="] - details: - selector: a[href^="/details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="/details.php?id="] - attribute: href - filters: - - name: replace - args: ["/details.php", "/download.php"] - files: - selector: td:nth-child(3) - date: - selector: td:nth-child(5) - filters: - - name: replace - args: ["ore", "hours ago"] - - name: replace - args: ["minute", "minutes ago"] - - name: dateparse - args: "01-02 2006" - - name: dateparse - args: "01-02" - size: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - downloadvolumefactor: - case: - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: torrentsmd + name: Torrents.Md + language: ru-mo + type: private + encoding: UTF-8 + links: + - https://torrentsmd.com/ + + caps: + categorymappings: + - {id: 1, cat: Movies, desc: "Filme"} + - {id: 2, cat: Audio, desc: "Muzică"} + - {id: 3, cat: PC, desc: "Software"} + - {id: 4, cat: Console, desc: "Jocuri"} + - {id: 5, cat: TV, desc: "Tv"} + - {id: 7, cat: Other, desc: "Alte"} + - {id: 8, cat: Books, desc: "Cărţi"} + - {id: 9, cat: Audio/Video, desc: "Muzică video"} + - {id: 10, cat: TV/Anime, desc: "Anime"} + - {id: 11, cat: Movies, desc: "Filme animate"} + - {id: 12, cat: Movies/DVD, desc: "DVD"} + - {id: 13, cat: Movies, desc: "Filme documentare"} + - {id: 14, cat: Audio/Audiobook, desc: "Cărţi audio"} + - {id: 15, cat: Other, desc: "Lecţii video"} + - {id: 16, cat: Other, desc: "Fotografii"} + - {id: 17, cat: TV/Sport, desc: "Sport"} + - {id: 18, cat: TV/HD, desc: "HDTV"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: login.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("eşuată")) + test: + path: browse.php + + search: + path: "{{if .Query.Keywords}}search.php{{else}}browse.php{{end}}" + inputs: + search_str: "{{ .Query.Keywords }}" + rows: + selector: table.tableTorrents > tbody > tr:has(a[href^="/details.php?id="]) + fields: + title: + selector: a[href^="/details.php?id="] + details: + selector: a[href^="/details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="/details.php?id="] + attribute: href + filters: + - name: replace + args: ["/details.php", "/download.php"] + files: + selector: td:nth-child(3) + date: + selector: td:nth-child(5) + filters: + - name: replace + args: ["ore", "hours ago"] + - name: replace + args: ["minute", "minutes ago"] + - name: dateparse + args: "01-02 2006" + - name: dateparse + args: "01-02" + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + downloadvolumefactor: + case: + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/torviet.yml b/src/Jackett/Definitions/torviet.yml index f4e75243..737f0575 100644 --- a/src/Jackett/Definitions/torviet.yml +++ b/src/Jackett/Definitions/torviet.yml @@ -1,131 +1,131 @@ ---- - site: torviet - name: TorViet - language: vi-vn - type: private - encoding: UTF-8 - links: - - http://torviet.com - - caps: - categorymappings: - - {id: 1, cat: Console, desc: "Game"} - - {id: 7, cat: PC/Games, desc: "PC"} - - {id: 133, cat: PC/Phone-Other, desc: "Handheld"} - - {id: 132, cat: Console, desc: "Console"} - - - {id: 2, cat: Movies, desc: "Movie"} - - {id: 23, cat: Movies/HD, desc: "mHD"} - - {id: 24, cat: Movies/SD, desc: "SD"} - - {id: 124, cat: Movies/HD, desc: "720p"} - - {id: 125, cat: Movies/HD, desc: "1080p"} - - {id: 127, cat: Movies/BluRay, desc: "Blu-ray"} - - - {id: 3, cat: TV, desc: "TV"} - - {id: 128, cat: TV/HD, desc: "HD"} - - {id: 129, cat: TV/SD, desc: "SD"} - - - {id: 4, cat: PC, desc: "Software"} - - {id: 76, cat: PC/0day, desc: "Windows"} - - {id: 77, cat: PC/Mac, desc: "MAC"} - - {id: 78, cat: PC, desc: "Linux"} - - {id: 79, cat: PC/Phone-Other, desc: "Handheld"} - - - {id: 5, cat: Audio, desc: "Music"} - - {id: 92, cat: Audio/Video, desc: "Music Video"} - - {id: 126, cat: Audio/Lossless, desc: "Lossless"} - - {id: 130, cat: Audio/MP3, desc: "Lossy"} - - {id: 131, cat: Audio, desc: "Surround"} - - - {id: 6, cat: Other, desc: "Misc"} - - {id: 112, cat: Books, desc: "Ebook"} - - {id: 113, cat: Other, desc: "Training Video"} - - {id: 117, cat: Audio/Audiobook, desc: "Audio book"} - - modes: - search: [q] - tv-search: [q, season, ep, imdbid] - movie-search: [q, imdbid] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /torrents.php - - ratio: - path: /torrents.php - selector: table#info_block - filters: - - name: regexp - args: "Ratio:\\s(.*?)\\s\\s" - - search: - path: /torrents.php - inputs: - search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" - sltCategory: 0 - sltSubCategory: 0 # can't sepcify multiple categorys so we're useing all always - sltGenre: 0 - incldead: 1 - spstate: 0 - inclbookmarked: 0 - search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" - search_mode: 0 - - rows: - selector: div#idtorrent > table.torrents > tbody > tr:has(table.torrentname) - fields: - title: - selector: a[class][title] - attribute: title - details: - selector: a[class][title] - attribute: href - description: - selector: td.embedded:has(a[title]) - remove: a[title] - category: - selector: a[href^="/torrents.php?sltSubCategory="] - attribute: href - filters: - - name: querystring - args: sltSubCategory - comments: - selector: td:nth-child(3) a - attribute: href - download: - selector: a[href^="/download.php?"] - attribute: href - size: - selector: td:nth-child(5) - seeders: - selector: td:nth-child(6) - leechers: - selector: td:nth-child(7) - date: - selector: td:nth-child(4) - filters: - - name: append - args: " ago" - grabs: - selector: td:nth-child(8) - downloadvolumefactor: - case: - img.pro_free: "0" - img.pro_free2up: "0" - img.pro_50pctdown: "0.5" - img.pro_50pctdown2up: "0.5" - img.pro_30pctdown: "0.3" - "*": "1" - uploadvolumefactor: - case: - img.pro_50pctdown2up: "2" - img.pro_free2up: "2" - img.pro_2up: "2" +--- + site: torviet + name: TorViet + language: vi-vn + type: private + encoding: UTF-8 + links: + - http://torviet.com + + caps: + categorymappings: + - {id: 1, cat: Console, desc: "Game"} + - {id: 7, cat: PC/Games, desc: "PC"} + - {id: 133, cat: PC/Phone-Other, desc: "Handheld"} + - {id: 132, cat: Console, desc: "Console"} + + - {id: 2, cat: Movies, desc: "Movie"} + - {id: 23, cat: Movies/HD, desc: "mHD"} + - {id: 24, cat: Movies/SD, desc: "SD"} + - {id: 124, cat: Movies/HD, desc: "720p"} + - {id: 125, cat: Movies/HD, desc: "1080p"} + - {id: 127, cat: Movies/BluRay, desc: "Blu-ray"} + + - {id: 3, cat: TV, desc: "TV"} + - {id: 128, cat: TV/HD, desc: "HD"} + - {id: 129, cat: TV/SD, desc: "SD"} + + - {id: 4, cat: PC, desc: "Software"} + - {id: 76, cat: PC/0day, desc: "Windows"} + - {id: 77, cat: PC/Mac, desc: "MAC"} + - {id: 78, cat: PC, desc: "Linux"} + - {id: 79, cat: PC/Phone-Other, desc: "Handheld"} + + - {id: 5, cat: Audio, desc: "Music"} + - {id: 92, cat: Audio/Video, desc: "Music Video"} + - {id: 126, cat: Audio/Lossless, desc: "Lossless"} + - {id: 130, cat: Audio/MP3, desc: "Lossy"} + - {id: 131, cat: Audio, desc: "Surround"} + + - {id: 6, cat: Other, desc: "Misc"} + - {id: 112, cat: Books, desc: "Ebook"} + - {id: 113, cat: Other, desc: "Training Video"} + - {id: 117, cat: Audio/Audiobook, desc: "Audio book"} + + modes: + search: [q] + tv-search: [q, season, ep, imdbid] + movie-search: [q, imdbid] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /torrents.php + + ratio: + path: /torrents.php + selector: table#info_block + filters: + - name: regexp + args: "Ratio:\\s(.*?)\\s\\s" + + search: + path: /torrents.php + inputs: + search: "{{if .Query.IMDBID}}{{ .Query.IMDBID }}{{else}}{{ .Keywords }}{{end}}" + sltCategory: 0 + sltSubCategory: 0 # can't sepcify multiple categorys so we're useing all always + sltGenre: 0 + incldead: 1 + spstate: 0 + inclbookmarked: 0 + search_area: "{{ if .Query.IMDBID }}4{{else}}0{{end}}" + search_mode: 0 + + rows: + selector: div#idtorrent > table.torrents > tbody > tr:has(table.torrentname) + fields: + title: + selector: a[class][title] + attribute: title + details: + selector: a[class][title] + attribute: href + description: + selector: td.embedded:has(a[title]) + remove: a[title] + category: + selector: a[href^="/torrents.php?sltSubCategory="] + attribute: href + filters: + - name: querystring + args: sltSubCategory + comments: + selector: td:nth-child(3) a + attribute: href + download: + selector: a[href^="/download.php?"] + attribute: href + size: + selector: td:nth-child(5) + seeders: + selector: td:nth-child(6) + leechers: + selector: td:nth-child(7) + date: + selector: td:nth-child(4) + filters: + - name: append + args: " ago" + grabs: + selector: td:nth-child(8) + downloadvolumefactor: + case: + img.pro_free: "0" + img.pro_free2up: "0" + img.pro_50pctdown: "0.5" + img.pro_50pctdown2up: "0.5" + img.pro_30pctdown: "0.3" + "*": "1" + uploadvolumefactor: + case: + img.pro_50pctdown2up: "2" + img.pro_free2up: "2" + img.pro_2up: "2" "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/totheglory.yml b/src/Jackett/Definitions/totheglory.yml index ac84a53b..0bd0dc7a 100644 --- a/src/Jackett/Definitions/totheglory.yml +++ b/src/Jackett/Definitions/totheglory.yml @@ -1,146 +1,146 @@ ---- - site: totheglory - name: ToTheGlory - description: "A chinese tracker" - language: zh-cn - type: private - encoding: UTF-8 - links: - - https://totheglory.im/ - - caps: - categories: - # 电影 - 电影DVDRip: Movies/SD # Movie DVDRip - 电影720p: Movies/HD # Movie 720p - 电影1080i/p: Movies/HD # Movie 1080i / p - BluRay原盘: Movies/BluRay # BluRay original disc - - # 纪录片 - 纪录片720p: Movies/HD # Documentary 720p - 纪录片1080i/p: Movies/HD # Documentary 1080i / p - 纪录片BluRay原盘: Movies/BluRay # Documentary BluRay Original - - # 剧集 - 欧美剧720p: TV/HD # 欧美剧720p - 欧美剧1080i/p: TV/HD # 欧美剧1080i/p - 高清日剧: TV/HD # 高清日剧 - 大陆港台剧1080i/p: TV/HD # 大陆港台剧1080i/p - 大陆港台剧720p: TV/HD # 大陆港台剧720p - 高清韩剧: TV/HD # 高清韩剧 - - # 剧集包 - 欧美剧包: TV/HD # 欧美剧包 - 日剧包: TV/HD # 日剧包 - 韩剧包: TV/HD # 韩剧包 - 华语剧包: TV/HD # 华语剧包 - - # 音乐 - (电影原声&Game)OST: Audio # (电影原声&Game)OST - 无损音乐FLAC&APE: Audio/Lossless # 无损音乐FLAC&APE - MV&演唱会: Audio/Video # MV&演唱会 - - # 其他 - 高清体育节目: TV/Sport # High-definition sports programs - 高清动漫: TV/Anime # HD animation - 韩国综艺: TV/HD # South Korea Variety - 日本综艺: TV/HD # Japanese variety - 高清综艺: TV/HD # HD Variety - MiniVideo: Other # MiniVideo - 补充音轨: Audio # Supplemental audio tracks - iPhone/iPad视频: PC/Phone-Other # IPhone / iPad video - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /login.php?returnto= - method: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: form#loginform > span.warning - test: - path: /my.php - - ratio: - path: /my.php - selector: span.smallfont:has(span#sp_signed) - filters: - - name: regexp - args: "分享率 : (.*?)\u00a0\u00a0" - - search: - path: /browse.php - inputs: - search_field: "{{range .Categories}}分类:`{{.}}` {{end}}{{ .Query.Keywords }}" - c: "M" - rows: - selector: table#torrent_table > tbody > tr[id] - fields: - description: - selector: div.name_left > a > b - title: - selector: div.name_left > a > b - remove: span - category: - selector: tr[id] td:nth-child(1) > a - attribute: href - filters: - - name: querystring - args: search_field - - name: replace - args: ["category:", ""] - - name: trim - args: "\"" - details: - selector: div.name_left > a - attribute: href - download: - selector: a.dl_a - attribute: href - filters: - - name: regexp - args: "^(/download.php/\\d+/).*" # cut off download url after ID to avoid bad request errors with curl - files: - selector: td:nth-child(3) - size: - selector: td:nth-child(7) - seeders: - selector: td:nth-child(9) - filters: - - name: split - args: ["/", 0] - leechers: - selector: td:nth-child(9) - filters: - - name: split - args: ["/", 1] - - name: replace - args: ["\n", ""] - grabs: - selector: td:nth-child(8) - filters: - - name: regexp - args: "(\\d+)" - date: - selector: td:nth-child(5) - filters: - - name: append - args: " +0800" - - name: dateparse - args: "2006-01-0215:04:05 -0700" - imdb: - selector: span.imdb_rate > a - attribute: href - downloadvolumefactor: - case: - img[alt="free"]: "0" - img[alt="50%"]: "0.5" - img[alt="30%"]: "0.3" - "*": "1" - uploadvolumefactor: - case: +--- + site: totheglory + name: ToTheGlory + description: "A chinese tracker" + language: zh-cn + type: private + encoding: UTF-8 + links: + - https://totheglory.im/ + + caps: + categories: + # 电影 + 电影DVDRip: Movies/SD # Movie DVDRip + 电影720p: Movies/HD # Movie 720p + 电影1080i/p: Movies/HD # Movie 1080i / p + BluRay原盘: Movies/BluRay # BluRay original disc + + # 纪录片 + 纪录片720p: Movies/HD # Documentary 720p + 纪录片1080i/p: Movies/HD # Documentary 1080i / p + 纪录片BluRay原盘: Movies/BluRay # Documentary BluRay Original + + # 剧集 + 欧美剧720p: TV/HD # 欧美剧720p + 欧美剧1080i/p: TV/HD # 欧美剧1080i/p + 高清日剧: TV/HD # 高清日剧 + 大陆港台剧1080i/p: TV/HD # 大陆港台剧1080i/p + 大陆港台剧720p: TV/HD # 大陆港台剧720p + 高清韩剧: TV/HD # 高清韩剧 + + # 剧集包 + 欧美剧包: TV/HD # 欧美剧包 + 日剧包: TV/HD # 日剧包 + 韩剧包: TV/HD # 韩剧包 + 华语剧包: TV/HD # 华语剧包 + + # 音乐 + (电影原声&Game)OST: Audio # (电影原声&Game)OST + 无损音乐FLAC&APE: Audio/Lossless # 无损音乐FLAC&APE + MV&演唱会: Audio/Video # MV&演唱会 + + # 其他 + 高清体育节目: TV/Sport # High-definition sports programs + 高清动漫: TV/Anime # HD animation + 韩国综艺: TV/HD # South Korea Variety + 日本综艺: TV/HD # Japanese variety + 高清综艺: TV/HD # HD Variety + MiniVideo: Other # MiniVideo + 补充音轨: Audio # Supplemental audio tracks + iPhone/iPad视频: PC/Phone-Other # IPhone / iPad video + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /login.php?returnto= + method: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: form#loginform > span.warning + test: + path: /my.php + + ratio: + path: /my.php + selector: span.smallfont:has(span#sp_signed) + filters: + - name: regexp + args: "分享率 : (.*?)\u00a0\u00a0" + + search: + path: /browse.php + inputs: + search_field: "{{range .Categories}}分类:`{{.}}` {{end}}{{ .Query.Keywords }}" + c: "M" + rows: + selector: table#torrent_table > tbody > tr[id] + fields: + description: + selector: div.name_left > a > b + title: + selector: div.name_left > a > b + remove: span + category: + selector: tr[id] td:nth-child(1) > a + attribute: href + filters: + - name: querystring + args: search_field + - name: replace + args: ["category:", ""] + - name: trim + args: "\"" + details: + selector: div.name_left > a + attribute: href + download: + selector: a.dl_a + attribute: href + filters: + - name: regexp + args: "^(/download.php/\\d+/).*" # cut off download url after ID to avoid bad request errors with curl + files: + selector: td:nth-child(3) + size: + selector: td:nth-child(7) + seeders: + selector: td:nth-child(9) + filters: + - name: split + args: ["/", 0] + leechers: + selector: td:nth-child(9) + filters: + - name: split + args: ["/", 1] + - name: replace + args: ["\n", ""] + grabs: + selector: td:nth-child(8) + filters: + - name: regexp + args: "(\\d+)" + date: + selector: td:nth-child(5) + filters: + - name: append + args: " +0800" + - name: dateparse + args: "2006-01-0215:04:05 -0700" + imdb: + selector: span.imdb_rate > a + attribute: href + downloadvolumefactor: + case: + img[alt="free"]: "0" + img[alt="50%"]: "0.5" + img[alt="30%"]: "0.3" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/uhdbits.yml b/src/Jackett/Definitions/uhdbits.yml index e399d479..daadb504 100644 --- a/src/Jackett/Definitions/uhdbits.yml +++ b/src/Jackett/Definitions/uhdbits.yml @@ -1,134 +1,134 @@ ---- - site: uhdbits - name: UHDBits - description: "A vietnamese general tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://uhdbits.org/ - - caps: - categories: - 1: Movies - 2: Audio - 3: TV - 4: Audio - 5: PC - 6: Other - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q, imdbid] - - login: - path: /login.php - form: form.auth_form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - keeplogged: "1" - error: - - selector: .auth_form > .warning - message: - selector: ".auth_form > .warning" - test: - path: /top10.php - - ratio: - path: /top10.php - selector: span.r99 - - search: - path: /torrents.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - searchstr: "{{if .Query.IMDBID}}{{else}}{{ .Query.Keywords }}{{end}}" - imdbid: "{{ .Query.IMDBIDShort }}" - tags_type: "1" - order_by: "time" - order_way: "desc" - action: "advanced" - searchsubmit: "1" - - rows: - selector: table#torrent_table > tbody > tr.torrent - fields: - # note: there are optinal extra colums - download: - selector: a[title="Download"] - attribute: href - filters: - - name: replace - args: ["\t", " "] - title: - selector: div.group_info - remove: span, div.tags - filters: - - name: replace - args: [" / Free", ""] - - name: replace - args: [" / ViE", ""] - - name: replace - args: [" / User", ""] - - name: replace - args: [" / Exclusive!", ""] - - name: replace - args: [" / ↓25%", ""] - - name: replace - args: [" / ↓50%", ""] - - name: replace - args: [" / ↓75%", ""] - - name: replace - args: [" / 2x 50%", ""] - - name: replace - args: [" / 2x Free", ""] - - name: replace - args: [" / 2x", ""] - downloadvolumefactor: - case: - "strong.blink_me:contains(\"Free\")": "0" - "strong.blink_me:contains(\"50\")": "0.5" - "strong.blink_me:contains(\"25\")": "0.75" - "strong.blink_me:contains(\"75\")": "0.25" - "*": "1" - uploadvolumefactor: - case: - "strong.blink_me:contains(\"2x\")": "2" - "*": "1" - category: - selector: a[href^="torrents.php?filter_cat"] - attribute: href - filters: - - name: regexp - args: "\\[(\\d+?)\\]" - comments: - selector: a.torrent_name - attribute: href - filters: - - name: replace - args: ["\t", " "] - details: - selector: a.torrent_name - attribute: href - filters: - - name: replace - args: ["\t", " "] - - name: regexp - args: (.*)#torrent\d+$ - size: - selector: td[class="number_column nobr"] - grabs: - selector: td[class="number_column nobr"] ~ td - files: - selector: td:nth-child(3) - seeders: - selector: td[class="number_column nobr"] ~ td ~ td - leechers: - selector: td[class="number_column nobr"] ~ td ~ td ~ td - date: - selector: td:nth-child(4) - filters: - - name: append - args: " ago" +--- + site: uhdbits + name: UHDBits + description: "A vietnamese general tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://uhdbits.org/ + + caps: + categories: + 1: Movies + 2: Audio + 3: TV + 4: Audio + 5: PC + 6: Other + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q, imdbid] + + login: + path: /login.php + form: form.auth_form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + keeplogged: "1" + error: + - selector: .auth_form > .warning + message: + selector: ".auth_form > .warning" + test: + path: /top10.php + + ratio: + path: /top10.php + selector: span.r99 + + search: + path: /torrents.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + searchstr: "{{if .Query.IMDBID}}{{else}}{{ .Query.Keywords }}{{end}}" + imdbid: "{{ .Query.IMDBIDShort }}" + tags_type: "1" + order_by: "time" + order_way: "desc" + action: "advanced" + searchsubmit: "1" + + rows: + selector: table#torrent_table > tbody > tr.torrent + fields: + # note: there are optinal extra colums + download: + selector: a[title="Download"] + attribute: href + filters: + - name: replace + args: ["\t", " "] + title: + selector: div.group_info + remove: span, div.tags + filters: + - name: replace + args: [" / Free", ""] + - name: replace + args: [" / ViE", ""] + - name: replace + args: [" / User", ""] + - name: replace + args: [" / Exclusive!", ""] + - name: replace + args: [" / ↓25%", ""] + - name: replace + args: [" / ↓50%", ""] + - name: replace + args: [" / ↓75%", ""] + - name: replace + args: [" / 2x 50%", ""] + - name: replace + args: [" / 2x Free", ""] + - name: replace + args: [" / 2x", ""] + downloadvolumefactor: + case: + "strong.blink_me:contains(\"Free\")": "0" + "strong.blink_me:contains(\"50\")": "0.5" + "strong.blink_me:contains(\"25\")": "0.75" + "strong.blink_me:contains(\"75\")": "0.25" + "*": "1" + uploadvolumefactor: + case: + "strong.blink_me:contains(\"2x\")": "2" + "*": "1" + category: + selector: a[href^="torrents.php?filter_cat"] + attribute: href + filters: + - name: regexp + args: "\\[(\\d+?)\\]" + comments: + selector: a.torrent_name + attribute: href + filters: + - name: replace + args: ["\t", " "] + details: + selector: a.torrent_name + attribute: href + filters: + - name: replace + args: ["\t", " "] + - name: regexp + args: (.*)#torrent\d+$ + size: + selector: td[class="number_column nobr"] + grabs: + selector: td[class="number_column nobr"] ~ td + files: + selector: td:nth-child(3) + seeders: + selector: td[class="number_column nobr"] ~ td ~ td + leechers: + selector: td[class="number_column nobr"] ~ td ~ td ~ td + date: + selector: td:nth-child(4) + filters: + - name: append + args: " ago" diff --git a/src/Jackett/Definitions/ultimategamerclub.yml b/src/Jackett/Definitions/ultimategamerclub.yml index b8fffe3f..292652d5 100644 --- a/src/Jackett/Definitions/ultimategamerclub.yml +++ b/src/Jackett/Definitions/ultimategamerclub.yml @@ -1,125 +1,125 @@ ---- - site: ultimategamerclub - name: Ultimate Gamer Club - language: en-us - type: private - encoding: UTF-8 - links: - - https://ultimategamer.club/ - - caps: - categorymappings: - # Computer - - {id: 10, cat: PC/Games, desc: "Windows"} - - {id: 11, cat: PC/Mac, desc: "Macintosh"} - - {id: 47, cat: PC, desc: "Linux"} - - {id: 56, cat: PC, desc: "VR"} - # Microsoft - - {id: 14, cat: Console/Xbox, desc: "Xbox"} - - {id: 61, cat: Console/Xbox360, desc: "Xbox 360"} - - {id: 62, cat: Console/XboxOne, desc: "Xbox One"} - # Sony - - {id: 43, cat: Console/PS3, desc: "Playstation "} - - {id: 63, cat: Console/PS3, desc: "Playstation 2"} - - {id: 64, cat: Console/PS3, desc: "Playstation 3"} - - {id: 67, cat: Console/PS4, desc: "Playstation 4"} - - {id: 12, cat: Console/Other, desc: "PSN"} - # Nintendo - - {id: 57, cat: Console/Other, desc: "Gamecube"} - - {id: 44, cat: Console/Wii, desc: "Wii"} - - {id: 46, cat: Console/Wii, desc: "Wii U"} - # Handheld - - {id: 15, cat: Console/NDS, desc: "DS"} - - {id: 68, cat: Console/NDS, desc: "3DS"} - - {id: 69, cat: Console/PSP, desc: "PSP"} - - {id: 70, cat: Console/PSVita, desc: "PSVita"} - # Mobile - - {id: 65, cat: PC/Phone-IOS, desc: "iOS"} - - {id: 49, cat: PC/Phone-Android, desc: "Android"} - - {id: 66, cat: PC/Phone-Other, desc: "Windows Mobile"} - # Reading - - {id: 53, cat: Books, desc: "Books/Mags"} - - {id: 60, cat: Books, desc: "Comics"} - - {id: 17, cat: Books, desc: "Guides"} - # Media - - {id: 58, cat: Audio/Video, desc: "Gaming Videos"} - - {id: 52, cat: Audio, desc: "OST"} - - {id: 55, cat: Other, desc: "Time for a Break"} - # Various - - {id: 59, cat: Other, desc: "Mods"} - - {id: 54, cat: Other, desc: "Updates/Fixes"} - - {id: 71, cat: PC/0day, desc: "Applications/Tools"} - - {id: 48, cat: Other, desc: "Retro"} - - {id: 72, cat: Other, desc: "Board Games"} - - {id: 75, cat: Other, desc: "Paper Crafting"} - - modes: - search: [q] - - login: - path: account-login.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.errFrame - test: - path: torrents-search.php - - search: - path: torrents-search.php - keywordsfilters: - - name: re_replace - args: ["[^a-zA-Z0-9]+", "+"] - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - rows: - selector: table.ttable_headinner > tbody > tr[class^="t-row"] - filters: - - name: andmatch - fields: - download: - selector: a[href^="download.php?id="] - attribute: href - title: - selector: a[href^="torrents-details.php?id="] - attribute: title - category: - selector: a[href^="torrents.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - details: - selector: a[href^="torrents-details.php?id="] - attribute: href - date: - selector: td:nth-child(2) span:contains("Added:") - filters: - - name: replace - args: ["Added: ", ""] - - name: replace - args: [" at", ""] - - name: append - args: " +00:00" - - name: dateparse - args: "02/01/2006 15:04:05 -07:00" - size: - selector: td:nth-child(7) - grabs: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(9) - leechers: - selector: td:nth-child(10) - downloadvolumefactor: - case: - ":root:has(globnfo:contains(\"sitewide freeleech\"))": "0" - img[title="freeleech"]: "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: ultimategamerclub + name: Ultimate Gamer Club + language: en-us + type: private + encoding: UTF-8 + links: + - https://ultimategamer.club/ + + caps: + categorymappings: + # Computer + - {id: 10, cat: PC/Games, desc: "Windows"} + - {id: 11, cat: PC/Mac, desc: "Macintosh"} + - {id: 47, cat: PC, desc: "Linux"} + - {id: 56, cat: PC, desc: "VR"} + # Microsoft + - {id: 14, cat: Console/Xbox, desc: "Xbox"} + - {id: 61, cat: Console/Xbox360, desc: "Xbox 360"} + - {id: 62, cat: Console/XboxOne, desc: "Xbox One"} + # Sony + - {id: 43, cat: Console/PS3, desc: "Playstation "} + - {id: 63, cat: Console/PS3, desc: "Playstation 2"} + - {id: 64, cat: Console/PS3, desc: "Playstation 3"} + - {id: 67, cat: Console/PS4, desc: "Playstation 4"} + - {id: 12, cat: Console/Other, desc: "PSN"} + # Nintendo + - {id: 57, cat: Console/Other, desc: "Gamecube"} + - {id: 44, cat: Console/Wii, desc: "Wii"} + - {id: 46, cat: Console/Wii, desc: "Wii U"} + # Handheld + - {id: 15, cat: Console/NDS, desc: "DS"} + - {id: 68, cat: Console/NDS, desc: "3DS"} + - {id: 69, cat: Console/PSP, desc: "PSP"} + - {id: 70, cat: Console/PSVita, desc: "PSVita"} + # Mobile + - {id: 65, cat: PC/Phone-IOS, desc: "iOS"} + - {id: 49, cat: PC/Phone-Android, desc: "Android"} + - {id: 66, cat: PC/Phone-Other, desc: "Windows Mobile"} + # Reading + - {id: 53, cat: Books, desc: "Books/Mags"} + - {id: 60, cat: Books, desc: "Comics"} + - {id: 17, cat: Books, desc: "Guides"} + # Media + - {id: 58, cat: Audio/Video, desc: "Gaming Videos"} + - {id: 52, cat: Audio, desc: "OST"} + - {id: 55, cat: Other, desc: "Time for a Break"} + # Various + - {id: 59, cat: Other, desc: "Mods"} + - {id: 54, cat: Other, desc: "Updates/Fixes"} + - {id: 71, cat: PC/0day, desc: "Applications/Tools"} + - {id: 48, cat: Other, desc: "Retro"} + - {id: 72, cat: Other, desc: "Board Games"} + - {id: 75, cat: Other, desc: "Paper Crafting"} + + modes: + search: [q] + + login: + path: account-login.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.errFrame + test: + path: torrents-search.php + + search: + path: torrents-search.php + keywordsfilters: + - name: re_replace + args: ["[^a-zA-Z0-9]+", "+"] + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + rows: + selector: table.ttable_headinner > tbody > tr[class^="t-row"] + filters: + - name: andmatch + fields: + download: + selector: a[href^="download.php?id="] + attribute: href + title: + selector: a[href^="torrents-details.php?id="] + attribute: title + category: + selector: a[href^="torrents.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + details: + selector: a[href^="torrents-details.php?id="] + attribute: href + date: + selector: td:nth-child(2) span:contains("Added:") + filters: + - name: replace + args: ["Added: ", ""] + - name: replace + args: [" at", ""] + - name: append + args: " +00:00" + - name: dateparse + args: "02/01/2006 15:04:05 -07:00" + size: + selector: td:nth-child(7) + grabs: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(9) + leechers: + selector: td:nth-child(10) + downloadvolumefactor: + case: + ":root:has(globnfo:contains(\"sitewide freeleech\"))": "0" + img[title="freeleech"]: "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/utorrents.yml b/src/Jackett/Definitions/utorrents.yml index 613742be..2562e394 100644 --- a/src/Jackett/Definitions/utorrents.yml +++ b/src/Jackett/Definitions/utorrents.yml @@ -1,128 +1,128 @@ ---- - site: utorrents - name: u-Torrent - language: ro-ro - type: private - encoding: windows-1252 - links: - - http://www.u-torrents.ro/ - - caps: - categorymappings: - - {id: 48, cat: Movies/3D, desc: "3D"} - - {id: 1, cat: PC/0day, desc: "Appz"} - - {id: 3, cat: Other, desc: "Cartoons"} - - {id: 42, cat: TV/Documentary, desc: "Documentaries"} - - {id: 6, cat: Books, desc: "eBooks"} - - {id: 11, cat: PC/Games, desc: "Games | PC"} - - {id: 12, cat: Console/PS3, desc: "Games | PS2"} - - {id: 36, cat: Console/PS3, desc: "Games | PS3"} - - {id: 40, cat: Console/PSP, desc: "Games | PSP"} - - {id: 25, cat: Console/Wii, desc: "Games | Wii"} - - {id: 16, cat: Console/Xbox, desc: "Games | XBOX"} - - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 43, cat: Movies/BluRay, desc: "Movies | Blu-Ray"} - - {id: 49, cat: Movies/BluRay, desc: "Movies | Blu-Ray-RO"} - - {id: 7, cat: Movies/DVD, desc: "Movies | DVD-R"} - - {id: 2, cat: Movies/DVD, desc: "Movies | DVD-RO"} - - {id: 17, cat: Movies/HD, desc: "Movies | HD"} - - {id: 45, cat: Movies/HD, desc: "Movies | HD-RO"} - - {id: 21, cat: Movies, desc: "Movies | Oldies"} - - {id: 38, cat: Movies, desc: "Movies | Packs"} - - {id: 8, cat: Movies/SD, desc: "Movies | x264"} - - {id: 4, cat: Movies/SD, desc: "Movies | x264-RO"} - - {id: 10, cat: Movies/SD, desc: "Movies | XviD"} - - {id: 44, cat: Movies/SD, desc: "Movies | XviD-RO"} - - {id: 5, cat: Audio/MP3, desc: "Music | Mp3"} - - {id: 39, cat: Audio, desc: "Music | Packs"} - - {id: 23, cat: Audio/Video, desc: "Music | Videos"} - - {id: 18, cat: Other, desc: "Pictures"} - - {id: 46, cat: XXX/Imageset, desc: "Pictures | xxx"} - - {id: 22, cat: TV/Sport, desc: "Sport"} - - {id: 50, cat: TV, desc: "STAR"} - - {id: 20, cat: TV/SD, desc: "TV | Episodes"} - - {id: 47, cat: TV/HD, desc: "TV | Episodes HD"} - - {id: 41, cat: TV, desc: "TV | Packs"} - - {id: 15, cat: XXX, desc: "xXx"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(h2:contains("failed")) - test: - path: /browse.php - - ratio: - path: /browse.php - selector: font:contains("Ratio:") > span - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: td.outer > table > tbody > tr:has(a[href^="details.php?id="]) - fields: - title: - selector: a[href^="details.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="download2.php"] - attribute: href - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: (\d+) - files: - selector: td:nth-child(3) - size: - selector: td:nth-child(6) - date: - selector: td:nth-child(5) - filters: - - name: trim - args: "\xF0" - - name: append - args: " +02:00" - - name: dateparse - args: "02-01-200615:04:05 -07:00" - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - banner: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: src=([^\s]+) - downloadvolumefactor: - case: - button.btnfree: "0" - "*": "1" - uploadvolumefactor: - case: - button.btn2xup: "2" - "*": "1" - description: - selector: td:nth-child(2) - remove: a[href^="details.php?id="] +--- + site: utorrents + name: u-Torrent + language: ro-ro + type: private + encoding: windows-1252 + links: + - http://www.u-torrents.ro/ + + caps: + categorymappings: + - {id: 48, cat: Movies/3D, desc: "3D"} + - {id: 1, cat: PC/0day, desc: "Appz"} + - {id: 3, cat: Other, desc: "Cartoons"} + - {id: 42, cat: TV/Documentary, desc: "Documentaries"} + - {id: 6, cat: Books, desc: "eBooks"} + - {id: 11, cat: PC/Games, desc: "Games | PC"} + - {id: 12, cat: Console/PS3, desc: "Games | PS2"} + - {id: 36, cat: Console/PS3, desc: "Games | PS3"} + - {id: 40, cat: Console/PSP, desc: "Games | PSP"} + - {id: 25, cat: Console/Wii, desc: "Games | Wii"} + - {id: 16, cat: Console/Xbox, desc: "Games | XBOX"} + - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 43, cat: Movies/BluRay, desc: "Movies | Blu-Ray"} + - {id: 49, cat: Movies/BluRay, desc: "Movies | Blu-Ray-RO"} + - {id: 7, cat: Movies/DVD, desc: "Movies | DVD-R"} + - {id: 2, cat: Movies/DVD, desc: "Movies | DVD-RO"} + - {id: 17, cat: Movies/HD, desc: "Movies | HD"} + - {id: 45, cat: Movies/HD, desc: "Movies | HD-RO"} + - {id: 21, cat: Movies, desc: "Movies | Oldies"} + - {id: 38, cat: Movies, desc: "Movies | Packs"} + - {id: 8, cat: Movies/SD, desc: "Movies | x264"} + - {id: 4, cat: Movies/SD, desc: "Movies | x264-RO"} + - {id: 10, cat: Movies/SD, desc: "Movies | XviD"} + - {id: 44, cat: Movies/SD, desc: "Movies | XviD-RO"} + - {id: 5, cat: Audio/MP3, desc: "Music | Mp3"} + - {id: 39, cat: Audio, desc: "Music | Packs"} + - {id: 23, cat: Audio/Video, desc: "Music | Videos"} + - {id: 18, cat: Other, desc: "Pictures"} + - {id: 46, cat: XXX/Imageset, desc: "Pictures | xxx"} + - {id: 22, cat: TV/Sport, desc: "Sport"} + - {id: 50, cat: TV, desc: "STAR"} + - {id: 20, cat: TV/SD, desc: "TV | Episodes"} + - {id: 47, cat: TV/HD, desc: "TV | Episodes HD"} + - {id: 41, cat: TV, desc: "TV | Packs"} + - {id: 15, cat: XXX, desc: "xXx"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(h2:contains("failed")) + test: + path: /browse.php + + ratio: + path: /browse.php + selector: font:contains("Ratio:") > span + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: td.outer > table > tbody > tr:has(a[href^="details.php?id="]) + fields: + title: + selector: a[href^="details.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="download2.php"] + attribute: href + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: (\d+) + files: + selector: td:nth-child(3) + size: + selector: td:nth-child(6) + date: + selector: td:nth-child(5) + filters: + - name: trim + args: "\xF0" + - name: append + args: " +02:00" + - name: dateparse + args: "02-01-200615:04:05 -07:00" + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + banner: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: src=([^\s]+) + downloadvolumefactor: + case: + button.btnfree: "0" + "*": "1" + uploadvolumefactor: + case: + button.btn2xup: "2" + "*": "1" + description: + selector: td:nth-child(2) + remove: a[href^="details.php?id="] diff --git a/src/Jackett/Definitions/waffles.yml b/src/Jackett/Definitions/waffles.yml index 4742da09..d3f74a06 100644 --- a/src/Jackett/Definitions/waffles.yml +++ b/src/Jackett/Definitions/waffles.yml @@ -1,165 +1,165 @@ ---- - site: waffles - name: Waffles - description: "Music, ebook and software tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://waffles.ch/ - - caps: - categorymappings: - - {id: 2, cat: Audio, desc: "70s"} - - {id: 3, cat: Audio, desc: "80s"} - - {id: 4, cat: Audio, desc: "90s"} - - {id: 82, cat: Audio, desc: "Acoustic"} - - {id: 5, cat: Audio, desc: "Alternative"} - - {id: 6, cat: Audio, desc: "Ambient"} - - {id: 85, cat: PC/ISO, desc: "Apps Linux"} - - {id: 84, cat: PC/Mac, desc: "Apps Mac"} - - {id: 83, cat: PC, desc: "Apps Win"} - - {id: 7, cat: Audio, desc: "Asian"} - - {id: 89, cat: Audio/Audiobook, desc: "Audiobook Fiction"} - - {id: 90, cat: Audio/Audiobook, desc: "Audiobook Non Fiction"} - - {id: 80, cat: Audio, desc: "Avant-Garde"} - - {id: 8, cat: Audio, desc: "Bluegrass"} - - {id: 9, cat: Audio, desc: "Blues"} - - {id: 10, cat: Audio, desc: "Breaks"} - - {id: 70, cat: Audio, desc: "Classic Rock"} - - {id: 11, cat: Audio, desc: "Classical"} - - {id: 72, cat: Audio, desc: "Comedy"} - - {id: 88, cat: Audio, desc: "Comics"} - - {id: 91, cat: Audio, desc: "Components"} - - {id: 12, cat: Audio, desc: "Country"} - - {id: 13, cat: Audio, desc: "Dance"} - - {id: 81, cat: Audio, desc: "Disco"} - - {id: 67, cat: Audio, desc: "Dream Pop"} - - {id: 14, cat: Audio, desc: "Drum 'n' Bass"} - - {id: 57, cat: Audio, desc: "Dubstep"} - - {id: 86, cat: Books, desc: "E-Book Fiction"} - - {id: 87, cat: Books, desc: "E-Book Nonfiction"} - - {id: 93, cat: Audio, desc: "E-Learning"} - - {id: 15, cat: Audio, desc: "Electronic"} - - {id: 16, cat: Audio, desc: "Emo"} - - {id: 17, cat: Audio, desc: "Experimental"} - - {id: 18, cat: Audio, desc: "Folk"} - - {id: 19, cat: Audio, desc: "Funk"} - - {id: 20, cat: Audio, desc: "Garage"} - - {id: 61, cat: Audio, desc: "Goth"} - - {id: 66, cat: Audio, desc: "Grime"} - - {id: 65, cat: Audio, desc: "Grindcore"} - - {id: 73, cat: Audio, desc: "Grunge"} - - {id: 21, cat: Audio, desc: "Hardcore"} - - {id: 22, cat: Audio, desc: "Hip-Hop/Rap"} - - {id: 23, cat: Audio, desc: "House"} - - {id: 24, cat: Audio, desc: "IDM"} - - {id: 25, cat: Audio, desc: "Indie"} - - {id: 26, cat: Audio, desc: "Industrial"} - - {id: 27, cat: Audio, desc: "J-Music"} - - {id: 28, cat: Audio, desc: "Jazz"} - - {id: 29, cat: Audio, desc: "Kids"} - - {id: 30, cat: Audio, desc: "Latin"} - - {id: 75, cat: Audio, desc: "Lounge"} - - {id: 31, cat: Audio, desc: "Metal"} - - {id: 32, cat: Audio, desc: "Misc"} - - {id: 79, cat: Audio, desc: "Musical"} - - {id: 59, cat: Audio, desc: "New Wave"} - - {id: 60, cat: Audio, desc: "No Wave"} - - {id: 63, cat: Audio, desc: "Noise"} - - {id: 64, cat: Audio, desc: "Noiserock"} - - {id: 33, cat: Audio, desc: "OST"} - - {id: 34, cat: Audio, desc: "Pop"} - - {id: 77, cat: Audio, desc: "Pop-Punk"} - - {id: 58, cat: Audio, desc: "Post-Punk"} - - {id: 35, cat: Audio, desc: "Post-Rock"} - - {id: 36, cat: Audio, desc: "Pre-60s"} - - {id: 69, cat: Audio, desc: "Progressive Rock"} - - {id: 68, cat: Audio, desc: "Protopunk"} - - {id: 37, cat: Audio, desc: "Psychedelic"} - - {id: 78, cat: Audio, desc: "Psytrance"} - - {id: 38, cat: Audio, desc: "Punk"} - - {id: 39, cat: Audio, desc: "R 'n' B"} - - {id: 40, cat: Audio, desc: "Reggae"} - - {id: 62, cat: Audio, desc: "Remixes"} - - {id: 41, cat: Audio, desc: "Rock"} - - {id: 71, cat: Audio, desc: "Screamo"} - - {id: 92, cat: Audio, desc: "Sheet music"} - - {id: 42, cat: Audio, desc: "Ska"} - - {id: 43, cat: Audio, desc: "Soul"} - - {id: 76, cat: Audio, desc: "Synthpop"} - - {id: 44, cat: Audio, desc: "Techno"} - - {id: 45, cat: Audio, desc: "Trance"} - - {id: 46, cat: Audio, desc: "Trip Hop"} - - {id: 47, cat: Audio, desc: "UK Garage"} - - {id: 74, cat: Audio, desc: "Video Game Music"} - - {id: 48, cat: Audio, desc: "World/Ethnic"} - - {id: 49, cat: Audio, desc: "Xmas"} - - modes: - search: [q] - - login: - path: login_check - method: post - inputs: - _username: "{{ .Config.username }}" - _password: "{{ .Config.password }}" - # error: - # - selector: title:contains("Redirecting to https://waffles.ch/login") - test: - path: index.php - - download: - selector: a[href^="download.php?id="] - - search: - path: browse.php - inputs: - $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" - q: "{{ .Query.Keywords }}" - rows: - selector: table#browsetable > tbody > tr:has(a[href^="/details.php?id="]) - fields: - category: - selector: a[href^="/browse.php?q="] - attribute: href - filters: - - name: querystring - args: c - title: - selector: td:nth-child(2) - download: - selector: a[href^="/details.php?id="] - attribute: href - filters: - - name: replace - args: ["/details.php?id=", "/download.php?id="] - details: - selector: a[href^="/details.php?id="] - attribute: href - grabs: - selector: td:nth-child(7) - filters: - - name: regexp - args: ([\d,]+) - files: - selector: td:nth-child(3) - size: - selector: td:nth-child(6) - seeders: - selector: td:nth-child(8) - leechers: - selector: td:nth-child(9) - date: - selector: td:nth-child(5) - filters: - - name: dateparse - args: "2 April 2017 +05:50" - downloadvolumefactor: - case: - "img[title=\"Free Torrent!\"]": "0" - "*": "1" - uploadvolumefactor: - case: +--- + site: waffles + name: Waffles + description: "Music, ebook and software tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://waffles.ch/ + + caps: + categorymappings: + - {id: 2, cat: Audio, desc: "70s"} + - {id: 3, cat: Audio, desc: "80s"} + - {id: 4, cat: Audio, desc: "90s"} + - {id: 82, cat: Audio, desc: "Acoustic"} + - {id: 5, cat: Audio, desc: "Alternative"} + - {id: 6, cat: Audio, desc: "Ambient"} + - {id: 85, cat: PC/ISO, desc: "Apps Linux"} + - {id: 84, cat: PC/Mac, desc: "Apps Mac"} + - {id: 83, cat: PC, desc: "Apps Win"} + - {id: 7, cat: Audio, desc: "Asian"} + - {id: 89, cat: Audio/Audiobook, desc: "Audiobook Fiction"} + - {id: 90, cat: Audio/Audiobook, desc: "Audiobook Non Fiction"} + - {id: 80, cat: Audio, desc: "Avant-Garde"} + - {id: 8, cat: Audio, desc: "Bluegrass"} + - {id: 9, cat: Audio, desc: "Blues"} + - {id: 10, cat: Audio, desc: "Breaks"} + - {id: 70, cat: Audio, desc: "Classic Rock"} + - {id: 11, cat: Audio, desc: "Classical"} + - {id: 72, cat: Audio, desc: "Comedy"} + - {id: 88, cat: Audio, desc: "Comics"} + - {id: 91, cat: Audio, desc: "Components"} + - {id: 12, cat: Audio, desc: "Country"} + - {id: 13, cat: Audio, desc: "Dance"} + - {id: 81, cat: Audio, desc: "Disco"} + - {id: 67, cat: Audio, desc: "Dream Pop"} + - {id: 14, cat: Audio, desc: "Drum 'n' Bass"} + - {id: 57, cat: Audio, desc: "Dubstep"} + - {id: 86, cat: Books, desc: "E-Book Fiction"} + - {id: 87, cat: Books, desc: "E-Book Nonfiction"} + - {id: 93, cat: Audio, desc: "E-Learning"} + - {id: 15, cat: Audio, desc: "Electronic"} + - {id: 16, cat: Audio, desc: "Emo"} + - {id: 17, cat: Audio, desc: "Experimental"} + - {id: 18, cat: Audio, desc: "Folk"} + - {id: 19, cat: Audio, desc: "Funk"} + - {id: 20, cat: Audio, desc: "Garage"} + - {id: 61, cat: Audio, desc: "Goth"} + - {id: 66, cat: Audio, desc: "Grime"} + - {id: 65, cat: Audio, desc: "Grindcore"} + - {id: 73, cat: Audio, desc: "Grunge"} + - {id: 21, cat: Audio, desc: "Hardcore"} + - {id: 22, cat: Audio, desc: "Hip-Hop/Rap"} + - {id: 23, cat: Audio, desc: "House"} + - {id: 24, cat: Audio, desc: "IDM"} + - {id: 25, cat: Audio, desc: "Indie"} + - {id: 26, cat: Audio, desc: "Industrial"} + - {id: 27, cat: Audio, desc: "J-Music"} + - {id: 28, cat: Audio, desc: "Jazz"} + - {id: 29, cat: Audio, desc: "Kids"} + - {id: 30, cat: Audio, desc: "Latin"} + - {id: 75, cat: Audio, desc: "Lounge"} + - {id: 31, cat: Audio, desc: "Metal"} + - {id: 32, cat: Audio, desc: "Misc"} + - {id: 79, cat: Audio, desc: "Musical"} + - {id: 59, cat: Audio, desc: "New Wave"} + - {id: 60, cat: Audio, desc: "No Wave"} + - {id: 63, cat: Audio, desc: "Noise"} + - {id: 64, cat: Audio, desc: "Noiserock"} + - {id: 33, cat: Audio, desc: "OST"} + - {id: 34, cat: Audio, desc: "Pop"} + - {id: 77, cat: Audio, desc: "Pop-Punk"} + - {id: 58, cat: Audio, desc: "Post-Punk"} + - {id: 35, cat: Audio, desc: "Post-Rock"} + - {id: 36, cat: Audio, desc: "Pre-60s"} + - {id: 69, cat: Audio, desc: "Progressive Rock"} + - {id: 68, cat: Audio, desc: "Protopunk"} + - {id: 37, cat: Audio, desc: "Psychedelic"} + - {id: 78, cat: Audio, desc: "Psytrance"} + - {id: 38, cat: Audio, desc: "Punk"} + - {id: 39, cat: Audio, desc: "R 'n' B"} + - {id: 40, cat: Audio, desc: "Reggae"} + - {id: 62, cat: Audio, desc: "Remixes"} + - {id: 41, cat: Audio, desc: "Rock"} + - {id: 71, cat: Audio, desc: "Screamo"} + - {id: 92, cat: Audio, desc: "Sheet music"} + - {id: 42, cat: Audio, desc: "Ska"} + - {id: 43, cat: Audio, desc: "Soul"} + - {id: 76, cat: Audio, desc: "Synthpop"} + - {id: 44, cat: Audio, desc: "Techno"} + - {id: 45, cat: Audio, desc: "Trance"} + - {id: 46, cat: Audio, desc: "Trip Hop"} + - {id: 47, cat: Audio, desc: "UK Garage"} + - {id: 74, cat: Audio, desc: "Video Game Music"} + - {id: 48, cat: Audio, desc: "World/Ethnic"} + - {id: 49, cat: Audio, desc: "Xmas"} + + modes: + search: [q] + + login: + path: login_check + method: post + inputs: + _username: "{{ .Config.username }}" + _password: "{{ .Config.password }}" + # error: + # - selector: title:contains("Redirecting to https://waffles.ch/login") + test: + path: index.php + + download: + selector: a[href^="download.php?id="] + + search: + path: browse.php + inputs: + $raw: "{{range .Categories}}filter_cat[{{.}}]=1&{{end}}" + q: "{{ .Query.Keywords }}" + rows: + selector: table#browsetable > tbody > tr:has(a[href^="/details.php?id="]) + fields: + category: + selector: a[href^="/browse.php?q="] + attribute: href + filters: + - name: querystring + args: c + title: + selector: td:nth-child(2) + download: + selector: a[href^="/details.php?id="] + attribute: href + filters: + - name: replace + args: ["/details.php?id=", "/download.php?id="] + details: + selector: a[href^="/details.php?id="] + attribute: href + grabs: + selector: td:nth-child(7) + filters: + - name: regexp + args: ([\d,]+) + files: + selector: td:nth-child(3) + size: + selector: td:nth-child(6) + seeders: + selector: td:nth-child(8) + leechers: + selector: td:nth-child(9) + date: + selector: td:nth-child(5) + filters: + - name: dateparse + args: "2 April 2017 +05:50" + downloadvolumefactor: + case: + "img[title=\"Free Torrent!\"]": "0" + "*": "1" + uploadvolumefactor: + case: "*": "1" \ No newline at end of file diff --git a/src/Jackett/Definitions/worldofp2p.yml b/src/Jackett/Definitions/worldofp2p.yml index 3ea615d0..8ccbe7e5 100644 --- a/src/Jackett/Definitions/worldofp2p.yml +++ b/src/Jackett/Definitions/worldofp2p.yml @@ -1,136 +1,136 @@ ---- - site: worldofp2p - name: WorldOfP2P - description: "A general tracker" - language: en-us - type: private - encoding: UTF-8 - links: - - https://worldofp2p.net - - caps: - categorymappings: - - {id: 9, cat: TV/Anime, desc: "Anime"} - - {id: 15, cat: PC/0day, desc: "Apps-Linux"} - - {id: 16, cat: PC/Mac, desc: "Apps-Macintosh"} - - {id: 17, cat: PC/Phone-Other, desc: "Apps-Mobile"} - - {id: 1, cat: PC/0day, desc: "Apps-Windows"} - - {id: 49, cat: Audio, desc: "Audio Tracks"} - - {id: 51, cat: Audio/Audiobook, desc: "AudioBook"} - - {id: 50, cat: Books, desc: "Ebooks"} - - {id: 23, cat: Console/Other, desc: "Games-Mixed"} - - {id: 32, cat: Console, desc: "Games-Packs"} - - {id: 2, cat: PC/Games, desc: "Games-PC"} - - {id: 12, cat: PC/Games, desc: "Games-PC Rips"} - - {id: 20, cat: Console/Other, desc: "Games-PS1"} - - {id: 8, cat: Console/Other, desc: "Games-PS2"} - - {id: 21, cat: Console/PS3, desc: "Games-PS3"} - - {id: 22, cat: Console/PS4, desc: "Games-PS4"} - - {id: 7, cat: Console/PSP, desc: "Games-PSP"} - - {id: 14, cat: Console/Wii, desc: "Games-Wii"} - - {id: 44, cat: Console/Xbox360, desc: "Games-Xbox 360"} - - {id: 45, cat: Console/Xbox, desc: "Games-Xbox One"} - - {id: 43, cat: Console/Xbox, desc: "Gamex-Xbox"} - - {id: 30, cat: Movies/HD, desc: "Movies-1080p"} - - {id: 56, cat: Movies/HD, desc: "Movies-2160p"} - - {id: 24, cat: Movies/3D, desc: "Movies-3D"} - - {id: 53, cat: Movies/SD, desc: "Movies-480p"} - - {id: 52, cat: Movies/SD, desc: "Movies-576p"} - - {id: 25, cat: Movies/HD, desc: "Movies-720p"} - - {id: 11, cat: Movies/BluRay, desc: "Movies-Bluray"} - - {id: 26, cat: Movies/HD, desc: "Movies-BRRip"} - - {id: 27, cat: Movies/SD, desc: "Movies-Camera"} - - {id: 10, cat: Movies/DVD, desc: "Movies-DVDR"} - - {id: 28, cat: Movies/Other, desc: "Movies-Oldies"} - - {id: 31, cat: Movies/Other, desc: "Movies-Packs"} - - {id: 57, cat: Movies/HD, desc: "Movies-Remux"} - - {id: 33, cat: Movies/Other, desc: "Movies-Sport"} - - {id: 29, cat: Movies/WEBDL, desc: "Movies-Web/DL"} - - {id: 3, cat: Movies/SD, desc: "Movies-XviD"} - - {id: 13, cat: Audio/Lossless, desc: "Music-Flac"} - - {id: 4, cat: Audio/MP3, desc: "Music-MP3"} - - {id: 18, cat: Audio, desc: "Music-Packs"} - - {id: 19, cat: Audio/Video, desc: "Music-Videos"} - - {id: 37, cat: TV/HD, desc: "TV-1080p"} - - {id: 54, cat: TV/HD, desc: "TV-2160p"} - - {id: 55, cat: TV/SD, desc: "TV-480p"} - - {id: 39, cat: TV/HD, desc: "TV-720p"} - - {id: 38, cat: TV/HD, desc: "TV-Bluray"} - - {id: 35, cat: TV/SD, desc: "TV-DVDR"} - - {id: 36, cat: TV/SD, desc: "TV-DVDRip"} - - {id: 41, cat: TV, desc: "TV-Packs"} - - {id: 42, cat: TV/WEB-DL, desc: "TV-Web/DL"} - - {id: 58, cat: TV/HD, desc: "TV-x264"} - - {id: 5, cat: TV/SD, desc: "TV-XviD"} - - {id: 46, cat: XXX, desc: "xXx-HD"} - - {id: 47, cat: XXX/Imageset, desc: "xXx-Images"} - - {id: 48, cat: XXX/Packs, desc: "xXx-Packs"} - - {id: 6, cat: XXX/XviD, desc: "xXx-XviD"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /takelogin.php - method: post - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - login: "Login" - error: - - selector: td.stdmsg2 - test: - path: /usercp.php?action=default - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: "1" - searchin: "title" - - rows: - selector: table.browsewidth100 > tbody > tr:has(a[href^="download.php?torrent="]) - filters: - - name: andmatch - fields: - title: - selector: a[href^="details.php?id="] - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - comments: - selector: a[href^="details.php?id="] - attribute: href - download: - selector: a[href^="download.php?torrent="] - attribute: href - files: - selector: td:nth-child(5) - size: - selector: td:nth-child(8) - seeders: - selector: td:nth-child(10) - leechers: - selector: td:nth-child(11) - date: - selector: td:nth-child(7) - grabs: - selector: a[href^="snatches.php?id="] - filters: - - name: regexp - args: "(\\d+)" - downloadvolumefactor: - case: - a.info:contains("Free"): "0" - img[src*="/free.png"]: "0" - "*": "1" - uploadvolumefactor: - case: - "*": "1" +--- + site: worldofp2p + name: WorldOfP2P + description: "A general tracker" + language: en-us + type: private + encoding: UTF-8 + links: + - https://worldofp2p.net + + caps: + categorymappings: + - {id: 9, cat: TV/Anime, desc: "Anime"} + - {id: 15, cat: PC/0day, desc: "Apps-Linux"} + - {id: 16, cat: PC/Mac, desc: "Apps-Macintosh"} + - {id: 17, cat: PC/Phone-Other, desc: "Apps-Mobile"} + - {id: 1, cat: PC/0day, desc: "Apps-Windows"} + - {id: 49, cat: Audio, desc: "Audio Tracks"} + - {id: 51, cat: Audio/Audiobook, desc: "AudioBook"} + - {id: 50, cat: Books, desc: "Ebooks"} + - {id: 23, cat: Console/Other, desc: "Games-Mixed"} + - {id: 32, cat: Console, desc: "Games-Packs"} + - {id: 2, cat: PC/Games, desc: "Games-PC"} + - {id: 12, cat: PC/Games, desc: "Games-PC Rips"} + - {id: 20, cat: Console/Other, desc: "Games-PS1"} + - {id: 8, cat: Console/Other, desc: "Games-PS2"} + - {id: 21, cat: Console/PS3, desc: "Games-PS3"} + - {id: 22, cat: Console/PS4, desc: "Games-PS4"} + - {id: 7, cat: Console/PSP, desc: "Games-PSP"} + - {id: 14, cat: Console/Wii, desc: "Games-Wii"} + - {id: 44, cat: Console/Xbox360, desc: "Games-Xbox 360"} + - {id: 45, cat: Console/Xbox, desc: "Games-Xbox One"} + - {id: 43, cat: Console/Xbox, desc: "Gamex-Xbox"} + - {id: 30, cat: Movies/HD, desc: "Movies-1080p"} + - {id: 56, cat: Movies/HD, desc: "Movies-2160p"} + - {id: 24, cat: Movies/3D, desc: "Movies-3D"} + - {id: 53, cat: Movies/SD, desc: "Movies-480p"} + - {id: 52, cat: Movies/SD, desc: "Movies-576p"} + - {id: 25, cat: Movies/HD, desc: "Movies-720p"} + - {id: 11, cat: Movies/BluRay, desc: "Movies-Bluray"} + - {id: 26, cat: Movies/HD, desc: "Movies-BRRip"} + - {id: 27, cat: Movies/SD, desc: "Movies-Camera"} + - {id: 10, cat: Movies/DVD, desc: "Movies-DVDR"} + - {id: 28, cat: Movies/Other, desc: "Movies-Oldies"} + - {id: 31, cat: Movies/Other, desc: "Movies-Packs"} + - {id: 57, cat: Movies/HD, desc: "Movies-Remux"} + - {id: 33, cat: Movies/Other, desc: "Movies-Sport"} + - {id: 29, cat: Movies/WEBDL, desc: "Movies-Web/DL"} + - {id: 3, cat: Movies/SD, desc: "Movies-XviD"} + - {id: 13, cat: Audio/Lossless, desc: "Music-Flac"} + - {id: 4, cat: Audio/MP3, desc: "Music-MP3"} + - {id: 18, cat: Audio, desc: "Music-Packs"} + - {id: 19, cat: Audio/Video, desc: "Music-Videos"} + - {id: 37, cat: TV/HD, desc: "TV-1080p"} + - {id: 54, cat: TV/HD, desc: "TV-2160p"} + - {id: 55, cat: TV/SD, desc: "TV-480p"} + - {id: 39, cat: TV/HD, desc: "TV-720p"} + - {id: 38, cat: TV/HD, desc: "TV-Bluray"} + - {id: 35, cat: TV/SD, desc: "TV-DVDR"} + - {id: 36, cat: TV/SD, desc: "TV-DVDRip"} + - {id: 41, cat: TV, desc: "TV-Packs"} + - {id: 42, cat: TV/WEB-DL, desc: "TV-Web/DL"} + - {id: 58, cat: TV/HD, desc: "TV-x264"} + - {id: 5, cat: TV/SD, desc: "TV-XviD"} + - {id: 46, cat: XXX, desc: "xXx-HD"} + - {id: 47, cat: XXX/Imageset, desc: "xXx-Images"} + - {id: 48, cat: XXX/Packs, desc: "xXx-Packs"} + - {id: 6, cat: XXX/XviD, desc: "xXx-XviD"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /takelogin.php + method: post + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + login: "Login" + error: + - selector: td.stdmsg2 + test: + path: /usercp.php?action=default + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: "1" + searchin: "title" + + rows: + selector: table.browsewidth100 > tbody > tr:has(a[href^="download.php?torrent="]) + filters: + - name: andmatch + fields: + title: + selector: a[href^="details.php?id="] + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + comments: + selector: a[href^="details.php?id="] + attribute: href + download: + selector: a[href^="download.php?torrent="] + attribute: href + files: + selector: td:nth-child(5) + size: + selector: td:nth-child(8) + seeders: + selector: td:nth-child(10) + leechers: + selector: td:nth-child(11) + date: + selector: td:nth-child(7) + grabs: + selector: a[href^="snatches.php?id="] + filters: + - name: regexp + args: "(\\d+)" + downloadvolumefactor: + case: + a.info:contains("Free"): "0" + img[src*="/free.png"]: "0" + "*": "1" + uploadvolumefactor: + case: + "*": "1" diff --git a/src/Jackett/Definitions/xtremezone.yml b/src/Jackett/Definitions/xtremezone.yml index 110e5bb6..3c7bdaaf 100644 --- a/src/Jackett/Definitions/xtremezone.yml +++ b/src/Jackett/Definitions/xtremezone.yml @@ -1,118 +1,118 @@ ---- - site: xtremezone - name: Xtreme Zone - language: ro-ro - type: semi-private - encoding: UTF-8 - links: - - https://www.myxz.org/ - - caps: - categorymappings: - - {id: 3, cat: TV/Anime, desc: "Anime/Hentai"} - - {id: 1, cat: PC/0day, desc: "Appz"} - - {id: 9, cat: TV/Documentary, desc: "Documentary"} - - {id: 6, cat: Books, desc: "eBooks"} - - {id: 52, cat: Console, desc: "Games-Console"} - - {id: 11, cat: PC/Games, desc: "Games-PC"} - - {id: 18, cat: Other, desc: "Images"} - - {id: 14, cat: PC, desc: "Linux"} - - {id: 37, cat: PC/Mac, desc: "Mac"} - - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} - - {id: 17, cat: Movies/BluRay, desc: "Movies-BluRay"} - - {id: 24, cat: Movies/BluRay, desc: "Movies-BluRayRO"} - - {id: 7, cat: Movies/DVD, desc: "Movies-DVD"} - - {id: 2, cat: Movies/DVD, desc: "Movies-DVD-RO"} - - {id: 8, cat: Movies/HD, desc: "Movies-HD"} - - {id: 29, cat: Movies/HD, desc: "Movies-HD-RO"} - - {id: 38, cat: Movies, desc: "Movies-Packs"} - - {id: 10, cat: Movies/SD, desc: "Movies-SD"} - - {id: 35, cat: Movies/SD, desc: "Movies-SD-RO"} - - {id: 5, cat: Audio, desc: "Music"} - - {id: 22, cat: TV/Sport, desc: "Sport"} - - {id: 43, cat: TV/HD, desc: "TV-HD"} - - {id: 44, cat: TV/HD, desc: "TV-HD-RO"} - - {id: 41, cat: TV, desc: "TV-Packs"} - - {id: 45, cat: TV/SD, desc: "TV-SD"} - - {id: 46, cat: TV/SD, desc: "TV-SD-RO"} - - {id: 15, cat: XXX, desc: "XXX"} - - {id: 47, cat: XXX, desc: "XXX-DVD"} - - {id: 48, cat: XXX, desc: "XXX-HD"} - - {id: 49, cat: XXX/Imageset, desc: "XXX-IMGSet"} - - {id: 50, cat: XXX, desc: "XXX-Packs"} - - {id: 51, cat: XXX, desc: "XXX-SD"} - - modes: - search: [q] - tv-search: [q, season, ep] - - login: - path: /login.php - method: form - form: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: td.embedded:has(center > h2:contains(failed)) - test: - path: /browse.php - - ratio: - path: /browse.php - selector: font:contains("Ratio:")+font - - search: - path: /browse.php - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - search: "{{ .Query.Keywords }}" - incldead: 1 - rows: - selector: table.browser > tbody > tr.browse[style] - fields: - title: - selector: a[href^="details.php?id="] - details: - selector: a[href^="details.php?id="] - attribute: href - category: - selector: a[href^="browse.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href^="dwn.php"] - attribute: href - size: - selector: td:nth-child(6) - date: - selector: td:nth-child(5) - filters: - - name: append - args: " +00:00" - - name: dateparse - args: "02-01-200615:04:05 -07:00" - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - banner: - selector: a[onmouseover][href^="details.php?id="] - attribute: onmouseover - filters: - - name: regexp - args: src=([^\s]+) - downloadvolumefactor: - case: - "img[title^=\"FreeLech: \"]": "0" - "img[title^=\"HALF: \"]": "0.5" - "*": "1" - uploadvolumefactor: - case: - "img[title^=\"2xUP: \"]": "2" - "*": "1" - description: - selector: td:nth-child(2) +--- + site: xtremezone + name: Xtreme Zone + language: ro-ro + type: semi-private + encoding: UTF-8 + links: + - https://www.myxz.org/ + + caps: + categorymappings: + - {id: 3, cat: TV/Anime, desc: "Anime/Hentai"} + - {id: 1, cat: PC/0day, desc: "Appz"} + - {id: 9, cat: TV/Documentary, desc: "Documentary"} + - {id: 6, cat: Books, desc: "eBooks"} + - {id: 52, cat: Console, desc: "Games-Console"} + - {id: 11, cat: PC/Games, desc: "Games-PC"} + - {id: 18, cat: Other, desc: "Images"} + - {id: 14, cat: PC, desc: "Linux"} + - {id: 37, cat: PC/Mac, desc: "Mac"} + - {id: 19, cat: PC/Phone-Other, desc: "Mobile"} + - {id: 17, cat: Movies/BluRay, desc: "Movies-BluRay"} + - {id: 24, cat: Movies/BluRay, desc: "Movies-BluRayRO"} + - {id: 7, cat: Movies/DVD, desc: "Movies-DVD"} + - {id: 2, cat: Movies/DVD, desc: "Movies-DVD-RO"} + - {id: 8, cat: Movies/HD, desc: "Movies-HD"} + - {id: 29, cat: Movies/HD, desc: "Movies-HD-RO"} + - {id: 38, cat: Movies, desc: "Movies-Packs"} + - {id: 10, cat: Movies/SD, desc: "Movies-SD"} + - {id: 35, cat: Movies/SD, desc: "Movies-SD-RO"} + - {id: 5, cat: Audio, desc: "Music"} + - {id: 22, cat: TV/Sport, desc: "Sport"} + - {id: 43, cat: TV/HD, desc: "TV-HD"} + - {id: 44, cat: TV/HD, desc: "TV-HD-RO"} + - {id: 41, cat: TV, desc: "TV-Packs"} + - {id: 45, cat: TV/SD, desc: "TV-SD"} + - {id: 46, cat: TV/SD, desc: "TV-SD-RO"} + - {id: 15, cat: XXX, desc: "XXX"} + - {id: 47, cat: XXX, desc: "XXX-DVD"} + - {id: 48, cat: XXX, desc: "XXX-HD"} + - {id: 49, cat: XXX/Imageset, desc: "XXX-IMGSet"} + - {id: 50, cat: XXX, desc: "XXX-Packs"} + - {id: 51, cat: XXX, desc: "XXX-SD"} + + modes: + search: [q] + tv-search: [q, season, ep] + + login: + path: /login.php + method: form + form: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: td.embedded:has(center > h2:contains(failed)) + test: + path: /browse.php + + ratio: + path: /browse.php + selector: font:contains("Ratio:")+font + + search: + path: /browse.php + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + search: "{{ .Query.Keywords }}" + incldead: 1 + rows: + selector: table.browser > tbody > tr.browse[style] + fields: + title: + selector: a[href^="details.php?id="] + details: + selector: a[href^="details.php?id="] + attribute: href + category: + selector: a[href^="browse.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href^="dwn.php"] + attribute: href + size: + selector: td:nth-child(6) + date: + selector: td:nth-child(5) + filters: + - name: append + args: " +00:00" + - name: dateparse + args: "02-01-200615:04:05 -07:00" + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + banner: + selector: a[onmouseover][href^="details.php?id="] + attribute: onmouseover + filters: + - name: regexp + args: src=([^\s]+) + downloadvolumefactor: + case: + "img[title^=\"FreeLech: \"]": "0" + "img[title^=\"HALF: \"]": "0.5" + "*": "1" + uploadvolumefactor: + case: + "img[title^=\"2xUP: \"]": "2" + "*": "1" + description: + selector: td:nth-child(2) remove: a, img \ No newline at end of file diff --git a/src/Jackett/Definitions/ztracker.yml b/src/Jackett/Definitions/ztracker.yml index 8a7f7fbc..34abc5e0 100644 --- a/src/Jackett/Definitions/ztracker.yml +++ b/src/Jackett/Definitions/ztracker.yml @@ -1,128 +1,128 @@ ---- - site: ztracker - name: Ztracker - language: hu-hu - type: semi-private - encoding: ISO-8859-2 - links: - - http://ztracker.org - - caps: - categorymappings: - - {id: 30, cat: Movies/SD, desc: "CAM/HUN"} - - {id: 29, cat: Movies/SD, desc: "CAM/Külf."} - - {id: 3, cat: Books, desc: "Ebook"} - - {id: 9, cat: Movies/HD, desc: "Film/HD-DVD/Hun"} - - {id: 10, cat: Movies/HD, desc: "Film/HD-DVD/Külf"} - - {id: 7, cat: Movies/SD, desc: "Film/Xvid/Hun"} - - {id: 8, cat: Movies/SD, desc: "Film/Xvid/Külf."} - - {id: 15, cat: XXX, desc: "Film/Xvid/XXX"} - - {id: 16, cat: XXX, desc: "Filmek/HD-DVD/XXX"} - - {id: 4, cat: PC/Games, desc: "Játék"} - - {id: 18, cat: Other, desc: "Képek"} - - {id: 17, cat: XXX, desc: "Képek/XXX"} - - {id: 27, cat: Books, desc: "Mese/Hun"} - - {id: 28, cat: Books, desc: "Mese/Külf."} - - {id: 24, cat: PC/Phone-Other, desc: "Program/Mobil"} - - {id: 1, cat: PC/0day, desc: "Program/Win"} - - {id: 25, cat: TV, desc: "Sorozat/Hun"} - - {id: 26, cat: TV, desc: "Sorozat/Külf."} - - {id: 11, cat: Audio, desc: "Zene/Hun"} - - {id: 12, cat: Audio, desc: "Zene/Külf."} - - modes: - search: [q] - tv-search: [q, season, ep] - movie-search: [q] - - login: - path: belepes.php - method: form - inputs: - username: "{{ .Config.username }}" - password: "{{ .Config.password }}" - error: - - selector: div.error - - selector: table:has(img[src="/pic/ts_error/error.jpg"]) - message: - selector: table:has(img[src="/pic/ts_error/error.jpg"]) - remove: style - test: - path: browse_old.php - - search: - path: browse_old.php - keywordsfilters: - - name: re_replace - args: ["[^a-zA-Z0-9]+", "%"] - inputs: - $raw: "{{range .Categories}}c{{.}}=1&{{end}}" - keywords: "{{ .Keywords }}" - search_type: "t_name" - rows: - selector: table[border="1"] > tbody > tr:has(a[href*="details.php?id="]) - fields: - title: - selector: a[href*="details.php?id="][onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: <font class=\\'smalltext\\'>(.*?)</font> - banner: - selector: a[href*="details.php?id="][onmouseover] - attribute: onmouseover - filters: - - name: regexp - args: img src=\\'(.*?)\\' - details: - selector: a[href*="details.php?id="][onmouseover] - attribute: href - category: - selector: a[href^="/browse_old.php?cat="] - attribute: href - filters: - - name: querystring - args: cat - download: - selector: a[href*="details.php?id="] - attribute: href - filters: - - name: replace - args: ["details.php", "download.php"] - seeders: - selector: td:nth-child(7) - leechers: - selector: td:nth-child(8) - files: - selector: td:nth-child(5) - grabs: - selector: td:nth-child(11) > b - filters: - - name: trim - args: "x" - size: - selector: td:nth-child(11) - remove: b - filters: - - name: replace - args: ["time", ""] - downloadvolumefactor: - case: - img[src="./pic/freedownload.gif"]: "0" - "*": "1" - uploadvolumefactor: - case: - img[src="./pic/x2.gif"]: "2" - "*": "1" - date: - selector: td:nth-child(2) - remove: a, img - filters: - - name: replace - args: ["\xA0", " "] - - name: replace - args: ["Ma", "Today"] - - name: replace - args: ["Tegnap", "Yesterday"] - - name: re_replace - args: ["12:(\\d\\d) PM", "00:$1 PM"] +--- + site: ztracker + name: Ztracker + language: hu-hu + type: semi-private + encoding: ISO-8859-2 + links: + - http://ztracker.org + + caps: + categorymappings: + - {id: 30, cat: Movies/SD, desc: "CAM/HUN"} + - {id: 29, cat: Movies/SD, desc: "CAM/Külf."} + - {id: 3, cat: Books, desc: "Ebook"} + - {id: 9, cat: Movies/HD, desc: "Film/HD-DVD/Hun"} + - {id: 10, cat: Movies/HD, desc: "Film/HD-DVD/Külf"} + - {id: 7, cat: Movies/SD, desc: "Film/Xvid/Hun"} + - {id: 8, cat: Movies/SD, desc: "Film/Xvid/Külf."} + - {id: 15, cat: XXX, desc: "Film/Xvid/XXX"} + - {id: 16, cat: XXX, desc: "Filmek/HD-DVD/XXX"} + - {id: 4, cat: PC/Games, desc: "Játék"} + - {id: 18, cat: Other, desc: "Képek"} + - {id: 17, cat: XXX, desc: "Képek/XXX"} + - {id: 27, cat: Books, desc: "Mese/Hun"} + - {id: 28, cat: Books, desc: "Mese/Külf."} + - {id: 24, cat: PC/Phone-Other, desc: "Program/Mobil"} + - {id: 1, cat: PC/0day, desc: "Program/Win"} + - {id: 25, cat: TV, desc: "Sorozat/Hun"} + - {id: 26, cat: TV, desc: "Sorozat/Külf."} + - {id: 11, cat: Audio, desc: "Zene/Hun"} + - {id: 12, cat: Audio, desc: "Zene/Külf."} + + modes: + search: [q] + tv-search: [q, season, ep] + movie-search: [q] + + login: + path: belepes.php + method: form + inputs: + username: "{{ .Config.username }}" + password: "{{ .Config.password }}" + error: + - selector: div.error + - selector: table:has(img[src="/pic/ts_error/error.jpg"]) + message: + selector: table:has(img[src="/pic/ts_error/error.jpg"]) + remove: style + test: + path: browse_old.php + + search: + path: browse_old.php + keywordsfilters: + - name: re_replace + args: ["[^a-zA-Z0-9]+", "%"] + inputs: + $raw: "{{range .Categories}}c{{.}}=1&{{end}}" + keywords: "{{ .Keywords }}" + search_type: "t_name" + rows: + selector: table[border="1"] > tbody > tr:has(a[href*="details.php?id="]) + fields: + title: + selector: a[href*="details.php?id="][onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: <font class=\\'smalltext\\'>(.*?)</font> + banner: + selector: a[href*="details.php?id="][onmouseover] + attribute: onmouseover + filters: + - name: regexp + args: img src=\\'(.*?)\\' + details: + selector: a[href*="details.php?id="][onmouseover] + attribute: href + category: + selector: a[href^="/browse_old.php?cat="] + attribute: href + filters: + - name: querystring + args: cat + download: + selector: a[href*="details.php?id="] + attribute: href + filters: + - name: replace + args: ["details.php", "download.php"] + seeders: + selector: td:nth-child(7) + leechers: + selector: td:nth-child(8) + files: + selector: td:nth-child(5) + grabs: + selector: td:nth-child(11) > b + filters: + - name: trim + args: "x" + size: + selector: td:nth-child(11) + remove: b + filters: + - name: replace + args: ["time", ""] + downloadvolumefactor: + case: + img[src="./pic/freedownload.gif"]: "0" + "*": "1" + uploadvolumefactor: + case: + img[src="./pic/x2.gif"]: "2" + "*": "1" + date: + selector: td:nth-child(2) + remove: a, img + filters: + - name: replace + args: ["\xA0", " "] + - name: replace + args: ["Ma", "Today"] + - name: replace + args: ["Tegnap", "Yesterday"] + - name: re_replace + args: ["12:(\\d\\d) PM", "00:$1 PM"] diff --git a/src/Jackett/Engine.cs b/src/Jackett/Engine.cs index 87e38fe1..2809aeda 100644 --- a/src/Jackett/Engine.cs +++ b/src/Jackett/Engine.cs @@ -1,191 +1,191 @@ -using Autofac; -using Jackett.Services; -using NLog; -using NLog.Config; -using NLog.LayoutRenderers; -using NLog.Targets; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett -{ - public class Engine - { - private static IContainer container = null; - - static Engine() - { - BuildContainer(); - - } - - public static void BuildContainer() - { - var builder = new ContainerBuilder(); - builder.RegisterModule<JackettModule>(); - container = builder.Build(); - - // Register the container in itself to allow for late resolves - var secondaryBuilder = new ContainerBuilder(); - secondaryBuilder.RegisterInstance<IContainer>(container).SingleInstance(); - SetupLogging(secondaryBuilder); - secondaryBuilder.Update(container); - - } - - public static IContainer GetContainer() - { - return container; - } - - public static bool IsWindows - { - get - { - return Environment.OSVersion.Platform == PlatformID.Win32NT; - } - } - - public static IConfigurationService ConfigService - { - get - { - return container.Resolve<IConfigurationService>(); - } - } - - public static IProcessService ProcessService - { - get - { - return container.Resolve<IProcessService>(); - } - } - - public static IServiceConfigService ServiceConfig - { - get - { - return container.Resolve<IServiceConfigService>(); - } - } - - public static ITrayLockService LockService - { - get - { - return container.Resolve<ITrayLockService>(); - } - } - - public static IServerService Server - { - get - { - return container.Resolve<IServerService>(); - } - } - - public static IRunTimeService RunTime - { - get - { - return container.Resolve<IRunTimeService>(); - } - } - - public static Logger Logger - { - get - { - return container.Resolve<Logger>(); - } - } - - public static ISecuityService SecurityService - { - get - { - return container.Resolve<ISecuityService>(); - } - } - - - public static void SetupLogging(ContainerBuilder builder = null, string logfile = "log.txt") - { - var logLevel = Startup.TracingEnabled ? LogLevel.Debug : LogLevel.Info; - // Add custom date time format renderer as the default is too long - ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("simpledatetime", typeof(SimpleDateTimeRenderer)); - - var logConfig = new LoggingConfiguration(); - var logFile = new FileTarget(); - logConfig.AddTarget("file", logFile); - logFile.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; - logFile.FileName = Path.Combine(ConfigurationService.GetAppDataFolderStatic(), logfile); - logFile.ArchiveFileName = "log.{#####}.txt"; - logFile.ArchiveAboveSize = 500000; - logFile.MaxArchiveFiles = 5; - logFile.KeepFileOpen = false; - logFile.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence; - var logFileRule = new LoggingRule("*", logLevel, logFile); - logConfig.LoggingRules.Add(logFileRule); - - var logConsole = new ColoredConsoleTarget(); - logConfig.AddTarget("console", logConsole); - - logConsole.Layout = "${simpledatetime} ${level} ${message} ${exception:format=ToString}"; - var logConsoleRule = new LoggingRule("*", logLevel, logConsole); - logConfig.LoggingRules.Add(logConsoleRule); - - var logService = new LogCacheService(); - logConfig.AddTarget("service", logService); - var serviceRule = new LoggingRule("*", logLevel, logService); - logConfig.LoggingRules.Add(serviceRule); - - LogManager.Configuration = logConfig; - if (builder != null) - { - builder.RegisterInstance<Logger>(LogManager.GetCurrentClassLogger()).SingleInstance(); - } - } - - public static void SetLogLevel(LogLevel level) - { - - foreach (var rule in LogManager.Configuration.LoggingRules) - { - if (level == LogLevel.Debug) - { - if (!rule.Levels.Contains(LogLevel.Debug)) - { - rule.EnableLoggingForLevel(LogLevel.Debug); - } - } - else - { - if (rule.Levels.Contains(LogLevel.Debug)) - { - rule.DisableLoggingForLevel(LogLevel.Debug); - } - } - - } - - LogManager.ReconfigExistingLoggers(); - } - } - - - [LayoutRenderer("simpledatetime")] - public class SimpleDateTimeRenderer : LayoutRenderer - { - protected override void Append(StringBuilder builder, LogEventInfo logEvent) - { - builder.Append(DateTime.Now.ToString("MM-dd HH:mm:ss")); - } - } -} +using Autofac; +using Jackett.Services; +using NLog; +using NLog.Config; +using NLog.LayoutRenderers; +using NLog.Targets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett +{ + public class Engine + { + private static IContainer container = null; + + static Engine() + { + BuildContainer(); + + } + + public static void BuildContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterModule<JackettModule>(); + container = builder.Build(); + + // Register the container in itself to allow for late resolves + var secondaryBuilder = new ContainerBuilder(); + secondaryBuilder.RegisterInstance<IContainer>(container).SingleInstance(); + SetupLogging(secondaryBuilder); + secondaryBuilder.Update(container); + + } + + public static IContainer GetContainer() + { + return container; + } + + public static bool IsWindows + { + get + { + return Environment.OSVersion.Platform == PlatformID.Win32NT; + } + } + + public static IConfigurationService ConfigService + { + get + { + return container.Resolve<IConfigurationService>(); + } + } + + public static IProcessService ProcessService + { + get + { + return container.Resolve<IProcessService>(); + } + } + + public static IServiceConfigService ServiceConfig + { + get + { + return container.Resolve<IServiceConfigService>(); + } + } + + public static ITrayLockService LockService + { + get + { + return container.Resolve<ITrayLockService>(); + } + } + + public static IServerService Server + { + get + { + return container.Resolve<IServerService>(); + } + } + + public static IRunTimeService RunTime + { + get + { + return container.Resolve<IRunTimeService>(); + } + } + + public static Logger Logger + { + get + { + return container.Resolve<Logger>(); + } + } + + public static ISecuityService SecurityService + { + get + { + return container.Resolve<ISecuityService>(); + } + } + + + public static void SetupLogging(ContainerBuilder builder = null, string logfile = "log.txt") + { + var logLevel = Startup.TracingEnabled ? LogLevel.Debug : LogLevel.Info; + // Add custom date time format renderer as the default is too long + ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("simpledatetime", typeof(SimpleDateTimeRenderer)); + + var logConfig = new LoggingConfiguration(); + var logFile = new FileTarget(); + logConfig.AddTarget("file", logFile); + logFile.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; + logFile.FileName = Path.Combine(ConfigurationService.GetAppDataFolderStatic(), logfile); + logFile.ArchiveFileName = "log.{#####}.txt"; + logFile.ArchiveAboveSize = 500000; + logFile.MaxArchiveFiles = 5; + logFile.KeepFileOpen = false; + logFile.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence; + var logFileRule = new LoggingRule("*", logLevel, logFile); + logConfig.LoggingRules.Add(logFileRule); + + var logConsole = new ColoredConsoleTarget(); + logConfig.AddTarget("console", logConsole); + + logConsole.Layout = "${simpledatetime} ${level} ${message} ${exception:format=ToString}"; + var logConsoleRule = new LoggingRule("*", logLevel, logConsole); + logConfig.LoggingRules.Add(logConsoleRule); + + var logService = new LogCacheService(); + logConfig.AddTarget("service", logService); + var serviceRule = new LoggingRule("*", logLevel, logService); + logConfig.LoggingRules.Add(serviceRule); + + LogManager.Configuration = logConfig; + if (builder != null) + { + builder.RegisterInstance<Logger>(LogManager.GetCurrentClassLogger()).SingleInstance(); + } + } + + public static void SetLogLevel(LogLevel level) + { + + foreach (var rule in LogManager.Configuration.LoggingRules) + { + if (level == LogLevel.Debug) + { + if (!rule.Levels.Contains(LogLevel.Debug)) + { + rule.EnableLoggingForLevel(LogLevel.Debug); + } + } + else + { + if (rule.Levels.Contains(LogLevel.Debug)) + { + rule.DisableLoggingForLevel(LogLevel.Debug); + } + } + + } + + LogManager.ReconfigExistingLoggers(); + } + } + + + [LayoutRenderer("simpledatetime")] + public class SimpleDateTimeRenderer : LayoutRenderer + { + protected override void Append(StringBuilder builder, LogEventInfo logEvent) + { + builder.Append(DateTime.Now.ToString("MM-dd HH:mm:ss")); + } + } +} diff --git a/src/Jackett/Indexers/7tor.cs b/src/Jackett/Indexers/7tor.cs index fc5bae7b..a2c53468 100644 --- a/src/Jackett/Indexers/7tor.cs +++ b/src/Jackett/Indexers/7tor.cs @@ -10,12 +10,12 @@ using System; using System.Text; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using AngleSharp.Parser.Html; -using AngleSharp.Dom; -using System.Text.RegularExpressions; -using System.Web; - +using System.Collections.Specialized; +using AngleSharp.Parser.Html; +using AngleSharp.Dom; +using System.Text.RegularExpressions; +using System.Web; + namespace Jackett.Indexers { public class SevenTor : BaseIndexer, IIndexer @@ -39,1548 +39,1548 @@ namespace Jackett.Indexers logger: l, p: ps, configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { + { Encoding = Encoding.UTF8; Language = "ru-ru"; Type = "semi-private"; - AddCategoryMapping(30, TorznabCatType.Movies, "Video content"); - AddCategoryMapping(31, TorznabCatType.TVDocumentary, " Documentary films, TV and other video"); - AddCategoryMapping(127, TorznabCatType.TVDocumentary, " Documentary movies and TV shows"); - AddCategoryMapping(1071, TorznabCatType.TVDocumentary, " Documentary (DVD)"); - AddCategoryMapping(1069, TorznabCatType.TVDocumentary, " Documentary (HD Video)"); - AddCategoryMapping(1070, TorznabCatType.TVDocumentary, " TV shows (HD Video), non-documentary"); - AddCategoryMapping(1843, TorznabCatType.TVDocumentary, " Biographies. Personality and idols (HD Video)"); - AddCategoryMapping(1844, TorznabCatType.TVDocumentary, " Military Science (HD Video)"); - AddCategoryMapping(1845, TorznabCatType.TVDocumentary, " Natural science, science and technology (HD Video)"); - AddCategoryMapping(1846, TorznabCatType.TVDocumentary, " Travel and Tourism (HD Video)"); - AddCategoryMapping(1847, TorznabCatType.TVDocumentary, " Flora and fauna (HD Video)"); - AddCategoryMapping(1848, TorznabCatType.TVDocumentary, " History (HD Video)"); - AddCategoryMapping(1849, TorznabCatType.TVDocumentary, " BBC, Discovery, National Geographic (HD Video)"); - AddCategoryMapping(1850, TorznabCatType.TVDocumentary, " Crime Documentary (HD Video)"); - AddCategoryMapping(1072, TorznabCatType.TVDocumentary, " Biographies. Personality and idols"); - AddCategoryMapping(1073, TorznabCatType.TVDocumentary, " Documentary movies and TV shows on film and animation (including biographies)"); - AddCategoryMapping(1074, TorznabCatType.TVDocumentary, " Art, Art History"); - AddCategoryMapping(1075, TorznabCatType.TVDocumentary, " Documentaries and television music (including biographies)"); - AddCategoryMapping(1076, TorznabCatType.TVDocumentary, " criminal documentary"); - AddCategoryMapping(1077, TorznabCatType.TVDocumentary, " Secrets of the Ages / Special Services / Conspiracy Theory"); - AddCategoryMapping(1078, TorznabCatType.TVDocumentary, " Movies and TV shows on military issues"); - AddCategoryMapping(1079, TorznabCatType.TVDocumentary, " The Second World War"); - AddCategoryMapping(1675, TorznabCatType.TVDocumentary, " Fleet"); - AddCategoryMapping(1080, TorznabCatType.TVDocumentary, " Accidents / Accidents / Disasters"); - AddCategoryMapping(1081, TorznabCatType.TVDocumentary, " Aviation (video)"); - AddCategoryMapping(1674, TorznabCatType.TVDocumentary, " Wings of Russia"); - AddCategoryMapping(1082, TorznabCatType.TVDocumentary, " Space (Video)"); - AddCategoryMapping(576, TorznabCatType.TVDocumentary, " Popular-science film"); - AddCategoryMapping(1083, TorznabCatType.TVDocumentary, " The flora and fauna of the (video)"); - AddCategoryMapping(1084, TorznabCatType.TVDocumentary, " Travel and Tourism (video)"); - AddCategoryMapping(1085, TorznabCatType.TVDocumentary, " Social talk show"); - AddCategoryMapping(1086, TorznabCatType.TVDocumentary, " Information-analytical and socio-political programs"); - AddCategoryMapping(1087, TorznabCatType.TVDocumentary, " Architecture and Construction (video)"); - AddCategoryMapping(1088, TorznabCatType.TVDocumentary, " All about home, life and design"); - AddCategoryMapping(1094, TorznabCatType.TVDocumentary, " The era of the Soviet Union (video)"); - AddCategoryMapping(1095, TorznabCatType.TVDocumentary, " Battle of psychics / Theory improbability / Seekers / Galileo"); - AddCategoryMapping(1096, TorznabCatType.TVDocumentary, " Russian sensation / Program Maximum / Profession Reporter / Ukrainian sensation"); - AddCategoryMapping(1097, TorznabCatType.TVDocumentary, " Paranormal activity"); - AddCategoryMapping(1098, TorznabCatType.TVDocumentary, " Alternative history, Science (video)"); - AddCategoryMapping(1099, TorznabCatType.TVDocumentary, " Vnezhanrovaya documentary"); - AddCategoryMapping(1660, TorznabCatType.TVDocumentary, " Foreign TV-brands"); - AddCategoryMapping(1089, TorznabCatType.TVDocumentary, " BBC"); - AddCategoryMapping(1090, TorznabCatType.TVDocumentary, " Discovery"); - AddCategoryMapping(1091, TorznabCatType.TVDocumentary, " National Geographic"); - AddCategoryMapping(1661, TorznabCatType.TVDocumentary, " Animal Planet"); - AddCategoryMapping(1662, TorznabCatType.TVDocumentary, " Da Vinci Learning"); - AddCategoryMapping(1663, TorznabCatType.TVDocumentary, " History Channel"); - AddCategoryMapping(1664, TorznabCatType.TVDocumentary, " PBS"); - AddCategoryMapping(1665, TorznabCatType.TVDocumentary, " Readers Digest"); - AddCategoryMapping(1666, TorznabCatType.TVDocumentary, " I wonder about everything"); - AddCategoryMapping(1667, TorznabCatType.TVDocumentary, " Mega-Projects"); - AddCategoryMapping(1668, TorznabCatType.TVDocumentary, " Prehistoric world"); - AddCategoryMapping(1669, TorznabCatType.TVDocumentary, " World of Tomorrow"); - AddCategoryMapping(1670, TorznabCatType.TVDocumentary, " Jacques Cousteau Odyssey"); - AddCategoryMapping(1671, TorznabCatType.TVDocumentary, " Secrets and Mysteries"); - AddCategoryMapping(1672, TorznabCatType.TVDocumentary, " History"); - AddCategoryMapping(1092, TorznabCatType.TVDocumentary, " History: Ancient World / Antiquity / Middle Ages (video)"); - AddCategoryMapping(1093, TorznabCatType.TVDocumentary, " History: modern and contemporary times"); - AddCategoryMapping(1673, TorznabCatType.TVDocumentary, " Relax, landscape film"); - AddCategoryMapping(1100, TorznabCatType.TVDocumentary, " Miscellaneous / nekonditsiya (documentary and transfer)"); - AddCategoryMapping(569, TorznabCatType.TV, " Entertaining TV programs and shows, fun and humor"); - AddCategoryMapping(1101, TorznabCatType.TV, " Mind games and quizzes"); - AddCategoryMapping(1102, TorznabCatType.TV, " Reality and talk show host / category / impressions"); - AddCategoryMapping(1103, TorznabCatType.TV, " children's TV Shows"); - AddCategoryMapping(1104, TorznabCatType.TV, " KVN"); - AddCategoryMapping(1105, TorznabCatType.TV, " Drink Post"); - AddCategoryMapping(1106, TorznabCatType.TV, " Distorting Mirror / town / in the town"); - AddCategoryMapping(1107, TorznabCatType.TV, " ice show"); - AddCategoryMapping(1108, TorznabCatType.TV, " Thank God you came!"); - AddCategoryMapping(1109, TorznabCatType.TV, " dinner Party"); - AddCategoryMapping(1110, TorznabCatType.TV, " Good jokes"); - AddCategoryMapping(1111, TorznabCatType.TV, " Evening Quarter"); - AddCategoryMapping(1112, TorznabCatType.TV, " Films with a funny transfer (parody)"); - AddCategoryMapping(1113, TorznabCatType.TV, " Stand-up comedy"); - AddCategoryMapping(1114, TorznabCatType.TV, " Moment of glory"); - AddCategoryMapping(1115, TorznabCatType.TV, " Ukrainian Show"); - AddCategoryMapping(1116, TorznabCatType.TV, " Star Factory"); - AddCategoryMapping(1117, TorznabCatType.TV, " Dance shows, concerts, performances"); - AddCategoryMapping(1118, TorznabCatType.TV, " Circus"); - AddCategoryMapping(1119, TorznabCatType.TV, " School for Scandal"); - AddCategoryMapping(1120, TorznabCatType.TV, " Satirists and humorists"); - AddCategoryMapping(1873, TorznabCatType.TV, " Musical show"); - AddCategoryMapping(1121, TorznabCatType.TV, " Humorous audio transmission"); - AddCategoryMapping(1122, TorznabCatType.TV, " Audio and video clips (Jokes and humor)"); - AddCategoryMapping(32, TorznabCatType.Movies, " Foreign movies"); - AddCategoryMapping(567, TorznabCatType.Movies, " Foreign films 2016"); - AddCategoryMapping(37, TorznabCatType.Movies, " Foreign films 2011 - 2015 the year"); - AddCategoryMapping(38, TorznabCatType.Movies, " Foreign films of the year 2006-2010"); - AddCategoryMapping(39, TorznabCatType.Movies, " Foreign films of the year 2001-2005"); - AddCategoryMapping(40, TorznabCatType.Movies, " Foreign films 1991-2000"); - AddCategoryMapping(1031, TorznabCatType.Movies, " Foreign films until 1990"); - AddCategoryMapping(41, TorznabCatType.Movies, " Classic foreign film"); - AddCategoryMapping(1044, TorznabCatType.Movies, " Classic foreign film (DVD Video)"); - AddCategoryMapping(1042, TorznabCatType.Movies, " Classic foreign film (HD Video)"); - AddCategoryMapping(1051, TorznabCatType.Movies, " Foreign films (DVD)"); - AddCategoryMapping(43, TorznabCatType.Movies, " Foreign films (HD Video)"); - AddCategoryMapping(773, TorznabCatType.Movies, " Grindhouse"); - AddCategoryMapping(1040, TorznabCatType.Movies, " Grindhouse DVD and HD Video"); - AddCategoryMapping(913, TorznabCatType.Movies, " Asian movies"); - AddCategoryMapping(1010, TorznabCatType.MoviesSD, " Asian movies (DVD Video)"); - AddCategoryMapping(1052, TorznabCatType.MoviesHD, " Asian films (HD Video)"); - AddCategoryMapping(1032, TorznabCatType.Movies, " Indian film"); - AddCategoryMapping(1043, TorznabCatType.Movies, " Indian Cinema DVD and HD Video"); - AddCategoryMapping(1039, TorznabCatType.Movies, " Shorts"); - AddCategoryMapping(1041, TorznabCatType.Movies, " Sound track and Translations"); - AddCategoryMapping(1804, TorznabCatType.Movies, " Foreign films without translation"); - AddCategoryMapping(1805, TorznabCatType.Movies, " Foreign films in the original"); - AddCategoryMapping(1806, TorznabCatType.Movies, " Foreign films in the original (HD)"); - AddCategoryMapping(1807, TorznabCatType.Movies, " Foreign films with translation into other languages"); - AddCategoryMapping(33, TorznabCatType.Movies, " national cinema"); - AddCategoryMapping(568, TorznabCatType.Movies, " Domestic films 2016"); - AddCategoryMapping(44, TorznabCatType.Movies, " Domestic films of 2011 - 2015 the year"); - AddCategoryMapping(45, TorznabCatType.Movies, " Domestic films of the year 2006-2010"); - AddCategoryMapping(46, TorznabCatType.Movies, " Domestic films of the year 2001-2005"); - AddCategoryMapping(47, TorznabCatType.Movies, " Domestic films of the year 1992-2000"); - AddCategoryMapping(48, TorznabCatType.Movies, " Cinema of the USSR, Soviet Russia, the Russian republic (1917-1991)"); - AddCategoryMapping(1609, TorznabCatType.Movies, " Films of the Russian Empire (until 1917)"); - AddCategoryMapping(1048, TorznabCatType.Movies, " National cinema (DVD)"); - AddCategoryMapping(49, TorznabCatType.Movies, " National cinema (HD Video)"); - AddCategoryMapping(1046, TorznabCatType.Movies, " Author debuts"); - AddCategoryMapping(1047, TorznabCatType.Movies, " Child domestic films"); - AddCategoryMapping(1011, TorznabCatType.Movies, " Art-house cinema and author"); - AddCategoryMapping(1012, TorznabCatType.Movies, " Art-house and auteur cinema (DVD)"); - AddCategoryMapping(1038, TorznabCatType.Movies, " Art-house and auteur cinema (HD Video)"); - AddCategoryMapping(1033, TorznabCatType.Movies, " Author cinema"); - AddCategoryMapping(1035, TorznabCatType.Movies, " Shorts (Art-house cinema and author)"); - AddCategoryMapping(1036, TorznabCatType.Movies, " Documentaries (Art-house cinema and author)"); - AddCategoryMapping(1037, TorznabCatType.Movies, " Animation (Art-house cinema and author)"); - AddCategoryMapping(1617, TorznabCatType.Movies, " Intelligent movie"); - AddCategoryMapping(34, TorznabCatType.TV, " TV series"); - AddCategoryMapping(51, TorznabCatType.TV, " Domestic series"); - AddCategoryMapping(1860, TorznabCatType.TV, " Domestic series 2016"); - AddCategoryMapping(1810, TorznabCatType.TV, " Domestic series 2015"); - AddCategoryMapping(574, TorznabCatType.TV, " Domestic series 2014"); - AddCategoryMapping(50, TorznabCatType.TV, " Foreign TV series"); - AddCategoryMapping(1861, TorznabCatType.TV, " Foreign series 2016"); - AddCategoryMapping(1809, TorznabCatType.TV, " Foreign series 2015"); - AddCategoryMapping(575, TorznabCatType.TV, " Foreign series 2014"); - AddCategoryMapping(1181, TorznabCatType.TV, " Foreign TV shows (HD Video)"); - AddCategoryMapping(1184, TorznabCatType.TV, " Soaps Spain, Italy, Latin America, Turkey and India"); - AddCategoryMapping(1185, TorznabCatType.TV, " Indian series"); - AddCategoryMapping(1186, TorznabCatType.TV, " spanish series"); - AddCategoryMapping(1187, TorznabCatType.TV, " Italian TV series"); - AddCategoryMapping(1615, TorznabCatType.TV, " Latin American soap operas"); - AddCategoryMapping(1189, TorznabCatType.TV, " Official short version Latin American serials"); - AddCategoryMapping(1190, TorznabCatType.TV, " Latin American soap operas with the voice acting (folders distribution)"); - AddCategoryMapping(1191, TorznabCatType.TV, " Latin American serials with subtitles"); - AddCategoryMapping(1188, TorznabCatType.TV, " turkish TV series"); - AddCategoryMapping(1192, TorznabCatType.TV, " Serials OST Spain, Italy, Latin America, Turkey and India"); - AddCategoryMapping(1193, TorznabCatType.TV, " For sub-standard hands"); - AddCategoryMapping(1194, TorznabCatType.TV, " Asian series"); - AddCategoryMapping(1195, TorznabCatType.TV, " Chinese serials with subtitles"); - AddCategoryMapping(1196, TorznabCatType.TV, " Korean soap operas with the voice acting"); - AddCategoryMapping(1197, TorznabCatType.TV, " Korean serials with subtitles"); - AddCategoryMapping(1198, TorznabCatType.TV, " Other Asian series with the voice acting"); - AddCategoryMapping(1199, TorznabCatType.TV, " Taiwanese serials with subtitles"); - AddCategoryMapping(1200, TorznabCatType.TV, " Japanese serials with subtitles"); - AddCategoryMapping(1201, TorznabCatType.TV, " Japanese TV series with the voice acting"); - AddCategoryMapping(1202, TorznabCatType.TV, " VMV and others. Videos"); - AddCategoryMapping(1203, TorznabCatType.TV, " OST Asian series"); - AddCategoryMapping(1616, TorznabCatType.TV, " Soaps with Ukrainian sound track"); - AddCategoryMapping(1049, TorznabCatType.TV, " Theater"); - AddCategoryMapping(1050, TorznabCatType.TV, " Benefit. Master of Arts of Russian theater and cinema."); - AddCategoryMapping(1053, TorznabCatType.Movies3D, " 3D / Stereo (Cinema, Animation, Video, TV & Sports)"); - AddCategoryMapping(1054, TorznabCatType.Movies3D, " 3D Movies"); - AddCategoryMapping(581, TorznabCatType.Movies3D, " Foreign Movies 3D"); - AddCategoryMapping(1614, TorznabCatType.Movies3D, " Asian Movies 3D"); - AddCategoryMapping(1613, TorznabCatType.Movies3D, " Domestic 3D Movies"); - AddCategoryMapping(586, TorznabCatType.Movies3D, " 3D Animation"); - AddCategoryMapping(1055, TorznabCatType.Movies3D, " 3D Documentaries"); - AddCategoryMapping(1056, TorznabCatType.Movies3D, " 3D Sports"); - AddCategoryMapping(1057, TorznabCatType.Movies3D, " 3D Clips, Music Videos, Movie Trailers"); - AddCategoryMapping(53, TorznabCatType.TVAnime, " Animation and cartoons"); - AddCategoryMapping(341, TorznabCatType.TVAnime, " Foreign cartoons"); - AddCategoryMapping(344, TorznabCatType.TVAnime, " Foreign cartoons (DVD)"); - AddCategoryMapping(342, TorznabCatType.TVAnime, " Domestic cartoons"); - AddCategoryMapping(1062, TorznabCatType.TVAnime, " Domestic full-length cartoons"); - AddCategoryMapping(1061, TorznabCatType.TVAnime, " Domestic cartoons (DVD)"); - AddCategoryMapping(346, TorznabCatType.TVAnime, " short cartoons"); - AddCategoryMapping(1058, TorznabCatType.TVAnime, " Short Film (HD Video)"); - AddCategoryMapping(1060, TorznabCatType.TVAnime, " Foreign short cartoons"); - AddCategoryMapping(1059, TorznabCatType.TVAnime, " Foreign Short Film (DVD)"); - AddCategoryMapping(345, TorznabCatType.TVAnime, " Cartoons HD-Video"); - AddCategoryMapping(1063, TorznabCatType.TVAnime, " cartoon Puzzle"); - AddCategoryMapping(343, TorznabCatType.TVAnime, " Serial cartoons"); - AddCategoryMapping(1813, TorznabCatType.TVAnime, " Cartoons and cartoons without translation"); - AddCategoryMapping(1814, TorznabCatType.TVAnime, " Cartoons and cartoons with the Ukrainian sound track"); - AddCategoryMapping(1064, TorznabCatType.TVAnime, " Archive and nekonditsiya cartoons and animated series"); - AddCategoryMapping(54, TorznabCatType.TVAnime, " Anime and everything associated with him"); - AddCategoryMapping(55, TorznabCatType.TVAnime, " Anime (Main)"); - AddCategoryMapping(976, TorznabCatType.TVAnime, " Anime (pleerny subsection)"); - AddCategoryMapping(977, TorznabCatType.TVAnime, " Anime (QC subsection)"); - AddCategoryMapping(333, TorznabCatType.TVAnime, " Anime DVD-Video"); - AddCategoryMapping(334, TorznabCatType.TVAnime, " Anime (HD and Blu-ray)"); - AddCategoryMapping(1815, TorznabCatType.TVAnime, " OST to Anime"); - AddCategoryMapping(979, TorznabCatType.TVAnime, " Anime OST to (lossless)"); - AddCategoryMapping(335, TorznabCatType.TVAnime, " OST to Anime (mp3 and others lossy-format)"); - AddCategoryMapping(336, TorznabCatType.TVAnime, " Manga and other art"); - AddCategoryMapping(474, TorznabCatType.TVAnime, " Manga"); - AddCategoryMapping(680, TorznabCatType.TVAnime, " Wallpapers, artbook, and others."); - AddCategoryMapping(60, TorznabCatType.TVAnime, " Anime (Hentai)"); - AddCategoryMapping(978, TorznabCatType.TVAnime, " AMV etc. Videos"); - AddCategoryMapping(980, TorznabCatType.TVAnime, " Japanese cartoons"); - AddCategoryMapping(1065, TorznabCatType.TVAnime, " Archive and nekonditsiya Anime"); - AddCategoryMapping(922, TorznabCatType.Movies, " Faith and Religion (Video)"); - AddCategoryMapping(1068, TorznabCatType.Movies, " Islam (video)"); - AddCategoryMapping(1067, TorznabCatType.Movies, " Cults and new religious movements (video)"); - AddCategoryMapping(1066, TorznabCatType.Movies, " Religions of India, Tibet and East Asia (video)"); - AddCategoryMapping(923, TorznabCatType.Movies, " Christianity (video)"); - AddCategoryMapping(577, TorznabCatType.TVSport, " Health & Sports (sports tournaments, films and programs etc)"); - AddCategoryMapping(583, TorznabCatType.TVSport, " wrestling"); - AddCategoryMapping(740, TorznabCatType.TVSport, " Professional Wrestling"); - AddCategoryMapping(1176, TorznabCatType.TVSport, " Independent Wrestling"); - AddCategoryMapping(1177, TorznabCatType.TVSport, " International Wrestling"); - AddCategoryMapping(1178, TorznabCatType.TVSport, " Oldschool Wrestling"); - AddCategoryMapping(1179, TorznabCatType.TVSport, " Documentary Wrestling"); - AddCategoryMapping(677, TorznabCatType.TVSport, " cycle racing"); - AddCategoryMapping(724, TorznabCatType.TVSport, " Tennis"); - AddCategoryMapping(925, TorznabCatType.TVSport, " Athletics / Water Sports"); - AddCategoryMapping(926, TorznabCatType.TVSport, " motorcycling"); - AddCategoryMapping(930, TorznabCatType.TVSport, " Hockey"); - AddCategoryMapping(1171, TorznabCatType.TVSport, " Hockey / Bandy"); - AddCategoryMapping(1172, TorznabCatType.TVSport, " International hockey tournaments"); - AddCategoryMapping(1173, TorznabCatType.TVSport, " KXL"); - AddCategoryMapping(932, TorznabCatType.TVSport, " NHL (until 2011/12)"); - AddCategoryMapping(931, TorznabCatType.TVSport, " NHL (2013)"); - AddCategoryMapping(1174, TorznabCatType.TVSport, " USSR - Canada"); - AddCategoryMapping(1175, TorznabCatType.TVSport, " Documentaries and Analysis (hockey)"); - AddCategoryMapping(1123, TorznabCatType.TVSport, " Motorsports"); - AddCategoryMapping(1125, TorznabCatType.TVSport, " Formula 1"); - AddCategoryMapping(1126, TorznabCatType.TVSport, " Formula 1 2012-2015"); - AddCategoryMapping(1127, TorznabCatType.TVSport, " Formula January 2016"); - AddCategoryMapping(1128, TorznabCatType.TVSport, " Volleyball / Handball"); - AddCategoryMapping(1129, TorznabCatType.TVSport, " Billiards"); - AddCategoryMapping(1130, TorznabCatType.TVSport, " Poker"); - AddCategoryMapping(1131, TorznabCatType.TVSport, " Bodybuilding / Power Sports"); - AddCategoryMapping(1132, TorznabCatType.TVSport, " Boxing"); - AddCategoryMapping(1133, TorznabCatType.TVSport, " Classic arts"); - AddCategoryMapping(1134, TorznabCatType.TVSport, " MMA and K-1"); - AddCategoryMapping(1135, TorznabCatType.TVSport, " American football"); - AddCategoryMapping(1136, TorznabCatType.TVSport, " Rugby"); - AddCategoryMapping(1137, TorznabCatType.TVSport, " Baseball"); - AddCategoryMapping(1138, TorznabCatType.TVSport, " Badminton / Table Tennis"); - AddCategoryMapping(1139, TorznabCatType.TVSport, " Gymnastics / Dance Competitions"); - AddCategoryMapping(1140, TorznabCatType.TVSport, " Winter sports"); - AddCategoryMapping(1141, TorznabCatType.TVSport, " Figure skating"); - AddCategoryMapping(1142, TorznabCatType.TVSport, " Biathlon"); - AddCategoryMapping(1143, TorznabCatType.TVSport, " Extreme sports"); - AddCategoryMapping(1144, TorznabCatType.TVSport, " Football"); - AddCategoryMapping(1146, TorznabCatType.TVSport, " Russia 2015-2016"); - AddCategoryMapping(1145, TorznabCatType.TVSport, " Russia 2014-2015"); - AddCategoryMapping(1147, TorznabCatType.TVSport, " Russia / USSR"); - AddCategoryMapping(1148, TorznabCatType.TVSport, " England"); - AddCategoryMapping(1149, TorznabCatType.TVSport, " Spain"); - AddCategoryMapping(1150, TorznabCatType.TVSport, " Italy"); - AddCategoryMapping(1151, TorznabCatType.TVSport, " Germany"); - AddCategoryMapping(1851, TorznabCatType.TVSport, " France"); - AddCategoryMapping(1152, TorznabCatType.TVSport, " Ukraine"); - AddCategoryMapping(1153, TorznabCatType.TVSport, " Other national championships and cups"); - AddCategoryMapping(1154, TorznabCatType.TVSport, " International football tournaments"); - AddCategoryMapping(1157, TorznabCatType.TVSport, " European Cups"); - AddCategoryMapping(1156, TorznabCatType.TVSport, " Eurocup 2011-2014"); - AddCategoryMapping(1155, TorznabCatType.TVSport, " Eurocup 2014-2015"); - AddCategoryMapping(1161, TorznabCatType.TVSport, " Eurocup 2015-2016"); - AddCategoryMapping(1158, TorznabCatType.TVSport, " European Championships"); - AddCategoryMapping(1159, TorznabCatType.TVSport, " European Championship 2016"); - AddCategoryMapping(1863, TorznabCatType.TVSport, " European Championships 2016 (Selection section)"); - AddCategoryMapping(1864, TorznabCatType.TVSport, " European Championship 2016 (the final part)"); - AddCategoryMapping(1160, TorznabCatType.TVSport, " World Championships"); - AddCategoryMapping(1852, TorznabCatType.TVSport, " World Championship 2018"); - AddCategoryMapping(1162, TorznabCatType.TVSport, " Friendly tournaments and matches"); - AddCategoryMapping(1163, TorznabCatType.TVSport, " The survey and analysis of transmission"); - AddCategoryMapping(1853, TorznabCatType.TVSport, " The survey and analytical programs 2014-2016"); - AddCategoryMapping(1164, TorznabCatType.TVSport, " Mini Soccer / Football"); - AddCategoryMapping(1165, TorznabCatType.TVSport, " Basketball"); - AddCategoryMapping(1166, TorznabCatType.TVSport, " International competitions"); - AddCategoryMapping(1167, TorznabCatType.TVSport, " NBA / NCAA (until 2000)"); - AddCategoryMapping(1168, TorznabCatType.TVSport, " NBA / NCAA (2000-2010 biennium)."); - AddCategoryMapping(1169, TorznabCatType.TVSport, " NBA / NCAA (2010-2016 biennium)."); - AddCategoryMapping(1170, TorznabCatType.TVSport, " European club basketball"); - AddCategoryMapping(1885, TorznabCatType.TVSport, " XXXI Summer Olympic Games. Rio de Janeiro 2016"); - AddCategoryMapping(1886, TorznabCatType.TVSport, " Football"); - AddCategoryMapping(1887, TorznabCatType.TVSport, " Basketball"); - AddCategoryMapping(1888, TorznabCatType.TVSport, " Volleyball / Beach Volleyball / Handball / Water Polo"); - AddCategoryMapping(1889, TorznabCatType.TVSport, " Athletics"); - AddCategoryMapping(1890, TorznabCatType.TVSport, " Tennis / Table Tennis / Badminton"); - AddCategoryMapping(1891, TorznabCatType.TVSport, " Boxing / Martial Arts and Martial Arts / Weightlifting"); - AddCategoryMapping(1892, TorznabCatType.TVSport, " Water Sports / Boating"); - AddCategoryMapping(1893, TorznabCatType.TVSport, " cycle racing"); - AddCategoryMapping(1894, TorznabCatType.TVSport, " Gymnastics"); - AddCategoryMapping(1895, TorznabCatType.TVSport, " Other Sports"); - AddCategoryMapping(1896, TorznabCatType.TVSport, " The survey and analysis of transmission"); - AddCategoryMapping(1897, TorznabCatType.Books, " Books, manuals, periodicals on the Olympic theme"); - AddCategoryMapping(1575, TorznabCatType.Movies, " Video for mobile devices"); - AddCategoryMapping(1576, TorznabCatType.Movies, " Video for Smartphones and PDAs"); - AddCategoryMapping(1577, TorznabCatType.Movies, " Mobile Video (3GP)"); - AddCategoryMapping(1589, TorznabCatType.Movies, " Video for Apple devices"); - AddCategoryMapping(1590, TorznabCatType.Movies, " Video (Apple)"); - AddCategoryMapping(1592, TorznabCatType.MoviesSD, " Movies for iPod, iPhone, iPad"); - AddCategoryMapping(1593, TorznabCatType.MoviesSD, " Soaps for iPod, iPhone, iPad"); - AddCategoryMapping(1594, TorznabCatType.MoviesSD, " Cartoons to iPod, iPhone, iPad"); - AddCategoryMapping(1595, TorznabCatType.MoviesSD, " Anime for iPod, iPhone, iPad"); - AddCategoryMapping(1596, TorznabCatType.MoviesSD, " The music video for iPod, iPhone, iPad"); - AddCategoryMapping(1591, TorznabCatType.MoviesHD, " Videos HD (Apple)"); - AddCategoryMapping(1597, TorznabCatType.MoviesHD, " HD Movies to Apple TV"); - AddCategoryMapping(1598, TorznabCatType.MoviesHD, " HD TV Shows on Apple TV"); - AddCategoryMapping(1599, TorznabCatType.MoviesHD, " Cartoon HD for Apple TV"); - AddCategoryMapping(1600, TorznabCatType.MoviesHD, " Documentary HD video for Apple TV"); - AddCategoryMapping(1601, TorznabCatType.MoviesHD, " Music HD video for Apple TV"); - AddCategoryMapping(1568, TorznabCatType.Movies, " Trailers and additional materials for films"); - AddCategoryMapping(1549, TorznabCatType.Movies, " Video consoles"); - AddCategoryMapping(1550, TorznabCatType.Movies, " Video for PSVita"); - AddCategoryMapping(1551, TorznabCatType.Movies, " Movies for PSP"); - AddCategoryMapping(1552, TorznabCatType.Movies, " for PSP TV Shows"); - AddCategoryMapping(1553, TorznabCatType.Movies, " Cartoons for PSP"); - AddCategoryMapping(1554, TorznabCatType.Movies, " Drama for PSP"); - AddCategoryMapping(1555, TorznabCatType.Movies, " Anime for PSP"); - AddCategoryMapping(1556, TorznabCatType.Movies, " Video to PSP"); - AddCategoryMapping(1557, TorznabCatType.Movies, " Videos for the PS3 and other consoles"); - AddCategoryMapping(165, TorznabCatType.Movies, " video Game"); - AddCategoryMapping(1544, TorznabCatType.Movies, " Walkthroughs"); - AddCategoryMapping(1545, TorznabCatType.Movies, " Lineage II Movies"); - AddCategoryMapping(1546, TorznabCatType.Movies, " World of Warcraft Movies"); - AddCategoryMapping(1547, TorznabCatType.Movies, " Counter Strike Movies"); - AddCategoryMapping(1045, TorznabCatType.Movies, " Video on moderation"); - AddCategoryMapping(1607, TorznabCatType.MoviesSD, " DVD Video on moderation"); - AddCategoryMapping(1608, TorznabCatType.MoviesHD, " HD Video on moderation"); - AddCategoryMapping(1837, TorznabCatType.PCGames, "Releases SE7ENKILLS"); - AddCategoryMapping(1839, TorznabCatType.PCGames, " Games"); - AddCategoryMapping(1840, TorznabCatType.PCGames, " Patches"); - AddCategoryMapping(1841, TorznabCatType.PCGames, " Frequently asked questions about cs: go"); - AddCategoryMapping(1182, TorznabCatType.PCGames, "Games"); - AddCategoryMapping(158, TorznabCatType.PCGames, " Games General Section"); - AddCategoryMapping(68, TorznabCatType.PCGames, " Games for PC"); - AddCategoryMapping(69, TorznabCatType.PCGames, " Hot New Releases Games"); - AddCategoryMapping(1030, TorznabCatType.PCGames, " Games without pills"); - AddCategoryMapping(70, TorznabCatType.PCGames, " Action"); - AddCategoryMapping(148, TorznabCatType.PCGames, " FPS (1st Person)"); - AddCategoryMapping(149, TorznabCatType.PCGames, " TPS (3rd Person)"); - AddCategoryMapping(150, TorznabCatType.PCGames, " Stealth Action"); - AddCategoryMapping(151, TorznabCatType.PCGames, " Tactical shooter"); - AddCategoryMapping(71, TorznabCatType.PCGames, " RPG"); - AddCategoryMapping(72, TorznabCatType.PCGames, " Strategy"); - AddCategoryMapping(152, TorznabCatType.PCGames, " RTS (real time strategy)"); - AddCategoryMapping(153, TorznabCatType.PCGames, " TBS (turn-based strategy)"); - AddCategoryMapping(154, TorznabCatType.PCGames, " Wargame"); - AddCategoryMapping(155, TorznabCatType.PCGames, " Economic strategies"); - AddCategoryMapping(73, TorznabCatType.PCGames, " Simulations"); - AddCategoryMapping(74, TorznabCatType.PCGames, " Autos and Racing"); - AddCategoryMapping(75, TorznabCatType.PCGames, " Sports simulators"); - AddCategoryMapping(464, TorznabCatType.PCGames, " Other simulators"); - AddCategoryMapping(1531, TorznabCatType.PCGames, " Space and flight simulators"); - AddCategoryMapping(76, TorznabCatType.PCGames, " Aviasimulators"); - AddCategoryMapping(463, TorznabCatType.PCGames, " space Simulation"); - AddCategoryMapping(1540, TorznabCatType.PCGames, " Microsoft Flight Simulator add-ons, and for him"); - AddCategoryMapping(1541, TorznabCatType.PCGames, " Scripts, meshes and airports"); - AddCategoryMapping(1542, TorznabCatType.PCGames, " Airplanes and helicopters"); - AddCategoryMapping(1543, TorznabCatType.PCGames, " Mission, traffic sounds, packs and tools"); - AddCategoryMapping(1899, TorznabCatType.PCGames, " Scenarios (FSX-P3D)"); - AddCategoryMapping(77, TorznabCatType.PCGames, " Arcade"); - AddCategoryMapping(459, TorznabCatType.PCGames, " Arcade (various)"); - AddCategoryMapping(461, TorznabCatType.PCGames, " Board & Card Arcade"); - AddCategoryMapping(78, TorznabCatType.PCGames, " Adventure Quests"); - AddCategoryMapping(746, TorznabCatType.PCGames, " Quest-style \"search objects\""); - AddCategoryMapping(79, TorznabCatType.PCGames, " Online Games"); - AddCategoryMapping(743, TorznabCatType.PCGames, " Free"); - AddCategoryMapping(744, TorznabCatType.PCGames, " paid"); - AddCategoryMapping(742, TorznabCatType.PCGames, " Other online gaming"); - AddCategoryMapping(157, TorznabCatType.PCGames, " For the little ones"); - AddCategoryMapping(465, TorznabCatType.PCGames, " Old games for PC"); - AddCategoryMapping(466, TorznabCatType.PCGames, " Arcade and Puzzle Games (old games)"); - AddCategoryMapping(1871, TorznabCatType.PCGames, " Arcade (Old Games)"); - AddCategoryMapping(1872, TorznabCatType.PCGames, " Puzzle games (old games)"); - AddCategoryMapping(467, TorznabCatType.PCGames, " Adventure quests (old games)"); - AddCategoryMapping(468, TorznabCatType.PCGames, " Action (old games)"); - AddCategoryMapping(469, TorznabCatType.PCGames, " Strategy (old games)"); - AddCategoryMapping(470, TorznabCatType.PCGames, " RPG (old games)"); - AddCategoryMapping(471, TorznabCatType.PCGames, " Simulations (old games)"); - AddCategoryMapping(1532, TorznabCatType.PCGames, " Autos and Racing (old games)"); - AddCategoryMapping(1533, TorznabCatType.PCGames, " Space simulators, flight simulators and aviaigry (old games)"); - AddCategoryMapping(1534, TorznabCatType.PCGames, " Sports simulators (old games)"); - AddCategoryMapping(1535, TorznabCatType.PCGames, " Other simulators (Old Games)"); - AddCategoryMapping(472, TorznabCatType.PCGames, " Multi-genre compilations (old games)"); - AddCategoryMapping(1536, TorznabCatType.PCGames, " Erotic games (old games)"); - AddCategoryMapping(1537, TorznabCatType.PCGames, " For the little ones (Old Games)"); - AddCategoryMapping(1538, TorznabCatType.PCGames, " Puzzle Games (Old Games)"); - AddCategoryMapping(1539, TorznabCatType.PCGames, " IBM PC are not compatible (old games)"); - AddCategoryMapping(473, TorznabCatType.PCGames, " Erotic games"); - AddCategoryMapping(745, TorznabCatType.PCGames, " Chess"); - AddCategoryMapping(924, TorznabCatType.PCGames, " game Collections"); - AddCategoryMapping(970, TorznabCatType.PCGames, " Other for PC-games"); - AddCategoryMapping(1803, TorznabCatType.PCGames, " Patches"); - AddCategoryMapping(80, TorznabCatType.PCGames, " Official patches"); - AddCategoryMapping(1790, TorznabCatType.PCGames, " Fashion, plug-ins, add-ons"); - AddCategoryMapping(972, TorznabCatType.PCGames, " Official mode, plug-ins, add-ons"); - AddCategoryMapping(162, TorznabCatType.PCGames, " Informal fashion, plugins, add-ons"); - AddCategoryMapping(161, TorznabCatType.PCGames, " Fun"); - AddCategoryMapping(973, TorznabCatType.PCGames, " Editors, emulators and other gaming utility"); - AddCategoryMapping(160, TorznabCatType.PCGames, " NoCD / NoDVD"); - AddCategoryMapping(974, TorznabCatType.PCGames, " Conservation games"); - AddCategoryMapping(971, TorznabCatType.PCGames, " Cheat program and trainers"); - AddCategoryMapping(164, TorznabCatType.PCGames, " Guidelines and passing"); - AddCategoryMapping(163, TorznabCatType.PCGames, " The bonus disc for the games"); - AddCategoryMapping(159, TorznabCatType.PCGames, " The demo version of the game and with early access"); - AddCategoryMapping(975, TorznabCatType.PCGames, " Anime Games"); - AddCategoryMapping(1025, TorznabCatType.PCGames, " Fighting"); - AddCategoryMapping(460, TorznabCatType.PCGames, " Logic games"); - AddCategoryMapping(462, TorznabCatType.PCGames, " Mini / Flash games"); - AddCategoryMapping(1029, TorznabCatType.PCGames, " Indie Game"); - AddCategoryMapping(111, TorznabCatType.Console, " Games for consoles"); - AddCategoryMapping(458, TorznabCatType.Console, " Portable and Console Games (general section of games for different platforms)"); - AddCategoryMapping(129, TorznabCatType.ConsoleXbox, " Xbox"); - AddCategoryMapping(131, TorznabCatType.ConsoleXbox360, " XBox360 | Games"); - AddCategoryMapping(132, TorznabCatType.ConsoleXbox360, " XBox360 | GOD Games"); - AddCategoryMapping(133, TorznabCatType.ConsoleXbox360, " XBox360 | JTAG"); - AddCategoryMapping(134, TorznabCatType.ConsoleXbox360, " XBox360 | 360E"); - AddCategoryMapping(135, TorznabCatType.ConsoleXbox360, " XBox360 | Demo"); - AddCategoryMapping(136, TorznabCatType.ConsoleXbox360, " XBox360 | Soft"); - AddCategoryMapping(137, TorznabCatType.ConsoleXbox, " Original XBox | Games"); - AddCategoryMapping(138, TorznabCatType.ConsolePS4, " PlayStation"); - AddCategoryMapping(621, TorznabCatType.ConsolePS3, " PS"); - AddCategoryMapping(141, TorznabCatType.ConsolePS3, " PS2 | Games"); - AddCategoryMapping(112, TorznabCatType.ConsolePS3, " PS3 | Games"); - AddCategoryMapping(142, TorznabCatType.ConsolePS3, " PS3 | Other"); - AddCategoryMapping(139, TorznabCatType.ConsolePS4, " PSN | Games"); - AddCategoryMapping(140, TorznabCatType.ConsolePSP, " PSP | Games"); - AddCategoryMapping(622, TorznabCatType.ConsolePSP, " PS1 games for PSP"); - AddCategoryMapping(143, TorznabCatType.ConsolePSP, " PSP | Programs | Other"); - AddCategoryMapping(1548, TorznabCatType.ConsolePSP, " Software for PSP (Homebrew)"); - AddCategoryMapping(455, TorznabCatType.ConsolePSVita, " PS Vita | Games"); - AddCategoryMapping(130, TorznabCatType.ConsoleOther, " Nintendo"); - AddCategoryMapping(144, TorznabCatType.ConsoleNDS, " NDS | Games"); - AddCategoryMapping(145, TorznabCatType.ConsoleWii, " Wii | Games"); - AddCategoryMapping(146, TorznabCatType.ConsoleWiiwareVC, " WiiWare | Games"); - AddCategoryMapping(147, TorznabCatType.ConsoleOther, " GameCube | Games"); - AddCategoryMapping(456, TorznabCatType.ConsoleOther, " Sega"); - AddCategoryMapping(588, TorznabCatType.ConsoleOther, " Dreamcast"); - AddCategoryMapping(457, TorznabCatType.ConsoleOther, " Games for older consoles"); - AddCategoryMapping(589, TorznabCatType.ConsoleOther, " Games for the DVD player"); - AddCategoryMapping(928, TorznabCatType.PCGames, " Games for Linux"); - AddCategoryMapping(1868, TorznabCatType.PCGames, " Native games for Linux"); - AddCategoryMapping(1869, TorznabCatType.PCGames, " Ported games for Linux"); - AddCategoryMapping(1870, TorznabCatType.PCGames, " Archive for Linux games"); - AddCategoryMapping(81, TorznabCatType.PC0day, "Software"); - AddCategoryMapping(570, TorznabCatType.PC0day, " General Section for software"); - AddCategoryMapping(109, TorznabCatType.PCPhoneOther, " Software for smart phones, mobile phones and PDAs"); - AddCategoryMapping(899, TorznabCatType.PCPhoneOther, " Java"); - AddCategoryMapping(900, TorznabCatType.PCPhoneOther, " Games for Java"); - AddCategoryMapping(901, TorznabCatType.PCPhoneOther, " Applications for Java"); - AddCategoryMapping(590, TorznabCatType.PCPhoneAndroid, " Android"); - AddCategoryMapping(592, TorznabCatType.PCPhoneAndroid, " Games for Android"); - AddCategoryMapping(1017, TorznabCatType.PCPhoneAndroid, " Games for Android [Eng]"); - AddCategoryMapping(895, TorznabCatType.PCPhoneAndroid, " Apps for Android OS"); - AddCategoryMapping(1018, TorznabCatType.PCPhoneAndroid, " Applications for Android [Eng]"); - AddCategoryMapping(480, TorznabCatType.PCPhoneIOS, " Apple Mobile Device Software"); - AddCategoryMapping(481, TorznabCatType.PCPhoneIOS, " Firmware (iPhone / iPod Touch / iPad / Apple TV)"); - AddCategoryMapping(482, TorznabCatType.PCPhoneIOS, " Programs for iOS (iPhone / iPod Touch / iPad)"); - AddCategoryMapping(483, TorznabCatType.PCPhoneIOS, " Games for iOS (iPhone / iPod Touch / iPad)"); - AddCategoryMapping(485, TorznabCatType.PCPhoneIOS, " Miscellaneous iOS (iPhone / iPod Touch / iPad)"); - AddCategoryMapping(896, TorznabCatType.PCPhoneOther, " Symbian"); - AddCategoryMapping(897, TorznabCatType.PCPhoneOther, " Games for Symbian"); - AddCategoryMapping(898, TorznabCatType.PCPhoneOther, " Applications for Symbian"); - AddCategoryMapping(902, TorznabCatType.PCPhoneOther, " Windows Mobile, Palm OS, BlackBerry etc"); - AddCategoryMapping(903, TorznabCatType.PCPhoneOther, " Games for Windows Mobile, Palm OS, BlackBerry etc"); - AddCategoryMapping(904, TorznabCatType.PCPhoneOther, " Applications for Windows Mobile, Palm OS, BlackBerry etc"); - AddCategoryMapping(1579, TorznabCatType.PCPhoneOther, " Windows Phone 7,8"); - AddCategoryMapping(1580, TorznabCatType.PCPhoneOther, " Games for Windows Phone 7,8"); - AddCategoryMapping(1581, TorznabCatType.PCPhoneOther, " Applications for Windows Phone 7,8"); - AddCategoryMapping(1582, TorznabCatType.PCPhoneOther, " Software for your phone"); - AddCategoryMapping(1583, TorznabCatType.PCPhoneOther, " Firmware for phones"); - AddCategoryMapping(106, TorznabCatType.PC0day, " On Linux, Unix etc"); - AddCategoryMapping(282, TorznabCatType.PC0day, " Operating Systems (Linux, Unix)"); - AddCategoryMapping(1574, TorznabCatType.PC0day, " Program (Linux, Unix)"); - AddCategoryMapping(284, TorznabCatType.PC0day, " Other operating systems and software for them"); - AddCategoryMapping(287, TorznabCatType.PC0day, " Archive (Linux OS, Unix etc)"); - AddCategoryMapping(276, TorznabCatType.PCMac, " Apple OS"); - AddCategoryMapping(277, TorznabCatType.PCMac, " Mac OS [for Macintosh]"); - AddCategoryMapping(278, TorznabCatType.PCMac, " Mac OS [PC-Hackintosh]"); - AddCategoryMapping(591, TorznabCatType.PCMac, " Games Mac OS"); - AddCategoryMapping(1019, TorznabCatType.PCMac, " Mac Games [ENG]"); - AddCategoryMapping(1021, TorznabCatType.PCMac, " Program for viewing and video processing (Mac OS)"); - AddCategoryMapping(1022, TorznabCatType.PCMac, " Programs for creating and processing graphs (Mac OS)"); - AddCategoryMapping(1023, TorznabCatType.PCMac, " Plug-ins for Adobe's software (Mac OS)"); - AddCategoryMapping(1584, TorznabCatType.PCMac, " Audio editor and converter (Mac OS)"); - AddCategoryMapping(1585, TorznabCatType.PCMac, " System software (Mac OS)"); - AddCategoryMapping(1586, TorznabCatType.PCMac, " Office software (Mac OS)"); - AddCategoryMapping(1587, TorznabCatType.PCMac, " Programs for the Internet and network (Mac OS)"); - AddCategoryMapping(1588, TorznabCatType.PCMac, " Other software (Mac OS)"); - AddCategoryMapping(103, TorznabCatType.PC0day, " Microsoft OS"); - AddCategoryMapping(104, TorznabCatType.PC0day, " Desktop operating system from Microsoft (released prior to Windows XP)"); - AddCategoryMapping(105, TorznabCatType.PC0day, " Desktop operating system from Microsoft (since Windows XP)"); - AddCategoryMapping(1629, TorznabCatType.PC0day, " Windows XP"); - AddCategoryMapping(1628, TorznabCatType.PC0day, " Windows Vista"); - AddCategoryMapping(981, TorznabCatType.PC0day, " Windows 7"); - AddCategoryMapping(1610, TorznabCatType.PC0day, " Windows 8"); - AddCategoryMapping(1811, TorznabCatType.PC0day, " Windows 10"); - AddCategoryMapping(274, TorznabCatType.PC0day, " Windows Server"); - AddCategoryMapping(927, TorznabCatType.PC0day, " Other (Operating Systems from Microsoft)"); - AddCategoryMapping(275, TorznabCatType.PC0day, " Archive (OS from Microsoft)"); - AddCategoryMapping(84, TorznabCatType.PC0day, " System programs"); - AddCategoryMapping(86, TorznabCatType.PC0day, " Programs for configuring and optimizing OS"); - AddCategoryMapping(87, TorznabCatType.PC0day, " Archivers and File Managers"); - AddCategoryMapping(1630, TorznabCatType.PC0day, " Safety protection system and PC"); - AddCategoryMapping(93, TorznabCatType.PC0day, " Software to protect your computer (antivirus software, firewalls)"); - AddCategoryMapping(580, TorznabCatType.PC0day, " Keys and Activation"); - AddCategoryMapping(94, TorznabCatType.PC0day, " Anti-spyware and anti-trojan"); - AddCategoryMapping(95, TorznabCatType.PC0day, " Programs for the protection of information"); - AddCategoryMapping(88, TorznabCatType.PC0day, " Backup"); - AddCategoryMapping(89, TorznabCatType.PC0day, " Service computer service"); - AddCategoryMapping(1631, TorznabCatType.PC0day, " LiveCD / DVD / Flash etc"); - AddCategoryMapping(90, TorznabCatType.PC0day, " Work with data carriers"); - AddCategoryMapping(91, TorznabCatType.PC0day, " Information and Diagnostics"); - AddCategoryMapping(92, TorznabCatType.PC0day, " Programs for Internet and networks"); - AddCategoryMapping(96, TorznabCatType.PC0day, " Drivers and Firmware"); - AddCategoryMapping(97, TorznabCatType.PC0day, " Original disks to computers and accessories"); - AddCategoryMapping(98, TorznabCatType.PC0day, " Server Software for Windows"); - AddCategoryMapping(99, TorznabCatType.PC0day, " Change the Windows interface"); - AddCategoryMapping(101, TorznabCatType.PC0day, " Screensavers"); - AddCategoryMapping(85, TorznabCatType.PC0day, " Work with hard drive"); - AddCategoryMapping(102, TorznabCatType.PC0day, " Miscellaneous (System programs on Windows)"); - AddCategoryMapping(82, TorznabCatType.PC0day, " Systems for business, office, research and project work"); - AddCategoryMapping(83, TorznabCatType.PC0day, " Business Systems"); - AddCategoryMapping(585, TorznabCatType.PC0day, " The company's products 1C"); - AddCategoryMapping(1829, TorznabCatType.PC0day, " typical configuration"); - AddCategoryMapping(1830, TorznabCatType.PC0day, " industry configuration"); - AddCategoryMapping(1831, TorznabCatType.PC0day, " ITS 2015"); - AddCategoryMapping(1832, TorznabCatType.PC0day, " ITS 2014"); - AddCategoryMapping(1833, TorznabCatType.PC0day, " ITS 2013"); - AddCategoryMapping(1834, TorznabCatType.PC0day, " ITS 2012"); - AddCategoryMapping(1835, TorznabCatType.PC0day, " ITS 2011"); - AddCategoryMapping(1836, TorznabCatType.PC0day, " Archive (Products 1C)"); - AddCategoryMapping(270, TorznabCatType.PC0day, " Office systems"); - AddCategoryMapping(266, TorznabCatType.PC0day, " Dictionaries, translators"); - AddCategoryMapping(272, TorznabCatType.PC0day, " Recognition of text, sound and speech synthesis"); - AddCategoryMapping(269, TorznabCatType.PC0day, " Miscellaneous (business systems, office, research and project work)"); - AddCategoryMapping(302, TorznabCatType.PC0day, " CAD software for architects"); - AddCategoryMapping(593, TorznabCatType.PC0day, " CAD (general and engineering)"); - AddCategoryMapping(594, TorznabCatType.PC0day, " CAD (electronics, automation, GAP)"); - AddCategoryMapping(940, TorznabCatType.PC0day, " Programs for architects and builders"); - AddCategoryMapping(937, TorznabCatType.PC0day, " All for house: dressmaking, sewing, cooking"); - AddCategoryMapping(938, TorznabCatType.PC0day, " Work with PDF and DjVu"); - AddCategoryMapping(939, TorznabCatType.PC0day, " Systems for scientific work"); - AddCategoryMapping(941, TorznabCatType.PC0day, " Libraries and projects for architects and interior designers"); - AddCategoryMapping(942, TorznabCatType.PC0day, " Other reference systems"); - AddCategoryMapping(107, TorznabCatType.PC0day, " Web Development and Programming"); - AddCategoryMapping(293, TorznabCatType.PC0day, " Search / Offer"); - AddCategoryMapping(943, TorznabCatType.PC0day, " WYSIWYG editors for web design"); - AddCategoryMapping(496, TorznabCatType.PC0day, " Database Management Systems (DBMS)"); - AddCategoryMapping(494, TorznabCatType.PC0day, " programming environments, compilers and software tools"); - AddCategoryMapping(290, TorznabCatType.PC0day, " The components for the development of media"); - AddCategoryMapping(495, TorznabCatType.PC0day, " Text editors Illuminated"); - AddCategoryMapping(291, TorznabCatType.PC0day, " Scripting engines and websites, CMS and extensions to it"); - AddCategoryMapping(944, TorznabCatType.PC0day, " Templates for websites and CMS"); - AddCategoryMapping(292, TorznabCatType.PC0day, " Miscellaneous (Web Development and Programming)"); - AddCategoryMapping(294, TorznabCatType.PC0day, " Archive (Web Development and Programming)"); - AddCategoryMapping(108, TorznabCatType.PC0day, " Programs to work with multimedia and 3D"); - AddCategoryMapping(487, TorznabCatType.PC0day, " Software kits"); - AddCategoryMapping(488, TorznabCatType.PC0day, " Plug-ins for Adobe's programs"); - AddCategoryMapping(491, TorznabCatType.PC0day, " 3D modeling, rendering and plugins for them"); - AddCategoryMapping(489, TorznabCatType.PC0day, " Graphic editor"); - AddCategoryMapping(303, TorznabCatType.PC0day, " Editors video"); - AddCategoryMapping(305, TorznabCatType.PC0day, " Virtual Studios, sequencers and audio editor"); - AddCategoryMapping(492, TorznabCatType.PC0day, " Animation"); - AddCategoryMapping(490, TorznabCatType.PC0day, " Programs for typesetting, printing, and working with fonts"); - AddCategoryMapping(304, TorznabCatType.PC0day, " Video, Audio Conversion"); - AddCategoryMapping(493, TorznabCatType.PC0day, " Creating a BD / HD / DVD-Video"); - AddCategoryMapping(306, TorznabCatType.PC0day, " Plug-ins for sound processing"); - AddCategoryMapping(308, TorznabCatType.PC0day, " Archive (Programme for multimedia and 3D)"); - AddCategoryMapping(595, TorznabCatType.PC0day, " Miscellaneous (Programme for multimedia and 3D)"); - AddCategoryMapping(596, TorznabCatType.PC0day, " Miscellaneous (Programs for working with audio)"); - AddCategoryMapping(597, TorznabCatType.PC0day, " Virtual instruments and synthesizers"); - AddCategoryMapping(264, TorznabCatType.PC0day, " Audio and video, players and catalogers"); - AddCategoryMapping(263, TorznabCatType.PC0day, " Cataloging and graphics viewers"); - AddCategoryMapping(348, TorznabCatType.PC0day, " Materials for Multimedia and Design"); - AddCategoryMapping(945, TorznabCatType.PC0day, " Author's works"); - AddCategoryMapping(946, TorznabCatType.PC0day, " Official collection vector clipart"); - AddCategoryMapping(948, TorznabCatType.PC0day, " Other vector cliparts"); - AddCategoryMapping(949, TorznabCatType.PC0day, " Photostosks"); - AddCategoryMapping(950, TorznabCatType.PC0day, " The costumes for the photomontage"); - AddCategoryMapping(350, TorznabCatType.PC0day, " Frames and Vignettes for processing photos"); - AddCategoryMapping(352, TorznabCatType.PC0day, " Other raster clipart"); - AddCategoryMapping(1634, TorznabCatType.PC0day, " backgrounds"); - AddCategoryMapping(1635, TorznabCatType.PC0day, " Templates"); - AddCategoryMapping(1637, TorznabCatType.PC0day, " Raster Graphics (photos)"); - AddCategoryMapping(1638, TorznabCatType.PC0day, " Raster Graphics (elements)"); - AddCategoryMapping(1639, TorznabCatType.PC0day, " Raster Graphics (illustrations)"); - AddCategoryMapping(353, TorznabCatType.PC0day, " 3D models, scenes and materials"); - AddCategoryMapping(1633, TorznabCatType.PC0day, " Textures"); - AddCategoryMapping(354, TorznabCatType.PC0day, " Footage"); - AddCategoryMapping(951, TorznabCatType.PC0day, " Other collections footage"); - AddCategoryMapping(952, TorznabCatType.PC0day, " music library"); - AddCategoryMapping(355, TorznabCatType.PC0day, " Sound effects"); - AddCategoryMapping(953, TorznabCatType.PC0day, " sample Libraries"); - AddCategoryMapping(954, TorznabCatType.PC0day, " Libraries and saundbanki for samplers, synth presets"); - AddCategoryMapping(955, TorznabCatType.PC0day, " Multitracks"); - AddCategoryMapping(956, TorznabCatType.PC0day, " Materials for creating menus and DVD covers"); - AddCategoryMapping(351, TorznabCatType.PC0day, " Styles, brushes, shapes and patterns for Adobe Photoshop"); - AddCategoryMapping(356, TorznabCatType.PC0day, " Fonts"); - AddCategoryMapping(358, TorznabCatType.PC0day, " Miscellaneous (Materials for Multimedia and Design)"); - AddCategoryMapping(1632, TorznabCatType.PC0day, " Digital Juice"); - AddCategoryMapping(1874, TorznabCatType.PC0day, " Projects"); - AddCategoryMapping(1875, TorznabCatType.PC0day, " Children (projects)"); - AddCategoryMapping(1876, TorznabCatType.PC0day, " Wedding and romantic (projects)"); - AddCategoryMapping(1877, TorznabCatType.PC0day, " Holiday (projects)"); - AddCategoryMapping(1878, TorznabCatType.PC0day, " Presentations (projects)"); - AddCategoryMapping(1879, TorznabCatType.PC0day, " Sport (projects)"); - AddCategoryMapping(1880, TorznabCatType.PC0day, " Logos (projects)"); - AddCategoryMapping(1881, TorznabCatType.PC0day, " Slideshow (projects)"); - AddCategoryMapping(1882, TorznabCatType.PC0day, " Titles (projects)"); - AddCategoryMapping(1883, TorznabCatType.PC0day, " Items (Projects)"); - AddCategoryMapping(1884, TorznabCatType.PC0day, " Miscellaneous (projects)"); - AddCategoryMapping(1898, TorznabCatType.PC0day, " Trailers (projects)"); - AddCategoryMapping(295, TorznabCatType.PC0day, " Reference and legal system"); - AddCategoryMapping(296, TorznabCatType.PC0day, " Consultant Plus"); - AddCategoryMapping(584, TorznabCatType.PC0day, " Consultant Accountant"); - AddCategoryMapping(755, TorznabCatType.PC0day, " Archive irrelevant hands"); - AddCategoryMapping(297, TorznabCatType.PC0day, " code"); - AddCategoryMapping(298, TorznabCatType.PC0day, " Guarantee"); - AddCategoryMapping(299, TorznabCatType.PC0day, " other"); - AddCategoryMapping(300, TorznabCatType.PC0day, " Archive (Reference and legal system)"); - AddCategoryMapping(301, TorznabCatType.PC0day, " RG PCA - a hidden forum"); - AddCategoryMapping(587, TorznabCatType.PC0day, " Collections of programs and WPI"); - AddCategoryMapping(929, TorznabCatType.PC0day, " Test drives to adjust the audio / video equipment"); - AddCategoryMapping(957, TorznabCatType.PC0day, " GIS, navigation systems and maps"); - AddCategoryMapping(958, TorznabCatType.PC0day, " GIS (Geographic Information Systems)"); - AddCategoryMapping(959, TorznabCatType.PC0day, " Maps provided with the program shell"); - AddCategoryMapping(960, TorznabCatType.PC0day, " Atlases and maps modern (after 1950)"); - AddCategoryMapping(961, TorznabCatType.PC0day, " Atlases and maps of old (pre-1950)"); - AddCategoryMapping(962, TorznabCatType.PC0day, " Cards Other (astronomical, historical, thematic)"); - AddCategoryMapping(963, TorznabCatType.PC0day, " Built-in car navigation"); - AddCategoryMapping(964, TorznabCatType.PC0day, " Garmin"); - AddCategoryMapping(965, TorznabCatType.PC0day, " Ozi"); - AddCategoryMapping(966, TorznabCatType.PC0day, " TomTom"); - AddCategoryMapping(967, TorznabCatType.PC0day, " Navigon / Navitel"); - AddCategoryMapping(968, TorznabCatType.PC0day, " Igo"); - AddCategoryMapping(969, TorznabCatType.PC0day, " Miscellaneous - navigation and maps"); - AddCategoryMapping(61, TorznabCatType.Audio, "Music and music videos"); - AddCategoryMapping(579, TorznabCatType.Audio, " Total music section"); - AddCategoryMapping(537, TorznabCatType.AudioVideo, " General Discussion unsorted music video"); - AddCategoryMapping(538, TorznabCatType.AudioVideo, " Music video (HD / DVD)"); - AddCategoryMapping(544, TorznabCatType.AudioVideo, " Concert recording"); - AddCategoryMapping(1781, TorznabCatType.AudioVideo, " Concerts (DVD)"); - AddCategoryMapping(1782, TorznabCatType.AudioVideo, " Concerts (HD)"); - AddCategoryMapping(1784, TorznabCatType.AudioVideo, " Opera, Ballet, Musicals"); - AddCategoryMapping(1785, TorznabCatType.AudioVideo, " Music videos (transit)"); - AddCategoryMapping(501, TorznabCatType.AudioLossless, " unsorted Lossless"); - AddCategoryMapping(532, TorznabCatType.Audio, " Multi-channel HD Audio and Music"); - AddCategoryMapping(533, TorznabCatType.Audio, " DVD-Audio, SACD, Audio-DVD"); - AddCategoryMapping(1687, TorznabCatType.Audio, " DVD-Audio"); - AddCategoryMapping(1688, TorznabCatType.Audio, " SACD-R"); - AddCategoryMapping(534, TorznabCatType.Audio, " DTS"); - AddCategoryMapping(535, TorznabCatType.Audio, " Vinyl-Rip and Hand-Made"); - AddCategoryMapping(536, TorznabCatType.Audio, " Hi-Res stereo"); - AddCategoryMapping(529, TorznabCatType.Audio, " discography"); - AddCategoryMapping(530, TorznabCatType.Audio, " Domestic"); - AddCategoryMapping(531, TorznabCatType.Audio, " foreign"); - AddCategoryMapping(1679, TorznabCatType.Audio, " Jazz, Blues, Soul (transit)"); - AddCategoryMapping(1680, TorznabCatType.Audio, " Jazz (transit lossless)"); - AddCategoryMapping(1681, TorznabCatType.Audio, " Jazz (transit lossy)"); - AddCategoryMapping(1682, TorznabCatType.Audio, " Blues, Soul (transit lossless)"); - AddCategoryMapping(1683, TorznabCatType.Audio, " Blues, Soul (transit lossy)"); - AddCategoryMapping(525, TorznabCatType.Audio, " Jazz, Blues, Soul (transit lossless)"); - AddCategoryMapping(1689, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (transit)"); - AddCategoryMapping(521, TorznabCatType.Audio, " Rock (transit Lossless)"); - AddCategoryMapping(1691, TorznabCatType.Audio, " Rock (transit Lossy)"); - AddCategoryMapping(1692, TorznabCatType.Audio, " Alternative, Punk (transit Lossless)"); - AddCategoryMapping(1693, TorznabCatType.Audio, " Alternative, Punk (transit Lossy)"); - AddCategoryMapping(1694, TorznabCatType.Audio, " Hard Rock (transit Lossless)"); - AddCategoryMapping(1695, TorznabCatType.Audio, " Hard Rock (transit Lossy)"); - AddCategoryMapping(506, TorznabCatType.Audio, " Metal (transit Lossless)"); - AddCategoryMapping(1697, TorznabCatType.Audio, " Metal (transit Lossy)"); - AddCategoryMapping(1698, TorznabCatType.Audio, " Russian Rock (transit Lossless)"); - AddCategoryMapping(1699, TorznabCatType.Audio, " Russian Rock (transit Lossy)"); - AddCategoryMapping(1817, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (transit Lossless)"); - AddCategoryMapping(1700, TorznabCatType.Audio, " Popular music (transit)"); - AddCategoryMapping(1701, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (transit Lossless)"); - AddCategoryMapping(1702, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (transit Lossy)"); - AddCategoryMapping(1703, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (transit Lossless)"); - AddCategoryMapping(1704, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (transit Lossy)"); - AddCategoryMapping(1705, TorznabCatType.Audio, " Patriotic Pop (transit lossless)"); - AddCategoryMapping(1706, TorznabCatType.Audio, " Patriotic Pop (transit Lossy)"); - AddCategoryMapping(1707, TorznabCatType.Audio, " Soviet stage, Retro (transit Lossless)"); - AddCategoryMapping(1708, TorznabCatType.Audio, " Soviet stage, Retro (transit Lossy)"); - AddCategoryMapping(1709, TorznabCatType.Audio, " Foreign pop music (transit Lossless)"); - AddCategoryMapping(1710, TorznabCatType.Audio, " Foreign pop music (transit Lossy)"); - AddCategoryMapping(1818, TorznabCatType.Audio, " Popular music (transit Lossless)"); - AddCategoryMapping(1711, TorznabCatType.Audio, " Electronic music (transit)"); - AddCategoryMapping(1712, TorznabCatType.Audio, " Trance (transit Lossless)"); - AddCategoryMapping(1713, TorznabCatType.Audio, " Trance (transit Lossy)"); - AddCategoryMapping(1714, TorznabCatType.Audio, " House, Techno, Electro, Minimal (transit Lossless)"); - AddCategoryMapping(1715, TorznabCatType.Audio, " House (transit Lossy)"); - AddCategoryMapping(1716, TorznabCatType.Audio, " Techno, Electro, Minimal (transit Lossy)"); - AddCategoryMapping(1717, TorznabCatType.Audio, " Easy listening (transit Lossless)"); - AddCategoryMapping(1718, TorznabCatType.Audio, " Easy listening (transit Lossy)"); - AddCategoryMapping(1719, TorznabCatType.Audio, " Experimental, Industrial, EBM, Dark Electro (Lossless)"); - AddCategoryMapping(1720, TorznabCatType.Audio, " Experimental Electronic (transit Lossy)"); - AddCategoryMapping(1721, TorznabCatType.Audio, " Industrial, EBM, Dark Electro (transit Lossy)"); - AddCategoryMapping(1722, TorznabCatType.Audio, " Synthpop, New Wave (Lossless transit)"); - AddCategoryMapping(1723, TorznabCatType.Audio, " Synthpop, New Wave (transit Lossy)"); - AddCategoryMapping(1724, TorznabCatType.Audio, " Drum'n'Bass, Jungle, Breaks, Breakbeat, Dubstep (transit Lossless)"); - AddCategoryMapping(1725, TorznabCatType.Audio, " Drum'n'Bass, Jungle, Breaks, Breakbeat, Dubstep (transit Lossy)"); - AddCategoryMapping(1726, TorznabCatType.Audio, " Hardstyle, Jumpstyle, Hardcore (transit Lossless)"); - AddCategoryMapping(1727, TorznabCatType.Audio, " Hardstyle, Jumpstyle, Hardcore (transit Lossy)"); - AddCategoryMapping(1728, TorznabCatType.Audio, " Psychedelic, psytrance, fullon (transit Lossless)"); - AddCategoryMapping(1729, TorznabCatType.Audio, " Psychedelic, psytrance, fullon (transit Lossy)"); - AddCategoryMapping(1730, TorznabCatType.Audio, " Radioshow, Live Mixes (transit Lossy)"); - AddCategoryMapping(1820, TorznabCatType.Audio, " Electronic music (transit Lossless)"); - AddCategoryMapping(1731, TorznabCatType.Audio, " Rap, Hip-hop, RnB, Reggae (transit)"); - AddCategoryMapping(1732, TorznabCatType.Audio, " Rap, Hip-hop overseas (transit Lossless)"); - AddCategoryMapping(1733, TorznabCatType.Audio, " Rap, Hip-hop overseas (transit Lossy)"); - AddCategoryMapping(1734, TorznabCatType.Audio, " Rap, Hip-hop domestic (Lossless)"); - AddCategoryMapping(1735, TorznabCatType.Audio, " Rap, Hip-hop domestic (transit Lossy)"); - AddCategoryMapping(1736, TorznabCatType.Audio, " RnB, Reggae (transit Lossless)"); - AddCategoryMapping(1737, TorznabCatType.Audio, " RnB, Reggae (transit Lossy)"); - AddCategoryMapping(1819, TorznabCatType.Audio, " Rap, Hip-hop, RnB (transit Lossless)"); - AddCategoryMapping(1738, TorznabCatType.Audio, " East Asian Music (transit)"); - AddCategoryMapping(1739, TorznabCatType.Audio, " Asian Traditional, Ethnic (transit Lossless)"); - AddCategoryMapping(1740, TorznabCatType.Audio, " Asian Traditional, Ethnic (transit Lossy)"); - AddCategoryMapping(1741, TorznabCatType.Audio, " Asian Pop (transit Lossless)"); - AddCategoryMapping(1742, TorznabCatType.Audio, " Asian Pop (transit Lossy)"); - AddCategoryMapping(1743, TorznabCatType.Audio, " Asian Rock, Metal (transit Lossless)"); - AddCategoryMapping(1744, TorznabCatType.Audio, " Asian Rock, Metal (transit Lossy)"); - AddCategoryMapping(1745, TorznabCatType.Audio, " Doujin Music (transit Lossless)"); - AddCategoryMapping(1746, TorznabCatType.Audio, " Doujin Music (transit Lossy)"); - AddCategoryMapping(1747, TorznabCatType.Audio, " Other Asian (transit Lossless)"); - AddCategoryMapping(1748, TorznabCatType.Audio, " Other Asian (transit Lossy)"); - AddCategoryMapping(1749, TorznabCatType.Audio, " Other Styles (transit)"); - AddCategoryMapping(1750, TorznabCatType.Audio, " Instrumental (transit Lossless)"); - AddCategoryMapping(1751, TorznabCatType.Audio, " Instrumental (transit Lossy)"); - AddCategoryMapping(1752, TorznabCatType.Audio, " New Age / Meditative / Relax (transit Lossless)"); - AddCategoryMapping(1753, TorznabCatType.Audio, " New Age / Meditative / Relax (transit Lossy)"); - AddCategoryMapping(1754, TorznabCatType.Audio, " Classical Crossover / Neoclassical (transit Lossless)"); - AddCategoryMapping(1755, TorznabCatType.Audio, " Classical Crossover / Neoclassical (transit Lossy)"); - AddCategoryMapping(1756, TorznabCatType.Audio, " Folk (transit Lossless)"); - AddCategoryMapping(1757, TorznabCatType.Audio, " Folk (transit Lossy)"); - AddCategoryMapping(1758, TorznabCatType.Audio, " Other (transit Lossless)"); - AddCategoryMapping(1759, TorznabCatType.Audio, " Other (transit Lossy)"); - AddCategoryMapping(1821, TorznabCatType.Audio, " Folklore / Folk / Folk / World Music (transit Lossy)"); - AddCategoryMapping(1822, TorznabCatType.Audio, " Compilations Folklore / Folk / Folk / World Music (transit Lossy)"); - AddCategoryMapping(1823, TorznabCatType.Audio, " Country & Folk (transit Lossy)"); - AddCategoryMapping(1760, TorznabCatType.Audio, " OST (transit Lossless)"); - AddCategoryMapping(1761, TorznabCatType.Audio, " OST (transit Lossy)"); - AddCategoryMapping(1762, TorznabCatType.Audio, " Classic (transit)"); - AddCategoryMapping(1763, TorznabCatType.Audio, " Notes (transit)"); - AddCategoryMapping(1764, TorznabCatType.Audio, " Complete Works (transit)"); - AddCategoryMapping(1765, TorznabCatType.Audio, " Vocals (transit)"); - AddCategoryMapping(1766, TorznabCatType.Audio, " Concerts (transit)"); - AddCategoryMapping(1767, TorznabCatType.Audio, " Orchestral (transit)"); - AddCategoryMapping(1768, TorznabCatType.Audio, " Chamber (transit)"); - AddCategoryMapping(1769, TorznabCatType.Audio, " Piano (transit)"); - AddCategoryMapping(1770, TorznabCatType.Audio, " Compilations (transit)"); - AddCategoryMapping(1771, TorznabCatType.Audio, " In processing (transit)"); - AddCategoryMapping(1783, TorznabCatType.Audio, " Classic (transit Lossless)"); - AddCategoryMapping(1800, TorznabCatType.Audio, " Author and military songs"); - AddCategoryMapping(1798, TorznabCatType.Audio, " Author and war songs (transit Lossless)"); - AddCategoryMapping(1799, TorznabCatType.Audio, " Author and war songs (transit Lossy)"); - AddCategoryMapping(1772, TorznabCatType.Audio, " Unofficial collections (transit)"); - AddCategoryMapping(1773, TorznabCatType.Audio, " Jazz, Blues, Soul (transit collections)"); - AddCategoryMapping(1774, TorznabCatType.Audio, " Chanson, Author and war songs (collections transit)"); - AddCategoryMapping(1775, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (collections of transit)"); - AddCategoryMapping(1776, TorznabCatType.Audio, " Pop (transit collections)"); - AddCategoryMapping(1777, TorznabCatType.Audio, " Electronic (transit collections)"); - AddCategoryMapping(1778, TorznabCatType.Audio, " Rap, Hip-hop, RnB, Reggae (transit collections)"); - AddCategoryMapping(1779, TorznabCatType.Audio, " Instrumental / New Age / Meditative / Relax (transit collections)"); - AddCategoryMapping(1780, TorznabCatType.Audio, " Other (transit collections)"); - AddCategoryMapping(1816, TorznabCatType.Audio, " Chanson, Author and war songs (transit)"); - AddCategoryMapping(1677, TorznabCatType.Audio, " Chanson, Author and war songs (transit lossless)"); - AddCategoryMapping(1678, TorznabCatType.Audio, " Chanson, Author and war songs (transit lossy)"); - AddCategoryMapping(63, TorznabCatType.Audio, " Electonic music"); - AddCategoryMapping(784, TorznabCatType.Audio, " Chillout, Lounge, Downtempo, Trip-Hop"); - AddCategoryMapping(785, TorznabCatType.Audio, " Chillout, Lounge, Downtempo (lossless)"); - AddCategoryMapping(225, TorznabCatType.Audio, " Chillout, Lounge, Downtempo (lossy)"); - AddCategoryMapping(786, TorznabCatType.Audio, " Nu Jazz, Acid Jazz, Future Jazz (lossless)"); - AddCategoryMapping(787, TorznabCatType.Audio, " Nu Jazz, Acid Jazz, Future Jazz (lossy)"); - AddCategoryMapping(788, TorznabCatType.Audio, " Trip Hop, Abstract Hip-Hop (lossless)"); - AddCategoryMapping(789, TorznabCatType.Audio, " Trip Hop, Abstract Hip-Hop (lossy)"); - AddCategoryMapping(800, TorznabCatType.Audio, " Drum & Bass, Jungle, Breakbeat, Dubstep, IDM, Electro"); - AddCategoryMapping(801, TorznabCatType.Audio, " Dubstep (lossy)"); - AddCategoryMapping(224, TorznabCatType.Audio, " Drum & Bass, Jungle (lossy)"); - AddCategoryMapping(803, TorznabCatType.Audio, " Drum & Bass, Jungle (lossless)"); - AddCategoryMapping(804, TorznabCatType.Audio, " Drum & Bass, Jungle (Radioshows, Podcasts, Livesets, Mixes)"); - AddCategoryMapping(805, TorznabCatType.Audio, " Breakbeat (lossless)"); - AddCategoryMapping(806, TorznabCatType.Audio, " Breakbeat (lossy)"); - AddCategoryMapping(1517, TorznabCatType.Audio, " Electro, Electro-Freestyle, Nu Electro (lossless)"); - AddCategoryMapping(1518, TorznabCatType.Audio, " Electro, Electro-Freestyle, Nu Electro (lossy)"); - AddCategoryMapping(1519, TorznabCatType.Audio, " Dubstep (lossless)"); - AddCategoryMapping(1520, TorznabCatType.Audio, " Breakbeat, Dubstep (Radioshows, Podcasts, Livesets, Mixes)"); - AddCategoryMapping(1521, TorznabCatType.Audio, " IDM (lossless)"); - AddCategoryMapping(1522, TorznabCatType.Audio, " IDM (lossy)"); - AddCategoryMapping(1523, TorznabCatType.Audio, " IDM Discography & Collections (lossy)"); - AddCategoryMapping(227, TorznabCatType.Audio, " Industrial, Noise, EBM, Dark Electro, Aggrotech, Synthpop, New Wave"); - AddCategoryMapping(774, TorznabCatType.Audio, " EBM, Dark Electro, Aggrotech (lossless)"); - AddCategoryMapping(775, TorznabCatType.Audio, " EBM, Dark Electro, Aggrotech (lossy)"); - AddCategoryMapping(776, TorznabCatType.Audio, " Industrial, Noise (lossless)"); - AddCategoryMapping(777, TorznabCatType.Audio, " Industrial, Noise (lossy)"); - AddCategoryMapping(778, TorznabCatType.Audio, " Synthpop, New Wave (lossless)"); - AddCategoryMapping(779, TorznabCatType.Audio, " Synthpop, New Wave (lossy)"); - AddCategoryMapping(780, TorznabCatType.Audio, " Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossless)"); - AddCategoryMapping(781, TorznabCatType.Audio, " Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossy)"); - AddCategoryMapping(752, TorznabCatType.Audio, " House, Techno, Hardcore, Hardstyle, Jumpstyle"); - AddCategoryMapping(760, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (lossy)"); - AddCategoryMapping(759, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (lossless)"); - AddCategoryMapping(753, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (vinyl, web)"); - AddCategoryMapping(223, TorznabCatType.Audio, " House (lossy)"); - AddCategoryMapping(756, TorznabCatType.Audio, " House (lossless)"); - AddCategoryMapping(770, TorznabCatType.Audio, " House (Radioshow, Podcast, Liveset, Mixes)"); - AddCategoryMapping(754, TorznabCatType.Audio, " House (Singles, EPs) (lossy)"); - AddCategoryMapping(771, TorznabCatType.Audio, " House (Promorelizy, collections)"); - AddCategoryMapping(757, TorznabCatType.Audio, " Techno (lossy)"); - AddCategoryMapping(758, TorznabCatType.Audio, " Techno (lossless)"); - AddCategoryMapping(769, TorznabCatType.Audio, " Techno (Radioshows, Podcasts, Livesets, Mixes)"); - AddCategoryMapping(761, TorznabCatType.Audio, " Techno (Singles, EPs) (lossy)"); - AddCategoryMapping(790, TorznabCatType.Audio, " Trance, Goa Trance, Psy-Trance, PsyChill, Ambient Dub"); - AddCategoryMapping(792, TorznabCatType.Audio, " Goa Trance, Psy-Trance (lossless)"); - AddCategoryMapping(793, TorznabCatType.Audio, " Goa Trance, Psy-Trance (lossy)"); - AddCategoryMapping(798, TorznabCatType.Audio, " Goa / Psy-Trance, PsyChill and Ambient Dub (Radioshows, Livesets, Mixes) (lossy)"); - AddCategoryMapping(791, TorznabCatType.Audio, " Trance (lossless)"); - AddCategoryMapping(222, TorznabCatType.Audio, " Trance (lossy)"); - AddCategoryMapping(795, TorznabCatType.Audio, " Trance (Radioshows, Podcasts, Live Sets, Mixes) (lossy)"); - AddCategoryMapping(794, TorznabCatType.Audio, " Trance (Singles, EPs) (lossy)"); - AddCategoryMapping(796, TorznabCatType.Audio, " PsyChill, Ambient Dub (lossless)"); - AddCategoryMapping(797, TorznabCatType.Audio, " PsyChill, Ambient Dub (lossy)"); - AddCategoryMapping(762, TorznabCatType.Audio, " Traditional Electronic, Ambient, Modern Classical, Electroacoustic, Experimental"); - AddCategoryMapping(768, TorznabCatType.Audio, " 8-bit, Chiptune (lossy & lossless)"); - AddCategoryMapping(679, TorznabCatType.Audio, " Experimental (lossy)"); - AddCategoryMapping(764, TorznabCatType.Audio, " Experimental (lossless)"); - AddCategoryMapping(767, TorznabCatType.Audio, " Modern Classical, Electroacoustic (lossy)"); - AddCategoryMapping(766, TorznabCatType.Audio, " Modern Classical, Electroacoustic (lossless)"); - AddCategoryMapping(226, TorznabCatType.Audio, " Traditional Electronic, Ambient (lossy)"); - AddCategoryMapping(763, TorznabCatType.Audio, " Traditional Electronic, Ambient (lossless)"); - AddCategoryMapping(799, TorznabCatType.Audio, " Label Packs (lossless)"); - AddCategoryMapping(802, TorznabCatType.Audio, " Label packs, Scene packs (lossy)"); - AddCategoryMapping(782, TorznabCatType.Audio, " Electronic music (Video, DVD Video / Audio, HD Video, DTS, SACD)"); - AddCategoryMapping(783, TorznabCatType.Audio, " Electronic music (own digitization)"); - AddCategoryMapping(914, TorznabCatType.Audio, " Electronic music (Video)"); - AddCategoryMapping(1524, TorznabCatType.Audio, " Electronic music (Official DVD Video)"); - AddCategoryMapping(1525, TorznabCatType.Audio, " Electronic music (Informal amateur DVD Video)"); - AddCategoryMapping(1526, TorznabCatType.Audio, " Electronic Music (Hi-Res stereo)"); - AddCategoryMapping(1527, TorznabCatType.Audio, " Multichannel music (Electronics)"); - AddCategoryMapping(1528, TorznabCatType.Audio, " Electronic music (HD Video)"); - AddCategoryMapping(64, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B"); - AddCategoryMapping(213, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (lossy)"); - AddCategoryMapping(214, TorznabCatType.Audio, " Domestic Rap, Hip-Hop (lossy)"); - AddCategoryMapping(692, TorznabCatType.Audio, " Foreign R'n'B (lossy)"); - AddCategoryMapping(894, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (lossless)"); - AddCategoryMapping(1387, TorznabCatType.Audio, " Minus (Instrumentals)"); - AddCategoryMapping(1388, TorznabCatType.Audio, " Domestic R'n'B (lossy)"); - AddCategoryMapping(1389, TorznabCatType.Audio, " Domestic Rap, Hip-Hop, R'n'B (lossless)"); - AddCategoryMapping(1390, TorznabCatType.Audio, " Domestic Rap, Hip-Hop (Video)"); - AddCategoryMapping(1391, TorznabCatType.Audio, " Domestic R'n'B (Video)"); - AddCategoryMapping(1392, TorznabCatType.Audio, " Foreign R'n'B (lossless)"); - AddCategoryMapping(1393, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (own digitization)"); - AddCategoryMapping(1394, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (Video)"); - AddCategoryMapping(1395, TorznabCatType.Audio, " Foreign R'n'B (Video)"); - AddCategoryMapping(1396, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (DVD Video)"); - AddCategoryMapping(1397, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (HD Video)"); - AddCategoryMapping(65, TorznabCatType.Audio, " Pop music"); - AddCategoryMapping(196, TorznabCatType.Audio, " International Pop Music"); - AddCategoryMapping(689, TorznabCatType.Audio, " Foreign pop music (lossy)"); - AddCategoryMapping(712, TorznabCatType.Audio, " Foreign pop music (lossless)"); - AddCategoryMapping(1429, TorznabCatType.Audio, " Foreign pop music (collections) (lossy)"); - AddCategoryMapping(711, TorznabCatType.Audio, " East Asian pop music (lossy)"); - AddCategoryMapping(1432, TorznabCatType.Audio, " East Asian pop music (lossless)"); - AddCategoryMapping(879, TorznabCatType.Audio, " Domestic Pop"); - AddCategoryMapping(197, TorznabCatType.Audio, " Patriotic Pop (lossy)"); - AddCategoryMapping(1425, TorznabCatType.Audio, " Patriotic Pop (lossless)"); - AddCategoryMapping(1426, TorznabCatType.Audio, " Patriotic Pop music (collections) (lossy)"); - AddCategoryMapping(1427, TorznabCatType.Audio, " Soviet stage, Retro (lossy)"); - AddCategoryMapping(1428, TorznabCatType.Audio, " Soviet stage, Retro (lossless)"); - AddCategoryMapping(198, TorznabCatType.Audio, " Eurodance, Disco, Hi-NRG"); - AddCategoryMapping(703, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (lossy)"); - AddCategoryMapping(877, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (lossless)"); - AddCategoryMapping(199, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (collections) (lossy)"); - AddCategoryMapping(704, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossy)"); - AddCategoryMapping(878, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossless)"); - AddCategoryMapping(1433, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (collections) (lossy)"); - AddCategoryMapping(1434, TorznabCatType.Audio, " Video, DVD Video, HD Video (Pop)"); - AddCategoryMapping(1435, TorznabCatType.Audio, " Patriotic Pop (Video)"); - AddCategoryMapping(1436, TorznabCatType.Audio, " Patriotic Pop (DVD Video)"); - AddCategoryMapping(1437, TorznabCatType.Audio, " Soviet stage, Retro (video)"); - AddCategoryMapping(1438, TorznabCatType.Audio, " Soviet stage, Retro (DVD Video)"); - AddCategoryMapping(1439, TorznabCatType.Audio, " Foreign pop music (Video)"); - AddCategoryMapping(1440, TorznabCatType.Audio, " Foreign pop music (DVD Video)"); - AddCategoryMapping(1441, TorznabCatType.Audio, " Eurodance, Disco (video)"); - AddCategoryMapping(1442, TorznabCatType.Audio, " Eurodance, Disco (DVD Video)"); - AddCategoryMapping(1443, TorznabCatType.Audio, " East Asian pop music (Video)"); - AddCategoryMapping(1444, TorznabCatType.Audio, " East Asian pop music (DVD Video)"); - AddCategoryMapping(1447, TorznabCatType.Audio, " Patriotic Pop (National concerts, Doc. Video) (Video and DVD)"); - AddCategoryMapping(1448, TorznabCatType.Audio, " Foreign pop music (National concerts, Doc. Video) (Video and DVD)"); - AddCategoryMapping(1449, TorznabCatType.Audio, " International Pop Music, Chanson, Eurodance, Disco (HD Video)"); - AddCategoryMapping(1450, TorznabCatType.Audio, " Patriotic Pop Music, Chanson, Eurodance, Disco (HD Video)"); - AddCategoryMapping(1451, TorznabCatType.Audio, " The multi-channel music and own digitization (pop music)"); - AddCategoryMapping(1452, TorznabCatType.Audio, " Foreign pop music (own digitization)"); - AddCategoryMapping(1453, TorznabCatType.Audio, " Eastern pop music (own digitization)"); - AddCategoryMapping(1454, TorznabCatType.Audio, " Patriotic Pop (own digitization)"); - AddCategoryMapping(1455, TorznabCatType.Audio, " Instrumental Pop (own digitization)"); - AddCategoryMapping(1456, TorznabCatType.Audio, " Multichannel music (pop music)"); - AddCategoryMapping(1457, TorznabCatType.Audio, " Foreign pop music (Hi-Res stereo)"); - AddCategoryMapping(66, TorznabCatType.Audio, " Soundtracks, Karaoke and Minus"); - AddCategoryMapping(917, TorznabCatType.Audio, " The arrangements of music from the game (lossy and lossless)"); - AddCategoryMapping(1400, TorznabCatType.Audio, " Minus (lossy and lossless)"); - AddCategoryMapping(1824, TorznabCatType.Audio, " Soundtracks"); - AddCategoryMapping(232, TorznabCatType.Audio, " Soundtracks to movies and cartoons (mp3)"); - AddCategoryMapping(234, TorznabCatType.Audio, " Soundtracks for games (lossy)"); - AddCategoryMapping(693, TorznabCatType.Audio, " Soundtracks to foreign films (lossy)"); - AddCategoryMapping(880, TorznabCatType.Audio, " Soundtracks to foreign films (lossless)"); - AddCategoryMapping(915, TorznabCatType.Audio, " Soundtracks for games (lossless)"); - AddCategoryMapping(916, TorznabCatType.Audio, " Informal soundtracks for games (lossy)"); - AddCategoryMapping(918, TorznabCatType.Audio, " Informal soundtracks for films and TV series (lossy)"); - AddCategoryMapping(919, TorznabCatType.Audio, " Soundtracks for domestic films (lossy)"); - AddCategoryMapping(920, TorznabCatType.Audio, " Soundtracks for domestic films (lossless)"); - AddCategoryMapping(921, TorznabCatType.Audio, " Soundtracks (own digitization)"); - AddCategoryMapping(1825, TorznabCatType.Audio, " Karaoke"); - AddCategoryMapping(1398, TorznabCatType.Audio, " Karaoke (Audio)"); - AddCategoryMapping(1399, TorznabCatType.Audio, " Karaoke (Video)"); - AddCategoryMapping(67, TorznabCatType.Audio, " Music of other genres"); - AddCategoryMapping(694, TorznabCatType.Audio, " Proper sampling (music of other genres)"); - AddCategoryMapping(695, TorznabCatType.Audio, " Patriotic music of other genres (lossy)"); - AddCategoryMapping(696, TorznabCatType.Audio, " Patriotic music of other genres (lossless)"); - AddCategoryMapping(697, TorznabCatType.Audio, " Foreign music of other genres (lossy)"); - AddCategoryMapping(1408, TorznabCatType.Audio, " Foreign music of other genres (lossless)"); - AddCategoryMapping(1409, TorznabCatType.Audio, " Music for ballroom dancing (lossy and lossless)"); - AddCategoryMapping(1410, TorznabCatType.Audio, " Orthodox chants (lossy)"); - AddCategoryMapping(1411, TorznabCatType.Audio, " Orthodox chants (lossless)"); - AddCategoryMapping(1412, TorznabCatType.Audio, " A collection of songs for children (lossy and lossless)"); - AddCategoryMapping(1686, TorznabCatType.Audio, " Classics for mothers and babies"); - AddCategoryMapping(1413, TorznabCatType.Audio, " Video (Music from other genres)"); - AddCategoryMapping(1414, TorznabCatType.Audio, " DVD Video (Music from other genres)"); - AddCategoryMapping(1415, TorznabCatType.Audio, " Musical (lossy and lossless)"); - AddCategoryMapping(1416, TorznabCatType.Audio, " Musical (Video and DVD Video)"); - AddCategoryMapping(1417, TorznabCatType.Audio, " Informal and vnezhanrovye collections (lossy)"); - AddCategoryMapping(172, TorznabCatType.Audio, " Classical and contemporary academic music"); - AddCategoryMapping(705, TorznabCatType.Audio, " Vocal music (lossless)"); - AddCategoryMapping(706, TorznabCatType.Audio, " Orchestral music (lossless)"); - AddCategoryMapping(707, TorznabCatType.Audio, " Concerto for instrument and orchestra (lossless)"); - AddCategoryMapping(708, TorznabCatType.Audio, " Chamber instrumental music (lossless)"); - AddCategoryMapping(709, TorznabCatType.Audio, " Solo instrumental music (lossless)"); - AddCategoryMapping(710, TorznabCatType.Audio, " Vocal and choral music (lossy)"); - AddCategoryMapping(1001, TorznabCatType.Audio, " Proper digitization (Classical Music)"); - AddCategoryMapping(1002, TorznabCatType.Audio, " Multichannel music (Classic and classic with a modern twist)"); - AddCategoryMapping(1003, TorznabCatType.Audio, " Classic and classic in modern processing (Hi-Res stereo)"); - AddCategoryMapping(1008, TorznabCatType.Audio, " Classical Music (Video)"); - AddCategoryMapping(1009, TorznabCatType.Audio, " Classical Music (DVD and HD Video)"); - AddCategoryMapping(1362, TorznabCatType.Audio, " Opera (Video)"); - AddCategoryMapping(1363, TorznabCatType.Audio, " Opera (DVD and HD Video)"); - AddCategoryMapping(1364, TorznabCatType.Audio, " Ballet and modern choreography (Video, DVD and HD Video)"); - AddCategoryMapping(1365, TorznabCatType.Audio, " The complete collection of works and multi-disc edition (lossless)"); - AddCategoryMapping(1366, TorznabCatType.Audio, " Opera (lossless)"); - AddCategoryMapping(1367, TorznabCatType.Audio, " Choral music (lossless)"); - AddCategoryMapping(1368, TorznabCatType.Audio, " The complete collection of works and multi-disc edition (lossy)"); - AddCategoryMapping(1369, TorznabCatType.Audio, " Orchestral music (lossy)"); - AddCategoryMapping(1370, TorznabCatType.Audio, " Chamber and solo instrumental music (lossy)"); - AddCategoryMapping(1371, TorznabCatType.Audio, " Classics in modern processing, Classical Crossover (lossy and lossless)"); - AddCategoryMapping(175, TorznabCatType.Audio, " Jazz, Blues"); - AddCategoryMapping(178, TorznabCatType.Audio, " foreign Jazz"); - AddCategoryMapping(747, TorznabCatType.Audio, " Avant-Garde Jazz, Free Improvisation (lossless)"); - AddCategoryMapping(741, TorznabCatType.Audio, " Bop (lossless)"); - AddCategoryMapping(842, TorznabCatType.Audio, " Early Jazz, Swing, Gypsy (lossless)"); - AddCategoryMapping(847, TorznabCatType.Audio, " Funk, Soul, R & B (lossless)"); - AddCategoryMapping(843, TorznabCatType.Audio, " Jazz Fusion (lossless)"); - AddCategoryMapping(599, TorznabCatType.Audio, " Mainstream Jazz, Cool (lossless)"); - AddCategoryMapping(845, TorznabCatType.Audio, " Modern Creative, Third Stream (lossless)"); - AddCategoryMapping(846, TorznabCatType.Audio, " Smooth, Jazz-Pop (lossless)"); - AddCategoryMapping(620, TorznabCatType.Audio, " Vocal Jazz (lossless)"); - AddCategoryMapping(844, TorznabCatType.Audio, " World Fusion, Ethnic Jazz (lossless)"); - AddCategoryMapping(673, TorznabCatType.Audio, " Foreign jazz (lossy)"); - AddCategoryMapping(848, TorznabCatType.Audio, " Collections of foreign jazz (lossless)"); - AddCategoryMapping(690, TorznabCatType.Audio, " foreign blues"); - AddCategoryMapping(839, TorznabCatType.Audio, " Blues-rock (lossless)"); - AddCategoryMapping(713, TorznabCatType.Audio, " Blues (Texas, Chicago, Modern and Others) (lossless)"); - AddCategoryMapping(840, TorznabCatType.Audio, " Roots, Pre-War Blues, Early R & B, Gospel (lossless)"); - AddCategoryMapping(691, TorznabCatType.Audio, " Foreign blues (lossy)"); - AddCategoryMapping(841, TorznabCatType.Audio, " Foreign blues (collections; Tribute VA) (lossless)"); - AddCategoryMapping(849, TorznabCatType.Audio, " Domestic jazz and blues"); - AddCategoryMapping(850, TorznabCatType.Audio, " Domestic Jazz (lossless)"); - AddCategoryMapping(851, TorznabCatType.Audio, " Domestic jazz (lossy)"); - AddCategoryMapping(853, TorznabCatType.Audio, " Domestic Blues (lossless)"); - AddCategoryMapping(854, TorznabCatType.Audio, " Domestic Blues (lossy)"); - AddCategoryMapping(1013, TorznabCatType.Audio, " The multi-channel music and own digitization (Jazz and Blues)"); - AddCategoryMapping(1014, TorznabCatType.Audio, " Multichannel music (Jazz and Blues)"); - AddCategoryMapping(1015, TorznabCatType.Audio, " Foreign Jazz and Blues (Hi-Res stereo)"); - AddCategoryMapping(1016, TorznabCatType.Audio, " Proper digitization (Jazz and Blues)"); - AddCategoryMapping(1458, TorznabCatType.Audio, " Video, DVD Video, HD Video (Jazz and Blues)"); - AddCategoryMapping(1459, TorznabCatType.Audio, " Jazz and Blues (Video)"); - AddCategoryMapping(1460, TorznabCatType.Audio, " Jazz and Blues (DVD Video)"); - AddCategoryMapping(1461, TorznabCatType.Audio, " Jazz and Blues (HD Video)"); - AddCategoryMapping(204, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco"); - AddCategoryMapping(207, TorznabCatType.Audio, " NewAge & Meditative (lossy)"); - AddCategoryMapping(1004, TorznabCatType.Audio, " NewAge & Meditative (lossless)"); - AddCategoryMapping(1005, TorznabCatType.Audio, " Flamenco and acoustic guitar (lossy)"); - AddCategoryMapping(1006, TorznabCatType.Audio, " Flamenco and acoustic guitar (lossless)"); - AddCategoryMapping(1385, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco (Video)"); - AddCategoryMapping(1386, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco (DVD and HD Video)"); - AddCategoryMapping(1007, TorznabCatType.Audio, " Sounds of nature"); - AddCategoryMapping(701, TorznabCatType.Audio, " Chanson, Author and military songs"); - AddCategoryMapping(702, TorznabCatType.Audio, " Domestic chanson (lossy)"); - AddCategoryMapping(891, TorznabCatType.Audio, " Domestic chanson (lossless)"); - AddCategoryMapping(892, TorznabCatType.Audio, " Military song (lossy)"); - AddCategoryMapping(893, TorznabCatType.Audio, " Chanson (lossy)"); - AddCategoryMapping(1401, TorznabCatType.Audio, " Collections domestic chanson (lossy)"); - AddCategoryMapping(1402, TorznabCatType.Audio, " Military song (lossless)"); - AddCategoryMapping(1403, TorznabCatType.Audio, " Chanson (lossless)"); - AddCategoryMapping(1404, TorznabCatType.Audio, " Minstrels and roleviki (lossy and lossless)"); - AddCategoryMapping(1405, TorznabCatType.Audio, " Proper digitization (Chanson, and Bards) lossless"); - AddCategoryMapping(1406, TorznabCatType.Audio, " Videos (Chanson, and Bards)"); - AddCategoryMapping(1407, TorznabCatType.Audio, " DVD Video (Chanson, and Bards)"); - AddCategoryMapping(1430, TorznabCatType.Audio, " Foreign chanson (lossy)"); - AddCategoryMapping(1431, TorznabCatType.Audio, " Foreign chanson (lossless)"); - AddCategoryMapping(1445, TorznabCatType.Audio, " Foreign chanson (Video)"); - AddCategoryMapping(1446, TorznabCatType.Audio, " Foreign chanson (DVD Video)"); - AddCategoryMapping(865, TorznabCatType.Audio, " Rock music"); - AddCategoryMapping(62, TorznabCatType.Audio, " foreign Rock"); - AddCategoryMapping(859, TorznabCatType.Audio, " AOR (Melodic Hard Rock, Arena rock) (lossless)"); - AddCategoryMapping(860, TorznabCatType.Audio, " AOR (Melodic Hard Rock, Arena rock) (lossy)"); - AddCategoryMapping(855, TorznabCatType.Audio, " Classic Rock & Hard Rock (lossless)"); - AddCategoryMapping(856, TorznabCatType.Audio, " Classic Rock & Hard Rock (lossy)"); - AddCategoryMapping(864, TorznabCatType.Audio, " Instrumental Guitar Rock (lossy)"); - AddCategoryMapping(1027, TorznabCatType.Audio, " Instrumental Guitar Rock (lossless)"); - AddCategoryMapping(858, TorznabCatType.Audio, " Folk-Rock (lossless)"); - AddCategoryMapping(675, TorznabCatType.Audio, " Folk-Rock (lossy)"); - AddCategoryMapping(861, TorznabCatType.Audio, " Pop-Rock & Soft Rock (lossless)"); - AddCategoryMapping(676, TorznabCatType.Audio, " Pop-Rock & Soft Rock (lossy)"); - AddCategoryMapping(857, TorznabCatType.Audio, " Progressive & Art-Rock (lossless)"); - AddCategoryMapping(674, TorznabCatType.Audio, " Progressive & Art-Rock (lossy)"); - AddCategoryMapping(863, TorznabCatType.Audio, " Rockabilly, Psychobilly, Rock'n'Roll (lossless)"); - AddCategoryMapping(730, TorznabCatType.Audio, " Rockabilly, Psychobilly, Rock'n'Roll (lossy)"); - AddCategoryMapping(1028, TorznabCatType.Audio, " East Asian Rock (lossless)"); - AddCategoryMapping(862, TorznabCatType.Audio, " East Asian rock (lossy)"); - AddCategoryMapping(1858, TorznabCatType.Audio, " Collections of foreign rock (lossless)"); - AddCategoryMapping(1859, TorznabCatType.Audio, " Collections of foreign rock (lossy)"); - AddCategoryMapping(187, TorznabCatType.Audio, " Domestic Rock"); - AddCategoryMapping(872, TorznabCatType.Audio, " Rock, Punk, Alternative (lossless)"); - AddCategoryMapping(190, TorznabCatType.Audio, " Rock, Punk, Alternative (lossy)"); - AddCategoryMapping(1489, TorznabCatType.Audio, " Metal (lossless)"); - AddCategoryMapping(191, TorznabCatType.Audio, " Metal (lossy)"); - AddCategoryMapping(1490, TorznabCatType.Audio, " Rock on the languages ??of the peoples xUSSR (lossless)"); - AddCategoryMapping(1491, TorznabCatType.Audio, " Rock on the languages ??of the peoples xUSSR (lossy)"); - AddCategoryMapping(866, TorznabCatType.Audio, " foreign Metal"); - AddCategoryMapping(727, TorznabCatType.Audio, " Black (lossy)"); - AddCategoryMapping(728, TorznabCatType.Audio, " Death, Doom (lossy)"); - AddCategoryMapping(729, TorznabCatType.Audio, " Heavy, Power, Progressive (lossy)"); - AddCategoryMapping(871, TorznabCatType.Audio, " Heavy, Power, Progressive (lossless)"); - AddCategoryMapping(1462, TorznabCatType.Audio, " Avant-garde, Experimental Metal (lossless)"); - AddCategoryMapping(1463, TorznabCatType.Audio, " Avant-garde, Experimental Metal (lossy)"); - AddCategoryMapping(1464, TorznabCatType.Audio, " Black (lossless)"); - AddCategoryMapping(1466, TorznabCatType.Audio, " Death, Doom (lossless)"); - AddCategoryMapping(1468, TorznabCatType.Audio, " Folk, Pagan, Viking (lossless)"); - AddCategoryMapping(1469, TorznabCatType.Audio, " Folk, Pagan, Viking (lossy)"); - AddCategoryMapping(1470, TorznabCatType.Audio, " Gothic Metal (lossless)"); - AddCategoryMapping(1471, TorznabCatType.Audio, " Gothic Metal (lossy)"); - AddCategoryMapping(1472, TorznabCatType.Audio, " Grind, Brutal Death (lossless)"); - AddCategoryMapping(1473, TorznabCatType.Audio, " Grind, Brutal Death (lossy)"); - AddCategoryMapping(1474, TorznabCatType.Audio, " Sludge, Stoner, Post-Metal (lossless)"); - AddCategoryMapping(1475, TorznabCatType.Audio, " Sludge, Stoner, Post-Metal (lossy)"); - AddCategoryMapping(1476, TorznabCatType.Audio, " Thrash, Speed ??(lossless)"); - AddCategoryMapping(1477, TorznabCatType.Audio, " Thrash, Speed ??(lossy)"); - AddCategoryMapping(1478, TorznabCatType.Audio, " Collections \"Foreign Metal\" (lossless)"); - AddCategoryMapping(1479, TorznabCatType.Audio, " Collections \"Foreign Metal\" (lossy)"); - AddCategoryMapping(867, TorznabCatType.Audio, " Foreign Alternative, Punk, Independent"); - AddCategoryMapping(185, TorznabCatType.Audio, " Alternative & Nu-metal (lossless)"); - AddCategoryMapping(868, TorznabCatType.Audio, " Alternative & Nu-metal (lossy)"); - AddCategoryMapping(869, TorznabCatType.Audio, " Indie, Post-Rock & Post-Punk (lossless)"); - AddCategoryMapping(870, TorznabCatType.Audio, " Indie, Post-Rock & Post-Punk (lossy)"); - AddCategoryMapping(873, TorznabCatType.Audio, " Avant-garde, Experimental Rock (lossy)"); - AddCategoryMapping(874, TorznabCatType.Audio, " Punk (lossy)"); - AddCategoryMapping(875, TorznabCatType.Audio, " Punk (lossless)"); - AddCategoryMapping(876, TorznabCatType.Audio, " Avant-garde, Experimental Rock (lossless)"); - AddCategoryMapping(1480, TorznabCatType.Audio, " Hardcore (lossless)"); - AddCategoryMapping(1481, TorznabCatType.Audio, " Hardcore (lossy)"); - AddCategoryMapping(1482, TorznabCatType.Audio, " Industrial & Post-industrial (lossless)"); - AddCategoryMapping(1483, TorznabCatType.Audio, " Industrial & Post-industrial (lossy)"); - AddCategoryMapping(1484, TorznabCatType.Audio, " Emocore, Post-hardcore, Metalcore (lossless)"); - AddCategoryMapping(1485, TorznabCatType.Audio, " Emocore, Post-hardcore, Metalcore (lossy)"); - AddCategoryMapping(1486, TorznabCatType.Audio, " Gothic Rock & Dark Folk (lossless)"); - AddCategoryMapping(1487, TorznabCatType.Audio, " Gothic Rock & Dark Folk (lossy)"); - AddCategoryMapping(1492, TorznabCatType.Audio, " The multi-channel music and own digitization (Rock)"); - AddCategoryMapping(1493, TorznabCatType.Audio, " Foreign rock (own digitization)"); - AddCategoryMapping(1494, TorznabCatType.Audio, " Domestic Rock (own digitization)"); - AddCategoryMapping(1495, TorznabCatType.Audio, " Foreign and domestic rock (multichannel music)"); - AddCategoryMapping(1496, TorznabCatType.Audio, " Foreign rock (Hi-Res stereo)"); - AddCategoryMapping(1497, TorznabCatType.Audio, " Conversion Quadraphonic (multichannel music)"); - AddCategoryMapping(1498, TorznabCatType.Audio, " Conversion SACD (multi-channel music)"); - AddCategoryMapping(1499, TorznabCatType.Audio, " Conversions in Blu-Ray (multichannel music)"); - AddCategoryMapping(1500, TorznabCatType.Audio, " Apmiksy-Upmixes / downmix-Downmix (multi-channel and Hi-Res stereo music)"); - AddCategoryMapping(1501, TorznabCatType.Audio, " Video, DVD Video, HD Video (Rock)"); - AddCategoryMapping(1502, TorznabCatType.Audio, " Rock (Video)"); - AddCategoryMapping(1503, TorznabCatType.Audio, " Rock (DVD Video)"); - AddCategoryMapping(1504, TorznabCatType.Audio, " Rock (Unofficial DVD Video)"); - AddCategoryMapping(1505, TorznabCatType.Audio, " Metal (Video)"); - AddCategoryMapping(1506, TorznabCatType.Audio, " Metal (DVD Video)"); - AddCategoryMapping(1507, TorznabCatType.Audio, " Metal (Unofficial DVD Video)"); - AddCategoryMapping(1508, TorznabCatType.Audio, " Alternative, Punk, Independent (Video)"); - AddCategoryMapping(1509, TorznabCatType.Audio, " Alternative, Punk, Independent (DVD Video)"); - AddCategoryMapping(1510, TorznabCatType.Audio, " Alternative, Punk, Independent (Unofficial DVD Video)"); - AddCategoryMapping(1511, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative (Video)"); - AddCategoryMapping(1512, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative (DVD Video)"); - AddCategoryMapping(1513, TorznabCatType.Audio, " Domestic Metal (Video)"); - AddCategoryMapping(1514, TorznabCatType.Audio, " Domestic Metal (DVD Video)"); - AddCategoryMapping(1515, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative, Metal (Unofficial DVD Video)"); - AddCategoryMapping(1516, TorznabCatType.Audio, " Rock (HD Video)"); - AddCategoryMapping(905, TorznabCatType.Audio, " Folklore, Folk and World Music"); - AddCategoryMapping(906, TorznabCatType.Audio, " Eastern European Folk (lossy)"); - AddCategoryMapping(907, TorznabCatType.Audio, " Eastern European Folk (lossless)"); - AddCategoryMapping(908, TorznabCatType.Audio, " Western European folk (lossy)"); - AddCategoryMapping(909, TorznabCatType.Audio, " Western European folk (lossless)"); - AddCategoryMapping(910, TorznabCatType.Audio, " Klezmer and Jewish folklore (lossy and lossless)"); - AddCategoryMapping(911, TorznabCatType.Audio, " Country, Bluegrass (lossy)"); - AddCategoryMapping(912, TorznabCatType.Audio, " Country, Bluegrass (lossless)"); - AddCategoryMapping(1372, TorznabCatType.Audio, " World Music Siberia, Central Asia and East Asia (lossy)"); - AddCategoryMapping(1373, TorznabCatType.Audio, " World Music Siberia, Central Asia and East Asia (lossless)"); - AddCategoryMapping(1374, TorznabCatType.Audio, " World Music India (lossy)"); - AddCategoryMapping(1375, TorznabCatType.Audio, " World Music India (lossless)"); - AddCategoryMapping(1376, TorznabCatType.Audio, " World Music Africa and the Middle East (lossy)"); - AddCategoryMapping(1377, TorznabCatType.Audio, " World Music Africa and the Middle East (lossless)"); - AddCategoryMapping(1378, TorznabCatType.Audio, " Ethnic Caucasus and Transcaucasia music (lossy and lossless)"); - AddCategoryMapping(1379, TorznabCatType.Audio, " World Music Americas (lossy)"); - AddCategoryMapping(1380, TorznabCatType.Audio, " World Music Americas (lossless)"); - AddCategoryMapping(1381, TorznabCatType.Audio, " World Music Australia, the Pacific and Indian Oceans (lossy and lossless)"); - AddCategoryMapping(1382, TorznabCatType.Audio, " Folklore, Folk and World Music (Video)"); - AddCategoryMapping(1383, TorznabCatType.Audio, " Folklore, Folk and World Music (DVD Video)"); - AddCategoryMapping(1384, TorznabCatType.Audio, " Folklore, Folk and World Music (HD Video)"); - AddCategoryMapping(1857, TorznabCatType.Audio, " Folklore, Folk and World Music (own digitization)"); - AddCategoryMapping(985, TorznabCatType.Audio, " Reggae, Ska, Dub"); - AddCategoryMapping(986, TorznabCatType.Audio, " Rocksteady, Early Reggae, Ska-Jazz, Trad.Ska (lossy and lossless)"); - AddCategoryMapping(987, TorznabCatType.Audio, " Punky-Reggae, Rocksteady-Punk, Ska Revival (lossy)"); - AddCategoryMapping(988, TorznabCatType.Audio, " 3rd Wave Ska (lossy)"); - AddCategoryMapping(989, TorznabCatType.Audio, " Ska-Punk, Ska-Core (lossy)"); - AddCategoryMapping(990, TorznabCatType.Audio, " Reggae (lossy)"); - AddCategoryMapping(1026, TorznabCatType.Audio, " Dub (lossy)"); - AddCategoryMapping(991, TorznabCatType.Audio, " Dancehall, Raggamuffin (lossy)"); - AddCategoryMapping(992, TorznabCatType.Audio, " Reggae, Dancehall, Dub (lossless)"); - AddCategoryMapping(993, TorznabCatType.Audio, " Ska, Ska-Punk, Ska-Jazz (lossless)"); - AddCategoryMapping(994, TorznabCatType.Audio, " Domestic reggae, dub (lossy and lossless)"); - AddCategoryMapping(995, TorznabCatType.Audio, " Domestic ska music (lossy and lossless)"); - AddCategoryMapping(997, TorznabCatType.Audio, " Reggae, Ska, Dub (own digitization)"); - AddCategoryMapping(998, TorznabCatType.Audio, " Reggae, Ska, Dub (compilation) (lossy)"); - AddCategoryMapping(999, TorznabCatType.Audio, " Reggae, Ska, Dub (Video)"); - AddCategoryMapping(1000, TorznabCatType.Audio, " Reggae, Ska, Dub (DVD and HD Video)"); - AddCategoryMapping(1418, TorznabCatType.Audio, " Sheet Music literature"); - AddCategoryMapping(1419, TorznabCatType.Audio, " Academic Music (Notes and Media CD)"); - AddCategoryMapping(1420, TorznabCatType.Audio, " More destinations (notes, tablature)"); - AddCategoryMapping(1421, TorznabCatType.Audio, " Self and School"); - AddCategoryMapping(1422, TorznabCatType.Audio, " Songbooks (Songbooks)"); - AddCategoryMapping(1423, TorznabCatType.Audio, " Music Literature and Theory"); - AddCategoryMapping(1424, TorznabCatType.Audio, " music magazines"); - AddCategoryMapping(1602, TorznabCatType.Audio, " Audio for Apple devices"); - AddCategoryMapping(1603, TorznabCatType.Audio, " Audiobooks (AAC, ALAC)"); - AddCategoryMapping(1604, TorznabCatType.Audio, " Music Lossless (ALAC)"); - AddCategoryMapping(1605, TorznabCatType.Audio, " Music Lossy (AAC)"); - AddCategoryMapping(1606, TorznabCatType.Audio, " Music Lossy (AAC) (Singles, EPs)"); - AddCategoryMapping(113, TorznabCatType.Books, "Books, Audio Books, Journals"); - AddCategoryMapping(561, TorznabCatType.Books, " Books, Audio Books, Journals (General Discussion)"); - AddCategoryMapping(316, TorznabCatType.Books, " Archive (Books, Audio Books, Journals)"); - AddCategoryMapping(1620, TorznabCatType.Books, " Meditation"); - AddCategoryMapping(1802, TorznabCatType.Books, " Historiography"); - AddCategoryMapping(116, TorznabCatType.AudioAudiobook, " Audiobooks"); - AddCategoryMapping(1231, TorznabCatType.AudioAudiobook, " Audio, history, memoirs (Audiobooks)"); - AddCategoryMapping(119, TorznabCatType.AudioAudiobook, " Audio and literary readings (Audiobooks)"); - AddCategoryMapping(1232, TorznabCatType.AudioAudiobook, " Lots of great people (Audiobooks)"); - AddCategoryMapping(1233, TorznabCatType.AudioAudiobook, " Historical book (Audiobooks)"); - AddCategoryMapping(321, TorznabCatType.AudioAudiobook, " Science fiction, fantasy, mystery, horror, fanfiction (Audiobooks)"); - AddCategoryMapping(1234, TorznabCatType.AudioAudiobook, " Russian fiction, fantasy, mystery, horror, fanfiction (audiobook)"); - AddCategoryMapping(1235, TorznabCatType.AudioAudiobook, " Foreign fiction, fantasy, mystery, horror, fanfiction (audiobook)"); - AddCategoryMapping(317, TorznabCatType.AudioAudiobook, " Fiction (Audiobooks)"); - AddCategoryMapping(1236, TorznabCatType.AudioAudiobook, " Poetry (audiobook)"); - AddCategoryMapping(118, TorznabCatType.AudioAudiobook, " Foreign literature (audiobook)"); - AddCategoryMapping(117, TorznabCatType.AudioAudiobook, " Russian Literature (audiobook)"); - AddCategoryMapping(120, TorznabCatType.AudioAudiobook, " Children's Literature (audiobook)"); - AddCategoryMapping(1237, TorznabCatType.AudioAudiobook, " Detectives, Adventure, Thriller, Action (audiobook)"); - AddCategoryMapping(318, TorznabCatType.AudioAudiobook, " Detectives (audiobook)"); - AddCategoryMapping(322, TorznabCatType.AudioAudiobook, " Psychology. philosophy, religion (Audiobooks)"); - AddCategoryMapping(1238, TorznabCatType.AudioAudiobook, " Religion (Audio)"); - AddCategoryMapping(1239, TorznabCatType.AudioAudiobook, " Orthodox (Audio)"); - AddCategoryMapping(1240, TorznabCatType.AudioAudiobook, " Islam (Audio)"); - AddCategoryMapping(1241, TorznabCatType.AudioAudiobook, " Other traditional religion (Audio)"); - AddCategoryMapping(1242, TorznabCatType.AudioAudiobook, " Nontraditional religious philosophies (Audio)"); - AddCategoryMapping(1243, TorznabCatType.AudioAudiobook, " Educational, scientific and popular literature (Audio)"); - AddCategoryMapping(1244, TorznabCatType.AudioAudiobook, " Audiobooks in lossless-format"); - AddCategoryMapping(323, TorznabCatType.AudioAudiobook, " Business (Audio)"); - AddCategoryMapping(319, TorznabCatType.AudioAudiobook, " Historical literature (Audiobooks)"); - AddCategoryMapping(1245, TorznabCatType.AudioAudiobook, " Miscellaneous (Audiobooks)"); - AddCategoryMapping(1622, TorznabCatType.AudioAudiobook, " Meditation (Audio)"); - AddCategoryMapping(1626, TorznabCatType.AudioAudiobook, " publicism"); - AddCategoryMapping(1627, TorznabCatType.AudioAudiobook, " Satire, humor"); - AddCategoryMapping(324, TorznabCatType.AudioAudiobook, " Archive and nekonditsiya audiobooks"); - AddCategoryMapping(670, TorznabCatType.Books, " Books and magazines"); - AddCategoryMapping(671, TorznabCatType.Books, " Esoteric Tarot, Feng Shui"); - AddCategoryMapping(885, TorznabCatType.Books, " Film, TV, animation"); - AddCategoryMapping(886, TorznabCatType.Books, " Drawing, Graphic Design"); - AddCategoryMapping(887, TorznabCatType.Books, " Photo and video shooting"); - AddCategoryMapping(888, TorznabCatType.Books, " Astrology"); - AddCategoryMapping(1865, TorznabCatType.Books, " Fashion. Style. Etiquette"); - AddCategoryMapping(889, TorznabCatType.Books, " Celebrities and idols"); - AddCategoryMapping(890, TorznabCatType.Books, " Miscellaneous"); - AddCategoryMapping(982, TorznabCatType.Books, " Magazines and newspapers (general section)"); - AddCategoryMapping(566, TorznabCatType.Books, " Men's magazines"); - AddCategoryMapping(1204, TorznabCatType.Books, " For women (magazines and books)"); - AddCategoryMapping(1793, TorznabCatType.Books, " Popular science magazines"); - AddCategoryMapping(1794, TorznabCatType.Books, " Journals of Electrical and Electronics"); - AddCategoryMapping(1795, TorznabCatType.Books, " Housekeeping (logs)"); - AddCategoryMapping(1796, TorznabCatType.Books, " Hobbies (logs)"); - AddCategoryMapping(1797, TorznabCatType.Books, " Other magazines"); - AddCategoryMapping(1205, TorznabCatType.Books, " Travel and tourism"); - AddCategoryMapping(258, TorznabCatType.Books, " For children, parents and teachers"); - AddCategoryMapping(1685, TorznabCatType.Books, " Tutorials (General)"); - AddCategoryMapping(681, TorznabCatType.Books, " Textbooks for kindergarten and elementary school (up to class 4)"); - AddCategoryMapping(682, TorznabCatType.Books, " Textbooks for high school (grades 5-11)"); - AddCategoryMapping(683, TorznabCatType.Books, " Teachers and educators"); - AddCategoryMapping(684, TorznabCatType.Books, " Popular science and cognitive literature (for children)"); - AddCategoryMapping(685, TorznabCatType.Books, " Leisure and creativity"); - AddCategoryMapping(686, TorznabCatType.Books, " Education and development"); - AddCategoryMapping(687, TorznabCatType.Books, " Hood. lit-ra for preschool and elementary grades"); - AddCategoryMapping(688, TorznabCatType.Books, " Hood. lit-ra for the middle and upper classes"); - AddCategoryMapping(731, TorznabCatType.Books, " Sports, physical training, martial arts"); - AddCategoryMapping(738, TorznabCatType.Books, " Autosport. Motorcycling. Cycling (literature)"); - AddCategoryMapping(737, TorznabCatType.Books, " Martial arts, martial arts (literature)"); - AddCategoryMapping(734, TorznabCatType.Books, " Team sports (literature)"); - AddCategoryMapping(1854, TorznabCatType.Books, " Athletics. Swimming. Gymnastics. Weightlifting. Rowing (literature)"); - AddCategoryMapping(739, TorznabCatType.Books, " Sport Editions"); - AddCategoryMapping(736, TorznabCatType.Books, " Fitness, fitness, bodybuilding (literature)"); - AddCategoryMapping(732, TorznabCatType.Books, " Football (literature)"); - AddCategoryMapping(733, TorznabCatType.Books, " Hockey (literature)"); - AddCategoryMapping(735, TorznabCatType.Books, " Chess. Checkers (literature)"); - AddCategoryMapping(1855, TorznabCatType.Books, " Extreme sports (literature)"); - AddCategoryMapping(649, TorznabCatType.Books, " Humanitarian sciences"); - AddCategoryMapping(650, TorznabCatType.Books, " Arts. Cultural"); - AddCategoryMapping(651, TorznabCatType.Books, " Folklore. Epic. Mythology"); - AddCategoryMapping(652, TorznabCatType.Books, " literary criticism"); - AddCategoryMapping(653, TorznabCatType.Books, " Linguistics"); - AddCategoryMapping(654, TorznabCatType.Books, " Philosophy"); - AddCategoryMapping(655, TorznabCatType.Books, " Political science"); - AddCategoryMapping(656, TorznabCatType.Books, " Sociology"); - AddCategoryMapping(657, TorznabCatType.Books, " Journalism, Journalism"); - AddCategoryMapping(658, TorznabCatType.Books, " Business, Management"); - AddCategoryMapping(659, TorznabCatType.Books, " Marketing"); - AddCategoryMapping(660, TorznabCatType.Books, " Economy"); - AddCategoryMapping(661, TorznabCatType.Books, " Finance"); - AddCategoryMapping(662, TorznabCatType.Books, " Jurisprudence. Right. criminalistics"); - AddCategoryMapping(664, TorznabCatType.Books, " Historical sciences"); - AddCategoryMapping(665, TorznabCatType.Books, " Historical person"); - AddCategoryMapping(807, TorznabCatType.Books, " Historical sources"); - AddCategoryMapping(808, TorznabCatType.Books, " Alternative historical theories"); - AddCategoryMapping(809, TorznabCatType.Books, " Archeology"); - AddCategoryMapping(810, TorznabCatType.Books, " Ancient world. Antiquity"); - AddCategoryMapping(811, TorznabCatType.Books, " Middle Ages"); - AddCategoryMapping(812, TorznabCatType.Books, " The history of modern and contemporary"); - AddCategoryMapping(813, TorznabCatType.Books, " History of Europe"); - AddCategoryMapping(814, TorznabCatType.Books, " History of Asia and Africa"); - AddCategoryMapping(815, TorznabCatType.Books, " The history of America, Australia, Oceania"); - AddCategoryMapping(816, TorznabCatType.Books, " Russian history"); - AddCategoryMapping(817, TorznabCatType.Books, " The era of the Soviet Union"); - AddCategoryMapping(818, TorznabCatType.Books, " History of the former Soviet Union"); - AddCategoryMapping(819, TorznabCatType.Books, " Ethnography, anthropology"); - AddCategoryMapping(820, TorznabCatType.Books, " International relationships. Diplomacy"); - AddCategoryMapping(1856, TorznabCatType.Books, " Methodology and philosophy of history"); - AddCategoryMapping(255, TorznabCatType.Books, " Accurate, natural and engineering sciences"); - AddCategoryMapping(648, TorznabCatType.Books, " Geography / Geology / Geodesy"); - AddCategoryMapping(672, TorznabCatType.Books, " Physics"); - AddCategoryMapping(723, TorznabCatType.Books, " Astronomy"); - AddCategoryMapping(725, TorznabCatType.Books, " Aviation / Astronautics"); - AddCategoryMapping(726, TorznabCatType.Books, " Mathematics"); - AddCategoryMapping(748, TorznabCatType.Books, " Welding / Soldering / Non-Destructive Testing"); - AddCategoryMapping(749, TorznabCatType.Books, " Architecture / construction / engineering services"); - AddCategoryMapping(750, TorznabCatType.Books, " Biology / Ecology"); - AddCategoryMapping(751, TorznabCatType.Books, " Chemistry / Biochemistry"); - AddCategoryMapping(821, TorznabCatType.Books, " Electronics / Radio"); - AddCategoryMapping(822, TorznabCatType.Books, " Diagrams and service manuals (original documents)"); - AddCategoryMapping(823, TorznabCatType.Books, " engineering"); - AddCategoryMapping(824, TorznabCatType.Books, " Automation / Robotics"); - AddCategoryMapping(825, TorznabCatType.Books, " Metallurgy / Materials"); - AddCategoryMapping(826, TorznabCatType.Books, " Mechanics, Strength of Materials"); - AddCategoryMapping(827, TorznabCatType.Books, " Energy / Electrical"); - AddCategoryMapping(828, TorznabCatType.Books, " Oil, gas and chemical industry"); - AddCategoryMapping(829, TorznabCatType.Books, " Agriculture and food industry"); - AddCategoryMapping(836, TorznabCatType.Books, " Railway deal"); - AddCategoryMapping(837, TorznabCatType.Books, " Normative documents"); - AddCategoryMapping(838, TorznabCatType.Books, " Journals: scientific, popular, radio and others."); - AddCategoryMapping(668, TorznabCatType.Books, " Warfare"); - AddCategoryMapping(669, TorznabCatType.Books, " History of the Second World War"); - AddCategoryMapping(830, TorznabCatType.Books, " Militaria"); - AddCategoryMapping(831, TorznabCatType.Books, " Military history"); - AddCategoryMapping(832, TorznabCatType.Books, " Military equipment"); - AddCategoryMapping(833, TorznabCatType.Books, " Weapon"); - AddCategoryMapping(834, TorznabCatType.Books, " Educational literature"); - AddCategoryMapping(835, TorznabCatType.Books, " The special services of the world"); - AddCategoryMapping(666, TorznabCatType.Books, " Faith and Religion"); - AddCategoryMapping(667, TorznabCatType.Books, " Christianity"); - AddCategoryMapping(881, TorznabCatType.Books, " Islam"); - AddCategoryMapping(882, TorznabCatType.Books, " Religions of India, Tibet and East Asia / Judaism"); - AddCategoryMapping(883, TorznabCatType.Books, " Nontraditional religious, spiritual and mystical teachings"); - AddCategoryMapping(884, TorznabCatType.Books, " Religious Studies. History of Religions. Atheism"); - AddCategoryMapping(1206, TorznabCatType.Books, " Psychology"); - AddCategoryMapping(1207, TorznabCatType.Books, " General and Applied Psychology"); - AddCategoryMapping(1208, TorznabCatType.Books, " Psychotherapy and counseling"); - AddCategoryMapping(1209, TorznabCatType.Books, " Psychological diagnostics and therapy"); - AddCategoryMapping(1210, TorznabCatType.Books, " Social psychology and psychology of relationships"); - AddCategoryMapping(1211, TorznabCatType.Books, " Training and Coaching"); - AddCategoryMapping(1212, TorznabCatType.Books, " Self-development and self-improvement"); - AddCategoryMapping(1213, TorznabCatType.Books, " Popular psychology"); - AddCategoryMapping(1214, TorznabCatType.Books, " Sexology. Relations between the sexes"); - AddCategoryMapping(254, TorznabCatType.Books, " Collecting, hobby and hobbies"); - AddCategoryMapping(633, TorznabCatType.Books, " Collecting and auxiliary ist. discipline"); - AddCategoryMapping(634, TorznabCatType.Books, " Embroidery"); - AddCategoryMapping(635, TorznabCatType.Books, " Knitting"); - AddCategoryMapping(636, TorznabCatType.Books, " Sewing, patchwork"); - AddCategoryMapping(637, TorznabCatType.Books, " lace"); - AddCategoryMapping(638, TorznabCatType.Books, " Beading"); - AddCategoryMapping(639, TorznabCatType.Books, " Paper art"); - AddCategoryMapping(640, TorznabCatType.Books, " Other arts and crafts"); - AddCategoryMapping(641, TorznabCatType.Books, " Pets and aquariums"); - AddCategoryMapping(642, TorznabCatType.Books, " Hunting and fishing"); - AddCategoryMapping(598, TorznabCatType.Books, " Cooking (Book)"); - AddCategoryMapping(312, TorznabCatType.Books, " Cooking (newspapers and magazines)"); - AddCategoryMapping(643, TorznabCatType.Books, " Modelling"); - AddCategoryMapping(644, TorznabCatType.Books, " Farmland / Floriculture"); - AddCategoryMapping(645, TorznabCatType.Books, " Repair, private construction, design of interiors"); - AddCategoryMapping(1866, TorznabCatType.Books, " Woodworking"); - AddCategoryMapping(646, TorznabCatType.Books, " Board games"); - AddCategoryMapping(647, TorznabCatType.Books, " Other hobbies"); - AddCategoryMapping(1786, TorznabCatType.Books, " Nonfiction"); - AddCategoryMapping(623, TorznabCatType.Books, " Fiction"); - AddCategoryMapping(624, TorznabCatType.Books, " Russian Literature (books)"); - AddCategoryMapping(627, TorznabCatType.Books, " The detective, thriller (book)"); - AddCategoryMapping(1624, TorznabCatType.Books, " Militants (Books)"); - AddCategoryMapping(1625, TorznabCatType.Books, " Detectives (Books)"); - AddCategoryMapping(628, TorznabCatType.Books, " Female Novel (Book)"); - AddCategoryMapping(631, TorznabCatType.Books, " Adventure (book)"); - AddCategoryMapping(632, TorznabCatType.Books, " Literary magazines"); - AddCategoryMapping(1611, TorznabCatType.Books, " Fiction / Fantasy / Mystic (book)"); - AddCategoryMapping(629, TorznabCatType.Books, " Domestic science fiction / fantasy / mystic"); - AddCategoryMapping(630, TorznabCatType.Books, " International science fiction / fantasy / mystic"); - AddCategoryMapping(1612, TorznabCatType.Books, " Foreign literature (books)"); - AddCategoryMapping(625, TorznabCatType.Books, " Foreign literature (up to 1900)"); - AddCategoryMapping(626, TorznabCatType.Books, " Foreign literature (XX and XXI century)"); - AddCategoryMapping(1618, TorznabCatType.Books, " Historical books"); - AddCategoryMapping(1789, TorznabCatType.Books, " Satire, humor (the book)"); - AddCategoryMapping(257, TorznabCatType.Books, " Computer books"); - AddCategoryMapping(678, TorznabCatType.Books, " Programming (Literature)"); - AddCategoryMapping(714, TorznabCatType.Books, " Programs from Microsoft (literature)"); - AddCategoryMapping(715, TorznabCatType.Books, " Other programs (literature)"); - AddCategoryMapping(716, TorznabCatType.Books, " Mac OS; Linux, FreeBSD and other * NIX (literature)"); - AddCategoryMapping(717, TorznabCatType.Books, " DBMS (literature)"); - AddCategoryMapping(718, TorznabCatType.Books, " Web Design and Programming (Literature)"); - AddCategoryMapping(719, TorznabCatType.Books, " Graphics, video processing (literature)"); - AddCategoryMapping(720, TorznabCatType.Books, " Network / VoIP (literature)"); - AddCategoryMapping(721, TorznabCatType.Books, " Hacking and Security (literature)"); - AddCategoryMapping(722, TorznabCatType.Books, " Iron (book on a PC)"); - AddCategoryMapping(1215, TorznabCatType.Books, " Engineering and science programs (literature)"); - AddCategoryMapping(1216, TorznabCatType.Books, " Computer magazines and annexes"); - AddCategoryMapping(1791, TorznabCatType.Books, " gaming magazines"); - AddCategoryMapping(1792, TorznabCatType.Books, " Computer magazines"); - AddCategoryMapping(1217, TorznabCatType.Books, " Disc applications to gaming magazines"); - AddCategoryMapping(311, TorznabCatType.Books, " Comics"); - AddCategoryMapping(1218, TorznabCatType.Books, " Comics in Russian"); - AddCategoryMapping(1219, TorznabCatType.Books, " Marvel Comics publishing"); - AddCategoryMapping(1220, TorznabCatType.Books, " DC Comics publishing"); - AddCategoryMapping(1221, TorznabCatType.Books, " Comics from other publishers"); - AddCategoryMapping(1222, TorznabCatType.Books, " Comics in other languages"); - AddCategoryMapping(1223, TorznabCatType.Books, " Substandard distribution (Comics)"); - AddCategoryMapping(259, TorznabCatType.Books, " Collections of books and libraries"); - AddCategoryMapping(983, TorznabCatType.Books, " Libraries (mirror network libraries / collections)"); - AddCategoryMapping(984, TorznabCatType.Books, " Thematic collections (collections)"); - AddCategoryMapping(1224, TorznabCatType.Books, " Multidisciplinary collection (compilation)"); - AddCategoryMapping(1788, TorznabCatType.Books, " Mnogoavtorskie collections, book series"); - AddCategoryMapping(1787, TorznabCatType.Books, " Encyclopedias and dictionaries"); - AddCategoryMapping(1225, TorznabCatType.Books, " Multimedia and online publications"); - AddCategoryMapping(1226, TorznabCatType.Books, " Multimedia encyclopedia"); - AddCategoryMapping(1227, TorznabCatType.Books, " Interactive tutorials and educational materials"); - AddCategoryMapping(1228, TorznabCatType.Books, " Educational publications for children"); - AddCategoryMapping(1229, TorznabCatType.Books, " Cooking. Floriculture. housekeeping"); - AddCategoryMapping(1230, TorznabCatType.Books, " Culture. Art. History"); - AddCategoryMapping(497, TorznabCatType.Books, "training materials"); - AddCategoryMapping(1246, TorznabCatType.Books, " Learning foreign languages"); - AddCategoryMapping(1248, TorznabCatType.Books, " Foreign languages ??for children"); - AddCategoryMapping(1249, TorznabCatType.Books, " English (for children)"); - AddCategoryMapping(1250, TorznabCatType.Books, " Other European languages ??(for children)"); - AddCategoryMapping(1251, TorznabCatType.Books, " Oriental languages ??(for children)"); - AddCategoryMapping(1252, TorznabCatType.Books, " School books, the exam (for children)"); - AddCategoryMapping(1253, TorznabCatType.Books, " Fiction in foreign languages"); - AddCategoryMapping(1254, TorznabCatType.Books, " Fiction in English"); - AddCategoryMapping(1255, TorznabCatType.Books, " Fiction French"); - AddCategoryMapping(1256, TorznabCatType.Books, " Fiction in other European languages"); - AddCategoryMapping(1257, TorznabCatType.Books, " Fiction in oriental languages"); - AddCategoryMapping(1258, TorznabCatType.Books, " Foreign Language for Adults"); - AddCategoryMapping(1259, TorznabCatType.Books, " English (for adults)"); - AddCategoryMapping(1260, TorznabCatType.Books, " German"); - AddCategoryMapping(1261, TorznabCatType.Books, " French"); - AddCategoryMapping(1262, TorznabCatType.Books, " Spanish"); - AddCategoryMapping(1263, TorznabCatType.Books, " Italian language"); - AddCategoryMapping(1264, TorznabCatType.Books, " Other European languages"); - AddCategoryMapping(1265, TorznabCatType.Books, " Arabic language"); - AddCategoryMapping(1266, TorznabCatType.Books, " Chinese"); - AddCategoryMapping(1267, TorznabCatType.Books, " Japanese"); - AddCategoryMapping(1268, TorznabCatType.Books, " Other oriental languages"); - AddCategoryMapping(1269, TorznabCatType.Books, " Russian as a foreign language"); - AddCategoryMapping(1270, TorznabCatType.Books, " Multilanguage collections"); - AddCategoryMapping(1271, TorznabCatType.Books, " Miscellaneous (foreign languages)"); - AddCategoryMapping(1867, TorznabCatType.Books, " LIM-courses"); - AddCategoryMapping(1272, TorznabCatType.Books, " Audio Books in foreign languages"); - AddCategoryMapping(1273, TorznabCatType.Books, " Audiobooks in English"); - AddCategoryMapping(1274, TorznabCatType.Books, " Audiobooks in German"); - AddCategoryMapping(1275, TorznabCatType.Books, " Audiobooks in other languages"); - AddCategoryMapping(1623, TorznabCatType.Books, " Educational audio materials"); - AddCategoryMapping(1247, TorznabCatType.Books, " video tutorials"); - AddCategoryMapping(933, TorznabCatType.Books, " Video tutorials and interactive training DVD"); - AddCategoryMapping(936, TorznabCatType.Books, " Cooking (video tutorial)"); - AddCategoryMapping(1276, TorznabCatType.Books, " Sport"); - AddCategoryMapping(934, TorznabCatType.Books, " Fitness - Cardio, Strength Training"); - AddCategoryMapping(1277, TorznabCatType.Books, " Fitness - Mind and Body"); - AddCategoryMapping(1278, TorznabCatType.Books, " Extreme sports (video tutorial)"); - AddCategoryMapping(935, TorznabCatType.Books, " Playing guitar"); - AddCategoryMapping(1279, TorznabCatType.Books, " Body-building"); - AddCategoryMapping(1280, TorznabCatType.Books, " Health practice"); - AddCategoryMapping(1281, TorznabCatType.Books, " Yoga"); - AddCategoryMapping(1282, TorznabCatType.Books, " Video and Snapshots"); - AddCategoryMapping(1283, TorznabCatType.Books, " Personal care"); - AddCategoryMapping(1284, TorznabCatType.Books, " Painting"); - AddCategoryMapping(1286, TorznabCatType.Books, " Percussion instruments"); - AddCategoryMapping(1287, TorznabCatType.Books, " Other musical instruments"); - AddCategoryMapping(1288, TorznabCatType.Books, " Playing bass guitar"); - AddCategoryMapping(1289, TorznabCatType.Books, " Ballroom dancing"); - AddCategoryMapping(1290, TorznabCatType.Books, " Belly dance"); - AddCategoryMapping(1291, TorznabCatType.Books, " Street and club dances"); - AddCategoryMapping(1292, TorznabCatType.Books, " Dancing, miscellaneous"); - AddCategoryMapping(1295, TorznabCatType.Books, " Tricks and stunts"); - AddCategoryMapping(1296, TorznabCatType.Books, " Education"); - AddCategoryMapping(1297, TorznabCatType.Books, " Business, Economics and Finance"); - AddCategoryMapping(1299, TorznabCatType.Books, " Pregnancy, childbirth, motherhood"); - AddCategoryMapping(1300, TorznabCatType.Books, " Educational video for children"); - AddCategoryMapping(1301, TorznabCatType.Books, " Psychology (video)"); - AddCategoryMapping(1302, TorznabCatType.Books, " Spirituality, self-development"); - AddCategoryMapping(1303, TorznabCatType.Books, " Pickup, love"); - AddCategoryMapping(1304, TorznabCatType.Books, " Construction, renovation and design"); - AddCategoryMapping(1305, TorznabCatType.Books, " Wood and metal"); - AddCategoryMapping(1306, TorznabCatType.Books, " Plants and Animals"); - AddCategoryMapping(1676, TorznabCatType.Books, " Fishing and hunting"); - AddCategoryMapping(1293, TorznabCatType.Books, " Hunting"); - AddCategoryMapping(1294, TorznabCatType.Books, " Fishing and spearfishing"); - AddCategoryMapping(1307, TorznabCatType.Books, " Miscellaneous (Video tutorials and educational interactive DVD)"); - AddCategoryMapping(1309, TorznabCatType.Books, " Martial Arts (Video Tutorials)"); - AddCategoryMapping(1310, TorznabCatType.Books, " Aikido and Aiki-jutsu"); - AddCategoryMapping(1311, TorznabCatType.Books, " Wing Chun"); - AddCategoryMapping(1312, TorznabCatType.Books, " Jujutsu"); - AddCategoryMapping(1313, TorznabCatType.Books, " Judo and Sambo"); - AddCategoryMapping(1314, TorznabCatType.Books, " Karate"); - AddCategoryMapping(1315, TorznabCatType.Books, " knife fight"); - AddCategoryMapping(1316, TorznabCatType.Books, " Work with weapon"); - AddCategoryMapping(1317, TorznabCatType.Books, " Russian style"); - AddCategoryMapping(1318, TorznabCatType.Books, " dogfight"); - AddCategoryMapping(1319, TorznabCatType.Books, " composite style"); - AddCategoryMapping(1320, TorznabCatType.Books, " shock styles"); - AddCategoryMapping(1321, TorznabCatType.Books, " Wushu"); - AddCategoryMapping(1322, TorznabCatType.Books, " Miscellaneous (Video Tutorials)"); - AddCategoryMapping(1323, TorznabCatType.Books, " Computer video tutorials and interactive training DVD"); - AddCategoryMapping(1324, TorznabCatType.Books, " Computer networks and security (video tutorial)"); - AddCategoryMapping(1325, TorznabCatType.Books, " OS and Microsoft server software (video tutorial)"); - AddCategoryMapping(1326, TorznabCatType.Books, " Microsoft Office software (video tutorial)"); - AddCategoryMapping(1327, TorznabCatType.Books, " OS and UNIX-program (video tutorial)"); - AddCategoryMapping(1329, TorznabCatType.Books, " Adobe Photoshop (video tutorial)"); - AddCategoryMapping(1330, TorznabCatType.Books, " Autodesk Maya (video tutorial)"); - AddCategoryMapping(1331, TorznabCatType.Books, " Autodesk 3ds Max (video tutorial)"); - AddCategoryMapping(1332, TorznabCatType.Books, " Autodesk Softimage (XSI) (video tutorial)"); - AddCategoryMapping(1333, TorznabCatType.Books, " ZBrush (video tutorial)"); - AddCategoryMapping(1334, TorznabCatType.Books, " Flash, Flex and ActionScript (video tutorial)"); - AddCategoryMapping(1335, TorznabCatType.Books, " 2D-graphics (video tutorial)"); - AddCategoryMapping(1336, TorznabCatType.Books, " 3D-graphics (video tutorial)"); - AddCategoryMapping(1337, TorznabCatType.Books, " Engineering and science programs (video tutorial)"); - AddCategoryMapping(1338, TorznabCatType.Books, " Web-design (video tutorial)"); - AddCategoryMapping(1339, TorznabCatType.Books, " Programming (video tutorial)"); - AddCategoryMapping(1340, TorznabCatType.Books, " Software for Mac OS (video tutorial)"); - AddCategoryMapping(1341, TorznabCatType.Books, " Working with video (video tutorial)"); - AddCategoryMapping(1342, TorznabCatType.Books, " Working with sound (video tutorial)"); - AddCategoryMapping(1343, TorznabCatType.Books, " Miscellaneous (Computer video tutorials)"); - AddCategoryMapping(1530, TorznabCatType.Other, "Subject forums"); - AddCategoryMapping(698, TorznabCatType.Other, " Auto and Moto"); - AddCategoryMapping(699, TorznabCatType.Other, " Repair and maintenance of vehicles"); - AddCategoryMapping(772, TorznabCatType.Other, " The original selection of spare parts catalogs"); - AddCategoryMapping(1344, TorznabCatType.Other, " Non-original spare parts catalogs for selection"); - AddCategoryMapping(1345, TorznabCatType.Other, " diagnostic and repair programs"); - AddCategoryMapping(1346, TorznabCatType.Other, " Tuning, chip tuning, tuning"); - AddCategoryMapping(700, TorznabCatType.Other, " Books for repair / maintenance / operation of the vehicle"); - AddCategoryMapping(1349, TorznabCatType.Other, " Multimediyki repair / maintenance / operation of the vehicle"); - AddCategoryMapping(1350, TorznabCatType.Other, " Accounting, utilities, etc."); - AddCategoryMapping(1351, TorznabCatType.Other, " Virtual Driving School"); - AddCategoryMapping(1352, TorznabCatType.Other, " Video lessons on driving vehicles"); - AddCategoryMapping(1353, TorznabCatType.Other, " Video lessons on repair of vehicles"); - AddCategoryMapping(1354, TorznabCatType.Other, " Magazines Auto / Moto"); - AddCategoryMapping(1355, TorznabCatType.Other, " Water transport"); - AddCategoryMapping(1356, TorznabCatType.Other, " Movies and television shows, car / moto"); - AddCategoryMapping(1357, TorznabCatType.Other, " Documentary / educational films"); - AddCategoryMapping(1358, TorznabCatType.Other, " entertainment shows"); - AddCategoryMapping(1359, TorznabCatType.Other, " Top Gear / Top Gear"); - AddCategoryMapping(1360, TorznabCatType.Other, " Test Drive / Reviews / Motor"); - AddCategoryMapping(1361, TorznabCatType.Other, " Tuning / Fast and the Furious"); - AddCategoryMapping(600, TorznabCatType.Other, " Medicine and Health"); - AddCategoryMapping(601, TorznabCatType.Other, " Books, magazines and on medicine and health program"); - AddCategoryMapping(603, TorznabCatType.Other, " Clinical medicine until 1980"); - AddCategoryMapping(604, TorznabCatType.Other, " Clinical Medicine from 1980 to 2000"); - AddCategoryMapping(605, TorznabCatType.Other, " Clinical Medicine since 2000"); - AddCategoryMapping(606, TorznabCatType.Other, " The popular medical periodicals (newspapers and magazines)"); - AddCategoryMapping(607, TorznabCatType.Other, " The scientific medical periodicals (newspapers and magazines)"); - AddCategoryMapping(608, TorznabCatType.Other, " Life Sciences"); - AddCategoryMapping(609, TorznabCatType.Other, " Pharmacy and Pharmacology"); - AddCategoryMapping(610, TorznabCatType.Other, " Non-traditional, traditional medicine and popular books on health"); - AddCategoryMapping(611, TorznabCatType.Other, " Veterinary, miscellaneous"); - AddCategoryMapping(612, TorznabCatType.Other, " Thematic collections of books"); - AddCategoryMapping(613, TorznabCatType.Other, " Audiobooks on medicine"); - AddCategoryMapping(614, TorznabCatType.Other, " Medical software"); - AddCategoryMapping(602, TorznabCatType.Other, " Tutorials, Doc. movies and TV shows on medicine"); - AddCategoryMapping(615, TorznabCatType.Other, " Medicine and Dentistry"); - AddCategoryMapping(616, TorznabCatType.Other, " Psychotherapy and clinical psychology"); - AddCategoryMapping(617, TorznabCatType.Other, " Massage"); - AddCategoryMapping(618, TorznabCatType.Other, " Health"); - AddCategoryMapping(619, TorznabCatType.Other, " Documentary movies and TV shows on medicine"); - AddCategoryMapping(560, TorznabCatType.Other, "other"); - AddCategoryMapping(578, TorznabCatType.Other, " Economy and Life"); - AddCategoryMapping(1558, TorznabCatType.Other, " psychoactive audio programs"); - AddCategoryMapping(1560, TorznabCatType.Other, " Avatars, Icons, Smileys, painting, drawing, sculpture, pictures, wallpaper, Photography, Digital Art"); - AddCategoryMapping(1651, TorznabCatType.Other, " reproductions of paintings"); - AddCategoryMapping(1652, TorznabCatType.Other, " Art photography"); - AddCategoryMapping(1653, TorznabCatType.Other, " Contemporary photography"); - AddCategoryMapping(1654, TorznabCatType.Other, " Collections of works of modern art painters"); - AddCategoryMapping(1655, TorznabCatType.Other, " hand-drawn graphics"); - AddCategoryMapping(1656, TorznabCatType.Other, " Computer graphics"); - AddCategoryMapping(1657, TorznabCatType.Other, " Illustrations"); - AddCategoryMapping(1659, TorznabCatType.Other, " Graphics (Other)"); - AddCategoryMapping(1562, TorznabCatType.Other, " Amateur photos"); - AddCategoryMapping(1561, TorznabCatType.Other, " Pictures"); - AddCategoryMapping(1563, TorznabCatType.Other, " Photos of celebrities"); - AddCategoryMapping(996, TorznabCatType.Other, " Desktop Wallpaper \\ Wallpapers"); - AddCategoryMapping(1578, TorznabCatType.Other, " Wallpapers and themes for mobile devices"); - AddCategoryMapping(1559, TorznabCatType.Other, " Avatars, Icons, Smileys"); - AddCategoryMapping(1564, TorznabCatType.Other, " Audio"); - AddCategoryMapping(1801, TorznabCatType.Other, " Mobile Audio"); - AddCategoryMapping(1565, TorznabCatType.Other, " Video (Other)"); - AddCategoryMapping(1566, TorznabCatType.Other, " Publications and educational materials (texts)"); - AddCategoryMapping(1567, TorznabCatType.Other, " Sports (video)"); + AddCategoryMapping(30, TorznabCatType.Movies, "Video content"); + AddCategoryMapping(31, TorznabCatType.TVDocumentary, " Documentary films, TV and other video"); + AddCategoryMapping(127, TorznabCatType.TVDocumentary, " Documentary movies and TV shows"); + AddCategoryMapping(1071, TorznabCatType.TVDocumentary, " Documentary (DVD)"); + AddCategoryMapping(1069, TorznabCatType.TVDocumentary, " Documentary (HD Video)"); + AddCategoryMapping(1070, TorznabCatType.TVDocumentary, " TV shows (HD Video), non-documentary"); + AddCategoryMapping(1843, TorznabCatType.TVDocumentary, " Biographies. Personality and idols (HD Video)"); + AddCategoryMapping(1844, TorznabCatType.TVDocumentary, " Military Science (HD Video)"); + AddCategoryMapping(1845, TorznabCatType.TVDocumentary, " Natural science, science and technology (HD Video)"); + AddCategoryMapping(1846, TorznabCatType.TVDocumentary, " Travel and Tourism (HD Video)"); + AddCategoryMapping(1847, TorznabCatType.TVDocumentary, " Flora and fauna (HD Video)"); + AddCategoryMapping(1848, TorznabCatType.TVDocumentary, " History (HD Video)"); + AddCategoryMapping(1849, TorznabCatType.TVDocumentary, " BBC, Discovery, National Geographic (HD Video)"); + AddCategoryMapping(1850, TorznabCatType.TVDocumentary, " Crime Documentary (HD Video)"); + AddCategoryMapping(1072, TorznabCatType.TVDocumentary, " Biographies. Personality and idols"); + AddCategoryMapping(1073, TorznabCatType.TVDocumentary, " Documentary movies and TV shows on film and animation (including biographies)"); + AddCategoryMapping(1074, TorznabCatType.TVDocumentary, " Art, Art History"); + AddCategoryMapping(1075, TorznabCatType.TVDocumentary, " Documentaries and television music (including biographies)"); + AddCategoryMapping(1076, TorznabCatType.TVDocumentary, " criminal documentary"); + AddCategoryMapping(1077, TorznabCatType.TVDocumentary, " Secrets of the Ages / Special Services / Conspiracy Theory"); + AddCategoryMapping(1078, TorznabCatType.TVDocumentary, " Movies and TV shows on military issues"); + AddCategoryMapping(1079, TorznabCatType.TVDocumentary, " The Second World War"); + AddCategoryMapping(1675, TorznabCatType.TVDocumentary, " Fleet"); + AddCategoryMapping(1080, TorznabCatType.TVDocumentary, " Accidents / Accidents / Disasters"); + AddCategoryMapping(1081, TorznabCatType.TVDocumentary, " Aviation (video)"); + AddCategoryMapping(1674, TorznabCatType.TVDocumentary, " Wings of Russia"); + AddCategoryMapping(1082, TorznabCatType.TVDocumentary, " Space (Video)"); + AddCategoryMapping(576, TorznabCatType.TVDocumentary, " Popular-science film"); + AddCategoryMapping(1083, TorznabCatType.TVDocumentary, " The flora and fauna of the (video)"); + AddCategoryMapping(1084, TorznabCatType.TVDocumentary, " Travel and Tourism (video)"); + AddCategoryMapping(1085, TorznabCatType.TVDocumentary, " Social talk show"); + AddCategoryMapping(1086, TorznabCatType.TVDocumentary, " Information-analytical and socio-political programs"); + AddCategoryMapping(1087, TorznabCatType.TVDocumentary, " Architecture and Construction (video)"); + AddCategoryMapping(1088, TorznabCatType.TVDocumentary, " All about home, life and design"); + AddCategoryMapping(1094, TorznabCatType.TVDocumentary, " The era of the Soviet Union (video)"); + AddCategoryMapping(1095, TorznabCatType.TVDocumentary, " Battle of psychics / Theory improbability / Seekers / Galileo"); + AddCategoryMapping(1096, TorznabCatType.TVDocumentary, " Russian sensation / Program Maximum / Profession Reporter / Ukrainian sensation"); + AddCategoryMapping(1097, TorznabCatType.TVDocumentary, " Paranormal activity"); + AddCategoryMapping(1098, TorznabCatType.TVDocumentary, " Alternative history, Science (video)"); + AddCategoryMapping(1099, TorznabCatType.TVDocumentary, " Vnezhanrovaya documentary"); + AddCategoryMapping(1660, TorznabCatType.TVDocumentary, " Foreign TV-brands"); + AddCategoryMapping(1089, TorznabCatType.TVDocumentary, " BBC"); + AddCategoryMapping(1090, TorznabCatType.TVDocumentary, " Discovery"); + AddCategoryMapping(1091, TorznabCatType.TVDocumentary, " National Geographic"); + AddCategoryMapping(1661, TorznabCatType.TVDocumentary, " Animal Planet"); + AddCategoryMapping(1662, TorznabCatType.TVDocumentary, " Da Vinci Learning"); + AddCategoryMapping(1663, TorznabCatType.TVDocumentary, " History Channel"); + AddCategoryMapping(1664, TorznabCatType.TVDocumentary, " PBS"); + AddCategoryMapping(1665, TorznabCatType.TVDocumentary, " Readers Digest"); + AddCategoryMapping(1666, TorznabCatType.TVDocumentary, " I wonder about everything"); + AddCategoryMapping(1667, TorznabCatType.TVDocumentary, " Mega-Projects"); + AddCategoryMapping(1668, TorznabCatType.TVDocumentary, " Prehistoric world"); + AddCategoryMapping(1669, TorznabCatType.TVDocumentary, " World of Tomorrow"); + AddCategoryMapping(1670, TorznabCatType.TVDocumentary, " Jacques Cousteau Odyssey"); + AddCategoryMapping(1671, TorznabCatType.TVDocumentary, " Secrets and Mysteries"); + AddCategoryMapping(1672, TorznabCatType.TVDocumentary, " History"); + AddCategoryMapping(1092, TorznabCatType.TVDocumentary, " History: Ancient World / Antiquity / Middle Ages (video)"); + AddCategoryMapping(1093, TorznabCatType.TVDocumentary, " History: modern and contemporary times"); + AddCategoryMapping(1673, TorznabCatType.TVDocumentary, " Relax, landscape film"); + AddCategoryMapping(1100, TorznabCatType.TVDocumentary, " Miscellaneous / nekonditsiya (documentary and transfer)"); + AddCategoryMapping(569, TorznabCatType.TV, " Entertaining TV programs and shows, fun and humor"); + AddCategoryMapping(1101, TorznabCatType.TV, " Mind games and quizzes"); + AddCategoryMapping(1102, TorznabCatType.TV, " Reality and talk show host / category / impressions"); + AddCategoryMapping(1103, TorznabCatType.TV, " children's TV Shows"); + AddCategoryMapping(1104, TorznabCatType.TV, " KVN"); + AddCategoryMapping(1105, TorznabCatType.TV, " Drink Post"); + AddCategoryMapping(1106, TorznabCatType.TV, " Distorting Mirror / town / in the town"); + AddCategoryMapping(1107, TorznabCatType.TV, " ice show"); + AddCategoryMapping(1108, TorznabCatType.TV, " Thank God you came!"); + AddCategoryMapping(1109, TorznabCatType.TV, " dinner Party"); + AddCategoryMapping(1110, TorznabCatType.TV, " Good jokes"); + AddCategoryMapping(1111, TorznabCatType.TV, " Evening Quarter"); + AddCategoryMapping(1112, TorznabCatType.TV, " Films with a funny transfer (parody)"); + AddCategoryMapping(1113, TorznabCatType.TV, " Stand-up comedy"); + AddCategoryMapping(1114, TorznabCatType.TV, " Moment of glory"); + AddCategoryMapping(1115, TorznabCatType.TV, " Ukrainian Show"); + AddCategoryMapping(1116, TorznabCatType.TV, " Star Factory"); + AddCategoryMapping(1117, TorznabCatType.TV, " Dance shows, concerts, performances"); + AddCategoryMapping(1118, TorznabCatType.TV, " Circus"); + AddCategoryMapping(1119, TorznabCatType.TV, " School for Scandal"); + AddCategoryMapping(1120, TorznabCatType.TV, " Satirists and humorists"); + AddCategoryMapping(1873, TorznabCatType.TV, " Musical show"); + AddCategoryMapping(1121, TorznabCatType.TV, " Humorous audio transmission"); + AddCategoryMapping(1122, TorznabCatType.TV, " Audio and video clips (Jokes and humor)"); + AddCategoryMapping(32, TorznabCatType.Movies, " Foreign movies"); + AddCategoryMapping(567, TorznabCatType.Movies, " Foreign films 2016"); + AddCategoryMapping(37, TorznabCatType.Movies, " Foreign films 2011 - 2015 the year"); + AddCategoryMapping(38, TorznabCatType.Movies, " Foreign films of the year 2006-2010"); + AddCategoryMapping(39, TorznabCatType.Movies, " Foreign films of the year 2001-2005"); + AddCategoryMapping(40, TorznabCatType.Movies, " Foreign films 1991-2000"); + AddCategoryMapping(1031, TorznabCatType.Movies, " Foreign films until 1990"); + AddCategoryMapping(41, TorznabCatType.Movies, " Classic foreign film"); + AddCategoryMapping(1044, TorznabCatType.Movies, " Classic foreign film (DVD Video)"); + AddCategoryMapping(1042, TorznabCatType.Movies, " Classic foreign film (HD Video)"); + AddCategoryMapping(1051, TorznabCatType.Movies, " Foreign films (DVD)"); + AddCategoryMapping(43, TorznabCatType.Movies, " Foreign films (HD Video)"); + AddCategoryMapping(773, TorznabCatType.Movies, " Grindhouse"); + AddCategoryMapping(1040, TorznabCatType.Movies, " Grindhouse DVD and HD Video"); + AddCategoryMapping(913, TorznabCatType.Movies, " Asian movies"); + AddCategoryMapping(1010, TorznabCatType.MoviesSD, " Asian movies (DVD Video)"); + AddCategoryMapping(1052, TorznabCatType.MoviesHD, " Asian films (HD Video)"); + AddCategoryMapping(1032, TorznabCatType.Movies, " Indian film"); + AddCategoryMapping(1043, TorznabCatType.Movies, " Indian Cinema DVD and HD Video"); + AddCategoryMapping(1039, TorznabCatType.Movies, " Shorts"); + AddCategoryMapping(1041, TorznabCatType.Movies, " Sound track and Translations"); + AddCategoryMapping(1804, TorznabCatType.Movies, " Foreign films without translation"); + AddCategoryMapping(1805, TorznabCatType.Movies, " Foreign films in the original"); + AddCategoryMapping(1806, TorznabCatType.Movies, " Foreign films in the original (HD)"); + AddCategoryMapping(1807, TorznabCatType.Movies, " Foreign films with translation into other languages"); + AddCategoryMapping(33, TorznabCatType.Movies, " national cinema"); + AddCategoryMapping(568, TorznabCatType.Movies, " Domestic films 2016"); + AddCategoryMapping(44, TorznabCatType.Movies, " Domestic films of 2011 - 2015 the year"); + AddCategoryMapping(45, TorznabCatType.Movies, " Domestic films of the year 2006-2010"); + AddCategoryMapping(46, TorznabCatType.Movies, " Domestic films of the year 2001-2005"); + AddCategoryMapping(47, TorznabCatType.Movies, " Domestic films of the year 1992-2000"); + AddCategoryMapping(48, TorznabCatType.Movies, " Cinema of the USSR, Soviet Russia, the Russian republic (1917-1991)"); + AddCategoryMapping(1609, TorznabCatType.Movies, " Films of the Russian Empire (until 1917)"); + AddCategoryMapping(1048, TorznabCatType.Movies, " National cinema (DVD)"); + AddCategoryMapping(49, TorznabCatType.Movies, " National cinema (HD Video)"); + AddCategoryMapping(1046, TorznabCatType.Movies, " Author debuts"); + AddCategoryMapping(1047, TorznabCatType.Movies, " Child domestic films"); + AddCategoryMapping(1011, TorznabCatType.Movies, " Art-house cinema and author"); + AddCategoryMapping(1012, TorznabCatType.Movies, " Art-house and auteur cinema (DVD)"); + AddCategoryMapping(1038, TorznabCatType.Movies, " Art-house and auteur cinema (HD Video)"); + AddCategoryMapping(1033, TorznabCatType.Movies, " Author cinema"); + AddCategoryMapping(1035, TorznabCatType.Movies, " Shorts (Art-house cinema and author)"); + AddCategoryMapping(1036, TorznabCatType.Movies, " Documentaries (Art-house cinema and author)"); + AddCategoryMapping(1037, TorznabCatType.Movies, " Animation (Art-house cinema and author)"); + AddCategoryMapping(1617, TorznabCatType.Movies, " Intelligent movie"); + AddCategoryMapping(34, TorznabCatType.TV, " TV series"); + AddCategoryMapping(51, TorznabCatType.TV, " Domestic series"); + AddCategoryMapping(1860, TorznabCatType.TV, " Domestic series 2016"); + AddCategoryMapping(1810, TorznabCatType.TV, " Domestic series 2015"); + AddCategoryMapping(574, TorznabCatType.TV, " Domestic series 2014"); + AddCategoryMapping(50, TorznabCatType.TV, " Foreign TV series"); + AddCategoryMapping(1861, TorznabCatType.TV, " Foreign series 2016"); + AddCategoryMapping(1809, TorznabCatType.TV, " Foreign series 2015"); + AddCategoryMapping(575, TorznabCatType.TV, " Foreign series 2014"); + AddCategoryMapping(1181, TorznabCatType.TV, " Foreign TV shows (HD Video)"); + AddCategoryMapping(1184, TorznabCatType.TV, " Soaps Spain, Italy, Latin America, Turkey and India"); + AddCategoryMapping(1185, TorznabCatType.TV, " Indian series"); + AddCategoryMapping(1186, TorznabCatType.TV, " spanish series"); + AddCategoryMapping(1187, TorznabCatType.TV, " Italian TV series"); + AddCategoryMapping(1615, TorznabCatType.TV, " Latin American soap operas"); + AddCategoryMapping(1189, TorznabCatType.TV, " Official short version Latin American serials"); + AddCategoryMapping(1190, TorznabCatType.TV, " Latin American soap operas with the voice acting (folders distribution)"); + AddCategoryMapping(1191, TorznabCatType.TV, " Latin American serials with subtitles"); + AddCategoryMapping(1188, TorznabCatType.TV, " turkish TV series"); + AddCategoryMapping(1192, TorznabCatType.TV, " Serials OST Spain, Italy, Latin America, Turkey and India"); + AddCategoryMapping(1193, TorznabCatType.TV, " For sub-standard hands"); + AddCategoryMapping(1194, TorznabCatType.TV, " Asian series"); + AddCategoryMapping(1195, TorznabCatType.TV, " Chinese serials with subtitles"); + AddCategoryMapping(1196, TorznabCatType.TV, " Korean soap operas with the voice acting"); + AddCategoryMapping(1197, TorznabCatType.TV, " Korean serials with subtitles"); + AddCategoryMapping(1198, TorznabCatType.TV, " Other Asian series with the voice acting"); + AddCategoryMapping(1199, TorznabCatType.TV, " Taiwanese serials with subtitles"); + AddCategoryMapping(1200, TorznabCatType.TV, " Japanese serials with subtitles"); + AddCategoryMapping(1201, TorznabCatType.TV, " Japanese TV series with the voice acting"); + AddCategoryMapping(1202, TorznabCatType.TV, " VMV and others. Videos"); + AddCategoryMapping(1203, TorznabCatType.TV, " OST Asian series"); + AddCategoryMapping(1616, TorznabCatType.TV, " Soaps with Ukrainian sound track"); + AddCategoryMapping(1049, TorznabCatType.TV, " Theater"); + AddCategoryMapping(1050, TorznabCatType.TV, " Benefit. Master of Arts of Russian theater and cinema."); + AddCategoryMapping(1053, TorznabCatType.Movies3D, " 3D / Stereo (Cinema, Animation, Video, TV & Sports)"); + AddCategoryMapping(1054, TorznabCatType.Movies3D, " 3D Movies"); + AddCategoryMapping(581, TorznabCatType.Movies3D, " Foreign Movies 3D"); + AddCategoryMapping(1614, TorznabCatType.Movies3D, " Asian Movies 3D"); + AddCategoryMapping(1613, TorznabCatType.Movies3D, " Domestic 3D Movies"); + AddCategoryMapping(586, TorznabCatType.Movies3D, " 3D Animation"); + AddCategoryMapping(1055, TorznabCatType.Movies3D, " 3D Documentaries"); + AddCategoryMapping(1056, TorznabCatType.Movies3D, " 3D Sports"); + AddCategoryMapping(1057, TorznabCatType.Movies3D, " 3D Clips, Music Videos, Movie Trailers"); + AddCategoryMapping(53, TorznabCatType.TVAnime, " Animation and cartoons"); + AddCategoryMapping(341, TorznabCatType.TVAnime, " Foreign cartoons"); + AddCategoryMapping(344, TorznabCatType.TVAnime, " Foreign cartoons (DVD)"); + AddCategoryMapping(342, TorznabCatType.TVAnime, " Domestic cartoons"); + AddCategoryMapping(1062, TorznabCatType.TVAnime, " Domestic full-length cartoons"); + AddCategoryMapping(1061, TorznabCatType.TVAnime, " Domestic cartoons (DVD)"); + AddCategoryMapping(346, TorznabCatType.TVAnime, " short cartoons"); + AddCategoryMapping(1058, TorznabCatType.TVAnime, " Short Film (HD Video)"); + AddCategoryMapping(1060, TorznabCatType.TVAnime, " Foreign short cartoons"); + AddCategoryMapping(1059, TorznabCatType.TVAnime, " Foreign Short Film (DVD)"); + AddCategoryMapping(345, TorznabCatType.TVAnime, " Cartoons HD-Video"); + AddCategoryMapping(1063, TorznabCatType.TVAnime, " cartoon Puzzle"); + AddCategoryMapping(343, TorznabCatType.TVAnime, " Serial cartoons"); + AddCategoryMapping(1813, TorznabCatType.TVAnime, " Cartoons and cartoons without translation"); + AddCategoryMapping(1814, TorznabCatType.TVAnime, " Cartoons and cartoons with the Ukrainian sound track"); + AddCategoryMapping(1064, TorznabCatType.TVAnime, " Archive and nekonditsiya cartoons and animated series"); + AddCategoryMapping(54, TorznabCatType.TVAnime, " Anime and everything associated with him"); + AddCategoryMapping(55, TorznabCatType.TVAnime, " Anime (Main)"); + AddCategoryMapping(976, TorznabCatType.TVAnime, " Anime (pleerny subsection)"); + AddCategoryMapping(977, TorznabCatType.TVAnime, " Anime (QC subsection)"); + AddCategoryMapping(333, TorznabCatType.TVAnime, " Anime DVD-Video"); + AddCategoryMapping(334, TorznabCatType.TVAnime, " Anime (HD and Blu-ray)"); + AddCategoryMapping(1815, TorznabCatType.TVAnime, " OST to Anime"); + AddCategoryMapping(979, TorznabCatType.TVAnime, " Anime OST to (lossless)"); + AddCategoryMapping(335, TorznabCatType.TVAnime, " OST to Anime (mp3 and others lossy-format)"); + AddCategoryMapping(336, TorznabCatType.TVAnime, " Manga and other art"); + AddCategoryMapping(474, TorznabCatType.TVAnime, " Manga"); + AddCategoryMapping(680, TorznabCatType.TVAnime, " Wallpapers, artbook, and others."); + AddCategoryMapping(60, TorznabCatType.TVAnime, " Anime (Hentai)"); + AddCategoryMapping(978, TorznabCatType.TVAnime, " AMV etc. Videos"); + AddCategoryMapping(980, TorznabCatType.TVAnime, " Japanese cartoons"); + AddCategoryMapping(1065, TorznabCatType.TVAnime, " Archive and nekonditsiya Anime"); + AddCategoryMapping(922, TorznabCatType.Movies, " Faith and Religion (Video)"); + AddCategoryMapping(1068, TorznabCatType.Movies, " Islam (video)"); + AddCategoryMapping(1067, TorznabCatType.Movies, " Cults and new religious movements (video)"); + AddCategoryMapping(1066, TorznabCatType.Movies, " Religions of India, Tibet and East Asia (video)"); + AddCategoryMapping(923, TorznabCatType.Movies, " Christianity (video)"); + AddCategoryMapping(577, TorznabCatType.TVSport, " Health & Sports (sports tournaments, films and programs etc)"); + AddCategoryMapping(583, TorznabCatType.TVSport, " wrestling"); + AddCategoryMapping(740, TorznabCatType.TVSport, " Professional Wrestling"); + AddCategoryMapping(1176, TorznabCatType.TVSport, " Independent Wrestling"); + AddCategoryMapping(1177, TorznabCatType.TVSport, " International Wrestling"); + AddCategoryMapping(1178, TorznabCatType.TVSport, " Oldschool Wrestling"); + AddCategoryMapping(1179, TorznabCatType.TVSport, " Documentary Wrestling"); + AddCategoryMapping(677, TorznabCatType.TVSport, " cycle racing"); + AddCategoryMapping(724, TorznabCatType.TVSport, " Tennis"); + AddCategoryMapping(925, TorznabCatType.TVSport, " Athletics / Water Sports"); + AddCategoryMapping(926, TorznabCatType.TVSport, " motorcycling"); + AddCategoryMapping(930, TorznabCatType.TVSport, " Hockey"); + AddCategoryMapping(1171, TorznabCatType.TVSport, " Hockey / Bandy"); + AddCategoryMapping(1172, TorznabCatType.TVSport, " International hockey tournaments"); + AddCategoryMapping(1173, TorznabCatType.TVSport, " KXL"); + AddCategoryMapping(932, TorznabCatType.TVSport, " NHL (until 2011/12)"); + AddCategoryMapping(931, TorznabCatType.TVSport, " NHL (2013)"); + AddCategoryMapping(1174, TorznabCatType.TVSport, " USSR - Canada"); + AddCategoryMapping(1175, TorznabCatType.TVSport, " Documentaries and Analysis (hockey)"); + AddCategoryMapping(1123, TorznabCatType.TVSport, " Motorsports"); + AddCategoryMapping(1125, TorznabCatType.TVSport, " Formula 1"); + AddCategoryMapping(1126, TorznabCatType.TVSport, " Formula 1 2012-2015"); + AddCategoryMapping(1127, TorznabCatType.TVSport, " Formula January 2016"); + AddCategoryMapping(1128, TorznabCatType.TVSport, " Volleyball / Handball"); + AddCategoryMapping(1129, TorznabCatType.TVSport, " Billiards"); + AddCategoryMapping(1130, TorznabCatType.TVSport, " Poker"); + AddCategoryMapping(1131, TorznabCatType.TVSport, " Bodybuilding / Power Sports"); + AddCategoryMapping(1132, TorznabCatType.TVSport, " Boxing"); + AddCategoryMapping(1133, TorznabCatType.TVSport, " Classic arts"); + AddCategoryMapping(1134, TorznabCatType.TVSport, " MMA and K-1"); + AddCategoryMapping(1135, TorznabCatType.TVSport, " American football"); + AddCategoryMapping(1136, TorznabCatType.TVSport, " Rugby"); + AddCategoryMapping(1137, TorznabCatType.TVSport, " Baseball"); + AddCategoryMapping(1138, TorznabCatType.TVSport, " Badminton / Table Tennis"); + AddCategoryMapping(1139, TorznabCatType.TVSport, " Gymnastics / Dance Competitions"); + AddCategoryMapping(1140, TorznabCatType.TVSport, " Winter sports"); + AddCategoryMapping(1141, TorznabCatType.TVSport, " Figure skating"); + AddCategoryMapping(1142, TorznabCatType.TVSport, " Biathlon"); + AddCategoryMapping(1143, TorznabCatType.TVSport, " Extreme sports"); + AddCategoryMapping(1144, TorznabCatType.TVSport, " Football"); + AddCategoryMapping(1146, TorznabCatType.TVSport, " Russia 2015-2016"); + AddCategoryMapping(1145, TorznabCatType.TVSport, " Russia 2014-2015"); + AddCategoryMapping(1147, TorznabCatType.TVSport, " Russia / USSR"); + AddCategoryMapping(1148, TorznabCatType.TVSport, " England"); + AddCategoryMapping(1149, TorznabCatType.TVSport, " Spain"); + AddCategoryMapping(1150, TorznabCatType.TVSport, " Italy"); + AddCategoryMapping(1151, TorznabCatType.TVSport, " Germany"); + AddCategoryMapping(1851, TorznabCatType.TVSport, " France"); + AddCategoryMapping(1152, TorznabCatType.TVSport, " Ukraine"); + AddCategoryMapping(1153, TorznabCatType.TVSport, " Other national championships and cups"); + AddCategoryMapping(1154, TorznabCatType.TVSport, " International football tournaments"); + AddCategoryMapping(1157, TorznabCatType.TVSport, " European Cups"); + AddCategoryMapping(1156, TorznabCatType.TVSport, " Eurocup 2011-2014"); + AddCategoryMapping(1155, TorznabCatType.TVSport, " Eurocup 2014-2015"); + AddCategoryMapping(1161, TorznabCatType.TVSport, " Eurocup 2015-2016"); + AddCategoryMapping(1158, TorznabCatType.TVSport, " European Championships"); + AddCategoryMapping(1159, TorznabCatType.TVSport, " European Championship 2016"); + AddCategoryMapping(1863, TorznabCatType.TVSport, " European Championships 2016 (Selection section)"); + AddCategoryMapping(1864, TorznabCatType.TVSport, " European Championship 2016 (the final part)"); + AddCategoryMapping(1160, TorznabCatType.TVSport, " World Championships"); + AddCategoryMapping(1852, TorznabCatType.TVSport, " World Championship 2018"); + AddCategoryMapping(1162, TorznabCatType.TVSport, " Friendly tournaments and matches"); + AddCategoryMapping(1163, TorznabCatType.TVSport, " The survey and analysis of transmission"); + AddCategoryMapping(1853, TorznabCatType.TVSport, " The survey and analytical programs 2014-2016"); + AddCategoryMapping(1164, TorznabCatType.TVSport, " Mini Soccer / Football"); + AddCategoryMapping(1165, TorznabCatType.TVSport, " Basketball"); + AddCategoryMapping(1166, TorznabCatType.TVSport, " International competitions"); + AddCategoryMapping(1167, TorznabCatType.TVSport, " NBA / NCAA (until 2000)"); + AddCategoryMapping(1168, TorznabCatType.TVSport, " NBA / NCAA (2000-2010 biennium)."); + AddCategoryMapping(1169, TorznabCatType.TVSport, " NBA / NCAA (2010-2016 biennium)."); + AddCategoryMapping(1170, TorznabCatType.TVSport, " European club basketball"); + AddCategoryMapping(1885, TorznabCatType.TVSport, " XXXI Summer Olympic Games. Rio de Janeiro 2016"); + AddCategoryMapping(1886, TorznabCatType.TVSport, " Football"); + AddCategoryMapping(1887, TorznabCatType.TVSport, " Basketball"); + AddCategoryMapping(1888, TorznabCatType.TVSport, " Volleyball / Beach Volleyball / Handball / Water Polo"); + AddCategoryMapping(1889, TorznabCatType.TVSport, " Athletics"); + AddCategoryMapping(1890, TorznabCatType.TVSport, " Tennis / Table Tennis / Badminton"); + AddCategoryMapping(1891, TorznabCatType.TVSport, " Boxing / Martial Arts and Martial Arts / Weightlifting"); + AddCategoryMapping(1892, TorznabCatType.TVSport, " Water Sports / Boating"); + AddCategoryMapping(1893, TorznabCatType.TVSport, " cycle racing"); + AddCategoryMapping(1894, TorznabCatType.TVSport, " Gymnastics"); + AddCategoryMapping(1895, TorznabCatType.TVSport, " Other Sports"); + AddCategoryMapping(1896, TorznabCatType.TVSport, " The survey and analysis of transmission"); + AddCategoryMapping(1897, TorznabCatType.Books, " Books, manuals, periodicals on the Olympic theme"); + AddCategoryMapping(1575, TorznabCatType.Movies, " Video for mobile devices"); + AddCategoryMapping(1576, TorznabCatType.Movies, " Video for Smartphones and PDAs"); + AddCategoryMapping(1577, TorznabCatType.Movies, " Mobile Video (3GP)"); + AddCategoryMapping(1589, TorznabCatType.Movies, " Video for Apple devices"); + AddCategoryMapping(1590, TorznabCatType.Movies, " Video (Apple)"); + AddCategoryMapping(1592, TorznabCatType.MoviesSD, " Movies for iPod, iPhone, iPad"); + AddCategoryMapping(1593, TorznabCatType.MoviesSD, " Soaps for iPod, iPhone, iPad"); + AddCategoryMapping(1594, TorznabCatType.MoviesSD, " Cartoons to iPod, iPhone, iPad"); + AddCategoryMapping(1595, TorznabCatType.MoviesSD, " Anime for iPod, iPhone, iPad"); + AddCategoryMapping(1596, TorznabCatType.MoviesSD, " The music video for iPod, iPhone, iPad"); + AddCategoryMapping(1591, TorznabCatType.MoviesHD, " Videos HD (Apple)"); + AddCategoryMapping(1597, TorznabCatType.MoviesHD, " HD Movies to Apple TV"); + AddCategoryMapping(1598, TorznabCatType.MoviesHD, " HD TV Shows on Apple TV"); + AddCategoryMapping(1599, TorznabCatType.MoviesHD, " Cartoon HD for Apple TV"); + AddCategoryMapping(1600, TorznabCatType.MoviesHD, " Documentary HD video for Apple TV"); + AddCategoryMapping(1601, TorznabCatType.MoviesHD, " Music HD video for Apple TV"); + AddCategoryMapping(1568, TorznabCatType.Movies, " Trailers and additional materials for films"); + AddCategoryMapping(1549, TorznabCatType.Movies, " Video consoles"); + AddCategoryMapping(1550, TorznabCatType.Movies, " Video for PSVita"); + AddCategoryMapping(1551, TorznabCatType.Movies, " Movies for PSP"); + AddCategoryMapping(1552, TorznabCatType.Movies, " for PSP TV Shows"); + AddCategoryMapping(1553, TorznabCatType.Movies, " Cartoons for PSP"); + AddCategoryMapping(1554, TorznabCatType.Movies, " Drama for PSP"); + AddCategoryMapping(1555, TorznabCatType.Movies, " Anime for PSP"); + AddCategoryMapping(1556, TorznabCatType.Movies, " Video to PSP"); + AddCategoryMapping(1557, TorznabCatType.Movies, " Videos for the PS3 and other consoles"); + AddCategoryMapping(165, TorznabCatType.Movies, " video Game"); + AddCategoryMapping(1544, TorznabCatType.Movies, " Walkthroughs"); + AddCategoryMapping(1545, TorznabCatType.Movies, " Lineage II Movies"); + AddCategoryMapping(1546, TorznabCatType.Movies, " World of Warcraft Movies"); + AddCategoryMapping(1547, TorznabCatType.Movies, " Counter Strike Movies"); + AddCategoryMapping(1045, TorznabCatType.Movies, " Video on moderation"); + AddCategoryMapping(1607, TorznabCatType.MoviesSD, " DVD Video on moderation"); + AddCategoryMapping(1608, TorznabCatType.MoviesHD, " HD Video on moderation"); + AddCategoryMapping(1837, TorznabCatType.PCGames, "Releases SE7ENKILLS"); + AddCategoryMapping(1839, TorznabCatType.PCGames, " Games"); + AddCategoryMapping(1840, TorznabCatType.PCGames, " Patches"); + AddCategoryMapping(1841, TorznabCatType.PCGames, " Frequently asked questions about cs: go"); + AddCategoryMapping(1182, TorznabCatType.PCGames, "Games"); + AddCategoryMapping(158, TorznabCatType.PCGames, " Games General Section"); + AddCategoryMapping(68, TorznabCatType.PCGames, " Games for PC"); + AddCategoryMapping(69, TorznabCatType.PCGames, " Hot New Releases Games"); + AddCategoryMapping(1030, TorznabCatType.PCGames, " Games without pills"); + AddCategoryMapping(70, TorznabCatType.PCGames, " Action"); + AddCategoryMapping(148, TorznabCatType.PCGames, " FPS (1st Person)"); + AddCategoryMapping(149, TorznabCatType.PCGames, " TPS (3rd Person)"); + AddCategoryMapping(150, TorznabCatType.PCGames, " Stealth Action"); + AddCategoryMapping(151, TorznabCatType.PCGames, " Tactical shooter"); + AddCategoryMapping(71, TorznabCatType.PCGames, " RPG"); + AddCategoryMapping(72, TorznabCatType.PCGames, " Strategy"); + AddCategoryMapping(152, TorznabCatType.PCGames, " RTS (real time strategy)"); + AddCategoryMapping(153, TorznabCatType.PCGames, " TBS (turn-based strategy)"); + AddCategoryMapping(154, TorznabCatType.PCGames, " Wargame"); + AddCategoryMapping(155, TorznabCatType.PCGames, " Economic strategies"); + AddCategoryMapping(73, TorznabCatType.PCGames, " Simulations"); + AddCategoryMapping(74, TorznabCatType.PCGames, " Autos and Racing"); + AddCategoryMapping(75, TorznabCatType.PCGames, " Sports simulators"); + AddCategoryMapping(464, TorznabCatType.PCGames, " Other simulators"); + AddCategoryMapping(1531, TorznabCatType.PCGames, " Space and flight simulators"); + AddCategoryMapping(76, TorznabCatType.PCGames, " Aviasimulators"); + AddCategoryMapping(463, TorznabCatType.PCGames, " space Simulation"); + AddCategoryMapping(1540, TorznabCatType.PCGames, " Microsoft Flight Simulator add-ons, and for him"); + AddCategoryMapping(1541, TorznabCatType.PCGames, " Scripts, meshes and airports"); + AddCategoryMapping(1542, TorznabCatType.PCGames, " Airplanes and helicopters"); + AddCategoryMapping(1543, TorznabCatType.PCGames, " Mission, traffic sounds, packs and tools"); + AddCategoryMapping(1899, TorznabCatType.PCGames, " Scenarios (FSX-P3D)"); + AddCategoryMapping(77, TorznabCatType.PCGames, " Arcade"); + AddCategoryMapping(459, TorznabCatType.PCGames, " Arcade (various)"); + AddCategoryMapping(461, TorznabCatType.PCGames, " Board & Card Arcade"); + AddCategoryMapping(78, TorznabCatType.PCGames, " Adventure Quests"); + AddCategoryMapping(746, TorznabCatType.PCGames, " Quest-style \"search objects\""); + AddCategoryMapping(79, TorznabCatType.PCGames, " Online Games"); + AddCategoryMapping(743, TorznabCatType.PCGames, " Free"); + AddCategoryMapping(744, TorznabCatType.PCGames, " paid"); + AddCategoryMapping(742, TorznabCatType.PCGames, " Other online gaming"); + AddCategoryMapping(157, TorznabCatType.PCGames, " For the little ones"); + AddCategoryMapping(465, TorznabCatType.PCGames, " Old games for PC"); + AddCategoryMapping(466, TorznabCatType.PCGames, " Arcade and Puzzle Games (old games)"); + AddCategoryMapping(1871, TorznabCatType.PCGames, " Arcade (Old Games)"); + AddCategoryMapping(1872, TorznabCatType.PCGames, " Puzzle games (old games)"); + AddCategoryMapping(467, TorznabCatType.PCGames, " Adventure quests (old games)"); + AddCategoryMapping(468, TorznabCatType.PCGames, " Action (old games)"); + AddCategoryMapping(469, TorznabCatType.PCGames, " Strategy (old games)"); + AddCategoryMapping(470, TorznabCatType.PCGames, " RPG (old games)"); + AddCategoryMapping(471, TorznabCatType.PCGames, " Simulations (old games)"); + AddCategoryMapping(1532, TorznabCatType.PCGames, " Autos and Racing (old games)"); + AddCategoryMapping(1533, TorznabCatType.PCGames, " Space simulators, flight simulators and aviaigry (old games)"); + AddCategoryMapping(1534, TorznabCatType.PCGames, " Sports simulators (old games)"); + AddCategoryMapping(1535, TorznabCatType.PCGames, " Other simulators (Old Games)"); + AddCategoryMapping(472, TorznabCatType.PCGames, " Multi-genre compilations (old games)"); + AddCategoryMapping(1536, TorznabCatType.PCGames, " Erotic games (old games)"); + AddCategoryMapping(1537, TorznabCatType.PCGames, " For the little ones (Old Games)"); + AddCategoryMapping(1538, TorznabCatType.PCGames, " Puzzle Games (Old Games)"); + AddCategoryMapping(1539, TorznabCatType.PCGames, " IBM PC are not compatible (old games)"); + AddCategoryMapping(473, TorznabCatType.PCGames, " Erotic games"); + AddCategoryMapping(745, TorznabCatType.PCGames, " Chess"); + AddCategoryMapping(924, TorznabCatType.PCGames, " game Collections"); + AddCategoryMapping(970, TorznabCatType.PCGames, " Other for PC-games"); + AddCategoryMapping(1803, TorznabCatType.PCGames, " Patches"); + AddCategoryMapping(80, TorznabCatType.PCGames, " Official patches"); + AddCategoryMapping(1790, TorznabCatType.PCGames, " Fashion, plug-ins, add-ons"); + AddCategoryMapping(972, TorznabCatType.PCGames, " Official mode, plug-ins, add-ons"); + AddCategoryMapping(162, TorznabCatType.PCGames, " Informal fashion, plugins, add-ons"); + AddCategoryMapping(161, TorznabCatType.PCGames, " Fun"); + AddCategoryMapping(973, TorznabCatType.PCGames, " Editors, emulators and other gaming utility"); + AddCategoryMapping(160, TorznabCatType.PCGames, " NoCD / NoDVD"); + AddCategoryMapping(974, TorznabCatType.PCGames, " Conservation games"); + AddCategoryMapping(971, TorznabCatType.PCGames, " Cheat program and trainers"); + AddCategoryMapping(164, TorznabCatType.PCGames, " Guidelines and passing"); + AddCategoryMapping(163, TorznabCatType.PCGames, " The bonus disc for the games"); + AddCategoryMapping(159, TorznabCatType.PCGames, " The demo version of the game and with early access"); + AddCategoryMapping(975, TorznabCatType.PCGames, " Anime Games"); + AddCategoryMapping(1025, TorznabCatType.PCGames, " Fighting"); + AddCategoryMapping(460, TorznabCatType.PCGames, " Logic games"); + AddCategoryMapping(462, TorznabCatType.PCGames, " Mini / Flash games"); + AddCategoryMapping(1029, TorznabCatType.PCGames, " Indie Game"); + AddCategoryMapping(111, TorznabCatType.Console, " Games for consoles"); + AddCategoryMapping(458, TorznabCatType.Console, " Portable and Console Games (general section of games for different platforms)"); + AddCategoryMapping(129, TorznabCatType.ConsoleXbox, " Xbox"); + AddCategoryMapping(131, TorznabCatType.ConsoleXbox360, " XBox360 | Games"); + AddCategoryMapping(132, TorznabCatType.ConsoleXbox360, " XBox360 | GOD Games"); + AddCategoryMapping(133, TorznabCatType.ConsoleXbox360, " XBox360 | JTAG"); + AddCategoryMapping(134, TorznabCatType.ConsoleXbox360, " XBox360 | 360E"); + AddCategoryMapping(135, TorznabCatType.ConsoleXbox360, " XBox360 | Demo"); + AddCategoryMapping(136, TorznabCatType.ConsoleXbox360, " XBox360 | Soft"); + AddCategoryMapping(137, TorznabCatType.ConsoleXbox, " Original XBox | Games"); + AddCategoryMapping(138, TorznabCatType.ConsolePS4, " PlayStation"); + AddCategoryMapping(621, TorznabCatType.ConsolePS3, " PS"); + AddCategoryMapping(141, TorznabCatType.ConsolePS3, " PS2 | Games"); + AddCategoryMapping(112, TorznabCatType.ConsolePS3, " PS3 | Games"); + AddCategoryMapping(142, TorznabCatType.ConsolePS3, " PS3 | Other"); + AddCategoryMapping(139, TorznabCatType.ConsolePS4, " PSN | Games"); + AddCategoryMapping(140, TorznabCatType.ConsolePSP, " PSP | Games"); + AddCategoryMapping(622, TorznabCatType.ConsolePSP, " PS1 games for PSP"); + AddCategoryMapping(143, TorznabCatType.ConsolePSP, " PSP | Programs | Other"); + AddCategoryMapping(1548, TorznabCatType.ConsolePSP, " Software for PSP (Homebrew)"); + AddCategoryMapping(455, TorznabCatType.ConsolePSVita, " PS Vita | Games"); + AddCategoryMapping(130, TorznabCatType.ConsoleOther, " Nintendo"); + AddCategoryMapping(144, TorznabCatType.ConsoleNDS, " NDS | Games"); + AddCategoryMapping(145, TorznabCatType.ConsoleWii, " Wii | Games"); + AddCategoryMapping(146, TorznabCatType.ConsoleWiiwareVC, " WiiWare | Games"); + AddCategoryMapping(147, TorznabCatType.ConsoleOther, " GameCube | Games"); + AddCategoryMapping(456, TorznabCatType.ConsoleOther, " Sega"); + AddCategoryMapping(588, TorznabCatType.ConsoleOther, " Dreamcast"); + AddCategoryMapping(457, TorznabCatType.ConsoleOther, " Games for older consoles"); + AddCategoryMapping(589, TorznabCatType.ConsoleOther, " Games for the DVD player"); + AddCategoryMapping(928, TorznabCatType.PCGames, " Games for Linux"); + AddCategoryMapping(1868, TorznabCatType.PCGames, " Native games for Linux"); + AddCategoryMapping(1869, TorznabCatType.PCGames, " Ported games for Linux"); + AddCategoryMapping(1870, TorznabCatType.PCGames, " Archive for Linux games"); + AddCategoryMapping(81, TorznabCatType.PC0day, "Software"); + AddCategoryMapping(570, TorznabCatType.PC0day, " General Section for software"); + AddCategoryMapping(109, TorznabCatType.PCPhoneOther, " Software for smart phones, mobile phones and PDAs"); + AddCategoryMapping(899, TorznabCatType.PCPhoneOther, " Java"); + AddCategoryMapping(900, TorznabCatType.PCPhoneOther, " Games for Java"); + AddCategoryMapping(901, TorznabCatType.PCPhoneOther, " Applications for Java"); + AddCategoryMapping(590, TorznabCatType.PCPhoneAndroid, " Android"); + AddCategoryMapping(592, TorznabCatType.PCPhoneAndroid, " Games for Android"); + AddCategoryMapping(1017, TorznabCatType.PCPhoneAndroid, " Games for Android [Eng]"); + AddCategoryMapping(895, TorznabCatType.PCPhoneAndroid, " Apps for Android OS"); + AddCategoryMapping(1018, TorznabCatType.PCPhoneAndroid, " Applications for Android [Eng]"); + AddCategoryMapping(480, TorznabCatType.PCPhoneIOS, " Apple Mobile Device Software"); + AddCategoryMapping(481, TorznabCatType.PCPhoneIOS, " Firmware (iPhone / iPod Touch / iPad / Apple TV)"); + AddCategoryMapping(482, TorznabCatType.PCPhoneIOS, " Programs for iOS (iPhone / iPod Touch / iPad)"); + AddCategoryMapping(483, TorznabCatType.PCPhoneIOS, " Games for iOS (iPhone / iPod Touch / iPad)"); + AddCategoryMapping(485, TorznabCatType.PCPhoneIOS, " Miscellaneous iOS (iPhone / iPod Touch / iPad)"); + AddCategoryMapping(896, TorznabCatType.PCPhoneOther, " Symbian"); + AddCategoryMapping(897, TorznabCatType.PCPhoneOther, " Games for Symbian"); + AddCategoryMapping(898, TorznabCatType.PCPhoneOther, " Applications for Symbian"); + AddCategoryMapping(902, TorznabCatType.PCPhoneOther, " Windows Mobile, Palm OS, BlackBerry etc"); + AddCategoryMapping(903, TorznabCatType.PCPhoneOther, " Games for Windows Mobile, Palm OS, BlackBerry etc"); + AddCategoryMapping(904, TorznabCatType.PCPhoneOther, " Applications for Windows Mobile, Palm OS, BlackBerry etc"); + AddCategoryMapping(1579, TorznabCatType.PCPhoneOther, " Windows Phone 7,8"); + AddCategoryMapping(1580, TorznabCatType.PCPhoneOther, " Games for Windows Phone 7,8"); + AddCategoryMapping(1581, TorznabCatType.PCPhoneOther, " Applications for Windows Phone 7,8"); + AddCategoryMapping(1582, TorznabCatType.PCPhoneOther, " Software for your phone"); + AddCategoryMapping(1583, TorznabCatType.PCPhoneOther, " Firmware for phones"); + AddCategoryMapping(106, TorznabCatType.PC0day, " On Linux, Unix etc"); + AddCategoryMapping(282, TorznabCatType.PC0day, " Operating Systems (Linux, Unix)"); + AddCategoryMapping(1574, TorznabCatType.PC0day, " Program (Linux, Unix)"); + AddCategoryMapping(284, TorznabCatType.PC0day, " Other operating systems and software for them"); + AddCategoryMapping(287, TorznabCatType.PC0day, " Archive (Linux OS, Unix etc)"); + AddCategoryMapping(276, TorznabCatType.PCMac, " Apple OS"); + AddCategoryMapping(277, TorznabCatType.PCMac, " Mac OS [for Macintosh]"); + AddCategoryMapping(278, TorznabCatType.PCMac, " Mac OS [PC-Hackintosh]"); + AddCategoryMapping(591, TorznabCatType.PCMac, " Games Mac OS"); + AddCategoryMapping(1019, TorznabCatType.PCMac, " Mac Games [ENG]"); + AddCategoryMapping(1021, TorznabCatType.PCMac, " Program for viewing and video processing (Mac OS)"); + AddCategoryMapping(1022, TorznabCatType.PCMac, " Programs for creating and processing graphs (Mac OS)"); + AddCategoryMapping(1023, TorznabCatType.PCMac, " Plug-ins for Adobe's software (Mac OS)"); + AddCategoryMapping(1584, TorznabCatType.PCMac, " Audio editor and converter (Mac OS)"); + AddCategoryMapping(1585, TorznabCatType.PCMac, " System software (Mac OS)"); + AddCategoryMapping(1586, TorznabCatType.PCMac, " Office software (Mac OS)"); + AddCategoryMapping(1587, TorznabCatType.PCMac, " Programs for the Internet and network (Mac OS)"); + AddCategoryMapping(1588, TorznabCatType.PCMac, " Other software (Mac OS)"); + AddCategoryMapping(103, TorznabCatType.PC0day, " Microsoft OS"); + AddCategoryMapping(104, TorznabCatType.PC0day, " Desktop operating system from Microsoft (released prior to Windows XP)"); + AddCategoryMapping(105, TorznabCatType.PC0day, " Desktop operating system from Microsoft (since Windows XP)"); + AddCategoryMapping(1629, TorznabCatType.PC0day, " Windows XP"); + AddCategoryMapping(1628, TorznabCatType.PC0day, " Windows Vista"); + AddCategoryMapping(981, TorznabCatType.PC0day, " Windows 7"); + AddCategoryMapping(1610, TorznabCatType.PC0day, " Windows 8"); + AddCategoryMapping(1811, TorznabCatType.PC0day, " Windows 10"); + AddCategoryMapping(274, TorznabCatType.PC0day, " Windows Server"); + AddCategoryMapping(927, TorznabCatType.PC0day, " Other (Operating Systems from Microsoft)"); + AddCategoryMapping(275, TorznabCatType.PC0day, " Archive (OS from Microsoft)"); + AddCategoryMapping(84, TorznabCatType.PC0day, " System programs"); + AddCategoryMapping(86, TorznabCatType.PC0day, " Programs for configuring and optimizing OS"); + AddCategoryMapping(87, TorznabCatType.PC0day, " Archivers and File Managers"); + AddCategoryMapping(1630, TorznabCatType.PC0day, " Safety protection system and PC"); + AddCategoryMapping(93, TorznabCatType.PC0day, " Software to protect your computer (antivirus software, firewalls)"); + AddCategoryMapping(580, TorznabCatType.PC0day, " Keys and Activation"); + AddCategoryMapping(94, TorznabCatType.PC0day, " Anti-spyware and anti-trojan"); + AddCategoryMapping(95, TorznabCatType.PC0day, " Programs for the protection of information"); + AddCategoryMapping(88, TorznabCatType.PC0day, " Backup"); + AddCategoryMapping(89, TorznabCatType.PC0day, " Service computer service"); + AddCategoryMapping(1631, TorznabCatType.PC0day, " LiveCD / DVD / Flash etc"); + AddCategoryMapping(90, TorznabCatType.PC0day, " Work with data carriers"); + AddCategoryMapping(91, TorznabCatType.PC0day, " Information and Diagnostics"); + AddCategoryMapping(92, TorznabCatType.PC0day, " Programs for Internet and networks"); + AddCategoryMapping(96, TorznabCatType.PC0day, " Drivers and Firmware"); + AddCategoryMapping(97, TorznabCatType.PC0day, " Original disks to computers and accessories"); + AddCategoryMapping(98, TorznabCatType.PC0day, " Server Software for Windows"); + AddCategoryMapping(99, TorznabCatType.PC0day, " Change the Windows interface"); + AddCategoryMapping(101, TorznabCatType.PC0day, " Screensavers"); + AddCategoryMapping(85, TorznabCatType.PC0day, " Work with hard drive"); + AddCategoryMapping(102, TorznabCatType.PC0day, " Miscellaneous (System programs on Windows)"); + AddCategoryMapping(82, TorznabCatType.PC0day, " Systems for business, office, research and project work"); + AddCategoryMapping(83, TorznabCatType.PC0day, " Business Systems"); + AddCategoryMapping(585, TorznabCatType.PC0day, " The company's products 1C"); + AddCategoryMapping(1829, TorznabCatType.PC0day, " typical configuration"); + AddCategoryMapping(1830, TorznabCatType.PC0day, " industry configuration"); + AddCategoryMapping(1831, TorznabCatType.PC0day, " ITS 2015"); + AddCategoryMapping(1832, TorznabCatType.PC0day, " ITS 2014"); + AddCategoryMapping(1833, TorznabCatType.PC0day, " ITS 2013"); + AddCategoryMapping(1834, TorznabCatType.PC0day, " ITS 2012"); + AddCategoryMapping(1835, TorznabCatType.PC0day, " ITS 2011"); + AddCategoryMapping(1836, TorznabCatType.PC0day, " Archive (Products 1C)"); + AddCategoryMapping(270, TorznabCatType.PC0day, " Office systems"); + AddCategoryMapping(266, TorznabCatType.PC0day, " Dictionaries, translators"); + AddCategoryMapping(272, TorznabCatType.PC0day, " Recognition of text, sound and speech synthesis"); + AddCategoryMapping(269, TorznabCatType.PC0day, " Miscellaneous (business systems, office, research and project work)"); + AddCategoryMapping(302, TorznabCatType.PC0day, " CAD software for architects"); + AddCategoryMapping(593, TorznabCatType.PC0day, " CAD (general and engineering)"); + AddCategoryMapping(594, TorznabCatType.PC0day, " CAD (electronics, automation, GAP)"); + AddCategoryMapping(940, TorznabCatType.PC0day, " Programs for architects and builders"); + AddCategoryMapping(937, TorznabCatType.PC0day, " All for house: dressmaking, sewing, cooking"); + AddCategoryMapping(938, TorznabCatType.PC0day, " Work with PDF and DjVu"); + AddCategoryMapping(939, TorznabCatType.PC0day, " Systems for scientific work"); + AddCategoryMapping(941, TorznabCatType.PC0day, " Libraries and projects for architects and interior designers"); + AddCategoryMapping(942, TorznabCatType.PC0day, " Other reference systems"); + AddCategoryMapping(107, TorznabCatType.PC0day, " Web Development and Programming"); + AddCategoryMapping(293, TorznabCatType.PC0day, " Search / Offer"); + AddCategoryMapping(943, TorznabCatType.PC0day, " WYSIWYG editors for web design"); + AddCategoryMapping(496, TorznabCatType.PC0day, " Database Management Systems (DBMS)"); + AddCategoryMapping(494, TorznabCatType.PC0day, " programming environments, compilers and software tools"); + AddCategoryMapping(290, TorznabCatType.PC0day, " The components for the development of media"); + AddCategoryMapping(495, TorznabCatType.PC0day, " Text editors Illuminated"); + AddCategoryMapping(291, TorznabCatType.PC0day, " Scripting engines and websites, CMS and extensions to it"); + AddCategoryMapping(944, TorznabCatType.PC0day, " Templates for websites and CMS"); + AddCategoryMapping(292, TorznabCatType.PC0day, " Miscellaneous (Web Development and Programming)"); + AddCategoryMapping(294, TorznabCatType.PC0day, " Archive (Web Development and Programming)"); + AddCategoryMapping(108, TorznabCatType.PC0day, " Programs to work with multimedia and 3D"); + AddCategoryMapping(487, TorznabCatType.PC0day, " Software kits"); + AddCategoryMapping(488, TorznabCatType.PC0day, " Plug-ins for Adobe's programs"); + AddCategoryMapping(491, TorznabCatType.PC0day, " 3D modeling, rendering and plugins for them"); + AddCategoryMapping(489, TorznabCatType.PC0day, " Graphic editor"); + AddCategoryMapping(303, TorznabCatType.PC0day, " Editors video"); + AddCategoryMapping(305, TorznabCatType.PC0day, " Virtual Studios, sequencers and audio editor"); + AddCategoryMapping(492, TorznabCatType.PC0day, " Animation"); + AddCategoryMapping(490, TorznabCatType.PC0day, " Programs for typesetting, printing, and working with fonts"); + AddCategoryMapping(304, TorznabCatType.PC0day, " Video, Audio Conversion"); + AddCategoryMapping(493, TorznabCatType.PC0day, " Creating a BD / HD / DVD-Video"); + AddCategoryMapping(306, TorznabCatType.PC0day, " Plug-ins for sound processing"); + AddCategoryMapping(308, TorznabCatType.PC0day, " Archive (Programme for multimedia and 3D)"); + AddCategoryMapping(595, TorznabCatType.PC0day, " Miscellaneous (Programme for multimedia and 3D)"); + AddCategoryMapping(596, TorznabCatType.PC0day, " Miscellaneous (Programs for working with audio)"); + AddCategoryMapping(597, TorznabCatType.PC0day, " Virtual instruments and synthesizers"); + AddCategoryMapping(264, TorznabCatType.PC0day, " Audio and video, players and catalogers"); + AddCategoryMapping(263, TorznabCatType.PC0day, " Cataloging and graphics viewers"); + AddCategoryMapping(348, TorznabCatType.PC0day, " Materials for Multimedia and Design"); + AddCategoryMapping(945, TorznabCatType.PC0day, " Author's works"); + AddCategoryMapping(946, TorznabCatType.PC0day, " Official collection vector clipart"); + AddCategoryMapping(948, TorznabCatType.PC0day, " Other vector cliparts"); + AddCategoryMapping(949, TorznabCatType.PC0day, " Photostosks"); + AddCategoryMapping(950, TorznabCatType.PC0day, " The costumes for the photomontage"); + AddCategoryMapping(350, TorznabCatType.PC0day, " Frames and Vignettes for processing photos"); + AddCategoryMapping(352, TorznabCatType.PC0day, " Other raster clipart"); + AddCategoryMapping(1634, TorznabCatType.PC0day, " backgrounds"); + AddCategoryMapping(1635, TorznabCatType.PC0day, " Templates"); + AddCategoryMapping(1637, TorznabCatType.PC0day, " Raster Graphics (photos)"); + AddCategoryMapping(1638, TorznabCatType.PC0day, " Raster Graphics (elements)"); + AddCategoryMapping(1639, TorznabCatType.PC0day, " Raster Graphics (illustrations)"); + AddCategoryMapping(353, TorznabCatType.PC0day, " 3D models, scenes and materials"); + AddCategoryMapping(1633, TorznabCatType.PC0day, " Textures"); + AddCategoryMapping(354, TorznabCatType.PC0day, " Footage"); + AddCategoryMapping(951, TorznabCatType.PC0day, " Other collections footage"); + AddCategoryMapping(952, TorznabCatType.PC0day, " music library"); + AddCategoryMapping(355, TorznabCatType.PC0day, " Sound effects"); + AddCategoryMapping(953, TorznabCatType.PC0day, " sample Libraries"); + AddCategoryMapping(954, TorznabCatType.PC0day, " Libraries and saundbanki for samplers, synth presets"); + AddCategoryMapping(955, TorznabCatType.PC0day, " Multitracks"); + AddCategoryMapping(956, TorznabCatType.PC0day, " Materials for creating menus and DVD covers"); + AddCategoryMapping(351, TorznabCatType.PC0day, " Styles, brushes, shapes and patterns for Adobe Photoshop"); + AddCategoryMapping(356, TorznabCatType.PC0day, " Fonts"); + AddCategoryMapping(358, TorznabCatType.PC0day, " Miscellaneous (Materials for Multimedia and Design)"); + AddCategoryMapping(1632, TorznabCatType.PC0day, " Digital Juice"); + AddCategoryMapping(1874, TorznabCatType.PC0day, " Projects"); + AddCategoryMapping(1875, TorznabCatType.PC0day, " Children (projects)"); + AddCategoryMapping(1876, TorznabCatType.PC0day, " Wedding and romantic (projects)"); + AddCategoryMapping(1877, TorznabCatType.PC0day, " Holiday (projects)"); + AddCategoryMapping(1878, TorznabCatType.PC0day, " Presentations (projects)"); + AddCategoryMapping(1879, TorznabCatType.PC0day, " Sport (projects)"); + AddCategoryMapping(1880, TorznabCatType.PC0day, " Logos (projects)"); + AddCategoryMapping(1881, TorznabCatType.PC0day, " Slideshow (projects)"); + AddCategoryMapping(1882, TorznabCatType.PC0day, " Titles (projects)"); + AddCategoryMapping(1883, TorznabCatType.PC0day, " Items (Projects)"); + AddCategoryMapping(1884, TorznabCatType.PC0day, " Miscellaneous (projects)"); + AddCategoryMapping(1898, TorznabCatType.PC0day, " Trailers (projects)"); + AddCategoryMapping(295, TorznabCatType.PC0day, " Reference and legal system"); + AddCategoryMapping(296, TorznabCatType.PC0day, " Consultant Plus"); + AddCategoryMapping(584, TorznabCatType.PC0day, " Consultant Accountant"); + AddCategoryMapping(755, TorznabCatType.PC0day, " Archive irrelevant hands"); + AddCategoryMapping(297, TorznabCatType.PC0day, " code"); + AddCategoryMapping(298, TorznabCatType.PC0day, " Guarantee"); + AddCategoryMapping(299, TorznabCatType.PC0day, " other"); + AddCategoryMapping(300, TorznabCatType.PC0day, " Archive (Reference and legal system)"); + AddCategoryMapping(301, TorznabCatType.PC0day, " RG PCA - a hidden forum"); + AddCategoryMapping(587, TorznabCatType.PC0day, " Collections of programs and WPI"); + AddCategoryMapping(929, TorznabCatType.PC0day, " Test drives to adjust the audio / video equipment"); + AddCategoryMapping(957, TorznabCatType.PC0day, " GIS, navigation systems and maps"); + AddCategoryMapping(958, TorznabCatType.PC0day, " GIS (Geographic Information Systems)"); + AddCategoryMapping(959, TorznabCatType.PC0day, " Maps provided with the program shell"); + AddCategoryMapping(960, TorznabCatType.PC0day, " Atlases and maps modern (after 1950)"); + AddCategoryMapping(961, TorznabCatType.PC0day, " Atlases and maps of old (pre-1950)"); + AddCategoryMapping(962, TorznabCatType.PC0day, " Cards Other (astronomical, historical, thematic)"); + AddCategoryMapping(963, TorznabCatType.PC0day, " Built-in car navigation"); + AddCategoryMapping(964, TorznabCatType.PC0day, " Garmin"); + AddCategoryMapping(965, TorznabCatType.PC0day, " Ozi"); + AddCategoryMapping(966, TorznabCatType.PC0day, " TomTom"); + AddCategoryMapping(967, TorznabCatType.PC0day, " Navigon / Navitel"); + AddCategoryMapping(968, TorznabCatType.PC0day, " Igo"); + AddCategoryMapping(969, TorznabCatType.PC0day, " Miscellaneous - navigation and maps"); + AddCategoryMapping(61, TorznabCatType.Audio, "Music and music videos"); + AddCategoryMapping(579, TorznabCatType.Audio, " Total music section"); + AddCategoryMapping(537, TorznabCatType.AudioVideo, " General Discussion unsorted music video"); + AddCategoryMapping(538, TorznabCatType.AudioVideo, " Music video (HD / DVD)"); + AddCategoryMapping(544, TorznabCatType.AudioVideo, " Concert recording"); + AddCategoryMapping(1781, TorznabCatType.AudioVideo, " Concerts (DVD)"); + AddCategoryMapping(1782, TorznabCatType.AudioVideo, " Concerts (HD)"); + AddCategoryMapping(1784, TorznabCatType.AudioVideo, " Opera, Ballet, Musicals"); + AddCategoryMapping(1785, TorznabCatType.AudioVideo, " Music videos (transit)"); + AddCategoryMapping(501, TorznabCatType.AudioLossless, " unsorted Lossless"); + AddCategoryMapping(532, TorznabCatType.Audio, " Multi-channel HD Audio and Music"); + AddCategoryMapping(533, TorznabCatType.Audio, " DVD-Audio, SACD, Audio-DVD"); + AddCategoryMapping(1687, TorznabCatType.Audio, " DVD-Audio"); + AddCategoryMapping(1688, TorznabCatType.Audio, " SACD-R"); + AddCategoryMapping(534, TorznabCatType.Audio, " DTS"); + AddCategoryMapping(535, TorznabCatType.Audio, " Vinyl-Rip and Hand-Made"); + AddCategoryMapping(536, TorznabCatType.Audio, " Hi-Res stereo"); + AddCategoryMapping(529, TorznabCatType.Audio, " discography"); + AddCategoryMapping(530, TorznabCatType.Audio, " Domestic"); + AddCategoryMapping(531, TorznabCatType.Audio, " foreign"); + AddCategoryMapping(1679, TorznabCatType.Audio, " Jazz, Blues, Soul (transit)"); + AddCategoryMapping(1680, TorznabCatType.Audio, " Jazz (transit lossless)"); + AddCategoryMapping(1681, TorznabCatType.Audio, " Jazz (transit lossy)"); + AddCategoryMapping(1682, TorznabCatType.Audio, " Blues, Soul (transit lossless)"); + AddCategoryMapping(1683, TorznabCatType.Audio, " Blues, Soul (transit lossy)"); + AddCategoryMapping(525, TorznabCatType.Audio, " Jazz, Blues, Soul (transit lossless)"); + AddCategoryMapping(1689, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (transit)"); + AddCategoryMapping(521, TorznabCatType.Audio, " Rock (transit Lossless)"); + AddCategoryMapping(1691, TorznabCatType.Audio, " Rock (transit Lossy)"); + AddCategoryMapping(1692, TorznabCatType.Audio, " Alternative, Punk (transit Lossless)"); + AddCategoryMapping(1693, TorznabCatType.Audio, " Alternative, Punk (transit Lossy)"); + AddCategoryMapping(1694, TorznabCatType.Audio, " Hard Rock (transit Lossless)"); + AddCategoryMapping(1695, TorznabCatType.Audio, " Hard Rock (transit Lossy)"); + AddCategoryMapping(506, TorznabCatType.Audio, " Metal (transit Lossless)"); + AddCategoryMapping(1697, TorznabCatType.Audio, " Metal (transit Lossy)"); + AddCategoryMapping(1698, TorznabCatType.Audio, " Russian Rock (transit Lossless)"); + AddCategoryMapping(1699, TorznabCatType.Audio, " Russian Rock (transit Lossy)"); + AddCategoryMapping(1817, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (transit Lossless)"); + AddCategoryMapping(1700, TorznabCatType.Audio, " Popular music (transit)"); + AddCategoryMapping(1701, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (transit Lossless)"); + AddCategoryMapping(1702, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (transit Lossy)"); + AddCategoryMapping(1703, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (transit Lossless)"); + AddCategoryMapping(1704, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (transit Lossy)"); + AddCategoryMapping(1705, TorznabCatType.Audio, " Patriotic Pop (transit lossless)"); + AddCategoryMapping(1706, TorznabCatType.Audio, " Patriotic Pop (transit Lossy)"); + AddCategoryMapping(1707, TorznabCatType.Audio, " Soviet stage, Retro (transit Lossless)"); + AddCategoryMapping(1708, TorznabCatType.Audio, " Soviet stage, Retro (transit Lossy)"); + AddCategoryMapping(1709, TorznabCatType.Audio, " Foreign pop music (transit Lossless)"); + AddCategoryMapping(1710, TorznabCatType.Audio, " Foreign pop music (transit Lossy)"); + AddCategoryMapping(1818, TorznabCatType.Audio, " Popular music (transit Lossless)"); + AddCategoryMapping(1711, TorznabCatType.Audio, " Electronic music (transit)"); + AddCategoryMapping(1712, TorznabCatType.Audio, " Trance (transit Lossless)"); + AddCategoryMapping(1713, TorznabCatType.Audio, " Trance (transit Lossy)"); + AddCategoryMapping(1714, TorznabCatType.Audio, " House, Techno, Electro, Minimal (transit Lossless)"); + AddCategoryMapping(1715, TorznabCatType.Audio, " House (transit Lossy)"); + AddCategoryMapping(1716, TorznabCatType.Audio, " Techno, Electro, Minimal (transit Lossy)"); + AddCategoryMapping(1717, TorznabCatType.Audio, " Easy listening (transit Lossless)"); + AddCategoryMapping(1718, TorznabCatType.Audio, " Easy listening (transit Lossy)"); + AddCategoryMapping(1719, TorznabCatType.Audio, " Experimental, Industrial, EBM, Dark Electro (Lossless)"); + AddCategoryMapping(1720, TorznabCatType.Audio, " Experimental Electronic (transit Lossy)"); + AddCategoryMapping(1721, TorznabCatType.Audio, " Industrial, EBM, Dark Electro (transit Lossy)"); + AddCategoryMapping(1722, TorznabCatType.Audio, " Synthpop, New Wave (Lossless transit)"); + AddCategoryMapping(1723, TorznabCatType.Audio, " Synthpop, New Wave (transit Lossy)"); + AddCategoryMapping(1724, TorznabCatType.Audio, " Drum'n'Bass, Jungle, Breaks, Breakbeat, Dubstep (transit Lossless)"); + AddCategoryMapping(1725, TorznabCatType.Audio, " Drum'n'Bass, Jungle, Breaks, Breakbeat, Dubstep (transit Lossy)"); + AddCategoryMapping(1726, TorznabCatType.Audio, " Hardstyle, Jumpstyle, Hardcore (transit Lossless)"); + AddCategoryMapping(1727, TorznabCatType.Audio, " Hardstyle, Jumpstyle, Hardcore (transit Lossy)"); + AddCategoryMapping(1728, TorznabCatType.Audio, " Psychedelic, psytrance, fullon (transit Lossless)"); + AddCategoryMapping(1729, TorznabCatType.Audio, " Psychedelic, psytrance, fullon (transit Lossy)"); + AddCategoryMapping(1730, TorznabCatType.Audio, " Radioshow, Live Mixes (transit Lossy)"); + AddCategoryMapping(1820, TorznabCatType.Audio, " Electronic music (transit Lossless)"); + AddCategoryMapping(1731, TorznabCatType.Audio, " Rap, Hip-hop, RnB, Reggae (transit)"); + AddCategoryMapping(1732, TorznabCatType.Audio, " Rap, Hip-hop overseas (transit Lossless)"); + AddCategoryMapping(1733, TorznabCatType.Audio, " Rap, Hip-hop overseas (transit Lossy)"); + AddCategoryMapping(1734, TorznabCatType.Audio, " Rap, Hip-hop domestic (Lossless)"); + AddCategoryMapping(1735, TorznabCatType.Audio, " Rap, Hip-hop domestic (transit Lossy)"); + AddCategoryMapping(1736, TorznabCatType.Audio, " RnB, Reggae (transit Lossless)"); + AddCategoryMapping(1737, TorznabCatType.Audio, " RnB, Reggae (transit Lossy)"); + AddCategoryMapping(1819, TorznabCatType.Audio, " Rap, Hip-hop, RnB (transit Lossless)"); + AddCategoryMapping(1738, TorznabCatType.Audio, " East Asian Music (transit)"); + AddCategoryMapping(1739, TorznabCatType.Audio, " Asian Traditional, Ethnic (transit Lossless)"); + AddCategoryMapping(1740, TorznabCatType.Audio, " Asian Traditional, Ethnic (transit Lossy)"); + AddCategoryMapping(1741, TorznabCatType.Audio, " Asian Pop (transit Lossless)"); + AddCategoryMapping(1742, TorznabCatType.Audio, " Asian Pop (transit Lossy)"); + AddCategoryMapping(1743, TorznabCatType.Audio, " Asian Rock, Metal (transit Lossless)"); + AddCategoryMapping(1744, TorznabCatType.Audio, " Asian Rock, Metal (transit Lossy)"); + AddCategoryMapping(1745, TorznabCatType.Audio, " Doujin Music (transit Lossless)"); + AddCategoryMapping(1746, TorznabCatType.Audio, " Doujin Music (transit Lossy)"); + AddCategoryMapping(1747, TorznabCatType.Audio, " Other Asian (transit Lossless)"); + AddCategoryMapping(1748, TorznabCatType.Audio, " Other Asian (transit Lossy)"); + AddCategoryMapping(1749, TorznabCatType.Audio, " Other Styles (transit)"); + AddCategoryMapping(1750, TorznabCatType.Audio, " Instrumental (transit Lossless)"); + AddCategoryMapping(1751, TorznabCatType.Audio, " Instrumental (transit Lossy)"); + AddCategoryMapping(1752, TorznabCatType.Audio, " New Age / Meditative / Relax (transit Lossless)"); + AddCategoryMapping(1753, TorznabCatType.Audio, " New Age / Meditative / Relax (transit Lossy)"); + AddCategoryMapping(1754, TorznabCatType.Audio, " Classical Crossover / Neoclassical (transit Lossless)"); + AddCategoryMapping(1755, TorznabCatType.Audio, " Classical Crossover / Neoclassical (transit Lossy)"); + AddCategoryMapping(1756, TorznabCatType.Audio, " Folk (transit Lossless)"); + AddCategoryMapping(1757, TorznabCatType.Audio, " Folk (transit Lossy)"); + AddCategoryMapping(1758, TorznabCatType.Audio, " Other (transit Lossless)"); + AddCategoryMapping(1759, TorznabCatType.Audio, " Other (transit Lossy)"); + AddCategoryMapping(1821, TorznabCatType.Audio, " Folklore / Folk / Folk / World Music (transit Lossy)"); + AddCategoryMapping(1822, TorznabCatType.Audio, " Compilations Folklore / Folk / Folk / World Music (transit Lossy)"); + AddCategoryMapping(1823, TorznabCatType.Audio, " Country & Folk (transit Lossy)"); + AddCategoryMapping(1760, TorznabCatType.Audio, " OST (transit Lossless)"); + AddCategoryMapping(1761, TorznabCatType.Audio, " OST (transit Lossy)"); + AddCategoryMapping(1762, TorznabCatType.Audio, " Classic (transit)"); + AddCategoryMapping(1763, TorznabCatType.Audio, " Notes (transit)"); + AddCategoryMapping(1764, TorznabCatType.Audio, " Complete Works (transit)"); + AddCategoryMapping(1765, TorznabCatType.Audio, " Vocals (transit)"); + AddCategoryMapping(1766, TorznabCatType.Audio, " Concerts (transit)"); + AddCategoryMapping(1767, TorznabCatType.Audio, " Orchestral (transit)"); + AddCategoryMapping(1768, TorznabCatType.Audio, " Chamber (transit)"); + AddCategoryMapping(1769, TorznabCatType.Audio, " Piano (transit)"); + AddCategoryMapping(1770, TorznabCatType.Audio, " Compilations (transit)"); + AddCategoryMapping(1771, TorznabCatType.Audio, " In processing (transit)"); + AddCategoryMapping(1783, TorznabCatType.Audio, " Classic (transit Lossless)"); + AddCategoryMapping(1800, TorznabCatType.Audio, " Author and military songs"); + AddCategoryMapping(1798, TorznabCatType.Audio, " Author and war songs (transit Lossless)"); + AddCategoryMapping(1799, TorznabCatType.Audio, " Author and war songs (transit Lossy)"); + AddCategoryMapping(1772, TorznabCatType.Audio, " Unofficial collections (transit)"); + AddCategoryMapping(1773, TorznabCatType.Audio, " Jazz, Blues, Soul (transit collections)"); + AddCategoryMapping(1774, TorznabCatType.Audio, " Chanson, Author and war songs (collections transit)"); + AddCategoryMapping(1775, TorznabCatType.Audio, " Rock, Alternative, Punk, Metal (collections of transit)"); + AddCategoryMapping(1776, TorznabCatType.Audio, " Pop (transit collections)"); + AddCategoryMapping(1777, TorznabCatType.Audio, " Electronic (transit collections)"); + AddCategoryMapping(1778, TorznabCatType.Audio, " Rap, Hip-hop, RnB, Reggae (transit collections)"); + AddCategoryMapping(1779, TorznabCatType.Audio, " Instrumental / New Age / Meditative / Relax (transit collections)"); + AddCategoryMapping(1780, TorznabCatType.Audio, " Other (transit collections)"); + AddCategoryMapping(1816, TorznabCatType.Audio, " Chanson, Author and war songs (transit)"); + AddCategoryMapping(1677, TorznabCatType.Audio, " Chanson, Author and war songs (transit lossless)"); + AddCategoryMapping(1678, TorznabCatType.Audio, " Chanson, Author and war songs (transit lossy)"); + AddCategoryMapping(63, TorznabCatType.Audio, " Electonic music"); + AddCategoryMapping(784, TorznabCatType.Audio, " Chillout, Lounge, Downtempo, Trip-Hop"); + AddCategoryMapping(785, TorznabCatType.Audio, " Chillout, Lounge, Downtempo (lossless)"); + AddCategoryMapping(225, TorznabCatType.Audio, " Chillout, Lounge, Downtempo (lossy)"); + AddCategoryMapping(786, TorznabCatType.Audio, " Nu Jazz, Acid Jazz, Future Jazz (lossless)"); + AddCategoryMapping(787, TorznabCatType.Audio, " Nu Jazz, Acid Jazz, Future Jazz (lossy)"); + AddCategoryMapping(788, TorznabCatType.Audio, " Trip Hop, Abstract Hip-Hop (lossless)"); + AddCategoryMapping(789, TorznabCatType.Audio, " Trip Hop, Abstract Hip-Hop (lossy)"); + AddCategoryMapping(800, TorznabCatType.Audio, " Drum & Bass, Jungle, Breakbeat, Dubstep, IDM, Electro"); + AddCategoryMapping(801, TorznabCatType.Audio, " Dubstep (lossy)"); + AddCategoryMapping(224, TorznabCatType.Audio, " Drum & Bass, Jungle (lossy)"); + AddCategoryMapping(803, TorznabCatType.Audio, " Drum & Bass, Jungle (lossless)"); + AddCategoryMapping(804, TorznabCatType.Audio, " Drum & Bass, Jungle (Radioshows, Podcasts, Livesets, Mixes)"); + AddCategoryMapping(805, TorznabCatType.Audio, " Breakbeat (lossless)"); + AddCategoryMapping(806, TorznabCatType.Audio, " Breakbeat (lossy)"); + AddCategoryMapping(1517, TorznabCatType.Audio, " Electro, Electro-Freestyle, Nu Electro (lossless)"); + AddCategoryMapping(1518, TorznabCatType.Audio, " Electro, Electro-Freestyle, Nu Electro (lossy)"); + AddCategoryMapping(1519, TorznabCatType.Audio, " Dubstep (lossless)"); + AddCategoryMapping(1520, TorznabCatType.Audio, " Breakbeat, Dubstep (Radioshows, Podcasts, Livesets, Mixes)"); + AddCategoryMapping(1521, TorznabCatType.Audio, " IDM (lossless)"); + AddCategoryMapping(1522, TorznabCatType.Audio, " IDM (lossy)"); + AddCategoryMapping(1523, TorznabCatType.Audio, " IDM Discography & Collections (lossy)"); + AddCategoryMapping(227, TorznabCatType.Audio, " Industrial, Noise, EBM, Dark Electro, Aggrotech, Synthpop, New Wave"); + AddCategoryMapping(774, TorznabCatType.Audio, " EBM, Dark Electro, Aggrotech (lossless)"); + AddCategoryMapping(775, TorznabCatType.Audio, " EBM, Dark Electro, Aggrotech (lossy)"); + AddCategoryMapping(776, TorznabCatType.Audio, " Industrial, Noise (lossless)"); + AddCategoryMapping(777, TorznabCatType.Audio, " Industrial, Noise (lossy)"); + AddCategoryMapping(778, TorznabCatType.Audio, " Synthpop, New Wave (lossless)"); + AddCategoryMapping(779, TorznabCatType.Audio, " Synthpop, New Wave (lossy)"); + AddCategoryMapping(780, TorznabCatType.Audio, " Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossless)"); + AddCategoryMapping(781, TorznabCatType.Audio, " Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossy)"); + AddCategoryMapping(752, TorznabCatType.Audio, " House, Techno, Hardcore, Hardstyle, Jumpstyle"); + AddCategoryMapping(760, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (lossy)"); + AddCategoryMapping(759, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (lossless)"); + AddCategoryMapping(753, TorznabCatType.Audio, " Hardcore, Hardstyle, Jumpstyle (vinyl, web)"); + AddCategoryMapping(223, TorznabCatType.Audio, " House (lossy)"); + AddCategoryMapping(756, TorznabCatType.Audio, " House (lossless)"); + AddCategoryMapping(770, TorznabCatType.Audio, " House (Radioshow, Podcast, Liveset, Mixes)"); + AddCategoryMapping(754, TorznabCatType.Audio, " House (Singles, EPs) (lossy)"); + AddCategoryMapping(771, TorznabCatType.Audio, " House (Promorelizy, collections)"); + AddCategoryMapping(757, TorznabCatType.Audio, " Techno (lossy)"); + AddCategoryMapping(758, TorznabCatType.Audio, " Techno (lossless)"); + AddCategoryMapping(769, TorznabCatType.Audio, " Techno (Radioshows, Podcasts, Livesets, Mixes)"); + AddCategoryMapping(761, TorznabCatType.Audio, " Techno (Singles, EPs) (lossy)"); + AddCategoryMapping(790, TorznabCatType.Audio, " Trance, Goa Trance, Psy-Trance, PsyChill, Ambient Dub"); + AddCategoryMapping(792, TorznabCatType.Audio, " Goa Trance, Psy-Trance (lossless)"); + AddCategoryMapping(793, TorznabCatType.Audio, " Goa Trance, Psy-Trance (lossy)"); + AddCategoryMapping(798, TorznabCatType.Audio, " Goa / Psy-Trance, PsyChill and Ambient Dub (Radioshows, Livesets, Mixes) (lossy)"); + AddCategoryMapping(791, TorznabCatType.Audio, " Trance (lossless)"); + AddCategoryMapping(222, TorznabCatType.Audio, " Trance (lossy)"); + AddCategoryMapping(795, TorznabCatType.Audio, " Trance (Radioshows, Podcasts, Live Sets, Mixes) (lossy)"); + AddCategoryMapping(794, TorznabCatType.Audio, " Trance (Singles, EPs) (lossy)"); + AddCategoryMapping(796, TorznabCatType.Audio, " PsyChill, Ambient Dub (lossless)"); + AddCategoryMapping(797, TorznabCatType.Audio, " PsyChill, Ambient Dub (lossy)"); + AddCategoryMapping(762, TorznabCatType.Audio, " Traditional Electronic, Ambient, Modern Classical, Electroacoustic, Experimental"); + AddCategoryMapping(768, TorznabCatType.Audio, " 8-bit, Chiptune (lossy & lossless)"); + AddCategoryMapping(679, TorznabCatType.Audio, " Experimental (lossy)"); + AddCategoryMapping(764, TorznabCatType.Audio, " Experimental (lossless)"); + AddCategoryMapping(767, TorznabCatType.Audio, " Modern Classical, Electroacoustic (lossy)"); + AddCategoryMapping(766, TorznabCatType.Audio, " Modern Classical, Electroacoustic (lossless)"); + AddCategoryMapping(226, TorznabCatType.Audio, " Traditional Electronic, Ambient (lossy)"); + AddCategoryMapping(763, TorznabCatType.Audio, " Traditional Electronic, Ambient (lossless)"); + AddCategoryMapping(799, TorznabCatType.Audio, " Label Packs (lossless)"); + AddCategoryMapping(802, TorznabCatType.Audio, " Label packs, Scene packs (lossy)"); + AddCategoryMapping(782, TorznabCatType.Audio, " Electronic music (Video, DVD Video / Audio, HD Video, DTS, SACD)"); + AddCategoryMapping(783, TorznabCatType.Audio, " Electronic music (own digitization)"); + AddCategoryMapping(914, TorznabCatType.Audio, " Electronic music (Video)"); + AddCategoryMapping(1524, TorznabCatType.Audio, " Electronic music (Official DVD Video)"); + AddCategoryMapping(1525, TorznabCatType.Audio, " Electronic music (Informal amateur DVD Video)"); + AddCategoryMapping(1526, TorznabCatType.Audio, " Electronic Music (Hi-Res stereo)"); + AddCategoryMapping(1527, TorznabCatType.Audio, " Multichannel music (Electronics)"); + AddCategoryMapping(1528, TorznabCatType.Audio, " Electronic music (HD Video)"); + AddCategoryMapping(64, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B"); + AddCategoryMapping(213, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (lossy)"); + AddCategoryMapping(214, TorznabCatType.Audio, " Domestic Rap, Hip-Hop (lossy)"); + AddCategoryMapping(692, TorznabCatType.Audio, " Foreign R'n'B (lossy)"); + AddCategoryMapping(894, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (lossless)"); + AddCategoryMapping(1387, TorznabCatType.Audio, " Minus (Instrumentals)"); + AddCategoryMapping(1388, TorznabCatType.Audio, " Domestic R'n'B (lossy)"); + AddCategoryMapping(1389, TorznabCatType.Audio, " Domestic Rap, Hip-Hop, R'n'B (lossless)"); + AddCategoryMapping(1390, TorznabCatType.Audio, " Domestic Rap, Hip-Hop (Video)"); + AddCategoryMapping(1391, TorznabCatType.Audio, " Domestic R'n'B (Video)"); + AddCategoryMapping(1392, TorznabCatType.Audio, " Foreign R'n'B (lossless)"); + AddCategoryMapping(1393, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (own digitization)"); + AddCategoryMapping(1394, TorznabCatType.Audio, " Foreign Rap, Hip-Hop (Video)"); + AddCategoryMapping(1395, TorznabCatType.Audio, " Foreign R'n'B (Video)"); + AddCategoryMapping(1396, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (DVD Video)"); + AddCategoryMapping(1397, TorznabCatType.Audio, " Rap, Hip-Hop, R'n'B (HD Video)"); + AddCategoryMapping(65, TorznabCatType.Audio, " Pop music"); + AddCategoryMapping(196, TorznabCatType.Audio, " International Pop Music"); + AddCategoryMapping(689, TorznabCatType.Audio, " Foreign pop music (lossy)"); + AddCategoryMapping(712, TorznabCatType.Audio, " Foreign pop music (lossless)"); + AddCategoryMapping(1429, TorznabCatType.Audio, " Foreign pop music (collections) (lossy)"); + AddCategoryMapping(711, TorznabCatType.Audio, " East Asian pop music (lossy)"); + AddCategoryMapping(1432, TorznabCatType.Audio, " East Asian pop music (lossless)"); + AddCategoryMapping(879, TorznabCatType.Audio, " Domestic Pop"); + AddCategoryMapping(197, TorznabCatType.Audio, " Patriotic Pop (lossy)"); + AddCategoryMapping(1425, TorznabCatType.Audio, " Patriotic Pop (lossless)"); + AddCategoryMapping(1426, TorznabCatType.Audio, " Patriotic Pop music (collections) (lossy)"); + AddCategoryMapping(1427, TorznabCatType.Audio, " Soviet stage, Retro (lossy)"); + AddCategoryMapping(1428, TorznabCatType.Audio, " Soviet stage, Retro (lossless)"); + AddCategoryMapping(198, TorznabCatType.Audio, " Eurodance, Disco, Hi-NRG"); + AddCategoryMapping(703, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (lossy)"); + AddCategoryMapping(877, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (lossless)"); + AddCategoryMapping(199, TorznabCatType.Audio, " Eurodance, Euro-House, Technopop (collections) (lossy)"); + AddCategoryMapping(704, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossy)"); + AddCategoryMapping(878, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossless)"); + AddCategoryMapping(1433, TorznabCatType.Audio, " Disco, Italo-Disco, Euro-Disco, Hi-NRG (collections) (lossy)"); + AddCategoryMapping(1434, TorznabCatType.Audio, " Video, DVD Video, HD Video (Pop)"); + AddCategoryMapping(1435, TorznabCatType.Audio, " Patriotic Pop (Video)"); + AddCategoryMapping(1436, TorznabCatType.Audio, " Patriotic Pop (DVD Video)"); + AddCategoryMapping(1437, TorznabCatType.Audio, " Soviet stage, Retro (video)"); + AddCategoryMapping(1438, TorznabCatType.Audio, " Soviet stage, Retro (DVD Video)"); + AddCategoryMapping(1439, TorznabCatType.Audio, " Foreign pop music (Video)"); + AddCategoryMapping(1440, TorznabCatType.Audio, " Foreign pop music (DVD Video)"); + AddCategoryMapping(1441, TorznabCatType.Audio, " Eurodance, Disco (video)"); + AddCategoryMapping(1442, TorznabCatType.Audio, " Eurodance, Disco (DVD Video)"); + AddCategoryMapping(1443, TorznabCatType.Audio, " East Asian pop music (Video)"); + AddCategoryMapping(1444, TorznabCatType.Audio, " East Asian pop music (DVD Video)"); + AddCategoryMapping(1447, TorznabCatType.Audio, " Patriotic Pop (National concerts, Doc. Video) (Video and DVD)"); + AddCategoryMapping(1448, TorznabCatType.Audio, " Foreign pop music (National concerts, Doc. Video) (Video and DVD)"); + AddCategoryMapping(1449, TorznabCatType.Audio, " International Pop Music, Chanson, Eurodance, Disco (HD Video)"); + AddCategoryMapping(1450, TorznabCatType.Audio, " Patriotic Pop Music, Chanson, Eurodance, Disco (HD Video)"); + AddCategoryMapping(1451, TorznabCatType.Audio, " The multi-channel music and own digitization (pop music)"); + AddCategoryMapping(1452, TorznabCatType.Audio, " Foreign pop music (own digitization)"); + AddCategoryMapping(1453, TorznabCatType.Audio, " Eastern pop music (own digitization)"); + AddCategoryMapping(1454, TorznabCatType.Audio, " Patriotic Pop (own digitization)"); + AddCategoryMapping(1455, TorznabCatType.Audio, " Instrumental Pop (own digitization)"); + AddCategoryMapping(1456, TorznabCatType.Audio, " Multichannel music (pop music)"); + AddCategoryMapping(1457, TorznabCatType.Audio, " Foreign pop music (Hi-Res stereo)"); + AddCategoryMapping(66, TorznabCatType.Audio, " Soundtracks, Karaoke and Minus"); + AddCategoryMapping(917, TorznabCatType.Audio, " The arrangements of music from the game (lossy and lossless)"); + AddCategoryMapping(1400, TorznabCatType.Audio, " Minus (lossy and lossless)"); + AddCategoryMapping(1824, TorznabCatType.Audio, " Soundtracks"); + AddCategoryMapping(232, TorznabCatType.Audio, " Soundtracks to movies and cartoons (mp3)"); + AddCategoryMapping(234, TorznabCatType.Audio, " Soundtracks for games (lossy)"); + AddCategoryMapping(693, TorznabCatType.Audio, " Soundtracks to foreign films (lossy)"); + AddCategoryMapping(880, TorznabCatType.Audio, " Soundtracks to foreign films (lossless)"); + AddCategoryMapping(915, TorznabCatType.Audio, " Soundtracks for games (lossless)"); + AddCategoryMapping(916, TorznabCatType.Audio, " Informal soundtracks for games (lossy)"); + AddCategoryMapping(918, TorznabCatType.Audio, " Informal soundtracks for films and TV series (lossy)"); + AddCategoryMapping(919, TorznabCatType.Audio, " Soundtracks for domestic films (lossy)"); + AddCategoryMapping(920, TorznabCatType.Audio, " Soundtracks for domestic films (lossless)"); + AddCategoryMapping(921, TorznabCatType.Audio, " Soundtracks (own digitization)"); + AddCategoryMapping(1825, TorznabCatType.Audio, " Karaoke"); + AddCategoryMapping(1398, TorznabCatType.Audio, " Karaoke (Audio)"); + AddCategoryMapping(1399, TorznabCatType.Audio, " Karaoke (Video)"); + AddCategoryMapping(67, TorznabCatType.Audio, " Music of other genres"); + AddCategoryMapping(694, TorznabCatType.Audio, " Proper sampling (music of other genres)"); + AddCategoryMapping(695, TorznabCatType.Audio, " Patriotic music of other genres (lossy)"); + AddCategoryMapping(696, TorznabCatType.Audio, " Patriotic music of other genres (lossless)"); + AddCategoryMapping(697, TorznabCatType.Audio, " Foreign music of other genres (lossy)"); + AddCategoryMapping(1408, TorznabCatType.Audio, " Foreign music of other genres (lossless)"); + AddCategoryMapping(1409, TorznabCatType.Audio, " Music for ballroom dancing (lossy and lossless)"); + AddCategoryMapping(1410, TorznabCatType.Audio, " Orthodox chants (lossy)"); + AddCategoryMapping(1411, TorznabCatType.Audio, " Orthodox chants (lossless)"); + AddCategoryMapping(1412, TorznabCatType.Audio, " A collection of songs for children (lossy and lossless)"); + AddCategoryMapping(1686, TorznabCatType.Audio, " Classics for mothers and babies"); + AddCategoryMapping(1413, TorznabCatType.Audio, " Video (Music from other genres)"); + AddCategoryMapping(1414, TorznabCatType.Audio, " DVD Video (Music from other genres)"); + AddCategoryMapping(1415, TorznabCatType.Audio, " Musical (lossy and lossless)"); + AddCategoryMapping(1416, TorznabCatType.Audio, " Musical (Video and DVD Video)"); + AddCategoryMapping(1417, TorznabCatType.Audio, " Informal and vnezhanrovye collections (lossy)"); + AddCategoryMapping(172, TorznabCatType.Audio, " Classical and contemporary academic music"); + AddCategoryMapping(705, TorznabCatType.Audio, " Vocal music (lossless)"); + AddCategoryMapping(706, TorznabCatType.Audio, " Orchestral music (lossless)"); + AddCategoryMapping(707, TorznabCatType.Audio, " Concerto for instrument and orchestra (lossless)"); + AddCategoryMapping(708, TorznabCatType.Audio, " Chamber instrumental music (lossless)"); + AddCategoryMapping(709, TorznabCatType.Audio, " Solo instrumental music (lossless)"); + AddCategoryMapping(710, TorznabCatType.Audio, " Vocal and choral music (lossy)"); + AddCategoryMapping(1001, TorznabCatType.Audio, " Proper digitization (Classical Music)"); + AddCategoryMapping(1002, TorznabCatType.Audio, " Multichannel music (Classic and classic with a modern twist)"); + AddCategoryMapping(1003, TorznabCatType.Audio, " Classic and classic in modern processing (Hi-Res stereo)"); + AddCategoryMapping(1008, TorznabCatType.Audio, " Classical Music (Video)"); + AddCategoryMapping(1009, TorznabCatType.Audio, " Classical Music (DVD and HD Video)"); + AddCategoryMapping(1362, TorznabCatType.Audio, " Opera (Video)"); + AddCategoryMapping(1363, TorznabCatType.Audio, " Opera (DVD and HD Video)"); + AddCategoryMapping(1364, TorznabCatType.Audio, " Ballet and modern choreography (Video, DVD and HD Video)"); + AddCategoryMapping(1365, TorznabCatType.Audio, " The complete collection of works and multi-disc edition (lossless)"); + AddCategoryMapping(1366, TorznabCatType.Audio, " Opera (lossless)"); + AddCategoryMapping(1367, TorznabCatType.Audio, " Choral music (lossless)"); + AddCategoryMapping(1368, TorznabCatType.Audio, " The complete collection of works and multi-disc edition (lossy)"); + AddCategoryMapping(1369, TorznabCatType.Audio, " Orchestral music (lossy)"); + AddCategoryMapping(1370, TorznabCatType.Audio, " Chamber and solo instrumental music (lossy)"); + AddCategoryMapping(1371, TorznabCatType.Audio, " Classics in modern processing, Classical Crossover (lossy and lossless)"); + AddCategoryMapping(175, TorznabCatType.Audio, " Jazz, Blues"); + AddCategoryMapping(178, TorznabCatType.Audio, " foreign Jazz"); + AddCategoryMapping(747, TorznabCatType.Audio, " Avant-Garde Jazz, Free Improvisation (lossless)"); + AddCategoryMapping(741, TorznabCatType.Audio, " Bop (lossless)"); + AddCategoryMapping(842, TorznabCatType.Audio, " Early Jazz, Swing, Gypsy (lossless)"); + AddCategoryMapping(847, TorznabCatType.Audio, " Funk, Soul, R & B (lossless)"); + AddCategoryMapping(843, TorznabCatType.Audio, " Jazz Fusion (lossless)"); + AddCategoryMapping(599, TorznabCatType.Audio, " Mainstream Jazz, Cool (lossless)"); + AddCategoryMapping(845, TorznabCatType.Audio, " Modern Creative, Third Stream (lossless)"); + AddCategoryMapping(846, TorznabCatType.Audio, " Smooth, Jazz-Pop (lossless)"); + AddCategoryMapping(620, TorznabCatType.Audio, " Vocal Jazz (lossless)"); + AddCategoryMapping(844, TorznabCatType.Audio, " World Fusion, Ethnic Jazz (lossless)"); + AddCategoryMapping(673, TorznabCatType.Audio, " Foreign jazz (lossy)"); + AddCategoryMapping(848, TorznabCatType.Audio, " Collections of foreign jazz (lossless)"); + AddCategoryMapping(690, TorznabCatType.Audio, " foreign blues"); + AddCategoryMapping(839, TorznabCatType.Audio, " Blues-rock (lossless)"); + AddCategoryMapping(713, TorznabCatType.Audio, " Blues (Texas, Chicago, Modern and Others) (lossless)"); + AddCategoryMapping(840, TorznabCatType.Audio, " Roots, Pre-War Blues, Early R & B, Gospel (lossless)"); + AddCategoryMapping(691, TorznabCatType.Audio, " Foreign blues (lossy)"); + AddCategoryMapping(841, TorznabCatType.Audio, " Foreign blues (collections; Tribute VA) (lossless)"); + AddCategoryMapping(849, TorznabCatType.Audio, " Domestic jazz and blues"); + AddCategoryMapping(850, TorznabCatType.Audio, " Domestic Jazz (lossless)"); + AddCategoryMapping(851, TorznabCatType.Audio, " Domestic jazz (lossy)"); + AddCategoryMapping(853, TorznabCatType.Audio, " Domestic Blues (lossless)"); + AddCategoryMapping(854, TorznabCatType.Audio, " Domestic Blues (lossy)"); + AddCategoryMapping(1013, TorznabCatType.Audio, " The multi-channel music and own digitization (Jazz and Blues)"); + AddCategoryMapping(1014, TorznabCatType.Audio, " Multichannel music (Jazz and Blues)"); + AddCategoryMapping(1015, TorznabCatType.Audio, " Foreign Jazz and Blues (Hi-Res stereo)"); + AddCategoryMapping(1016, TorznabCatType.Audio, " Proper digitization (Jazz and Blues)"); + AddCategoryMapping(1458, TorznabCatType.Audio, " Video, DVD Video, HD Video (Jazz and Blues)"); + AddCategoryMapping(1459, TorznabCatType.Audio, " Jazz and Blues (Video)"); + AddCategoryMapping(1460, TorznabCatType.Audio, " Jazz and Blues (DVD Video)"); + AddCategoryMapping(1461, TorznabCatType.Audio, " Jazz and Blues (HD Video)"); + AddCategoryMapping(204, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco"); + AddCategoryMapping(207, TorznabCatType.Audio, " NewAge & Meditative (lossy)"); + AddCategoryMapping(1004, TorznabCatType.Audio, " NewAge & Meditative (lossless)"); + AddCategoryMapping(1005, TorznabCatType.Audio, " Flamenco and acoustic guitar (lossy)"); + AddCategoryMapping(1006, TorznabCatType.Audio, " Flamenco and acoustic guitar (lossless)"); + AddCategoryMapping(1385, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco (Video)"); + AddCategoryMapping(1386, TorznabCatType.Audio, " New Age, Relax, Meditative & Flamenco (DVD and HD Video)"); + AddCategoryMapping(1007, TorznabCatType.Audio, " Sounds of nature"); + AddCategoryMapping(701, TorznabCatType.Audio, " Chanson, Author and military songs"); + AddCategoryMapping(702, TorznabCatType.Audio, " Domestic chanson (lossy)"); + AddCategoryMapping(891, TorznabCatType.Audio, " Domestic chanson (lossless)"); + AddCategoryMapping(892, TorznabCatType.Audio, " Military song (lossy)"); + AddCategoryMapping(893, TorznabCatType.Audio, " Chanson (lossy)"); + AddCategoryMapping(1401, TorznabCatType.Audio, " Collections domestic chanson (lossy)"); + AddCategoryMapping(1402, TorznabCatType.Audio, " Military song (lossless)"); + AddCategoryMapping(1403, TorznabCatType.Audio, " Chanson (lossless)"); + AddCategoryMapping(1404, TorznabCatType.Audio, " Minstrels and roleviki (lossy and lossless)"); + AddCategoryMapping(1405, TorznabCatType.Audio, " Proper digitization (Chanson, and Bards) lossless"); + AddCategoryMapping(1406, TorznabCatType.Audio, " Videos (Chanson, and Bards)"); + AddCategoryMapping(1407, TorznabCatType.Audio, " DVD Video (Chanson, and Bards)"); + AddCategoryMapping(1430, TorznabCatType.Audio, " Foreign chanson (lossy)"); + AddCategoryMapping(1431, TorznabCatType.Audio, " Foreign chanson (lossless)"); + AddCategoryMapping(1445, TorznabCatType.Audio, " Foreign chanson (Video)"); + AddCategoryMapping(1446, TorznabCatType.Audio, " Foreign chanson (DVD Video)"); + AddCategoryMapping(865, TorznabCatType.Audio, " Rock music"); + AddCategoryMapping(62, TorznabCatType.Audio, " foreign Rock"); + AddCategoryMapping(859, TorznabCatType.Audio, " AOR (Melodic Hard Rock, Arena rock) (lossless)"); + AddCategoryMapping(860, TorznabCatType.Audio, " AOR (Melodic Hard Rock, Arena rock) (lossy)"); + AddCategoryMapping(855, TorznabCatType.Audio, " Classic Rock & Hard Rock (lossless)"); + AddCategoryMapping(856, TorznabCatType.Audio, " Classic Rock & Hard Rock (lossy)"); + AddCategoryMapping(864, TorznabCatType.Audio, " Instrumental Guitar Rock (lossy)"); + AddCategoryMapping(1027, TorznabCatType.Audio, " Instrumental Guitar Rock (lossless)"); + AddCategoryMapping(858, TorznabCatType.Audio, " Folk-Rock (lossless)"); + AddCategoryMapping(675, TorznabCatType.Audio, " Folk-Rock (lossy)"); + AddCategoryMapping(861, TorznabCatType.Audio, " Pop-Rock & Soft Rock (lossless)"); + AddCategoryMapping(676, TorznabCatType.Audio, " Pop-Rock & Soft Rock (lossy)"); + AddCategoryMapping(857, TorznabCatType.Audio, " Progressive & Art-Rock (lossless)"); + AddCategoryMapping(674, TorznabCatType.Audio, " Progressive & Art-Rock (lossy)"); + AddCategoryMapping(863, TorznabCatType.Audio, " Rockabilly, Psychobilly, Rock'n'Roll (lossless)"); + AddCategoryMapping(730, TorznabCatType.Audio, " Rockabilly, Psychobilly, Rock'n'Roll (lossy)"); + AddCategoryMapping(1028, TorznabCatType.Audio, " East Asian Rock (lossless)"); + AddCategoryMapping(862, TorznabCatType.Audio, " East Asian rock (lossy)"); + AddCategoryMapping(1858, TorznabCatType.Audio, " Collections of foreign rock (lossless)"); + AddCategoryMapping(1859, TorznabCatType.Audio, " Collections of foreign rock (lossy)"); + AddCategoryMapping(187, TorznabCatType.Audio, " Domestic Rock"); + AddCategoryMapping(872, TorznabCatType.Audio, " Rock, Punk, Alternative (lossless)"); + AddCategoryMapping(190, TorznabCatType.Audio, " Rock, Punk, Alternative (lossy)"); + AddCategoryMapping(1489, TorznabCatType.Audio, " Metal (lossless)"); + AddCategoryMapping(191, TorznabCatType.Audio, " Metal (lossy)"); + AddCategoryMapping(1490, TorznabCatType.Audio, " Rock on the languages ??of the peoples xUSSR (lossless)"); + AddCategoryMapping(1491, TorznabCatType.Audio, " Rock on the languages ??of the peoples xUSSR (lossy)"); + AddCategoryMapping(866, TorznabCatType.Audio, " foreign Metal"); + AddCategoryMapping(727, TorznabCatType.Audio, " Black (lossy)"); + AddCategoryMapping(728, TorznabCatType.Audio, " Death, Doom (lossy)"); + AddCategoryMapping(729, TorznabCatType.Audio, " Heavy, Power, Progressive (lossy)"); + AddCategoryMapping(871, TorznabCatType.Audio, " Heavy, Power, Progressive (lossless)"); + AddCategoryMapping(1462, TorznabCatType.Audio, " Avant-garde, Experimental Metal (lossless)"); + AddCategoryMapping(1463, TorznabCatType.Audio, " Avant-garde, Experimental Metal (lossy)"); + AddCategoryMapping(1464, TorznabCatType.Audio, " Black (lossless)"); + AddCategoryMapping(1466, TorznabCatType.Audio, " Death, Doom (lossless)"); + AddCategoryMapping(1468, TorznabCatType.Audio, " Folk, Pagan, Viking (lossless)"); + AddCategoryMapping(1469, TorznabCatType.Audio, " Folk, Pagan, Viking (lossy)"); + AddCategoryMapping(1470, TorznabCatType.Audio, " Gothic Metal (lossless)"); + AddCategoryMapping(1471, TorznabCatType.Audio, " Gothic Metal (lossy)"); + AddCategoryMapping(1472, TorznabCatType.Audio, " Grind, Brutal Death (lossless)"); + AddCategoryMapping(1473, TorznabCatType.Audio, " Grind, Brutal Death (lossy)"); + AddCategoryMapping(1474, TorznabCatType.Audio, " Sludge, Stoner, Post-Metal (lossless)"); + AddCategoryMapping(1475, TorznabCatType.Audio, " Sludge, Stoner, Post-Metal (lossy)"); + AddCategoryMapping(1476, TorznabCatType.Audio, " Thrash, Speed ??(lossless)"); + AddCategoryMapping(1477, TorznabCatType.Audio, " Thrash, Speed ??(lossy)"); + AddCategoryMapping(1478, TorznabCatType.Audio, " Collections \"Foreign Metal\" (lossless)"); + AddCategoryMapping(1479, TorznabCatType.Audio, " Collections \"Foreign Metal\" (lossy)"); + AddCategoryMapping(867, TorznabCatType.Audio, " Foreign Alternative, Punk, Independent"); + AddCategoryMapping(185, TorznabCatType.Audio, " Alternative & Nu-metal (lossless)"); + AddCategoryMapping(868, TorznabCatType.Audio, " Alternative & Nu-metal (lossy)"); + AddCategoryMapping(869, TorznabCatType.Audio, " Indie, Post-Rock & Post-Punk (lossless)"); + AddCategoryMapping(870, TorznabCatType.Audio, " Indie, Post-Rock & Post-Punk (lossy)"); + AddCategoryMapping(873, TorznabCatType.Audio, " Avant-garde, Experimental Rock (lossy)"); + AddCategoryMapping(874, TorznabCatType.Audio, " Punk (lossy)"); + AddCategoryMapping(875, TorznabCatType.Audio, " Punk (lossless)"); + AddCategoryMapping(876, TorznabCatType.Audio, " Avant-garde, Experimental Rock (lossless)"); + AddCategoryMapping(1480, TorznabCatType.Audio, " Hardcore (lossless)"); + AddCategoryMapping(1481, TorznabCatType.Audio, " Hardcore (lossy)"); + AddCategoryMapping(1482, TorznabCatType.Audio, " Industrial & Post-industrial (lossless)"); + AddCategoryMapping(1483, TorznabCatType.Audio, " Industrial & Post-industrial (lossy)"); + AddCategoryMapping(1484, TorznabCatType.Audio, " Emocore, Post-hardcore, Metalcore (lossless)"); + AddCategoryMapping(1485, TorznabCatType.Audio, " Emocore, Post-hardcore, Metalcore (lossy)"); + AddCategoryMapping(1486, TorznabCatType.Audio, " Gothic Rock & Dark Folk (lossless)"); + AddCategoryMapping(1487, TorznabCatType.Audio, " Gothic Rock & Dark Folk (lossy)"); + AddCategoryMapping(1492, TorznabCatType.Audio, " The multi-channel music and own digitization (Rock)"); + AddCategoryMapping(1493, TorznabCatType.Audio, " Foreign rock (own digitization)"); + AddCategoryMapping(1494, TorznabCatType.Audio, " Domestic Rock (own digitization)"); + AddCategoryMapping(1495, TorznabCatType.Audio, " Foreign and domestic rock (multichannel music)"); + AddCategoryMapping(1496, TorznabCatType.Audio, " Foreign rock (Hi-Res stereo)"); + AddCategoryMapping(1497, TorznabCatType.Audio, " Conversion Quadraphonic (multichannel music)"); + AddCategoryMapping(1498, TorznabCatType.Audio, " Conversion SACD (multi-channel music)"); + AddCategoryMapping(1499, TorznabCatType.Audio, " Conversions in Blu-Ray (multichannel music)"); + AddCategoryMapping(1500, TorznabCatType.Audio, " Apmiksy-Upmixes / downmix-Downmix (multi-channel and Hi-Res stereo music)"); + AddCategoryMapping(1501, TorznabCatType.Audio, " Video, DVD Video, HD Video (Rock)"); + AddCategoryMapping(1502, TorznabCatType.Audio, " Rock (Video)"); + AddCategoryMapping(1503, TorznabCatType.Audio, " Rock (DVD Video)"); + AddCategoryMapping(1504, TorznabCatType.Audio, " Rock (Unofficial DVD Video)"); + AddCategoryMapping(1505, TorznabCatType.Audio, " Metal (Video)"); + AddCategoryMapping(1506, TorznabCatType.Audio, " Metal (DVD Video)"); + AddCategoryMapping(1507, TorznabCatType.Audio, " Metal (Unofficial DVD Video)"); + AddCategoryMapping(1508, TorznabCatType.Audio, " Alternative, Punk, Independent (Video)"); + AddCategoryMapping(1509, TorznabCatType.Audio, " Alternative, Punk, Independent (DVD Video)"); + AddCategoryMapping(1510, TorznabCatType.Audio, " Alternative, Punk, Independent (Unofficial DVD Video)"); + AddCategoryMapping(1511, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative (Video)"); + AddCategoryMapping(1512, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative (DVD Video)"); + AddCategoryMapping(1513, TorznabCatType.Audio, " Domestic Metal (Video)"); + AddCategoryMapping(1514, TorznabCatType.Audio, " Domestic Metal (DVD Video)"); + AddCategoryMapping(1515, TorznabCatType.Audio, " Domestic Rock, Punk, Alternative, Metal (Unofficial DVD Video)"); + AddCategoryMapping(1516, TorznabCatType.Audio, " Rock (HD Video)"); + AddCategoryMapping(905, TorznabCatType.Audio, " Folklore, Folk and World Music"); + AddCategoryMapping(906, TorznabCatType.Audio, " Eastern European Folk (lossy)"); + AddCategoryMapping(907, TorznabCatType.Audio, " Eastern European Folk (lossless)"); + AddCategoryMapping(908, TorznabCatType.Audio, " Western European folk (lossy)"); + AddCategoryMapping(909, TorznabCatType.Audio, " Western European folk (lossless)"); + AddCategoryMapping(910, TorznabCatType.Audio, " Klezmer and Jewish folklore (lossy and lossless)"); + AddCategoryMapping(911, TorznabCatType.Audio, " Country, Bluegrass (lossy)"); + AddCategoryMapping(912, TorznabCatType.Audio, " Country, Bluegrass (lossless)"); + AddCategoryMapping(1372, TorznabCatType.Audio, " World Music Siberia, Central Asia and East Asia (lossy)"); + AddCategoryMapping(1373, TorznabCatType.Audio, " World Music Siberia, Central Asia and East Asia (lossless)"); + AddCategoryMapping(1374, TorznabCatType.Audio, " World Music India (lossy)"); + AddCategoryMapping(1375, TorznabCatType.Audio, " World Music India (lossless)"); + AddCategoryMapping(1376, TorznabCatType.Audio, " World Music Africa and the Middle East (lossy)"); + AddCategoryMapping(1377, TorznabCatType.Audio, " World Music Africa and the Middle East (lossless)"); + AddCategoryMapping(1378, TorznabCatType.Audio, " Ethnic Caucasus and Transcaucasia music (lossy and lossless)"); + AddCategoryMapping(1379, TorznabCatType.Audio, " World Music Americas (lossy)"); + AddCategoryMapping(1380, TorznabCatType.Audio, " World Music Americas (lossless)"); + AddCategoryMapping(1381, TorznabCatType.Audio, " World Music Australia, the Pacific and Indian Oceans (lossy and lossless)"); + AddCategoryMapping(1382, TorznabCatType.Audio, " Folklore, Folk and World Music (Video)"); + AddCategoryMapping(1383, TorznabCatType.Audio, " Folklore, Folk and World Music (DVD Video)"); + AddCategoryMapping(1384, TorznabCatType.Audio, " Folklore, Folk and World Music (HD Video)"); + AddCategoryMapping(1857, TorznabCatType.Audio, " Folklore, Folk and World Music (own digitization)"); + AddCategoryMapping(985, TorznabCatType.Audio, " Reggae, Ska, Dub"); + AddCategoryMapping(986, TorznabCatType.Audio, " Rocksteady, Early Reggae, Ska-Jazz, Trad.Ska (lossy and lossless)"); + AddCategoryMapping(987, TorznabCatType.Audio, " Punky-Reggae, Rocksteady-Punk, Ska Revival (lossy)"); + AddCategoryMapping(988, TorznabCatType.Audio, " 3rd Wave Ska (lossy)"); + AddCategoryMapping(989, TorznabCatType.Audio, " Ska-Punk, Ska-Core (lossy)"); + AddCategoryMapping(990, TorznabCatType.Audio, " Reggae (lossy)"); + AddCategoryMapping(1026, TorznabCatType.Audio, " Dub (lossy)"); + AddCategoryMapping(991, TorznabCatType.Audio, " Dancehall, Raggamuffin (lossy)"); + AddCategoryMapping(992, TorznabCatType.Audio, " Reggae, Dancehall, Dub (lossless)"); + AddCategoryMapping(993, TorznabCatType.Audio, " Ska, Ska-Punk, Ska-Jazz (lossless)"); + AddCategoryMapping(994, TorznabCatType.Audio, " Domestic reggae, dub (lossy and lossless)"); + AddCategoryMapping(995, TorznabCatType.Audio, " Domestic ska music (lossy and lossless)"); + AddCategoryMapping(997, TorznabCatType.Audio, " Reggae, Ska, Dub (own digitization)"); + AddCategoryMapping(998, TorznabCatType.Audio, " Reggae, Ska, Dub (compilation) (lossy)"); + AddCategoryMapping(999, TorznabCatType.Audio, " Reggae, Ska, Dub (Video)"); + AddCategoryMapping(1000, TorznabCatType.Audio, " Reggae, Ska, Dub (DVD and HD Video)"); + AddCategoryMapping(1418, TorznabCatType.Audio, " Sheet Music literature"); + AddCategoryMapping(1419, TorznabCatType.Audio, " Academic Music (Notes and Media CD)"); + AddCategoryMapping(1420, TorznabCatType.Audio, " More destinations (notes, tablature)"); + AddCategoryMapping(1421, TorznabCatType.Audio, " Self and School"); + AddCategoryMapping(1422, TorznabCatType.Audio, " Songbooks (Songbooks)"); + AddCategoryMapping(1423, TorznabCatType.Audio, " Music Literature and Theory"); + AddCategoryMapping(1424, TorznabCatType.Audio, " music magazines"); + AddCategoryMapping(1602, TorznabCatType.Audio, " Audio for Apple devices"); + AddCategoryMapping(1603, TorznabCatType.Audio, " Audiobooks (AAC, ALAC)"); + AddCategoryMapping(1604, TorznabCatType.Audio, " Music Lossless (ALAC)"); + AddCategoryMapping(1605, TorznabCatType.Audio, " Music Lossy (AAC)"); + AddCategoryMapping(1606, TorznabCatType.Audio, " Music Lossy (AAC) (Singles, EPs)"); + AddCategoryMapping(113, TorznabCatType.Books, "Books, Audio Books, Journals"); + AddCategoryMapping(561, TorznabCatType.Books, " Books, Audio Books, Journals (General Discussion)"); + AddCategoryMapping(316, TorznabCatType.Books, " Archive (Books, Audio Books, Journals)"); + AddCategoryMapping(1620, TorznabCatType.Books, " Meditation"); + AddCategoryMapping(1802, TorznabCatType.Books, " Historiography"); + AddCategoryMapping(116, TorznabCatType.AudioAudiobook, " Audiobooks"); + AddCategoryMapping(1231, TorznabCatType.AudioAudiobook, " Audio, history, memoirs (Audiobooks)"); + AddCategoryMapping(119, TorznabCatType.AudioAudiobook, " Audio and literary readings (Audiobooks)"); + AddCategoryMapping(1232, TorznabCatType.AudioAudiobook, " Lots of great people (Audiobooks)"); + AddCategoryMapping(1233, TorznabCatType.AudioAudiobook, " Historical book (Audiobooks)"); + AddCategoryMapping(321, TorznabCatType.AudioAudiobook, " Science fiction, fantasy, mystery, horror, fanfiction (Audiobooks)"); + AddCategoryMapping(1234, TorznabCatType.AudioAudiobook, " Russian fiction, fantasy, mystery, horror, fanfiction (audiobook)"); + AddCategoryMapping(1235, TorznabCatType.AudioAudiobook, " Foreign fiction, fantasy, mystery, horror, fanfiction (audiobook)"); + AddCategoryMapping(317, TorznabCatType.AudioAudiobook, " Fiction (Audiobooks)"); + AddCategoryMapping(1236, TorznabCatType.AudioAudiobook, " Poetry (audiobook)"); + AddCategoryMapping(118, TorznabCatType.AudioAudiobook, " Foreign literature (audiobook)"); + AddCategoryMapping(117, TorznabCatType.AudioAudiobook, " Russian Literature (audiobook)"); + AddCategoryMapping(120, TorznabCatType.AudioAudiobook, " Children's Literature (audiobook)"); + AddCategoryMapping(1237, TorznabCatType.AudioAudiobook, " Detectives, Adventure, Thriller, Action (audiobook)"); + AddCategoryMapping(318, TorznabCatType.AudioAudiobook, " Detectives (audiobook)"); + AddCategoryMapping(322, TorznabCatType.AudioAudiobook, " Psychology. philosophy, religion (Audiobooks)"); + AddCategoryMapping(1238, TorznabCatType.AudioAudiobook, " Religion (Audio)"); + AddCategoryMapping(1239, TorznabCatType.AudioAudiobook, " Orthodox (Audio)"); + AddCategoryMapping(1240, TorznabCatType.AudioAudiobook, " Islam (Audio)"); + AddCategoryMapping(1241, TorznabCatType.AudioAudiobook, " Other traditional religion (Audio)"); + AddCategoryMapping(1242, TorznabCatType.AudioAudiobook, " Nontraditional religious philosophies (Audio)"); + AddCategoryMapping(1243, TorznabCatType.AudioAudiobook, " Educational, scientific and popular literature (Audio)"); + AddCategoryMapping(1244, TorznabCatType.AudioAudiobook, " Audiobooks in lossless-format"); + AddCategoryMapping(323, TorznabCatType.AudioAudiobook, " Business (Audio)"); + AddCategoryMapping(319, TorznabCatType.AudioAudiobook, " Historical literature (Audiobooks)"); + AddCategoryMapping(1245, TorznabCatType.AudioAudiobook, " Miscellaneous (Audiobooks)"); + AddCategoryMapping(1622, TorznabCatType.AudioAudiobook, " Meditation (Audio)"); + AddCategoryMapping(1626, TorznabCatType.AudioAudiobook, " publicism"); + AddCategoryMapping(1627, TorznabCatType.AudioAudiobook, " Satire, humor"); + AddCategoryMapping(324, TorznabCatType.AudioAudiobook, " Archive and nekonditsiya audiobooks"); + AddCategoryMapping(670, TorznabCatType.Books, " Books and magazines"); + AddCategoryMapping(671, TorznabCatType.Books, " Esoteric Tarot, Feng Shui"); + AddCategoryMapping(885, TorznabCatType.Books, " Film, TV, animation"); + AddCategoryMapping(886, TorznabCatType.Books, " Drawing, Graphic Design"); + AddCategoryMapping(887, TorznabCatType.Books, " Photo and video shooting"); + AddCategoryMapping(888, TorznabCatType.Books, " Astrology"); + AddCategoryMapping(1865, TorznabCatType.Books, " Fashion. Style. Etiquette"); + AddCategoryMapping(889, TorznabCatType.Books, " Celebrities and idols"); + AddCategoryMapping(890, TorznabCatType.Books, " Miscellaneous"); + AddCategoryMapping(982, TorznabCatType.Books, " Magazines and newspapers (general section)"); + AddCategoryMapping(566, TorznabCatType.Books, " Men's magazines"); + AddCategoryMapping(1204, TorznabCatType.Books, " For women (magazines and books)"); + AddCategoryMapping(1793, TorznabCatType.Books, " Popular science magazines"); + AddCategoryMapping(1794, TorznabCatType.Books, " Journals of Electrical and Electronics"); + AddCategoryMapping(1795, TorznabCatType.Books, " Housekeeping (logs)"); + AddCategoryMapping(1796, TorznabCatType.Books, " Hobbies (logs)"); + AddCategoryMapping(1797, TorznabCatType.Books, " Other magazines"); + AddCategoryMapping(1205, TorznabCatType.Books, " Travel and tourism"); + AddCategoryMapping(258, TorznabCatType.Books, " For children, parents and teachers"); + AddCategoryMapping(1685, TorznabCatType.Books, " Tutorials (General)"); + AddCategoryMapping(681, TorznabCatType.Books, " Textbooks for kindergarten and elementary school (up to class 4)"); + AddCategoryMapping(682, TorznabCatType.Books, " Textbooks for high school (grades 5-11)"); + AddCategoryMapping(683, TorznabCatType.Books, " Teachers and educators"); + AddCategoryMapping(684, TorznabCatType.Books, " Popular science and cognitive literature (for children)"); + AddCategoryMapping(685, TorznabCatType.Books, " Leisure and creativity"); + AddCategoryMapping(686, TorznabCatType.Books, " Education and development"); + AddCategoryMapping(687, TorznabCatType.Books, " Hood. lit-ra for preschool and elementary grades"); + AddCategoryMapping(688, TorznabCatType.Books, " Hood. lit-ra for the middle and upper classes"); + AddCategoryMapping(731, TorznabCatType.Books, " Sports, physical training, martial arts"); + AddCategoryMapping(738, TorznabCatType.Books, " Autosport. Motorcycling. Cycling (literature)"); + AddCategoryMapping(737, TorznabCatType.Books, " Martial arts, martial arts (literature)"); + AddCategoryMapping(734, TorznabCatType.Books, " Team sports (literature)"); + AddCategoryMapping(1854, TorznabCatType.Books, " Athletics. Swimming. Gymnastics. Weightlifting. Rowing (literature)"); + AddCategoryMapping(739, TorznabCatType.Books, " Sport Editions"); + AddCategoryMapping(736, TorznabCatType.Books, " Fitness, fitness, bodybuilding (literature)"); + AddCategoryMapping(732, TorznabCatType.Books, " Football (literature)"); + AddCategoryMapping(733, TorznabCatType.Books, " Hockey (literature)"); + AddCategoryMapping(735, TorznabCatType.Books, " Chess. Checkers (literature)"); + AddCategoryMapping(1855, TorznabCatType.Books, " Extreme sports (literature)"); + AddCategoryMapping(649, TorznabCatType.Books, " Humanitarian sciences"); + AddCategoryMapping(650, TorznabCatType.Books, " Arts. Cultural"); + AddCategoryMapping(651, TorznabCatType.Books, " Folklore. Epic. Mythology"); + AddCategoryMapping(652, TorznabCatType.Books, " literary criticism"); + AddCategoryMapping(653, TorznabCatType.Books, " Linguistics"); + AddCategoryMapping(654, TorznabCatType.Books, " Philosophy"); + AddCategoryMapping(655, TorznabCatType.Books, " Political science"); + AddCategoryMapping(656, TorznabCatType.Books, " Sociology"); + AddCategoryMapping(657, TorznabCatType.Books, " Journalism, Journalism"); + AddCategoryMapping(658, TorznabCatType.Books, " Business, Management"); + AddCategoryMapping(659, TorznabCatType.Books, " Marketing"); + AddCategoryMapping(660, TorznabCatType.Books, " Economy"); + AddCategoryMapping(661, TorznabCatType.Books, " Finance"); + AddCategoryMapping(662, TorznabCatType.Books, " Jurisprudence. Right. criminalistics"); + AddCategoryMapping(664, TorznabCatType.Books, " Historical sciences"); + AddCategoryMapping(665, TorznabCatType.Books, " Historical person"); + AddCategoryMapping(807, TorznabCatType.Books, " Historical sources"); + AddCategoryMapping(808, TorznabCatType.Books, " Alternative historical theories"); + AddCategoryMapping(809, TorznabCatType.Books, " Archeology"); + AddCategoryMapping(810, TorznabCatType.Books, " Ancient world. Antiquity"); + AddCategoryMapping(811, TorznabCatType.Books, " Middle Ages"); + AddCategoryMapping(812, TorznabCatType.Books, " The history of modern and contemporary"); + AddCategoryMapping(813, TorznabCatType.Books, " History of Europe"); + AddCategoryMapping(814, TorznabCatType.Books, " History of Asia and Africa"); + AddCategoryMapping(815, TorznabCatType.Books, " The history of America, Australia, Oceania"); + AddCategoryMapping(816, TorznabCatType.Books, " Russian history"); + AddCategoryMapping(817, TorznabCatType.Books, " The era of the Soviet Union"); + AddCategoryMapping(818, TorznabCatType.Books, " History of the former Soviet Union"); + AddCategoryMapping(819, TorznabCatType.Books, " Ethnography, anthropology"); + AddCategoryMapping(820, TorznabCatType.Books, " International relationships. Diplomacy"); + AddCategoryMapping(1856, TorznabCatType.Books, " Methodology and philosophy of history"); + AddCategoryMapping(255, TorznabCatType.Books, " Accurate, natural and engineering sciences"); + AddCategoryMapping(648, TorznabCatType.Books, " Geography / Geology / Geodesy"); + AddCategoryMapping(672, TorznabCatType.Books, " Physics"); + AddCategoryMapping(723, TorznabCatType.Books, " Astronomy"); + AddCategoryMapping(725, TorznabCatType.Books, " Aviation / Astronautics"); + AddCategoryMapping(726, TorznabCatType.Books, " Mathematics"); + AddCategoryMapping(748, TorznabCatType.Books, " Welding / Soldering / Non-Destructive Testing"); + AddCategoryMapping(749, TorznabCatType.Books, " Architecture / construction / engineering services"); + AddCategoryMapping(750, TorznabCatType.Books, " Biology / Ecology"); + AddCategoryMapping(751, TorznabCatType.Books, " Chemistry / Biochemistry"); + AddCategoryMapping(821, TorznabCatType.Books, " Electronics / Radio"); + AddCategoryMapping(822, TorznabCatType.Books, " Diagrams and service manuals (original documents)"); + AddCategoryMapping(823, TorznabCatType.Books, " engineering"); + AddCategoryMapping(824, TorznabCatType.Books, " Automation / Robotics"); + AddCategoryMapping(825, TorznabCatType.Books, " Metallurgy / Materials"); + AddCategoryMapping(826, TorznabCatType.Books, " Mechanics, Strength of Materials"); + AddCategoryMapping(827, TorznabCatType.Books, " Energy / Electrical"); + AddCategoryMapping(828, TorznabCatType.Books, " Oil, gas and chemical industry"); + AddCategoryMapping(829, TorznabCatType.Books, " Agriculture and food industry"); + AddCategoryMapping(836, TorznabCatType.Books, " Railway deal"); + AddCategoryMapping(837, TorznabCatType.Books, " Normative documents"); + AddCategoryMapping(838, TorznabCatType.Books, " Journals: scientific, popular, radio and others."); + AddCategoryMapping(668, TorznabCatType.Books, " Warfare"); + AddCategoryMapping(669, TorznabCatType.Books, " History of the Second World War"); + AddCategoryMapping(830, TorznabCatType.Books, " Militaria"); + AddCategoryMapping(831, TorznabCatType.Books, " Military history"); + AddCategoryMapping(832, TorznabCatType.Books, " Military equipment"); + AddCategoryMapping(833, TorznabCatType.Books, " Weapon"); + AddCategoryMapping(834, TorznabCatType.Books, " Educational literature"); + AddCategoryMapping(835, TorznabCatType.Books, " The special services of the world"); + AddCategoryMapping(666, TorznabCatType.Books, " Faith and Religion"); + AddCategoryMapping(667, TorznabCatType.Books, " Christianity"); + AddCategoryMapping(881, TorznabCatType.Books, " Islam"); + AddCategoryMapping(882, TorznabCatType.Books, " Religions of India, Tibet and East Asia / Judaism"); + AddCategoryMapping(883, TorznabCatType.Books, " Nontraditional religious, spiritual and mystical teachings"); + AddCategoryMapping(884, TorznabCatType.Books, " Religious Studies. History of Religions. Atheism"); + AddCategoryMapping(1206, TorznabCatType.Books, " Psychology"); + AddCategoryMapping(1207, TorznabCatType.Books, " General and Applied Psychology"); + AddCategoryMapping(1208, TorznabCatType.Books, " Psychotherapy and counseling"); + AddCategoryMapping(1209, TorznabCatType.Books, " Psychological diagnostics and therapy"); + AddCategoryMapping(1210, TorznabCatType.Books, " Social psychology and psychology of relationships"); + AddCategoryMapping(1211, TorznabCatType.Books, " Training and Coaching"); + AddCategoryMapping(1212, TorznabCatType.Books, " Self-development and self-improvement"); + AddCategoryMapping(1213, TorznabCatType.Books, " Popular psychology"); + AddCategoryMapping(1214, TorznabCatType.Books, " Sexology. Relations between the sexes"); + AddCategoryMapping(254, TorznabCatType.Books, " Collecting, hobby and hobbies"); + AddCategoryMapping(633, TorznabCatType.Books, " Collecting and auxiliary ist. discipline"); + AddCategoryMapping(634, TorznabCatType.Books, " Embroidery"); + AddCategoryMapping(635, TorznabCatType.Books, " Knitting"); + AddCategoryMapping(636, TorznabCatType.Books, " Sewing, patchwork"); + AddCategoryMapping(637, TorznabCatType.Books, " lace"); + AddCategoryMapping(638, TorznabCatType.Books, " Beading"); + AddCategoryMapping(639, TorznabCatType.Books, " Paper art"); + AddCategoryMapping(640, TorznabCatType.Books, " Other arts and crafts"); + AddCategoryMapping(641, TorznabCatType.Books, " Pets and aquariums"); + AddCategoryMapping(642, TorznabCatType.Books, " Hunting and fishing"); + AddCategoryMapping(598, TorznabCatType.Books, " Cooking (Book)"); + AddCategoryMapping(312, TorznabCatType.Books, " Cooking (newspapers and magazines)"); + AddCategoryMapping(643, TorznabCatType.Books, " Modelling"); + AddCategoryMapping(644, TorznabCatType.Books, " Farmland / Floriculture"); + AddCategoryMapping(645, TorznabCatType.Books, " Repair, private construction, design of interiors"); + AddCategoryMapping(1866, TorznabCatType.Books, " Woodworking"); + AddCategoryMapping(646, TorznabCatType.Books, " Board games"); + AddCategoryMapping(647, TorznabCatType.Books, " Other hobbies"); + AddCategoryMapping(1786, TorznabCatType.Books, " Nonfiction"); + AddCategoryMapping(623, TorznabCatType.Books, " Fiction"); + AddCategoryMapping(624, TorznabCatType.Books, " Russian Literature (books)"); + AddCategoryMapping(627, TorznabCatType.Books, " The detective, thriller (book)"); + AddCategoryMapping(1624, TorznabCatType.Books, " Militants (Books)"); + AddCategoryMapping(1625, TorznabCatType.Books, " Detectives (Books)"); + AddCategoryMapping(628, TorznabCatType.Books, " Female Novel (Book)"); + AddCategoryMapping(631, TorznabCatType.Books, " Adventure (book)"); + AddCategoryMapping(632, TorznabCatType.Books, " Literary magazines"); + AddCategoryMapping(1611, TorznabCatType.Books, " Fiction / Fantasy / Mystic (book)"); + AddCategoryMapping(629, TorznabCatType.Books, " Domestic science fiction / fantasy / mystic"); + AddCategoryMapping(630, TorznabCatType.Books, " International science fiction / fantasy / mystic"); + AddCategoryMapping(1612, TorznabCatType.Books, " Foreign literature (books)"); + AddCategoryMapping(625, TorznabCatType.Books, " Foreign literature (up to 1900)"); + AddCategoryMapping(626, TorznabCatType.Books, " Foreign literature (XX and XXI century)"); + AddCategoryMapping(1618, TorznabCatType.Books, " Historical books"); + AddCategoryMapping(1789, TorznabCatType.Books, " Satire, humor (the book)"); + AddCategoryMapping(257, TorznabCatType.Books, " Computer books"); + AddCategoryMapping(678, TorznabCatType.Books, " Programming (Literature)"); + AddCategoryMapping(714, TorznabCatType.Books, " Programs from Microsoft (literature)"); + AddCategoryMapping(715, TorznabCatType.Books, " Other programs (literature)"); + AddCategoryMapping(716, TorznabCatType.Books, " Mac OS; Linux, FreeBSD and other * NIX (literature)"); + AddCategoryMapping(717, TorznabCatType.Books, " DBMS (literature)"); + AddCategoryMapping(718, TorznabCatType.Books, " Web Design and Programming (Literature)"); + AddCategoryMapping(719, TorznabCatType.Books, " Graphics, video processing (literature)"); + AddCategoryMapping(720, TorznabCatType.Books, " Network / VoIP (literature)"); + AddCategoryMapping(721, TorznabCatType.Books, " Hacking and Security (literature)"); + AddCategoryMapping(722, TorznabCatType.Books, " Iron (book on a PC)"); + AddCategoryMapping(1215, TorznabCatType.Books, " Engineering and science programs (literature)"); + AddCategoryMapping(1216, TorznabCatType.Books, " Computer magazines and annexes"); + AddCategoryMapping(1791, TorznabCatType.Books, " gaming magazines"); + AddCategoryMapping(1792, TorznabCatType.Books, " Computer magazines"); + AddCategoryMapping(1217, TorznabCatType.Books, " Disc applications to gaming magazines"); + AddCategoryMapping(311, TorznabCatType.Books, " Comics"); + AddCategoryMapping(1218, TorznabCatType.Books, " Comics in Russian"); + AddCategoryMapping(1219, TorznabCatType.Books, " Marvel Comics publishing"); + AddCategoryMapping(1220, TorznabCatType.Books, " DC Comics publishing"); + AddCategoryMapping(1221, TorznabCatType.Books, " Comics from other publishers"); + AddCategoryMapping(1222, TorznabCatType.Books, " Comics in other languages"); + AddCategoryMapping(1223, TorznabCatType.Books, " Substandard distribution (Comics)"); + AddCategoryMapping(259, TorznabCatType.Books, " Collections of books and libraries"); + AddCategoryMapping(983, TorznabCatType.Books, " Libraries (mirror network libraries / collections)"); + AddCategoryMapping(984, TorznabCatType.Books, " Thematic collections (collections)"); + AddCategoryMapping(1224, TorznabCatType.Books, " Multidisciplinary collection (compilation)"); + AddCategoryMapping(1788, TorznabCatType.Books, " Mnogoavtorskie collections, book series"); + AddCategoryMapping(1787, TorznabCatType.Books, " Encyclopedias and dictionaries"); + AddCategoryMapping(1225, TorznabCatType.Books, " Multimedia and online publications"); + AddCategoryMapping(1226, TorznabCatType.Books, " Multimedia encyclopedia"); + AddCategoryMapping(1227, TorznabCatType.Books, " Interactive tutorials and educational materials"); + AddCategoryMapping(1228, TorznabCatType.Books, " Educational publications for children"); + AddCategoryMapping(1229, TorznabCatType.Books, " Cooking. Floriculture. housekeeping"); + AddCategoryMapping(1230, TorznabCatType.Books, " Culture. Art. History"); + AddCategoryMapping(497, TorznabCatType.Books, "training materials"); + AddCategoryMapping(1246, TorznabCatType.Books, " Learning foreign languages"); + AddCategoryMapping(1248, TorznabCatType.Books, " Foreign languages ??for children"); + AddCategoryMapping(1249, TorznabCatType.Books, " English (for children)"); + AddCategoryMapping(1250, TorznabCatType.Books, " Other European languages ??(for children)"); + AddCategoryMapping(1251, TorznabCatType.Books, " Oriental languages ??(for children)"); + AddCategoryMapping(1252, TorznabCatType.Books, " School books, the exam (for children)"); + AddCategoryMapping(1253, TorznabCatType.Books, " Fiction in foreign languages"); + AddCategoryMapping(1254, TorznabCatType.Books, " Fiction in English"); + AddCategoryMapping(1255, TorznabCatType.Books, " Fiction French"); + AddCategoryMapping(1256, TorznabCatType.Books, " Fiction in other European languages"); + AddCategoryMapping(1257, TorznabCatType.Books, " Fiction in oriental languages"); + AddCategoryMapping(1258, TorznabCatType.Books, " Foreign Language for Adults"); + AddCategoryMapping(1259, TorznabCatType.Books, " English (for adults)"); + AddCategoryMapping(1260, TorznabCatType.Books, " German"); + AddCategoryMapping(1261, TorznabCatType.Books, " French"); + AddCategoryMapping(1262, TorznabCatType.Books, " Spanish"); + AddCategoryMapping(1263, TorznabCatType.Books, " Italian language"); + AddCategoryMapping(1264, TorznabCatType.Books, " Other European languages"); + AddCategoryMapping(1265, TorznabCatType.Books, " Arabic language"); + AddCategoryMapping(1266, TorznabCatType.Books, " Chinese"); + AddCategoryMapping(1267, TorznabCatType.Books, " Japanese"); + AddCategoryMapping(1268, TorznabCatType.Books, " Other oriental languages"); + AddCategoryMapping(1269, TorznabCatType.Books, " Russian as a foreign language"); + AddCategoryMapping(1270, TorznabCatType.Books, " Multilanguage collections"); + AddCategoryMapping(1271, TorznabCatType.Books, " Miscellaneous (foreign languages)"); + AddCategoryMapping(1867, TorznabCatType.Books, " LIM-courses"); + AddCategoryMapping(1272, TorznabCatType.Books, " Audio Books in foreign languages"); + AddCategoryMapping(1273, TorznabCatType.Books, " Audiobooks in English"); + AddCategoryMapping(1274, TorznabCatType.Books, " Audiobooks in German"); + AddCategoryMapping(1275, TorznabCatType.Books, " Audiobooks in other languages"); + AddCategoryMapping(1623, TorznabCatType.Books, " Educational audio materials"); + AddCategoryMapping(1247, TorznabCatType.Books, " video tutorials"); + AddCategoryMapping(933, TorznabCatType.Books, " Video tutorials and interactive training DVD"); + AddCategoryMapping(936, TorznabCatType.Books, " Cooking (video tutorial)"); + AddCategoryMapping(1276, TorznabCatType.Books, " Sport"); + AddCategoryMapping(934, TorznabCatType.Books, " Fitness - Cardio, Strength Training"); + AddCategoryMapping(1277, TorznabCatType.Books, " Fitness - Mind and Body"); + AddCategoryMapping(1278, TorznabCatType.Books, " Extreme sports (video tutorial)"); + AddCategoryMapping(935, TorznabCatType.Books, " Playing guitar"); + AddCategoryMapping(1279, TorznabCatType.Books, " Body-building"); + AddCategoryMapping(1280, TorznabCatType.Books, " Health practice"); + AddCategoryMapping(1281, TorznabCatType.Books, " Yoga"); + AddCategoryMapping(1282, TorznabCatType.Books, " Video and Snapshots"); + AddCategoryMapping(1283, TorznabCatType.Books, " Personal care"); + AddCategoryMapping(1284, TorznabCatType.Books, " Painting"); + AddCategoryMapping(1286, TorznabCatType.Books, " Percussion instruments"); + AddCategoryMapping(1287, TorznabCatType.Books, " Other musical instruments"); + AddCategoryMapping(1288, TorznabCatType.Books, " Playing bass guitar"); + AddCategoryMapping(1289, TorznabCatType.Books, " Ballroom dancing"); + AddCategoryMapping(1290, TorznabCatType.Books, " Belly dance"); + AddCategoryMapping(1291, TorznabCatType.Books, " Street and club dances"); + AddCategoryMapping(1292, TorznabCatType.Books, " Dancing, miscellaneous"); + AddCategoryMapping(1295, TorznabCatType.Books, " Tricks and stunts"); + AddCategoryMapping(1296, TorznabCatType.Books, " Education"); + AddCategoryMapping(1297, TorznabCatType.Books, " Business, Economics and Finance"); + AddCategoryMapping(1299, TorznabCatType.Books, " Pregnancy, childbirth, motherhood"); + AddCategoryMapping(1300, TorznabCatType.Books, " Educational video for children"); + AddCategoryMapping(1301, TorznabCatType.Books, " Psychology (video)"); + AddCategoryMapping(1302, TorznabCatType.Books, " Spirituality, self-development"); + AddCategoryMapping(1303, TorznabCatType.Books, " Pickup, love"); + AddCategoryMapping(1304, TorznabCatType.Books, " Construction, renovation and design"); + AddCategoryMapping(1305, TorznabCatType.Books, " Wood and metal"); + AddCategoryMapping(1306, TorznabCatType.Books, " Plants and Animals"); + AddCategoryMapping(1676, TorznabCatType.Books, " Fishing and hunting"); + AddCategoryMapping(1293, TorznabCatType.Books, " Hunting"); + AddCategoryMapping(1294, TorznabCatType.Books, " Fishing and spearfishing"); + AddCategoryMapping(1307, TorznabCatType.Books, " Miscellaneous (Video tutorials and educational interactive DVD)"); + AddCategoryMapping(1309, TorznabCatType.Books, " Martial Arts (Video Tutorials)"); + AddCategoryMapping(1310, TorznabCatType.Books, " Aikido and Aiki-jutsu"); + AddCategoryMapping(1311, TorznabCatType.Books, " Wing Chun"); + AddCategoryMapping(1312, TorznabCatType.Books, " Jujutsu"); + AddCategoryMapping(1313, TorznabCatType.Books, " Judo and Sambo"); + AddCategoryMapping(1314, TorznabCatType.Books, " Karate"); + AddCategoryMapping(1315, TorznabCatType.Books, " knife fight"); + AddCategoryMapping(1316, TorznabCatType.Books, " Work with weapon"); + AddCategoryMapping(1317, TorznabCatType.Books, " Russian style"); + AddCategoryMapping(1318, TorznabCatType.Books, " dogfight"); + AddCategoryMapping(1319, TorznabCatType.Books, " composite style"); + AddCategoryMapping(1320, TorznabCatType.Books, " shock styles"); + AddCategoryMapping(1321, TorznabCatType.Books, " Wushu"); + AddCategoryMapping(1322, TorznabCatType.Books, " Miscellaneous (Video Tutorials)"); + AddCategoryMapping(1323, TorznabCatType.Books, " Computer video tutorials and interactive training DVD"); + AddCategoryMapping(1324, TorznabCatType.Books, " Computer networks and security (video tutorial)"); + AddCategoryMapping(1325, TorznabCatType.Books, " OS and Microsoft server software (video tutorial)"); + AddCategoryMapping(1326, TorznabCatType.Books, " Microsoft Office software (video tutorial)"); + AddCategoryMapping(1327, TorznabCatType.Books, " OS and UNIX-program (video tutorial)"); + AddCategoryMapping(1329, TorznabCatType.Books, " Adobe Photoshop (video tutorial)"); + AddCategoryMapping(1330, TorznabCatType.Books, " Autodesk Maya (video tutorial)"); + AddCategoryMapping(1331, TorznabCatType.Books, " Autodesk 3ds Max (video tutorial)"); + AddCategoryMapping(1332, TorznabCatType.Books, " Autodesk Softimage (XSI) (video tutorial)"); + AddCategoryMapping(1333, TorznabCatType.Books, " ZBrush (video tutorial)"); + AddCategoryMapping(1334, TorznabCatType.Books, " Flash, Flex and ActionScript (video tutorial)"); + AddCategoryMapping(1335, TorznabCatType.Books, " 2D-graphics (video tutorial)"); + AddCategoryMapping(1336, TorznabCatType.Books, " 3D-graphics (video tutorial)"); + AddCategoryMapping(1337, TorznabCatType.Books, " Engineering and science programs (video tutorial)"); + AddCategoryMapping(1338, TorznabCatType.Books, " Web-design (video tutorial)"); + AddCategoryMapping(1339, TorznabCatType.Books, " Programming (video tutorial)"); + AddCategoryMapping(1340, TorznabCatType.Books, " Software for Mac OS (video tutorial)"); + AddCategoryMapping(1341, TorznabCatType.Books, " Working with video (video tutorial)"); + AddCategoryMapping(1342, TorznabCatType.Books, " Working with sound (video tutorial)"); + AddCategoryMapping(1343, TorznabCatType.Books, " Miscellaneous (Computer video tutorials)"); + AddCategoryMapping(1530, TorznabCatType.Other, "Subject forums"); + AddCategoryMapping(698, TorznabCatType.Other, " Auto and Moto"); + AddCategoryMapping(699, TorznabCatType.Other, " Repair and maintenance of vehicles"); + AddCategoryMapping(772, TorznabCatType.Other, " The original selection of spare parts catalogs"); + AddCategoryMapping(1344, TorznabCatType.Other, " Non-original spare parts catalogs for selection"); + AddCategoryMapping(1345, TorznabCatType.Other, " diagnostic and repair programs"); + AddCategoryMapping(1346, TorznabCatType.Other, " Tuning, chip tuning, tuning"); + AddCategoryMapping(700, TorznabCatType.Other, " Books for repair / maintenance / operation of the vehicle"); + AddCategoryMapping(1349, TorznabCatType.Other, " Multimediyki repair / maintenance / operation of the vehicle"); + AddCategoryMapping(1350, TorznabCatType.Other, " Accounting, utilities, etc."); + AddCategoryMapping(1351, TorznabCatType.Other, " Virtual Driving School"); + AddCategoryMapping(1352, TorznabCatType.Other, " Video lessons on driving vehicles"); + AddCategoryMapping(1353, TorznabCatType.Other, " Video lessons on repair of vehicles"); + AddCategoryMapping(1354, TorznabCatType.Other, " Magazines Auto / Moto"); + AddCategoryMapping(1355, TorznabCatType.Other, " Water transport"); + AddCategoryMapping(1356, TorznabCatType.Other, " Movies and television shows, car / moto"); + AddCategoryMapping(1357, TorznabCatType.Other, " Documentary / educational films"); + AddCategoryMapping(1358, TorznabCatType.Other, " entertainment shows"); + AddCategoryMapping(1359, TorznabCatType.Other, " Top Gear / Top Gear"); + AddCategoryMapping(1360, TorznabCatType.Other, " Test Drive / Reviews / Motor"); + AddCategoryMapping(1361, TorznabCatType.Other, " Tuning / Fast and the Furious"); + AddCategoryMapping(600, TorznabCatType.Other, " Medicine and Health"); + AddCategoryMapping(601, TorznabCatType.Other, " Books, magazines and on medicine and health program"); + AddCategoryMapping(603, TorznabCatType.Other, " Clinical medicine until 1980"); + AddCategoryMapping(604, TorznabCatType.Other, " Clinical Medicine from 1980 to 2000"); + AddCategoryMapping(605, TorznabCatType.Other, " Clinical Medicine since 2000"); + AddCategoryMapping(606, TorznabCatType.Other, " The popular medical periodicals (newspapers and magazines)"); + AddCategoryMapping(607, TorznabCatType.Other, " The scientific medical periodicals (newspapers and magazines)"); + AddCategoryMapping(608, TorznabCatType.Other, " Life Sciences"); + AddCategoryMapping(609, TorznabCatType.Other, " Pharmacy and Pharmacology"); + AddCategoryMapping(610, TorznabCatType.Other, " Non-traditional, traditional medicine and popular books on health"); + AddCategoryMapping(611, TorznabCatType.Other, " Veterinary, miscellaneous"); + AddCategoryMapping(612, TorznabCatType.Other, " Thematic collections of books"); + AddCategoryMapping(613, TorznabCatType.Other, " Audiobooks on medicine"); + AddCategoryMapping(614, TorznabCatType.Other, " Medical software"); + AddCategoryMapping(602, TorznabCatType.Other, " Tutorials, Doc. movies and TV shows on medicine"); + AddCategoryMapping(615, TorznabCatType.Other, " Medicine and Dentistry"); + AddCategoryMapping(616, TorznabCatType.Other, " Psychotherapy and clinical psychology"); + AddCategoryMapping(617, TorznabCatType.Other, " Massage"); + AddCategoryMapping(618, TorznabCatType.Other, " Health"); + AddCategoryMapping(619, TorznabCatType.Other, " Documentary movies and TV shows on medicine"); + AddCategoryMapping(560, TorznabCatType.Other, "other"); + AddCategoryMapping(578, TorznabCatType.Other, " Economy and Life"); + AddCategoryMapping(1558, TorznabCatType.Other, " psychoactive audio programs"); + AddCategoryMapping(1560, TorznabCatType.Other, " Avatars, Icons, Smileys, painting, drawing, sculpture, pictures, wallpaper, Photography, Digital Art"); + AddCategoryMapping(1651, TorznabCatType.Other, " reproductions of paintings"); + AddCategoryMapping(1652, TorznabCatType.Other, " Art photography"); + AddCategoryMapping(1653, TorznabCatType.Other, " Contemporary photography"); + AddCategoryMapping(1654, TorznabCatType.Other, " Collections of works of modern art painters"); + AddCategoryMapping(1655, TorznabCatType.Other, " hand-drawn graphics"); + AddCategoryMapping(1656, TorznabCatType.Other, " Computer graphics"); + AddCategoryMapping(1657, TorznabCatType.Other, " Illustrations"); + AddCategoryMapping(1659, TorznabCatType.Other, " Graphics (Other)"); + AddCategoryMapping(1562, TorznabCatType.Other, " Amateur photos"); + AddCategoryMapping(1561, TorznabCatType.Other, " Pictures"); + AddCategoryMapping(1563, TorznabCatType.Other, " Photos of celebrities"); + AddCategoryMapping(996, TorznabCatType.Other, " Desktop Wallpaper \\ Wallpapers"); + AddCategoryMapping(1578, TorznabCatType.Other, " Wallpapers and themes for mobile devices"); + AddCategoryMapping(1559, TorznabCatType.Other, " Avatars, Icons, Smileys"); + AddCategoryMapping(1564, TorznabCatType.Other, " Audio"); + AddCategoryMapping(1801, TorznabCatType.Other, " Mobile Audio"); + AddCategoryMapping(1565, TorznabCatType.Other, " Video (Other)"); + AddCategoryMapping(1566, TorznabCatType.Other, " Publications and educational materials (texts)"); + AddCategoryMapping(1567, TorznabCatType.Other, " Sports (video)"); AddCategoryMapping(1569, TorznabCatType.Other, " Amateur videos"); } @@ -1598,10 +1598,10 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("ucp.php?mode=logout&"), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("ucp.php?mode=logout&"), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } @@ -1609,113 +1609,113 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - WebClientStringResult results = null; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("st", "0"); - queryCollection.Add("sd", "d"); - queryCollection.Add("sk", "t"); - queryCollection.Add("tracker_search", "torrent"); - queryCollection.Add("t", "0"); - queryCollection.Add("submit", "Search"); - queryCollection.Add("sr", "topics"); - //queryCollection.Add("sr", "posts"); - //queryCollection.Add("ch", "99999"); - - // if the search string is empty use the getnew view - if (string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search_id", "newposts"); + var searchString = query.GetQueryString(); + + WebClientStringResult results = null; + var queryCollection = new NameValueCollection(); + + queryCollection.Add("st", "0"); + queryCollection.Add("sd", "d"); + queryCollection.Add("sk", "t"); + queryCollection.Add("tracker_search", "torrent"); + queryCollection.Add("t", "0"); + queryCollection.Add("submit", "Search"); + queryCollection.Add("sr", "topics"); + //queryCollection.Add("sr", "posts"); + //queryCollection.Add("ch", "99999"); + + // if the search string is empty use the getnew view + if (string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search_id", "newposts"); } - else // use the normal search - { - searchString = searchString.Replace("-", " "); - queryCollection.Add("terms", "all"); - queryCollection.Add("keywords", searchString); - queryCollection.Add("author", ""); - queryCollection.Add("sc", "1"); - queryCollection.Add("sf", "titleonly"); + else // use the normal search + { + searchString = searchString.Replace("-", " "); + queryCollection.Add("terms", "all"); + queryCollection.Add("keywords", searchString); + queryCollection.Add("author", ""); + queryCollection.Add("sc", "1"); + queryCollection.Add("sf", "titleonly"); } var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString(); - results = await RequestStringWithCookies(searchUrl); + results = await RequestStringWithCookies(searchUrl); try { string RowsSelector = "ul.topics > li"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + foreach (var Row in Rows) { - try + try { var release = new ReleaseInfo(); - release.MinimumRatio = 1; + release.MinimumRatio = 1; release.MinimumSeedTime = 0; - - var qDetailsLink = Row.QuerySelector("a.topictitle"); - var qDownloadLink = Row.QuerySelector("a[href^=\"./download/file.php?id=\"]"); - - release.Title = qDetailsLink.TextContent; - release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); - release.Link = new Uri(SiteLink + qDownloadLink.GetAttribute("href")); - release.Guid = release.Comments; - - release.Seeders = ParseUtil.CoerceInt(Row.QuerySelector("span.seed").TextContent); - release.Peers = ParseUtil.CoerceInt(Row.QuerySelector("span.leech").TextContent) + release.Seeders; - release.Grabs = ParseUtil.CoerceLong(Row.QuerySelector("span.complet").TextContent); - - var author = Row.QuerySelector("a[href^=\"./memberlist.php?mode=viewprofile&\"]"); - var timestr = author.NextSibling.NodeValue.Substring(3).Split('\n')[0].Trim(); - - timestr = timestr.Replace("менее минуты назад", "now"); - timestr = timestr.Replace("назад", "ago"); - timestr = timestr.Replace("минуту", "minute"); - timestr = timestr.Replace("минуты", "minutes"); - timestr = timestr.Replace("минут", "minutes"); - - timestr = timestr.Replace("Сегодня", "Today"); - timestr = timestr.Replace("Вчера", "Yesterday"); // untested - - timestr = timestr.Replace("янв", "Jan"); - timestr = timestr.Replace("фев", "Feb"); - timestr = timestr.Replace("мар", "Mar"); - timestr = timestr.Replace("апр", "Apr"); - timestr = timestr.Replace("май", "May"); - timestr = timestr.Replace("июн", "Jun"); - timestr = timestr.Replace("июл", "Jul"); - timestr = timestr.Replace("авг", "Aug"); - timestr = timestr.Replace("сен", "Sep"); - timestr = timestr.Replace("окт", "Oct"); - timestr = timestr.Replace("ноя", "Nov"); - timestr = timestr.Replace("дек", "Dec"); - release.PublishDate = DateTimeUtil.FromUnknown(timestr, "UK"); - - var forum = Row.QuerySelector("a[href^=\"./viewforum.php?f=\"]"); - var forumid = forum.GetAttribute("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(forumid); - - var size = forum.NextElementSibling; - var sizestr = size.TextContent; - sizestr = sizestr.Replace("ГБ", "GB"); - sizestr = sizestr.Replace("МБ", "MB"); - sizestr = sizestr.Replace("КБ", "KB"); // untested - release.Size = ReleaseInfo.GetBytes(sizestr); - - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); + var qDetailsLink = Row.QuerySelector("a.topictitle"); + var qDownloadLink = Row.QuerySelector("a[href^=\"./download/file.php?id=\"]"); + + release.Title = qDetailsLink.TextContent; + release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); + release.Link = new Uri(SiteLink + qDownloadLink.GetAttribute("href")); + release.Guid = release.Comments; + + release.Seeders = ParseUtil.CoerceInt(Row.QuerySelector("span.seed").TextContent); + release.Peers = ParseUtil.CoerceInt(Row.QuerySelector("span.leech").TextContent) + release.Seeders; + release.Grabs = ParseUtil.CoerceLong(Row.QuerySelector("span.complet").TextContent); + + var author = Row.QuerySelector("a[href^=\"./memberlist.php?mode=viewprofile&\"]"); + var timestr = author.NextSibling.NodeValue.Substring(3).Split('\n')[0].Trim(); + + timestr = timestr.Replace("менее минуты назад", "now"); + timestr = timestr.Replace("назад", "ago"); + timestr = timestr.Replace("минуту", "minute"); + timestr = timestr.Replace("минуты", "minutes"); + timestr = timestr.Replace("минут", "minutes"); + + timestr = timestr.Replace("Сегодня", "Today"); + timestr = timestr.Replace("Вчера", "Yesterday"); // untested + + timestr = timestr.Replace("янв", "Jan"); + timestr = timestr.Replace("фев", "Feb"); + timestr = timestr.Replace("мар", "Mar"); + timestr = timestr.Replace("апр", "Apr"); + timestr = timestr.Replace("май", "May"); + timestr = timestr.Replace("июн", "Jun"); + timestr = timestr.Replace("июл", "Jul"); + timestr = timestr.Replace("авг", "Aug"); + timestr = timestr.Replace("сен", "Sep"); + timestr = timestr.Replace("окт", "Oct"); + timestr = timestr.Replace("ноя", "Nov"); + timestr = timestr.Replace("дек", "Dec"); + release.PublishDate = DateTimeUtil.FromUnknown(timestr, "UK"); + + var forum = Row.QuerySelector("a[href^=\"./viewforum.php?f=\"]"); + var forumid = forum.GetAttribute("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(forumid); + + var size = forum.NextElementSibling; + var sizestr = size.TextContent; + sizestr = sizestr.Replace("ГБ", "GB"); + sizestr = sizestr.Replace("МБ", "MB"); + sizestr = sizestr.Replace("КБ", "KB"); // untested + release.Size = ReleaseInfo.GetBytes(sizestr); + + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + catch (Exception ex) + { + logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); } - } + } } catch (Exception ex) { diff --git a/src/Jackett/Indexers/Abnormal.cs b/src/Jackett/Indexers/Abnormal.cs index c9948062..56bd2ca9 100644 --- a/src/Jackett/Indexers/Abnormal.cs +++ b/src/Jackett/Indexers/Abnormal.cs @@ -1,883 +1,883 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Web; -using CsQuery; -using Jackett.Models; -using Jackett.Models.IndexerConfig.Bespoke; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NLog; - -namespace Jackett.Indexers -{ - /// <summary> - /// Provider for Abnormal Private French Tracker - /// </summary> - public class Abnormal : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string SearchUrl { get { return SiteLink + "torrents.php"; } } - private string TorrentCommentUrl { get { return TorrentDescriptionUrl; } } - private string TorrentDescriptionUrl { get { return SiteLink + "torrents.php?id="; } } - private string TorrentDownloadUrl { get { return SiteLink + "torrents.php?action=download&id={id}&authkey={auth_key}&torrent_pass={torrent_pass}"; } } - private bool Latency { get { return ConfigData.Latency.Value; } } - private bool DevMode { get { return ConfigData.DevMode.Value; } } - private bool CacheMode { get { return ConfigData.HardDriveCache.Value; } } - private string directory { get { return System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType.Name + "\\"; } } - - private Dictionary<string, string> emulatedBrowserHeaders = new Dictionary<string, string>(); - private CQ fDom = null; - - private ConfigurationDataAbnormal ConfigData - { - get { return (ConfigurationDataAbnormal)configData; } - set { base.configData = value; } - } - - public Abnormal(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) - : base( - name: "Abnormal", - description: "General French Private Tracker", - link: "https://abnormal.ws/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - downloadBase: "https://abnormal.ws/torrents.php?action=download&id=", - configData: new ConfigurationDataAbnormal()) - { - Language = "fr-fr"; - Encoding = Encoding.UTF8; - Type = "private"; - - // Clean capabilities - TorznabCaps.Categories.Clear(); - - // Movies - AddCategoryMapping("MOVIE|DVDR", TorznabCatType.MoviesDVD); // DVDR - AddCategoryMapping("MOVIE|DVDRIP", TorznabCatType.MoviesSD); // DVDRIP - AddCategoryMapping("MOVIE|BDRIP", TorznabCatType.MoviesSD); // BDRIP - AddCategoryMapping("MOVIE|VOSTFR", TorznabCatType.MoviesOther); // VOSTFR - AddCategoryMapping("MOVIE|HD|720p", TorznabCatType.MoviesHD); // HD 720P - AddCategoryMapping("MOVIE|HD|1080p", TorznabCatType.MoviesHD); // HD 1080P - AddCategoryMapping("MOVIE|REMUXBR", TorznabCatType.MoviesBluRay); // REMUX BLURAY - AddCategoryMapping("MOVIE|FULLBR", TorznabCatType.MoviesBluRay); // FULL BLURAY - - // Series - AddCategoryMapping("TV|SD|VOSTFR", TorznabCatType.TV); // SD VOSTFR - AddCategoryMapping("TV|HD|VOSTFR", TorznabCatType.TVHD); // HD VOSTFR - AddCategoryMapping("TV|SD|VF", TorznabCatType.TVSD); // SD VF - AddCategoryMapping("TV|HD|VF", TorznabCatType.TVHD); // HD VF - AddCategoryMapping("TV|PACK|FR", TorznabCatType.TVOTHER); // PACK FR - AddCategoryMapping("TV|PACK|VOSTFR", TorznabCatType.TVOTHER); // PACK VOSTFR - AddCategoryMapping("TV|EMISSIONS", TorznabCatType.TVOTHER); // EMISSIONS - - // Anime - AddCategoryMapping("ANIME", TorznabCatType.TVAnime); // ANIME - - // Documentaries - AddCategoryMapping("DOCS", TorznabCatType.TVDocumentary); // DOCS - - // Music - AddCategoryMapping("MUSIC|FLAC", TorznabCatType.AudioLossless); // FLAC - AddCategoryMapping("MUSIC|MP3", TorznabCatType.AudioMP3); // MP3 - AddCategoryMapping("MUSIC|CONCERT", TorznabCatType.AudioVideo); // CONCERT - - // Other - AddCategoryMapping("PC|APP", TorznabCatType.PC); // PC - AddCategoryMapping("PC|GAMES", TorznabCatType.PCGames); // GAMES - AddCategoryMapping("EBOOKS", TorznabCatType.BooksEbook); // EBOOKS - } - - /// <summary> - /// Configure our WiHD Provider - /// </summary> - /// <param name="configJson">Our params in Json</param> - /// <returns>Configuration state</returns> - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - // Retrieve config values set by Jackett's user - 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"); - - // If we want to simulate a browser - if (ConfigData.Browser.Value) { - - // Clean headers - emulatedBrowserHeaders.Clear(); - - // Inject headers - emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value); - emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value); - emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDNT.Value).ToString()); - emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString()); - emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value); - } - - - // Getting login form to retrieve CSRF token - var myRequest = new Utils.Clients.WebRequest() - { - Url = LoginUrl - }; - - // Add our headers to request - myRequest.Headers = emulatedBrowserHeaders; - - // Building login form data - var pairs = new Dictionary<string, string> { - { "username", ConfigData.Username.Value }, - { "password", ConfigData.Password.Value }, - { "keeplogged", "1" }, - { "login", "Connexion" } - }; - - // Do the login - var request = new Utils.Clients.WebRequest(){ - PostData = pairs, - Referer = LoginUrl, - Type = RequestType.POST, - Url = LoginUrl, - Headers = emulatedBrowserHeaders - }; - - // Perform loggin - latencyNow(); - output("\nPerform loggin.. with " + LoginUrl); - var response = await webclient.GetString(request); - - // Test if we are logged in - await ConfigureIfOK(response.Cookies, response.Cookies.Contains("session="), () => - { - // Parse error page - CQ dom = response.Content; - string message = dom[".warning"].Text().Split('.').Reverse().Skip(1).First(); - - // Try left - string left = dom[".info"].Text().Trim(); - - // Oops, unable to login - output("-> Login failed: \"" + message + "\" and " + left + " tries left before being banned for 6 hours !", "error"); - throw new ExceptionWithConfigData("Login failed: " + message, configData); - }); - - output("-> Login Success"); - - return IndexerConfigurationStatus.RequiresTesting; - } - - /// <summary> - /// Execute our search query - /// </summary> - /// <param name="query">Query</param> - /// <returns>Releases</returns> - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var torrentRowList = new List<CQ>(); - var searchTerm = query.GetQueryString(); - var searchUrl = SearchUrl; - int nbResults = 0; - int pageLinkCount = 0; - - // 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.Where(i => i.Query == searchTerm).FirstOrDefault(); - if (cachedResult != null) - return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); - } - } - - // Build our query - var request = buildQuery(searchTerm, query, searchUrl); - - // Getting results & Store content - WebClientStringResult results = await queryExec(request); - fDom = results.Content; - - try - { - // Find torrent rows - var firstPageRows = findTorrentRows(); - - // Add them to torrents list - torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq())); - - // Check if there are pagination links at bottom - Boolean pagination = (fDom[".linkbox > a"].Length != 0); - - // If pagination available - if (pagination) { - // Calculate numbers of pages available for this search query (Based on number results and number of torrents on first page) - pageLinkCount = ParseUtil.CoerceInt(Regex.Match(fDom[".linkbox > a"].Last().Attr("href").ToString(), @"\d+").Value); - - // Calculate average number of results (based on torrents rows lenght on first page) - nbResults = firstPageRows.Count() * pageLinkCount; - } - else { - // Check if we have a minimum of one result - if (firstPageRows.Length >= 1) - { - // Retrieve total count on our alone page - nbResults = firstPageRows.Count(); - pageLinkCount = 1; - } - else - { - output("\nNo result found for your query, please try another search term ...\n", "info"); - // No result found for this query - return releases; - } - } - output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); - output("\nThere are " + firstPageRows.Length + " results on the first page !"); - - // If we have a term used for search and pagination result superior to one - if (!string.IsNullOrWhiteSpace(query.GetQueryString()) && pageLinkCount > 1) - { - // Starting with page #2 - for (int i = 2; i <= Math.Min(Int32.Parse(ConfigData.Pages.Value), pageLinkCount); i++) - { - output("\nProcessing page #" + i); - - // Request our page - latencyNow(); - - // Build our query - var pageRequest = buildQuery(searchTerm, query, searchUrl, i); - - // Getting results & Store content - WebClientStringResult pageResults = await queryExec(pageRequest); - - // Assign response - fDom = pageResults.Content; - - // Process page results - var additionalPageRows = findTorrentRows(); - - // Add them to torrents list - torrentRowList.AddRange(additionalPageRows.Select(fRow => fRow.Cq())); - } - } - else - { - // No search term, maybe testing... so registring autkey and torrentpass for future uses - string infosData = firstPageRows.First().Find("td:eq(3) > a").Attr("href"); - IList<string> infosList = infosData.Split('&').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); - IList<string> infosTracker = infosList.Select(s => s.Split(new[] { '=' }, 2)[1].Trim()).ToList(); - - output("\nStoring Authkey for future uses..."); - ConfigData.AuthKey.Value = infosTracker[2]; - - output("\nStoring TorrentPass for future uses..."); - ConfigData.TorrentPass.Value = infosTracker[3]; - - } - - // Loop on results - foreach (CQ tRow in torrentRowList) - { - output("\n=>> Torrent #" + (releases.Count + 1)); - - // ID - int id = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(1) > a").Attr("href").ToString(), @"\d+").Value); - output("ID: " + id); - - // Release Name - string name = tRow.Find("td:eq(1) > a").Text().ToString(); - output("Release: " + name); - - // Category - string categoryID = tRow.Find("td:eq(0) > a").Attr("href").Replace("torrents.php?cat[]=", String.Empty); - output("Category: " + MapTrackerCatToNewznab(categoryID) + " (" + categoryID + ")"); - - // Seeders - int seeders = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); - output("Seeders: " + seeders); - - // Leechers - int leechers = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(6)").Text(), @"\d+").Value); - output("Leechers: " + leechers); - - // Completed - int completed = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); - output("Completed: " + completed); - - // Size - string sizeStr = tRow.Find("td:eq(4)").Text().Replace("Go", "gb").Replace("Mo", "mb").Replace("Ko", "kb"); - long size = ReleaseInfo.GetBytes(sizeStr); - output("Size: " + sizeStr + " (" + size + " bytes)"); - - // Publish DateToString - IList<string> clockList = tRow.Find("td:eq(2) > span").Text().Replace("Il y a", "").Split(',').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); - var date = agoToDate(clockList); - output("Released on: " + date.ToLocalTime()); - - // Torrent Details URL - Uri detailsLink = new Uri(TorrentDescriptionUrl + id); - output("Details: " + detailsLink.AbsoluteUri); - - // Torrent Comments URL - Uri commentsLink = new Uri(TorrentCommentUrl + id); - output("Comments Link: " + commentsLink.AbsoluteUri); - - // Torrent Download URL - Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{auth_key}", ConfigData.AuthKey.Value).Replace("{torrent_pass}", ConfigData.TorrentPass.Value)); - output("Download Link: " + downloadLink.AbsoluteUri); - - // Building release infos - var release = new ReleaseInfo(); - release.Category = MapTrackerCatToNewznab(categoryID.ToString()); - release.Title = name; - release.Seeders = seeders; - release.Peers = seeders + leechers; - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.PublishDate = date; - release.Size = size; - release.Guid = detailsLink; - release.Comments = commentsLink; - release.Link = downloadLink; - - // freeleech - if (tRow.Find("img[alt=\"Freeleech\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - - } - catch (Exception ex) - { - OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); - } - - // Return found releases - return releases; - } - - /// <summary> - /// Build query to process - /// </summary> - /// <param name="term">Term to search</param> - /// <param name="query">Torznab Query for categories mapping</param> - /// <param name="url">Search url for provider</param> - /// <param name="page">Page number to request</param> - /// <returns>URL to query for parsing and processing results</returns> - private string buildQuery(string term, TorznabQuery query, string url, int page = 0) - { - var parameters = new NameValueCollection(); - List<string> categoriesList = MapTorznabCapsToTrackers(query); - string categories = null; - - // Check if we are processing a new page - if (page > 0) - { - // Adding page number to query - parameters.Add("page", page.ToString()); - } - - // Loop on Categories needed - foreach (string category in categoriesList) - { - // If last, build ! - if (categoriesList.Last() == category) - { - // Adding previous categories to URL with latest category - parameters.Add(Uri.EscapeDataString("cat[]"), HttpUtility.UrlEncode(category) + categories); - } - else - { - // Build categories parameter - categories += "&" + Uri.EscapeDataString("cat[]") + "=" + HttpUtility.UrlEncode(category); - } - } - - // If search term provided - if (!string.IsNullOrWhiteSpace(term)) - { - // Add search term - parameters.Add("search", HttpUtility.UrlEncode(term)); - } - else - { - parameters.Add("search", HttpUtility.UrlEncode("%")); - // Showing all torrents (just for output function) - term = "all"; - } - - // Building our query -- Cannot use GetQueryString due to UrlEncode (generating wrong cat[] param) - url += "?" + string.Join("&", parameters.AllKeys.Select(a => a + "=" + parameters[a])); - - output("\nBuilded query for \"" + term + "\"... " + url); - - // Return our search url - return url; - } - - /// <summary> - /// Switch Method for Querying - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> queryExec(string request) - { - WebClientStringResult results = null; - - // 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; - } - - /// <summary> - /// Get Torrents Page from Cache by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> queryCache(string request) - { - WebClientStringResult results = null; - - // 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<WebClientStringResult>(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; - } - - /// <summary> - /// Get Torrents Page from Tracker by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> queryTracker(string request) - { - WebClientStringResult results = null; - - // Cache mode not enabled or cached file didn't exist for our query - output("\nQuerying tracker for results...."); - - // Request our first page - latencyNow(); - results = await RequestStringWithCookiesAndRetry(request, null, null, emulatedBrowserHeaders); - - // Return results from tracker - return results; - } - - /// <summary> - /// Clean Hard Drive Cache Storage - /// </summary> - /// <param name="force">Force Provider Folder deletion</param> - private void cleanCacheStorage(Boolean 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 - { - int 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."); - } - } - } - - /// <summary> - /// Generate a random fake latency to avoid detection on tracker side - /// </summary> - private void latencyNow() - { - // Need latency ? - if(Latency) - { - // Generate a random value in our range - var random = new Random(DateTime.Now.Millisecond); - int waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value), Convert.ToInt32(ConfigData.LatencyEnd.Value)); - output("\nLatency Faker => Sleeping for " + waiting + " ms..."); - - // Sleep now... - System.Threading.Thread.Sleep(waiting); - } - } - - /// <summary> - /// Find torrent rows in search pages - /// </summary> - /// <returns>JQuery Object</returns> - private CQ findTorrentRows() - { - // Return all occurencis of torrents found - return fDom[".torrent_table > tbody > tr"].Not(".colhead"); - } - - /// <summary> - /// Convert Ago date to DateTime - /// </summary> - /// <param name="clockList"></param> - /// <returns>A DateTime</returns> - private DateTime agoToDate(IList<string> clockList) - { - DateTime release = DateTime.Now; - foreach (var ago in clockList) - { - // Check for years - if (ago.Contains("années") || ago.Contains("année")) - { - // Number of years to remove - int years = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddYears(-years); - - continue; - } - // Check for months - else if (ago.Contains("mois")) - { - // Number of months to remove - int months = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddMonths(-months); - - continue; - } - // Check for weeks - else if (ago.Contains("semaines") || ago.Contains("semaine")) - { - // Number of weeks to remove - int weeks = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddDays(-(7 * weeks)); - - continue; - } - // Check for days - else if (ago.Contains("jours") || ago.Contains("jour")) - { - // Number of days to remove - int days = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddDays(-days); - - continue; - } - // Check for hours - else if (ago.Contains("heures") || ago.Contains("heure")) - { - // Number of hours to remove - int hours = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddHours(-hours); - - continue; - } - // Check for minutes - else if (ago.Contains("mins") || ago.Contains("min")) - { - // Number of minutes to remove - int minutes = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddMinutes(-minutes); - - continue; - } - // Check for seconds - else if (ago.Contains("secondes") || ago.Contains("seconde")) - { - // Number of seconds to remove - int seconds = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); - // Removing - release = release.AddSeconds(-seconds); - - continue; - } - else - { - output("Unable to detect release date of torrent", "error"); - //throw new Exception("Unable to detect release date of torrent"); - } - } - return release; - } - - /// <summary> - /// Output message for logging or developpment (console) - /// </summary> - /// <param name="message">Message to output</param> - /// <param name="level">Level for Logger</param> - 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; - } - } - } - - /// <summary> - /// Validate Config entered by user on Jackett - /// </summary> - private void validateConfig() - { - output("\nValidating Settings ... \n"); - - // Check Username Setting - if (string.IsNullOrEmpty(ConfigData.Username.Value)) - { - throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData); - } - else - { - output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value.ToString()); - } - - // Check Password Setting - if (string.IsNullOrEmpty(ConfigData.Password.Value)) - { - throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData); - } - else - { - output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value.ToString()); - } - - // Check Max Page Setting - if (!string.IsNullOrEmpty(ConfigData.Pages.Value)) - { - try - { - output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData); - } - - // Check Latency Setting - if (ConfigData.Latency.Value) - { - output("\nValidated Setting -- Latency Simulation enabled"); - - // Check Latency Start Setting - if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value)) - { - try - { - output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData); - } - - // Check Latency End Setting - if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value)) - { - try - { - output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData); - } - } - - // Check Browser Setting - if (ConfigData.Browser.Value) - { - output("\nValidated Setting -- Browser Simulation enabled"); - - // Check ACCEPT header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData); - } - else - { - output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value.ToString()); - } - - // Check ACCEPT-LANG header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData); - } - else - { - output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value.ToString()); - } - - // Check USER-AGENT header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData); - } - else - { - output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value.ToString()); - } - } - - // Check Dev Cache Settings - if (ConfigData.HardDriveCache.Value == true) - { - 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); - } - } - } +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; +using CsQuery; +using Jackett.Models; +using Jackett.Models.IndexerConfig.Bespoke; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; + +namespace Jackett.Indexers +{ + /// <summary> + /// Provider for Abnormal Private French Tracker + /// </summary> + public class Abnormal : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string SearchUrl { get { return SiteLink + "torrents.php"; } } + private string TorrentCommentUrl { get { return TorrentDescriptionUrl; } } + private string TorrentDescriptionUrl { get { return SiteLink + "torrents.php?id="; } } + private string TorrentDownloadUrl { get { return SiteLink + "torrents.php?action=download&id={id}&authkey={auth_key}&torrent_pass={torrent_pass}"; } } + private bool Latency { get { return ConfigData.Latency.Value; } } + private bool DevMode { get { return ConfigData.DevMode.Value; } } + private bool CacheMode { get { return ConfigData.HardDriveCache.Value; } } + private string directory { get { return System.IO.Path.GetTempPath() + "Jackett\\" + MethodBase.GetCurrentMethod().DeclaringType.Name + "\\"; } } + + private Dictionary<string, string> emulatedBrowserHeaders = new Dictionary<string, string>(); + private CQ fDom = null; + + private ConfigurationDataAbnormal ConfigData + { + get { return (ConfigurationDataAbnormal)configData; } + set { base.configData = value; } + } + + public Abnormal(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) + : base( + name: "Abnormal", + description: "General French Private Tracker", + link: "https://abnormal.ws/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + downloadBase: "https://abnormal.ws/torrents.php?action=download&id=", + configData: new ConfigurationDataAbnormal()) + { + Language = "fr-fr"; + Encoding = Encoding.UTF8; + Type = "private"; + + // Clean capabilities + TorznabCaps.Categories.Clear(); + + // Movies + AddCategoryMapping("MOVIE|DVDR", TorznabCatType.MoviesDVD); // DVDR + AddCategoryMapping("MOVIE|DVDRIP", TorznabCatType.MoviesSD); // DVDRIP + AddCategoryMapping("MOVIE|BDRIP", TorznabCatType.MoviesSD); // BDRIP + AddCategoryMapping("MOVIE|VOSTFR", TorznabCatType.MoviesOther); // VOSTFR + AddCategoryMapping("MOVIE|HD|720p", TorznabCatType.MoviesHD); // HD 720P + AddCategoryMapping("MOVIE|HD|1080p", TorznabCatType.MoviesHD); // HD 1080P + AddCategoryMapping("MOVIE|REMUXBR", TorznabCatType.MoviesBluRay); // REMUX BLURAY + AddCategoryMapping("MOVIE|FULLBR", TorznabCatType.MoviesBluRay); // FULL BLURAY + + // Series + AddCategoryMapping("TV|SD|VOSTFR", TorznabCatType.TV); // SD VOSTFR + AddCategoryMapping("TV|HD|VOSTFR", TorznabCatType.TVHD); // HD VOSTFR + AddCategoryMapping("TV|SD|VF", TorznabCatType.TVSD); // SD VF + AddCategoryMapping("TV|HD|VF", TorznabCatType.TVHD); // HD VF + AddCategoryMapping("TV|PACK|FR", TorznabCatType.TVOTHER); // PACK FR + AddCategoryMapping("TV|PACK|VOSTFR", TorznabCatType.TVOTHER); // PACK VOSTFR + AddCategoryMapping("TV|EMISSIONS", TorznabCatType.TVOTHER); // EMISSIONS + + // Anime + AddCategoryMapping("ANIME", TorznabCatType.TVAnime); // ANIME + + // Documentaries + AddCategoryMapping("DOCS", TorznabCatType.TVDocumentary); // DOCS + + // Music + AddCategoryMapping("MUSIC|FLAC", TorznabCatType.AudioLossless); // FLAC + AddCategoryMapping("MUSIC|MP3", TorznabCatType.AudioMP3); // MP3 + AddCategoryMapping("MUSIC|CONCERT", TorznabCatType.AudioVideo); // CONCERT + + // Other + AddCategoryMapping("PC|APP", TorznabCatType.PC); // PC + AddCategoryMapping("PC|GAMES", TorznabCatType.PCGames); // GAMES + AddCategoryMapping("EBOOKS", TorznabCatType.BooksEbook); // EBOOKS + } + + /// <summary> + /// Configure our WiHD Provider + /// </summary> + /// <param name="configJson">Our params in Json</param> + /// <returns>Configuration state</returns> + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + // Retrieve config values set by Jackett's user + 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"); + + // If we want to simulate a browser + if (ConfigData.Browser.Value) { + + // Clean headers + emulatedBrowserHeaders.Clear(); + + // Inject headers + emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value); + emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value); + emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDNT.Value).ToString()); + emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString()); + emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value); + } + + + // Getting login form to retrieve CSRF token + var myRequest = new Utils.Clients.WebRequest() + { + Url = LoginUrl + }; + + // Add our headers to request + myRequest.Headers = emulatedBrowserHeaders; + + // Building login form data + var pairs = new Dictionary<string, string> { + { "username", ConfigData.Username.Value }, + { "password", ConfigData.Password.Value }, + { "keeplogged", "1" }, + { "login", "Connexion" } + }; + + // Do the login + var request = new Utils.Clients.WebRequest(){ + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + Url = LoginUrl, + Headers = emulatedBrowserHeaders + }; + + // Perform loggin + latencyNow(); + output("\nPerform loggin.. with " + LoginUrl); + var response = await webclient.GetString(request); + + // Test if we are logged in + await ConfigureIfOK(response.Cookies, response.Cookies.Contains("session="), () => + { + // Parse error page + CQ dom = response.Content; + string message = dom[".warning"].Text().Split('.').Reverse().Skip(1).First(); + + // Try left + string left = dom[".info"].Text().Trim(); + + // Oops, unable to login + output("-> Login failed: \"" + message + "\" and " + left + " tries left before being banned for 6 hours !", "error"); + throw new ExceptionWithConfigData("Login failed: " + message, configData); + }); + + output("-> Login Success"); + + return IndexerConfigurationStatus.RequiresTesting; + } + + /// <summary> + /// Execute our search query + /// </summary> + /// <param name="query">Query</param> + /// <returns>Releases</returns> + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var torrentRowList = new List<CQ>(); + var searchTerm = query.GetQueryString(); + var searchUrl = SearchUrl; + int nbResults = 0; + int pageLinkCount = 0; + + // 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.Where(i => i.Query == searchTerm).FirstOrDefault(); + if (cachedResult != null) + return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); + } + } + + // Build our query + var request = buildQuery(searchTerm, query, searchUrl); + + // Getting results & Store content + WebClientStringResult results = await queryExec(request); + fDom = results.Content; + + try + { + // Find torrent rows + var firstPageRows = findTorrentRows(); + + // Add them to torrents list + torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq())); + + // Check if there are pagination links at bottom + Boolean pagination = (fDom[".linkbox > a"].Length != 0); + + // If pagination available + if (pagination) { + // Calculate numbers of pages available for this search query (Based on number results and number of torrents on first page) + pageLinkCount = ParseUtil.CoerceInt(Regex.Match(fDom[".linkbox > a"].Last().Attr("href").ToString(), @"\d+").Value); + + // Calculate average number of results (based on torrents rows lenght on first page) + nbResults = firstPageRows.Count() * pageLinkCount; + } + else { + // Check if we have a minimum of one result + if (firstPageRows.Length >= 1) + { + // Retrieve total count on our alone page + nbResults = firstPageRows.Count(); + pageLinkCount = 1; + } + else + { + output("\nNo result found for your query, please try another search term ...\n", "info"); + // No result found for this query + return releases; + } + } + output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); + output("\nThere are " + firstPageRows.Length + " results on the first page !"); + + // If we have a term used for search and pagination result superior to one + if (!string.IsNullOrWhiteSpace(query.GetQueryString()) && pageLinkCount > 1) + { + // Starting with page #2 + for (int i = 2; i <= Math.Min(Int32.Parse(ConfigData.Pages.Value), pageLinkCount); i++) + { + output("\nProcessing page #" + i); + + // Request our page + latencyNow(); + + // Build our query + var pageRequest = buildQuery(searchTerm, query, searchUrl, i); + + // Getting results & Store content + WebClientStringResult pageResults = await queryExec(pageRequest); + + // Assign response + fDom = pageResults.Content; + + // Process page results + var additionalPageRows = findTorrentRows(); + + // Add them to torrents list + torrentRowList.AddRange(additionalPageRows.Select(fRow => fRow.Cq())); + } + } + else + { + // No search term, maybe testing... so registring autkey and torrentpass for future uses + string infosData = firstPageRows.First().Find("td:eq(3) > a").Attr("href"); + IList<string> infosList = infosData.Split('&').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); + IList<string> infosTracker = infosList.Select(s => s.Split(new[] { '=' }, 2)[1].Trim()).ToList(); + + output("\nStoring Authkey for future uses..."); + ConfigData.AuthKey.Value = infosTracker[2]; + + output("\nStoring TorrentPass for future uses..."); + ConfigData.TorrentPass.Value = infosTracker[3]; + + } + + // Loop on results + foreach (CQ tRow in torrentRowList) + { + output("\n=>> Torrent #" + (releases.Count + 1)); + + // ID + int id = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(1) > a").Attr("href").ToString(), @"\d+").Value); + output("ID: " + id); + + // Release Name + string name = tRow.Find("td:eq(1) > a").Text().ToString(); + output("Release: " + name); + + // Category + string categoryID = tRow.Find("td:eq(0) > a").Attr("href").Replace("torrents.php?cat[]=", String.Empty); + output("Category: " + MapTrackerCatToNewznab(categoryID) + " (" + categoryID + ")"); + + // Seeders + int seeders = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); + output("Seeders: " + seeders); + + // Leechers + int leechers = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(6)").Text(), @"\d+").Value); + output("Leechers: " + leechers); + + // Completed + int completed = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(5)").Text(), @"\d+").Value); + output("Completed: " + completed); + + // Size + string sizeStr = tRow.Find("td:eq(4)").Text().Replace("Go", "gb").Replace("Mo", "mb").Replace("Ko", "kb"); + long size = ReleaseInfo.GetBytes(sizeStr); + output("Size: " + sizeStr + " (" + size + " bytes)"); + + // Publish DateToString + IList<string> clockList = tRow.Find("td:eq(2) > span").Text().Replace("Il y a", "").Split(',').Select(s => s.Trim()).Where(s => s != String.Empty).ToList(); + var date = agoToDate(clockList); + output("Released on: " + date.ToLocalTime()); + + // Torrent Details URL + Uri detailsLink = new Uri(TorrentDescriptionUrl + id); + output("Details: " + detailsLink.AbsoluteUri); + + // Torrent Comments URL + Uri commentsLink = new Uri(TorrentCommentUrl + id); + output("Comments Link: " + commentsLink.AbsoluteUri); + + // Torrent Download URL + Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{auth_key}", ConfigData.AuthKey.Value).Replace("{torrent_pass}", ConfigData.TorrentPass.Value)); + output("Download Link: " + downloadLink.AbsoluteUri); + + // Building release infos + var release = new ReleaseInfo(); + release.Category = MapTrackerCatToNewznab(categoryID.ToString()); + release.Title = name; + release.Seeders = seeders; + release.Peers = seeders + leechers; + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.PublishDate = date; + release.Size = size; + release.Guid = detailsLink; + release.Comments = commentsLink; + release.Link = downloadLink; + + // freeleech + if (tRow.Find("img[alt=\"Freeleech\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + + } + catch (Exception ex) + { + OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); + } + + // Return found releases + return releases; + } + + /// <summary> + /// Build query to process + /// </summary> + /// <param name="term">Term to search</param> + /// <param name="query">Torznab Query for categories mapping</param> + /// <param name="url">Search url for provider</param> + /// <param name="page">Page number to request</param> + /// <returns>URL to query for parsing and processing results</returns> + private string buildQuery(string term, TorznabQuery query, string url, int page = 0) + { + var parameters = new NameValueCollection(); + List<string> categoriesList = MapTorznabCapsToTrackers(query); + string categories = null; + + // Check if we are processing a new page + if (page > 0) + { + // Adding page number to query + parameters.Add("page", page.ToString()); + } + + // Loop on Categories needed + foreach (string category in categoriesList) + { + // If last, build ! + if (categoriesList.Last() == category) + { + // Adding previous categories to URL with latest category + parameters.Add(Uri.EscapeDataString("cat[]"), HttpUtility.UrlEncode(category) + categories); + } + else + { + // Build categories parameter + categories += "&" + Uri.EscapeDataString("cat[]") + "=" + HttpUtility.UrlEncode(category); + } + } + + // If search term provided + if (!string.IsNullOrWhiteSpace(term)) + { + // Add search term + parameters.Add("search", HttpUtility.UrlEncode(term)); + } + else + { + parameters.Add("search", HttpUtility.UrlEncode("%")); + // Showing all torrents (just for output function) + term = "all"; + } + + // Building our query -- Cannot use GetQueryString due to UrlEncode (generating wrong cat[] param) + url += "?" + string.Join("&", parameters.AllKeys.Select(a => a + "=" + parameters[a])); + + output("\nBuilded query for \"" + term + "\"... " + url); + + // Return our search url + return url; + } + + /// <summary> + /// Switch Method for Querying + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> queryExec(string request) + { + WebClientStringResult results = null; + + // 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; + } + + /// <summary> + /// Get Torrents Page from Cache by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> queryCache(string request) + { + WebClientStringResult results = null; + + // 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<WebClientStringResult>(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; + } + + /// <summary> + /// Get Torrents Page from Tracker by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> queryTracker(string request) + { + WebClientStringResult results = null; + + // Cache mode not enabled or cached file didn't exist for our query + output("\nQuerying tracker for results...."); + + // Request our first page + latencyNow(); + results = await RequestStringWithCookiesAndRetry(request, null, null, emulatedBrowserHeaders); + + // Return results from tracker + return results; + } + + /// <summary> + /// Clean Hard Drive Cache Storage + /// </summary> + /// <param name="force">Force Provider Folder deletion</param> + private void cleanCacheStorage(Boolean 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 + { + int 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."); + } + } + } + + /// <summary> + /// Generate a random fake latency to avoid detection on tracker side + /// </summary> + private void latencyNow() + { + // Need latency ? + if(Latency) + { + // Generate a random value in our range + var random = new Random(DateTime.Now.Millisecond); + int waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value), Convert.ToInt32(ConfigData.LatencyEnd.Value)); + output("\nLatency Faker => Sleeping for " + waiting + " ms..."); + + // Sleep now... + System.Threading.Thread.Sleep(waiting); + } + } + + /// <summary> + /// Find torrent rows in search pages + /// </summary> + /// <returns>JQuery Object</returns> + private CQ findTorrentRows() + { + // Return all occurencis of torrents found + return fDom[".torrent_table > tbody > tr"].Not(".colhead"); + } + + /// <summary> + /// Convert Ago date to DateTime + /// </summary> + /// <param name="clockList"></param> + /// <returns>A DateTime</returns> + private DateTime agoToDate(IList<string> clockList) + { + DateTime release = DateTime.Now; + foreach (var ago in clockList) + { + // Check for years + if (ago.Contains("années") || ago.Contains("année")) + { + // Number of years to remove + int years = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddYears(-years); + + continue; + } + // Check for months + else if (ago.Contains("mois")) + { + // Number of months to remove + int months = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddMonths(-months); + + continue; + } + // Check for weeks + else if (ago.Contains("semaines") || ago.Contains("semaine")) + { + // Number of weeks to remove + int weeks = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddDays(-(7 * weeks)); + + continue; + } + // Check for days + else if (ago.Contains("jours") || ago.Contains("jour")) + { + // Number of days to remove + int days = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddDays(-days); + + continue; + } + // Check for hours + else if (ago.Contains("heures") || ago.Contains("heure")) + { + // Number of hours to remove + int hours = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddHours(-hours); + + continue; + } + // Check for minutes + else if (ago.Contains("mins") || ago.Contains("min")) + { + // Number of minutes to remove + int minutes = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddMinutes(-minutes); + + continue; + } + // Check for seconds + else if (ago.Contains("secondes") || ago.Contains("seconde")) + { + // Number of seconds to remove + int seconds = ParseUtil.CoerceInt(Regex.Match(ago.ToString(), @"\d+").Value); + // Removing + release = release.AddSeconds(-seconds); + + continue; + } + else + { + output("Unable to detect release date of torrent", "error"); + //throw new Exception("Unable to detect release date of torrent"); + } + } + return release; + } + + /// <summary> + /// Output message for logging or developpment (console) + /// </summary> + /// <param name="message">Message to output</param> + /// <param name="level">Level for Logger</param> + 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; + } + } + } + + /// <summary> + /// Validate Config entered by user on Jackett + /// </summary> + private void validateConfig() + { + output("\nValidating Settings ... \n"); + + // Check Username Setting + if (string.IsNullOrEmpty(ConfigData.Username.Value)) + { + throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData); + } + else + { + output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value.ToString()); + } + + // Check Password Setting + if (string.IsNullOrEmpty(ConfigData.Password.Value)) + { + throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData); + } + else + { + output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value.ToString()); + } + + // Check Max Page Setting + if (!string.IsNullOrEmpty(ConfigData.Pages.Value)) + { + try + { + output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData); + } + + // Check Latency Setting + if (ConfigData.Latency.Value) + { + output("\nValidated Setting -- Latency Simulation enabled"); + + // Check Latency Start Setting + if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value)) + { + try + { + output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData); + } + + // Check Latency End Setting + if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value)) + { + try + { + output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData); + } + } + + // Check Browser Setting + if (ConfigData.Browser.Value) + { + output("\nValidated Setting -- Browser Simulation enabled"); + + // Check ACCEPT header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData); + } + else + { + output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value.ToString()); + } + + // Check ACCEPT-LANG header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData); + } + else + { + output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value.ToString()); + } + + // Check USER-AGENT header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData); + } + else + { + output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value.ToString()); + } + } + + // Check Dev Cache Settings + if (ConfigData.HardDriveCache.Value == true) + { + 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/Indexers/Abstract/AvistazTracker.cs b/src/Jackett/Indexers/Abstract/AvistazTracker.cs index e82cdc34..b3475e35 100644 --- a/src/Jackett/Indexers/Abstract/AvistazTracker.cs +++ b/src/Jackett/Indexers/Abstract/AvistazTracker.cs @@ -61,7 +61,7 @@ namespace Jackett.Indexers { "email_username", configData.Username.Value }, { "password", configData.Password.Value }, { "remember", "1" } - }; + }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginUrl); await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("auth/logout"), () => @@ -90,11 +90,11 @@ namespace Jackett.Indexers var episodeSearchUrl = string.Format(SearchUrl, category, HttpUtility.UrlEncode(query.GetQueryString())); var response = await RequestStringWithCookiesAndRetry(episodeSearchUrl); - if (response.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(episodeSearchUrl); + if (response.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(episodeSearchUrl); } try @@ -138,15 +138,15 @@ namespace Jackett.Indexers var grabs = row.Cq().Find("td:nth-child(9)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (row.Cq().Find("i.fa-star").Any()) - release.DownloadVolumeFactor = 0; - else if (row.Cq().Find("i.fa-star-half-o").Any()) - release.DownloadVolumeFactor = 0.5; + if (row.Cq().Find("i.fa-star").Any()) + release.DownloadVolumeFactor = 0; + else if (row.Cq().Find("i.fa-star-half-o").Any()) + release.DownloadVolumeFactor = 0.5; else release.DownloadVolumeFactor = 1; - if (row.Cq().Find("i.fa-diamond").Any()) - release.UploadVolumeFactor = 2; + if (row.Cq().Find("i.fa-diamond").Any()) + release.UploadVolumeFactor = 2; else release.UploadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/Abstract/GazelleTracker.cs b/src/Jackett/Indexers/Abstract/GazelleTracker.cs index 6c7d2154..de539650 100644 --- a/src/Jackett/Indexers/Abstract/GazelleTracker.cs +++ b/src/Jackett/Indexers/Abstract/GazelleTracker.cs @@ -1,27 +1,27 @@ -using AngleSharp.Parser.Html; -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web; - -namespace Jackett.Indexers.Abstract -{ +using AngleSharp.Parser.Html; +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; + +namespace Jackett.Indexers.Abstract +{ public abstract class GazelleTracker : BaseIndexer { protected string LoginUrl { get { return SiteLink + "login.php"; } } protected string APIUrl { get { return SiteLink + "ajax.php"; } } - protected string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } } + protected string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } } protected string DetailsUrl { get { return SiteLink + "torrents.php?torrentid="; } } new ConfigurationDataBasicLogin configData @@ -44,199 +44,199 @@ namespace Jackett.Indexers.Abstract Encoding = Encoding.GetEncoding("UTF-8"); } - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - }; - - var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink); - await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () => - { - var loginResultParser = new HtmlParser(); - var loginResultDocument = loginResultParser.Parse(response.Content); - var loginform = loginResultDocument.QuerySelector("#loginform"); - if (loginform == null) - throw new ExceptionWithConfigData(response.Content, configData); - - loginform.QuerySelector("table").Remove(); - var errorMessage = loginform.TextContent.Replace("\n\t", " ").Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + }; + + var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink); + await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php"), () => + { + var loginResultParser = new HtmlParser(); + var loginResultDocument = loginResultParser.Parse(response.Content); + var loginform = loginResultDocument.QuerySelector("#loginform"); + if (loginform == null) + throw new ExceptionWithConfigData(response.Content, configData); + + loginform.QuerySelector("table").Remove(); + var errorMessage = loginform.TextContent.Replace("\n\t", " ").Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - var searchUrl = APIUrl; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("action", "browse"); - //queryCollection.Add("group_results", "0"); # results won't include all information - queryCollection.Add("order_by", "time"); - queryCollection.Add("order_way", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("searchstr", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("filter_cat[" + cat + "]", "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var response = await RequestStringWithCookiesAndRetry(searchUrl); - - if (response.IsRedirect || query.IsTest) - { - // re-login - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(searchUrl); - } - - try - { - var json = JObject.Parse(response.Content); - foreach (JObject r in json["response"]["results"]) - { - var groupTime = DateTimeUtil.UnixTimestampToDateTime(long.Parse((string)r["groupTime"])); - var groupName = HttpUtility.HtmlDecode((string)r["groupName"]); - var artist = HttpUtility.HtmlDecode((string)r["artist"]); - var cover = (string)r["cover"]; - var tags = r["tags"].ToList(); - var groupYear = (string)r["groupYear"]; - var releaseType = (string)r["releaseType"]; - - var release = new ReleaseInfo(); - - release.PublishDate = groupTime; - - if (!string.IsNullOrEmpty(cover)) - release.BannerUrl = new Uri(cover); - - release.Title = ""; - if (!string.IsNullOrEmpty(artist)) - release.Title += artist + " - "; - release.Title += groupName; - if (!string.IsNullOrEmpty(groupYear)) - release.Title += " [" + groupYear + "]"; - if (!string.IsNullOrEmpty(releaseType)) - release.Title += " [" + releaseType + "]"; - - release.Description = ""; - if (tags != null && tags.Count > 0 && (string)tags[0] != "") - release.Description += "Tags: " + string.Join(", ", tags) + "\n"; - - if (r["torrents"] is JArray) - { - foreach (JObject torrent in r["torrents"]) - { - ReleaseInfo release2 = (ReleaseInfo)release.Clone(); - FillReleaseInfoFromJson(release2, torrent); - if (ReleaseInfoPostParse(release2, torrent, r)) - releases.Add(release2); - } - } - else - { - FillReleaseInfoFromJson(release, r); - if (ReleaseInfoPostParse(release, r, r)) - releases.Add(release); - } - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - - return releases; + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + + var searchUrl = APIUrl; + var queryCollection = new NameValueCollection(); + + queryCollection.Add("action", "browse"); + //queryCollection.Add("group_results", "0"); # results won't include all information + queryCollection.Add("order_by", "time"); + queryCollection.Add("order_way", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("searchstr", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("filter_cat[" + cat + "]", "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + + var response = await RequestStringWithCookiesAndRetry(searchUrl); + + if (response.IsRedirect || query.IsTest) + { + // re-login + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(searchUrl); + } + + try + { + var json = JObject.Parse(response.Content); + foreach (JObject r in json["response"]["results"]) + { + var groupTime = DateTimeUtil.UnixTimestampToDateTime(long.Parse((string)r["groupTime"])); + var groupName = HttpUtility.HtmlDecode((string)r["groupName"]); + var artist = HttpUtility.HtmlDecode((string)r["artist"]); + var cover = (string)r["cover"]; + var tags = r["tags"].ToList(); + var groupYear = (string)r["groupYear"]; + var releaseType = (string)r["releaseType"]; + + var release = new ReleaseInfo(); + + release.PublishDate = groupTime; + + if (!string.IsNullOrEmpty(cover)) + release.BannerUrl = new Uri(cover); + + release.Title = ""; + if (!string.IsNullOrEmpty(artist)) + release.Title += artist + " - "; + release.Title += groupName; + if (!string.IsNullOrEmpty(groupYear)) + release.Title += " [" + groupYear + "]"; + if (!string.IsNullOrEmpty(releaseType)) + release.Title += " [" + releaseType + "]"; + + release.Description = ""; + if (tags != null && tags.Count > 0 && (string)tags[0] != "") + release.Description += "Tags: " + string.Join(", ", tags) + "\n"; + + if (r["torrents"] is JArray) + { + foreach (JObject torrent in r["torrents"]) + { + ReleaseInfo release2 = (ReleaseInfo)release.Clone(); + FillReleaseInfoFromJson(release2, torrent); + if (ReleaseInfoPostParse(release2, torrent, r)) + releases.Add(release2); + } + } + else + { + FillReleaseInfoFromJson(release, r); + if (ReleaseInfoPostParse(release, r, r)) + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + return releases; } // hook to add/modify the parsed information, return false to exclude the torrent from the results - protected virtual bool ReleaseInfoPostParse(ReleaseInfo release, JObject torrent, JObject result) - { - return true; + protected virtual bool ReleaseInfoPostParse(ReleaseInfo release, JObject torrent, JObject result) + { + return true; } - void FillReleaseInfoFromJson(ReleaseInfo release, JObject torrent) - { - var torrentId = torrent["torrentId"]; - - var time = (string)torrent["time"]; - if (!string.IsNullOrEmpty(time)) { - release.PublishDate = DateTime.ParseExact(time+" +0000", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); - } - - var flags = new List<string>(); - - var format = (string)torrent["format"]; - if (!string.IsNullOrEmpty(format)) - flags.Add(format); - - var encoding = (string)torrent["encoding"]; - if (!string.IsNullOrEmpty(encoding)) - flags.Add(encoding); - - if(torrent["hasLog"] != null && (bool)torrent["hasLog"]) - { - var logScore = (string)torrent["logScore"]; - flags.Add("Log (" + logScore + "%)"); - } - - if (torrent["hasCue"] != null && (bool)torrent["hasCue"]) - flags.Add("Cue"); - - var media = (string)torrent["media"]; - if (!string.IsNullOrEmpty(media)) - flags.Add(media); - - if (torrent["remastered"] != null && (bool)torrent["remastered"]) - { - var remasterYear = (string)torrent["remasterYear"]; - var remasterTitle = HttpUtility.HtmlDecode((string)torrent["remasterTitle"]); - flags.Add(remasterYear + (!string.IsNullOrEmpty(remasterTitle) ? " " + remasterTitle : "")); - } - - if (flags.Count > 0) - release.Title += " " + string.Join(" / ", flags); - - release.Size = (long)torrent["size"]; - release.Seeders = (int)torrent["seeders"]; - release.Peers = (int)torrent["leechers"] + release.Seeders; - release.Comments = new Uri(DetailsUrl + torrentId); - release.Guid = release.Comments; - release.Link = new Uri(DownloadUrl + torrentId); - var category = (string)torrent["category"]; - if (category == null || category.Contains("Select Category")) - release.Category = MapTrackerCatToNewznab("1"); - else - release.Category = MapTrackerCatDescToNewznab(category); - release.Files = (int)torrent["fileCount"]; - release.Grabs = (int)torrent["snatches"]; - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - if ((bool)torrent["isFreeleech"]) - { - release.DownloadVolumeFactor = 0; - } - if ((bool)torrent["isPersonalFreeleech"]) - { - release.DownloadVolumeFactor = 0; - } - if ((bool)torrent["isNeutralLeech"]) - { - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 0; - } + void FillReleaseInfoFromJson(ReleaseInfo release, JObject torrent) + { + var torrentId = torrent["torrentId"]; + + var time = (string)torrent["time"]; + if (!string.IsNullOrEmpty(time)) { + release.PublishDate = DateTime.ParseExact(time+" +0000", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); + } + + var flags = new List<string>(); + + var format = (string)torrent["format"]; + if (!string.IsNullOrEmpty(format)) + flags.Add(format); + + var encoding = (string)torrent["encoding"]; + if (!string.IsNullOrEmpty(encoding)) + flags.Add(encoding); + + if(torrent["hasLog"] != null && (bool)torrent["hasLog"]) + { + var logScore = (string)torrent["logScore"]; + flags.Add("Log (" + logScore + "%)"); + } + + if (torrent["hasCue"] != null && (bool)torrent["hasCue"]) + flags.Add("Cue"); + + var media = (string)torrent["media"]; + if (!string.IsNullOrEmpty(media)) + flags.Add(media); + + if (torrent["remastered"] != null && (bool)torrent["remastered"]) + { + var remasterYear = (string)torrent["remasterYear"]; + var remasterTitle = HttpUtility.HtmlDecode((string)torrent["remasterTitle"]); + flags.Add(remasterYear + (!string.IsNullOrEmpty(remasterTitle) ? " " + remasterTitle : "")); + } + + if (flags.Count > 0) + release.Title += " " + string.Join(" / ", flags); + + release.Size = (long)torrent["size"]; + release.Seeders = (int)torrent["seeders"]; + release.Peers = (int)torrent["leechers"] + release.Seeders; + release.Comments = new Uri(DetailsUrl + torrentId); + release.Guid = release.Comments; + release.Link = new Uri(DownloadUrl + torrentId); + var category = (string)torrent["category"]; + if (category == null || category.Contains("Select Category")) + release.Category = MapTrackerCatToNewznab("1"); + else + release.Category = MapTrackerCatDescToNewznab(category); + release.Files = (int)torrent["fileCount"]; + release.Grabs = (int)torrent["snatches"]; + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + if ((bool)torrent["isFreeleech"]) + { + release.DownloadVolumeFactor = 0; + } + if ((bool)torrent["isPersonalFreeleech"]) + { + release.DownloadVolumeFactor = 0; + } + if ((bool)torrent["isNeutralLeech"]) + { + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 0; + } } - } -} + } +} diff --git a/src/Jackett/Indexers/AlphaRatio.cs b/src/Jackett/Indexers/AlphaRatio.cs index b00215b7..d79da44d 100644 --- a/src/Jackett/Indexers/AlphaRatio.cs +++ b/src/Jackett/Indexers/AlphaRatio.cs @@ -1,219 +1,219 @@ -using CsQuery; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Net.Http.Headers; -using Jackett.Models; -using Jackett.Utils; -using NLog; -using Jackett.Services; -using Jackett.Utils.Clients; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - -namespace Jackett.Indexers -{ - public class AlphaRatio : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string SearchUrl { get { return SiteLink + "ajax.php?action=browse&order_by=time&order_way=desc&"; } } - private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } } - private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } } - - public AlphaRatio(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) - : base(name: "AlphaRatio", - description: "Legendary", - link: "https://alpharatio.cc/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - downloadBase: "https://alpharatio.cc/torrents.php?action=download&id=", - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(1, TorznabCatType.TVSD); - AddCategoryMapping(2, TorznabCatType.TVHD); - AddCategoryMapping(3, TorznabCatType.TVSD); - AddCategoryMapping(4, TorznabCatType.TVSD); - AddCategoryMapping(5, TorznabCatType.TVHD); - AddCategoryMapping(6, TorznabCatType.MoviesSD); - AddCategoryMapping(7, TorznabCatType.MoviesHD); - AddCategoryMapping(8, TorznabCatType.MoviesSD); - AddCategoryMapping(9, TorznabCatType.MoviesHD); - AddCategoryMapping(10, TorznabCatType.XXX); - AddCategoryMapping(20, TorznabCatType.XXX); - AddCategoryMapping(12, TorznabCatType.PCGames); - AddCategoryMapping(13, TorznabCatType.ConsoleXbox); - AddCategoryMapping(14, TorznabCatType.ConsolePS3); - AddCategoryMapping(15, TorznabCatType.ConsoleWii); - AddCategoryMapping(16, TorznabCatType.PC); - AddCategoryMapping(17, TorznabCatType.PCMac); - AddCategoryMapping(19, TorznabCatType.PCPhoneOther); - AddCategoryMapping(21, TorznabCatType.BooksEbook); - AddCategoryMapping(22, TorznabCatType.AudioAudiobook); - AddCategoryMapping(23, TorznabCatType.Audio); - } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "login", "Login" }, - { "keeplogged", "1" } - }; - - // Do the login - var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink); - await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php?"), () => - { - CQ dom = response.Content; - dom["#loginform > table"].Remove(); - var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " "); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - void FillReleaseInfoFromJson(ReleaseInfo release, JObject r) - { - var id = r["torrentId"]; - release.Size = (long)r["size"]; - release.Seeders = (int)r["seeders"]; - release.Peers = (int)r["leechers"] + release.Seeders; - release.Guid = new Uri(GuidUrl + id); - release.Comments = release.Guid; - release.Link = new Uri(DownloadUrl + id); - release.Category = MapTrackerCatToNewznab(CategoryReverseMapper((string)r["category"])); - release.Files = (int)r["fileCount"]; - release.Grabs = (int)r["snatches"]; - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - if ((bool)r["isFreeleech"]) - { - release.DownloadVolumeFactor = 0; - } - if ((bool)r["isPersonalFreeleech"]) - { - release.DownloadVolumeFactor = 0; - } - if ((bool)r["isNeutralLeech"]) - { - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 0; - } - - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("searchstr", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("filter_cat[" + cat + "]", "1"); - } - - searchUrl += queryCollection.GetQueryString(); - var response = await RequestStringWithCookiesAndRetry(searchUrl); - if (response.IsRedirect) - { - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(searchUrl); - } - - try - { - var json = JObject.Parse(response.Content); - foreach (JObject r in json["response"]["results"]) - { - DateTime pubDate = DateTime.MinValue; - double dateNum; - if (double.TryParse((string)r["groupTime"], out dateNum)) - pubDate = UnixTimestampToDateTime(dateNum); - - var groupName = (string)r["groupName"]; - - if (r["torrents"] is JArray) - { - foreach (JObject t in r["torrents"]) - { - var release = new ReleaseInfo(); - release.PublishDate = pubDate; - release.Title = groupName; - release.Description = groupName; - FillReleaseInfoFromJson(release, t); - releases.Add(release); - } - } - else - { - var release = new ReleaseInfo(); - release.PublishDate = pubDate; - release.Title = groupName; - release.Description = groupName; - FillReleaseInfoFromJson(release, r); - releases.Add(release); - } - - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - - return releases; - } - - static DateTime UnixTimestampToDateTime(double unixTime) - { - DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); - long unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond); - return new DateTime(unixStart.Ticks + unixTimeStampInTicks, DateTimeKind.Utc).ToLocalTime(); - } - - static string CategoryReverseMapper(string categoryName) - { - Dictionary<string, string> dictionary = new Dictionary<string, string>(); - - dictionary.Add("TvSD", "1"); - dictionary.Add("TvHD", "2"); - dictionary.Add("MovieSD", "6"); - dictionary.Add("MovieHD", "7"); - - if (dictionary.ContainsKey(categoryName)) - { - return dictionary[categoryName]; - } - return string.Empty; - } - } -} +using CsQuery; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Net.Http.Headers; +using Jackett.Models; +using Jackett.Utils; +using NLog; +using Jackett.Services; +using Jackett.Utils.Clients; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + public class AlphaRatio : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string SearchUrl { get { return SiteLink + "ajax.php?action=browse&order_by=time&order_way=desc&"; } } + private string DownloadUrl { get { return SiteLink + "torrents.php?action=download&id="; } } + private string GuidUrl { get { return SiteLink + "torrents.php?torrentid="; } } + + public AlphaRatio(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) + : base(name: "AlphaRatio", + description: "Legendary", + link: "https://alpharatio.cc/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + downloadBase: "https://alpharatio.cc/torrents.php?action=download&id=", + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(1, TorznabCatType.TVSD); + AddCategoryMapping(2, TorznabCatType.TVHD); + AddCategoryMapping(3, TorznabCatType.TVSD); + AddCategoryMapping(4, TorznabCatType.TVSD); + AddCategoryMapping(5, TorznabCatType.TVHD); + AddCategoryMapping(6, TorznabCatType.MoviesSD); + AddCategoryMapping(7, TorznabCatType.MoviesHD); + AddCategoryMapping(8, TorznabCatType.MoviesSD); + AddCategoryMapping(9, TorznabCatType.MoviesHD); + AddCategoryMapping(10, TorznabCatType.XXX); + AddCategoryMapping(20, TorznabCatType.XXX); + AddCategoryMapping(12, TorznabCatType.PCGames); + AddCategoryMapping(13, TorznabCatType.ConsoleXbox); + AddCategoryMapping(14, TorznabCatType.ConsolePS3); + AddCategoryMapping(15, TorznabCatType.ConsoleWii); + AddCategoryMapping(16, TorznabCatType.PC); + AddCategoryMapping(17, TorznabCatType.PCMac); + AddCategoryMapping(19, TorznabCatType.PCPhoneOther); + AddCategoryMapping(21, TorznabCatType.BooksEbook); + AddCategoryMapping(22, TorznabCatType.AudioAudiobook); + AddCategoryMapping(23, TorznabCatType.Audio); + } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "login", "Login" }, + { "keeplogged", "1" } + }; + + // Do the login + var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, string.Empty, true, SiteLink); + await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("logout.php?"), () => + { + CQ dom = response.Content; + dom["#loginform > table"].Remove(); + var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " "); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + void FillReleaseInfoFromJson(ReleaseInfo release, JObject r) + { + var id = r["torrentId"]; + release.Size = (long)r["size"]; + release.Seeders = (int)r["seeders"]; + release.Peers = (int)r["leechers"] + release.Seeders; + release.Guid = new Uri(GuidUrl + id); + release.Comments = release.Guid; + release.Link = new Uri(DownloadUrl + id); + release.Category = MapTrackerCatToNewznab(CategoryReverseMapper((string)r["category"])); + release.Files = (int)r["fileCount"]; + release.Grabs = (int)r["snatches"]; + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + if ((bool)r["isFreeleech"]) + { + release.DownloadVolumeFactor = 0; + } + if ((bool)r["isPersonalFreeleech"]) + { + release.DownloadVolumeFactor = 0; + } + if ((bool)r["isNeutralLeech"]) + { + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 0; + } + + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("searchstr", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("filter_cat[" + cat + "]", "1"); + } + + searchUrl += queryCollection.GetQueryString(); + var response = await RequestStringWithCookiesAndRetry(searchUrl); + if (response.IsRedirect) + { + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(searchUrl); + } + + try + { + var json = JObject.Parse(response.Content); + foreach (JObject r in json["response"]["results"]) + { + DateTime pubDate = DateTime.MinValue; + double dateNum; + if (double.TryParse((string)r["groupTime"], out dateNum)) + pubDate = UnixTimestampToDateTime(dateNum); + + var groupName = (string)r["groupName"]; + + if (r["torrents"] is JArray) + { + foreach (JObject t in r["torrents"]) + { + var release = new ReleaseInfo(); + release.PublishDate = pubDate; + release.Title = groupName; + release.Description = groupName; + FillReleaseInfoFromJson(release, t); + releases.Add(release); + } + } + else + { + var release = new ReleaseInfo(); + release.PublishDate = pubDate; + release.Title = groupName; + release.Description = groupName; + FillReleaseInfoFromJson(release, r); + releases.Add(release); + } + + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + return releases; + } + + static DateTime UnixTimestampToDateTime(double unixTime) + { + DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + long unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond); + return new DateTime(unixStart.Ticks + unixTimeStampInTicks, DateTimeKind.Utc).ToLocalTime(); + } + + static string CategoryReverseMapper(string categoryName) + { + Dictionary<string, string> dictionary = new Dictionary<string, string>(); + + dictionary.Add("TvSD", "1"); + dictionary.Add("TvHD", "2"); + dictionary.Add("MovieSD", "6"); + dictionary.Add("MovieHD", "7"); + + if (dictionary.ContainsKey(categoryName)) + { + return dictionary[categoryName]; + } + return string.Empty; + } + } +} diff --git a/src/Jackett/Indexers/Andraste.cs b/src/Jackett/Indexers/Andraste.cs index 03cd3f83..790b49a2 100644 --- a/src/Jackett/Indexers/Andraste.cs +++ b/src/Jackett/Indexers/Andraste.cs @@ -10,10 +10,10 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; -using System.Linq; - +using System.Collections.Specialized; +using System.Text; +using System.Linq; + namespace Jackett.Indexers { public class Andraste : BaseIndexer, IIndexer @@ -42,35 +42,35 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - AddCategoryMapping(9, TorznabCatType.Other); // Anderes - AddCategoryMapping(23, TorznabCatType.TVAnime); // Animation - Film &; Serie - AddCategoryMapping(1, TorznabCatType.PC); // Appz - AddCategoryMapping(52, TorznabCatType.Other); // Botuploads - AddCategoryMapping(25, TorznabCatType.TVDocumentary); // Doku - Alle Formate - AddCategoryMapping(27, TorznabCatType.Books); // E-Books - AddCategoryMapping(51, TorznabCatType.Movies3D); // Film/3D - AddCategoryMapping(20, TorznabCatType.MoviesDVD); // Film/DVDr - AddCategoryMapping(37, TorznabCatType.MoviesHD); // Film/HD 1080p++ - AddCategoryMapping(38, TorznabCatType.MoviesSD); // Film/HD 720p - AddCategoryMapping(36, TorznabCatType.Movies); // Film/im Kino - AddCategoryMapping(19, TorznabCatType.Movies); // Film/XviD,DivX,x264 - AddCategoryMapping(4, TorznabCatType.PCGames); // Games/PC - AddCategoryMapping(12, TorznabCatType.ConsolePS4); // Games/Playstation - AddCategoryMapping(22, TorznabCatType.ConsoleWii); // Games/Wii & DS - AddCategoryMapping(21, TorznabCatType.ConsoleXbox); // Games/Xbox & 360 - AddCategoryMapping(48, TorznabCatType.PCPhoneAndroid); // Handy & PDA/Android - AddCategoryMapping(47, TorznabCatType.PCPhoneIOS); // Handy & PDA/iOS - AddCategoryMapping(44, TorznabCatType.PCMac); // Macintosh - AddCategoryMapping(41, TorznabCatType.Other); // MegaPack - AddCategoryMapping(24, TorznabCatType.AudioAudiobook); // Musik/Hörbuch & Hörspiel - AddCategoryMapping(46, TorznabCatType.Audio); // Musik/HQ 320++ - AddCategoryMapping(6, TorznabCatType.Audio); // Musik/Musik - AddCategoryMapping(26, TorznabCatType.AudioVideo); // Musik/Musikvideos - AddCategoryMapping(29, TorznabCatType.TVSD); // Serien/DVDr - AddCategoryMapping(35, TorznabCatType.TVHD); // Serien/HD 720p++ - AddCategoryMapping(7, TorznabCatType.TV); // Serien/XviD,DivX,x264 - AddCategoryMapping(45, TorznabCatType.TV); // Shows - AddCategoryMapping(40, TorznabCatType.TVSport); // Sport + AddCategoryMapping(9, TorznabCatType.Other); // Anderes + AddCategoryMapping(23, TorznabCatType.TVAnime); // Animation - Film &; Serie + AddCategoryMapping(1, TorznabCatType.PC); // Appz + AddCategoryMapping(52, TorznabCatType.Other); // Botuploads + AddCategoryMapping(25, TorznabCatType.TVDocumentary); // Doku - Alle Formate + AddCategoryMapping(27, TorznabCatType.Books); // E-Books + AddCategoryMapping(51, TorznabCatType.Movies3D); // Film/3D + AddCategoryMapping(20, TorznabCatType.MoviesDVD); // Film/DVDr + AddCategoryMapping(37, TorznabCatType.MoviesHD); // Film/HD 1080p++ + AddCategoryMapping(38, TorznabCatType.MoviesSD); // Film/HD 720p + AddCategoryMapping(36, TorznabCatType.Movies); // Film/im Kino + AddCategoryMapping(19, TorznabCatType.Movies); // Film/XviD,DivX,x264 + AddCategoryMapping(4, TorznabCatType.PCGames); // Games/PC + AddCategoryMapping(12, TorznabCatType.ConsolePS4); // Games/Playstation + AddCategoryMapping(22, TorznabCatType.ConsoleWii); // Games/Wii & DS + AddCategoryMapping(21, TorznabCatType.ConsoleXbox); // Games/Xbox & 360 + AddCategoryMapping(48, TorznabCatType.PCPhoneAndroid); // Handy & PDA/Android + AddCategoryMapping(47, TorznabCatType.PCPhoneIOS); // Handy & PDA/iOS + AddCategoryMapping(44, TorznabCatType.PCMac); // Macintosh + AddCategoryMapping(41, TorznabCatType.Other); // MegaPack + AddCategoryMapping(24, TorznabCatType.AudioAudiobook); // Musik/Hörbuch & Hörspiel + AddCategoryMapping(46, TorznabCatType.Audio); // Musik/HQ 320++ + AddCategoryMapping(6, TorznabCatType.Audio); // Musik/Musik + AddCategoryMapping(26, TorznabCatType.AudioVideo); // Musik/Musikvideos + AddCategoryMapping(29, TorznabCatType.TVSD); // Serien/DVDr + AddCategoryMapping(35, TorznabCatType.TVHD); // Serien/HD 720p++ + AddCategoryMapping(7, TorznabCatType.TV); // Serien/XviD,DivX,x264 + AddCategoryMapping(45, TorznabCatType.TV); // Shows + AddCategoryMapping(40, TorznabCatType.TVSport); // Sport AddCategoryMapping(32, TorznabCatType.XXX); // XXX } @@ -85,44 +85,44 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var errorMessage = dom["table.tableinborder"].Html(); - errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom["table.tableinborder"].Html(); + errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("showsearch", "1"); - queryCollection.Add("incldead", "1"); - queryCollection.Add("orderby", "added"); - queryCollection.Add("sort", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "1"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookies(searchUrl); @@ -136,50 +136,50 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - release.Title = qDetailsLink.Attr("title"); - - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - var qDLLink = qRow.Find("a[href^=download.php?torrent=]").First(); - var qSeeders = qRow.Find("span:contains(Seeder) > b:eq(0)"); - var qLeechers = qRow.Find("span:contains(Seeder) > b:eq(1)"); - var qDateStr = qRow.Find("td > table > tbody > tr > td:eq(7)").First(); - var qSize = qRow.Find("span:contains(Volumen) > b:eq(0)").First(); - var qOnlyUpload = qRow.Find("img[title=OnlyUpload]"); - - if(qOnlyUpload.Any()) - { - release.MinimumRatio = 2; - release.MinimumSeedTime = 144 * 60 * 60; - } - else - { - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 60 * 60; - } - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDLLink.Attr("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Attr("title"); + + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qDLLink = qRow.Find("a[href^=download.php?torrent=]").First(); + var qSeeders = qRow.Find("span:contains(Seeder) > b:eq(0)"); + var qLeechers = qRow.Find("span:contains(Seeder) > b:eq(1)"); + var qDateStr = qRow.Find("td > table > tbody > tr > td:eq(7)").First(); + var qSize = qRow.Find("span:contains(Volumen) > b:eq(0)").First(); + var qOnlyUpload = qRow.Find("img[title=OnlyUpload]"); + + if(qOnlyUpload.Any()) + { + release.MinimumRatio = 2; + release.MinimumSeedTime = 144 * 60 * 60; + } + else + { + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + } + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDLLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text().Trim().Replace('\xA0', ' '); - DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc.ToLocalTime(); var files = qRow.Find("a[href*=\"&filelist=1\"] ~ font ~ b").Text(); @@ -190,8 +190,8 @@ namespace Jackett.Indexers if (globalFreeleech) release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[alt=\"OU\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[alt=\"OU\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs index 99739e64..f3495cfa 100644 --- a/src/Jackett/Indexers/AnimeBytes.cs +++ b/src/Jackett/Indexers/AnimeBytes.cs @@ -1,474 +1,474 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Models.IndexerConfig.Bespoke; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Web; - -namespace Jackett.Indexers -{ - public class AnimeBytes : BaseIndexer, IIndexer - { - enum SearchType - { - Video, - Audio - } - - private string LoginUrl { get { return SiteLink + "user/login"; } } - private string SearchUrl { get { return SiteLink + "torrents.php?"; } } - private string MusicSearchUrl { get { return SiteLink + "torrents2.php?"; } } - public bool AllowRaws { get { return configData.IncludeRaw.Value; } } - public bool InsertSeason { get { return configData.InsertSeason!=null && configData.InsertSeason.Value; } } - - new ConfigurationDataAnimeBytes configData - { - get { return (ConfigurationDataAnimeBytes)base.configData; } - set { base.configData = value; } - } - - public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps) - : base(name: "AnimeBytes", - link: "https://animebytes.tv/", - description: "Powered by Tentacles", - manager: i, - client: client, - caps: new TorznabCapabilities(TorznabCatType.TVAnime, - TorznabCatType.Movies, - TorznabCatType.BooksComics, - TorznabCatType.ConsolePSP, - TorznabCatType.ConsoleOther, - TorznabCatType.PCGames, - TorznabCatType.AudioMP3, - TorznabCatType.AudioLossless, - TorznabCatType.AudioOther), - logger: l, - p: ps, - configData: new ConfigurationDataAnimeBytes()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - } - - - public override IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> input) - { - // Prevent filtering - return input; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - lock (cache) - { - cache.Clear(); - } - - // Get the login form as we need the CSRF Token - var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() - { - Url = LoginUrl, - Encoding = Encoding - }); - - CQ loginPageDom = loginPage.Content; - var csrfIndex = loginPageDom["input[name=\"_CSRF_INDEX\"]"].Last(); - var csrfToken = loginPageDom["input[name=\"_CSRF_TOKEN\"]"].Last(); - - // Build login form - var pairs = new Dictionary<string, string> { - { "_CSRF_INDEX", csrfIndex.Attr("value") }, - { "_CSRF_TOKEN", csrfToken.Attr("value") }, - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "keeplogged_sent", "true" }, - { "keeplogged", "on" }, - { "login", "Log In!" } - }; - - // Do the login - var request = new Utils.Clients.WebRequest() - { - Cookies = loginPage.Cookies, - PostData = pairs, - Referer = LoginUrl, - Type = RequestType.POST, - Encoding = Encoding, - Url = LoginUrl - }; - var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null); - - // Follow the redirect - await FollowIfRedirect(response, request.Url, SearchUrl); - - await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () => - { - // Their login page appears to be broken and just gives a 500 error. - throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - // Override to load legacy config format - public override void LoadFromSavedConfiguration(JToken jsonConfig) - { - if (jsonConfig is JObject) - { - configData.CookieHeader.Value = jsonConfig.Value<string>("cookies"); - configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws"); - SaveConfig(); - IsConfigured = true; - return; - } - - base.LoadFromSavedConfiguration(jsonConfig); - } - - private string StripEpisodeNumber(string term) - { - // Tracer does not support searching with episode number so strip it if we have one - term = Regex.Replace(term, @"\W(\dx)?\d?\d$", string.Empty); - term = Regex.Replace(term, @"\W(S\d\d?E)?\d?\d$", string.Empty); - return term; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - // The result list - var releases = new List<ReleaseInfo>(); - - if (ContainsMusicCategories(query.Categories)) - { - foreach (var result in await GetResults(SearchType.Audio, query.SanitizedSearchTerm)) - { - releases.Add(result); - } - } - - foreach (var result in await GetResults(SearchType.Video, StripEpisodeNumber(query.SanitizedSearchTerm))) - { - releases.Add(result); - } - - return releases.ToArray(); - } - - private bool ContainsMusicCategories(int[] categories) - { - var music = new[] - { - TorznabCatType.Audio.ID, - TorznabCatType.AudioMP3.ID, - TorznabCatType.AudioLossless.ID, - TorznabCatType.AudioOther.ID, - TorznabCatType.AudioForeign.ID - }; - - return categories.Length == 0 || music.Any(categories.Contains); - } - - private async Task<IEnumerable<ReleaseInfo>> GetResults(SearchType searchType, string searchTerm) - { - var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm); - - // The result list - var releases = new List<ReleaseInfo>(); - - var queryUrl = searchType == SearchType.Video ? SearchUrl : MusicSearchUrl; - // Only include the query bit if its required as hopefully the site caches the non query page - if (!string.IsNullOrWhiteSpace(searchTerm)) - { - queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm); - } - - // Check cache first so we don't query the server for each episode when searching for each episode in a series. - lock (cache) - { - // Remove old cache items - CleanCache(); - - var cachedResult = cache.Where(i => i.Query == queryUrl).FirstOrDefault(); - if (cachedResult != null) - return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); - } - - // Get the content from the tracker - var response = await RequestStringWithCookiesAndRetry(queryUrl); - if (response.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(queryUrl); - } - - CQ dom = response.Content; - - // Parse - try - { - var releaseInfo = "S01"; - var root = dom.Find(".group_cont"); - // We may have got redirected to the series page if we have none of these - if (root.Count() == 0) - root = dom.Find(".torrent_table"); - - foreach (var series in root) - { - var seriesCq = series.Cq(); - - var synonyms = new List<string>(); - string mainTitle; - if (searchType == SearchType.Video) - mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim(); - else - mainTitle = seriesCq.Find(".group_title strong").Text().Trim(); - - var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim(); - int yearIndex = yearStr.LastIndexOf("["); - if (yearIndex > -1) - yearStr = yearStr.Substring(yearIndex + 1); - - int year = 0; - if (!int.TryParse(yearStr, out year)) - year = DateTime.Now.Year; - - synonyms.Add(mainTitle); - - // If the title contains a comma then we can't use the synonyms as they are comma seperated - if (!mainTitle.Contains(",")) - { - var symnomnNames = string.Empty; - foreach (var e in seriesCq.Find(".group_statbox li")) - { - if (e.FirstChild.InnerText == "Synonyms:") - { - symnomnNames = e.InnerText; - } - } - - if (!string.IsNullOrWhiteSpace(symnomnNames)) - { - foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) - { - var theName = name.Trim(); - if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName)) - { - synonyms.Add(theName); - } - } - } - } - - foreach (var title in synonyms) - { - var releaseRows = seriesCq.Find(".torrent_group tr"); - - // Skip the first two info rows - for (int r = 1; r < releaseRows.Count(); r++) - { - var row = releaseRows.Get(r); - var rowCq = row.Cq(); - if (rowCq.HasClass("edition_info")) - { - releaseInfo = rowCq.Find("td").Text(); - - if (string.IsNullOrWhiteSpace(releaseInfo)) - { - // Single episodes alpha - Reported that this info is missing. - // It should self correct when availible - break; - } - - releaseInfo = releaseInfo.Replace("Episode ", ""); - releaseInfo = releaseInfo.Replace("Season ", "S"); - releaseInfo = releaseInfo.Trim(); - int test = 0; - if (InsertSeason && int.TryParse(releaseInfo, out test) && releaseInfo.Length==1) - { - releaseInfo = "S01E0" + releaseInfo; - } - - } - else if (rowCq.HasClass("torrent")) - { - var links = rowCq.Find("a"); - // Protect against format changes - if (links.Count() != 2) - { - continue; - } - - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 259200; - var downloadLink = links.Get(0); - - // We dont know this so try to fake based on the release year - release.PublishDate = new DateTime(year, 1, 1); - release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1); - - var infoLink = links.Get(1); - release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href")); - release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name. - release.Link = new Uri(downloadLink.Attributes.GetAttribute("href")); - - string category = null; - if (searchType == SearchType.Video) - { - category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim(); - if (category == "TV Series") - release.Category = new List<int> { TorznabCatType.TVAnime.ID }; - - // Ignore these categories as they'll cause hell with the matcher - // TV Special, OVA, ONA, DVD Special, BD Special - - if (category == "Movie") - release.Category = new List<int> { TorznabCatType.Movies.ID }; - - if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel") - release.Category = new List<int> { TorznabCatType.BooksComics.ID }; - - if (category == "Novel" || category == "Artbook") - release.Category = new List<int> { TorznabCatType.BooksComics.ID }; - - if (category == "Game" || category == "Visual Novel") - { - var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); - if (description.Contains(" PSP ")) - release.Category = new List<int> { TorznabCatType.ConsolePSP.ID }; - if (description.Contains("PSX")) - release.Category = new List<int> { TorznabCatType.ConsoleOther.ID }; - if (description.Contains(" NES ")) - release.Category = new List<int> { TorznabCatType.ConsoleOther.ID }; - if (description.Contains(" PC ")) - release.Category = new List<int> { TorznabCatType.PCGames.ID }; - } - } - - if (searchType == SearchType.Audio) - { - category = seriesCq.Find(".group_img .cat a").Text(); - if (category == "Single" || category == "Album" || category == "Compilation" || category == "Soundtrack" || category == "Remix CD") - { - var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); - if (description.Contains(" Lossless ")) - release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; - else if (description.Contains("MP3")) - release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; - else - release.Category = new List<int> { TorznabCatType.AudioOther.ID }; - } - } - - - - // We dont actually have a release name >.> so try to create one - var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList(); - for (int i = releaseTags.Count - 1; i >= 0; i--) - { - releaseTags[i] = releaseTags[i].Trim(); - if (string.IsNullOrWhiteSpace(releaseTags[i])) - releaseTags.RemoveAt(i); - } - - var group = releaseTags.Last(); - if (group.Contains("(") && group.Contains(")")) - { - // Skip raws if set - if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws) - { - continue; - } - - var start = group.IndexOf("("); - group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] "; - } - else - { - group = string.Empty; - } - - var infoString = ""; - - for (int i = 0; i + 1 < releaseTags.Count(); i++) - { - if (releaseTags[i] == "Raw" && !AllowRaws) - continue; - infoString += "[" + releaseTags[i] + "]"; - } - - if (category == "Movie") - { - release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString); - } - else - { - release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString); - } - release.Description = title; - - var size = rowCq.Find(".torrent_size"); - if (size.Count() > 0) - { - release.Size = ReleaseInfo.GetBytes(size.First().Text()); - } - - // Additional 5 hours per GB - release.MinimumSeedTime += (release.Size / 1000000000) * 18000; - - // Peer info - release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text()); - release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text()); - - // grabs - var grabs = rowCq.Find("td.torrent_snatched").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - // freeleech - if (rowCq.Find("img[alt=\"Freeleech!\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - if (release.Category != null) - releases.Add(release); - } - } - } - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - - // Add to the cache - lock (cache) - { - cache.Add(new CachedQueryResult(queryUrl, releases)); - } - - return releases.Select(s => (ReleaseInfo)s.Clone()); - } - } -} +using CsQuery; +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Models.IndexerConfig.Bespoke; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; + +namespace Jackett.Indexers +{ + public class AnimeBytes : BaseIndexer, IIndexer + { + enum SearchType + { + Video, + Audio + } + + private string LoginUrl { get { return SiteLink + "user/login"; } } + private string SearchUrl { get { return SiteLink + "torrents.php?"; } } + private string MusicSearchUrl { get { return SiteLink + "torrents2.php?"; } } + public bool AllowRaws { get { return configData.IncludeRaw.Value; } } + public bool InsertSeason { get { return configData.InsertSeason!=null && configData.InsertSeason.Value; } } + + new ConfigurationDataAnimeBytes configData + { + get { return (ConfigurationDataAnimeBytes)base.configData; } + set { base.configData = value; } + } + + public AnimeBytes(IIndexerManagerService i, IWebClient client, Logger l, IProtectionService ps) + : base(name: "AnimeBytes", + link: "https://animebytes.tv/", + description: "Powered by Tentacles", + manager: i, + client: client, + caps: new TorznabCapabilities(TorznabCatType.TVAnime, + TorznabCatType.Movies, + TorznabCatType.BooksComics, + TorznabCatType.ConsolePSP, + TorznabCatType.ConsoleOther, + TorznabCatType.PCGames, + TorznabCatType.AudioMP3, + TorznabCatType.AudioLossless, + TorznabCatType.AudioOther), + logger: l, + p: ps, + configData: new ConfigurationDataAnimeBytes()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + } + + + public override IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> input) + { + // Prevent filtering + return input; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + lock (cache) + { + cache.Clear(); + } + + // Get the login form as we need the CSRF Token + var loginPage = await webclient.GetString(new Utils.Clients.WebRequest() + { + Url = LoginUrl, + Encoding = Encoding + }); + + CQ loginPageDom = loginPage.Content; + var csrfIndex = loginPageDom["input[name=\"_CSRF_INDEX\"]"].Last(); + var csrfToken = loginPageDom["input[name=\"_CSRF_TOKEN\"]"].Last(); + + // Build login form + var pairs = new Dictionary<string, string> { + { "_CSRF_INDEX", csrfIndex.Attr("value") }, + { "_CSRF_TOKEN", csrfToken.Attr("value") }, + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "keeplogged_sent", "true" }, + { "keeplogged", "on" }, + { "login", "Log In!" } + }; + + // Do the login + var request = new Utils.Clients.WebRequest() + { + Cookies = loginPage.Cookies, + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + Encoding = Encoding, + Url = LoginUrl + }; + var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null); + + // Follow the redirect + await FollowIfRedirect(response, request.Url, SearchUrl); + + await ConfigureIfOK(response.Cookies, response.Content != null && response.Content.Contains("/user/logout"), () => + { + // Their login page appears to be broken and just gives a 500 error. + throw new ExceptionWithConfigData("Failed to login, 6 failed attempts will get you banned for 6 hours.", configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + // Override to load legacy config format + public override void LoadFromSavedConfiguration(JToken jsonConfig) + { + if (jsonConfig is JObject) + { + configData.CookieHeader.Value = jsonConfig.Value<string>("cookies"); + configData.IncludeRaw.Value = jsonConfig.Value<bool>("raws"); + SaveConfig(); + IsConfigured = true; + return; + } + + base.LoadFromSavedConfiguration(jsonConfig); + } + + private string StripEpisodeNumber(string term) + { + // Tracer does not support searching with episode number so strip it if we have one + term = Regex.Replace(term, @"\W(\dx)?\d?\d$", string.Empty); + term = Regex.Replace(term, @"\W(S\d\d?E)?\d?\d$", string.Empty); + return term; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + // The result list + var releases = new List<ReleaseInfo>(); + + if (ContainsMusicCategories(query.Categories)) + { + foreach (var result in await GetResults(SearchType.Audio, query.SanitizedSearchTerm)) + { + releases.Add(result); + } + } + + foreach (var result in await GetResults(SearchType.Video, StripEpisodeNumber(query.SanitizedSearchTerm))) + { + releases.Add(result); + } + + return releases.ToArray(); + } + + private bool ContainsMusicCategories(int[] categories) + { + var music = new[] + { + TorznabCatType.Audio.ID, + TorznabCatType.AudioMP3.ID, + TorznabCatType.AudioLossless.ID, + TorznabCatType.AudioOther.ID, + TorznabCatType.AudioForeign.ID + }; + + return categories.Length == 0 || music.Any(categories.Contains); + } + + private async Task<IEnumerable<ReleaseInfo>> GetResults(SearchType searchType, string searchTerm) + { + var cleanSearchTerm = HttpUtility.UrlEncode(searchTerm); + + // The result list + var releases = new List<ReleaseInfo>(); + + var queryUrl = searchType == SearchType.Video ? SearchUrl : MusicSearchUrl; + // Only include the query bit if its required as hopefully the site caches the non query page + if (!string.IsNullOrWhiteSpace(searchTerm)) + { + queryUrl += string.Format("searchstr={0}&action=advanced&search_type=title&year=&year2=&tags=&tags_type=0&sort=time_added&way=desc&hentai=2&releasegroup=&epcount=&epcount2=&artbooktitle=", cleanSearchTerm); + } + + // Check cache first so we don't query the server for each episode when searching for each episode in a series. + lock (cache) + { + // Remove old cache items + CleanCache(); + + var cachedResult = cache.Where(i => i.Query == queryUrl).FirstOrDefault(); + if (cachedResult != null) + return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); + } + + // Get the content from the tracker + var response = await RequestStringWithCookiesAndRetry(queryUrl); + if (response.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(queryUrl); + } + + CQ dom = response.Content; + + // Parse + try + { + var releaseInfo = "S01"; + var root = dom.Find(".group_cont"); + // We may have got redirected to the series page if we have none of these + if (root.Count() == 0) + root = dom.Find(".torrent_table"); + + foreach (var series in root) + { + var seriesCq = series.Cq(); + + var synonyms = new List<string>(); + string mainTitle; + if (searchType == SearchType.Video) + mainTitle = seriesCq.Find(".group_title strong a").First().Text().Trim(); + else + mainTitle = seriesCq.Find(".group_title strong").Text().Trim(); + + var yearStr = seriesCq.Find(".group_title strong").First().Text().Trim().Replace("]", "").Trim(); + int yearIndex = yearStr.LastIndexOf("["); + if (yearIndex > -1) + yearStr = yearStr.Substring(yearIndex + 1); + + int year = 0; + if (!int.TryParse(yearStr, out year)) + year = DateTime.Now.Year; + + synonyms.Add(mainTitle); + + // If the title contains a comma then we can't use the synonyms as they are comma seperated + if (!mainTitle.Contains(",")) + { + var symnomnNames = string.Empty; + foreach (var e in seriesCq.Find(".group_statbox li")) + { + if (e.FirstChild.InnerText == "Synonyms:") + { + symnomnNames = e.InnerText; + } + } + + if (!string.IsNullOrWhiteSpace(symnomnNames)) + { + foreach (var name in symnomnNames.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) + { + var theName = name.Trim(); + if (!theName.Contains("&#") && !string.IsNullOrWhiteSpace(theName)) + { + synonyms.Add(theName); + } + } + } + } + + foreach (var title in synonyms) + { + var releaseRows = seriesCq.Find(".torrent_group tr"); + + // Skip the first two info rows + for (int r = 1; r < releaseRows.Count(); r++) + { + var row = releaseRows.Get(r); + var rowCq = row.Cq(); + if (rowCq.HasClass("edition_info")) + { + releaseInfo = rowCq.Find("td").Text(); + + if (string.IsNullOrWhiteSpace(releaseInfo)) + { + // Single episodes alpha - Reported that this info is missing. + // It should self correct when availible + break; + } + + releaseInfo = releaseInfo.Replace("Episode ", ""); + releaseInfo = releaseInfo.Replace("Season ", "S"); + releaseInfo = releaseInfo.Trim(); + int test = 0; + if (InsertSeason && int.TryParse(releaseInfo, out test) && releaseInfo.Length==1) + { + releaseInfo = "S01E0" + releaseInfo; + } + + } + else if (rowCq.HasClass("torrent")) + { + var links = rowCq.Find("a"); + // Protect against format changes + if (links.Count() != 2) + { + continue; + } + + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 259200; + var downloadLink = links.Get(0); + + // We dont know this so try to fake based on the release year + release.PublishDate = new DateTime(year, 1, 1); + release.PublishDate = release.PublishDate.AddDays(Math.Min(DateTime.Now.DayOfYear, 365) - 1); + + var infoLink = links.Get(1); + release.Comments = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href")); + release.Guid = new Uri(SiteLink + infoLink.Attributes.GetAttribute("href") + "&nh=" + StringUtil.Hash(title)); // Sonarr should dedupe on this url - allow a url per name. + release.Link = new Uri(downloadLink.Attributes.GetAttribute("href")); + + string category = null; + if (searchType == SearchType.Video) + { + category = seriesCq.Find("a[title=\"View Torrent\"]").Text().Trim(); + if (category == "TV Series") + release.Category = new List<int> { TorznabCatType.TVAnime.ID }; + + // Ignore these categories as they'll cause hell with the matcher + // TV Special, OVA, ONA, DVD Special, BD Special + + if (category == "Movie") + release.Category = new List<int> { TorznabCatType.Movies.ID }; + + if (category == "Manga" || category == "Oneshot" || category == "Anthology" || category == "Manhwa" || category == "Manhua" || category == "Light Novel") + release.Category = new List<int> { TorznabCatType.BooksComics.ID }; + + if (category == "Novel" || category == "Artbook") + release.Category = new List<int> { TorznabCatType.BooksComics.ID }; + + if (category == "Game" || category == "Visual Novel") + { + var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); + if (description.Contains(" PSP ")) + release.Category = new List<int> { TorznabCatType.ConsolePSP.ID }; + if (description.Contains("PSX")) + release.Category = new List<int> { TorznabCatType.ConsoleOther.ID }; + if (description.Contains(" NES ")) + release.Category = new List<int> { TorznabCatType.ConsoleOther.ID }; + if (description.Contains(" PC ")) + release.Category = new List<int> { TorznabCatType.PCGames.ID }; + } + } + + if (searchType == SearchType.Audio) + { + category = seriesCq.Find(".group_img .cat a").Text(); + if (category == "Single" || category == "Album" || category == "Compilation" || category == "Soundtrack" || category == "Remix CD") + { + var description = rowCq.Find(".torrent_properties a:eq(1)").Text(); + if (description.Contains(" Lossless ")) + release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; + else if (description.Contains("MP3")) + release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; + else + release.Category = new List<int> { TorznabCatType.AudioOther.ID }; + } + } + + + + // We dont actually have a release name >.> so try to create one + var releaseTags = infoLink.InnerText.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList(); + for (int i = releaseTags.Count - 1; i >= 0; i--) + { + releaseTags[i] = releaseTags[i].Trim(); + if (string.IsNullOrWhiteSpace(releaseTags[i])) + releaseTags.RemoveAt(i); + } + + var group = releaseTags.Last(); + if (group.Contains("(") && group.Contains(")")) + { + // Skip raws if set + if (group.ToLowerInvariant().StartsWith("raw") && !AllowRaws) + { + continue; + } + + var start = group.IndexOf("("); + group = "[" + group.Substring(start + 1, (group.IndexOf(")") - 1) - start) + "] "; + } + else + { + group = string.Empty; + } + + var infoString = ""; + + for (int i = 0; i + 1 < releaseTags.Count(); i++) + { + if (releaseTags[i] == "Raw" && !AllowRaws) + continue; + infoString += "[" + releaseTags[i] + "]"; + } + + if (category == "Movie") + { + release.Title = string.Format("{0} {1} {2}{3}", title, year, group, infoString); + } + else + { + release.Title = string.Format("{0}{1} {2} {3}", group, title, releaseInfo, infoString); + } + release.Description = title; + + var size = rowCq.Find(".torrent_size"); + if (size.Count() > 0) + { + release.Size = ReleaseInfo.GetBytes(size.First().Text()); + } + + // Additional 5 hours per GB + release.MinimumSeedTime += (release.Size / 1000000000) * 18000; + + // Peer info + release.Seeders = ParseUtil.CoerceInt(rowCq.Find(".torrent_seeders").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(rowCq.Find(".torrent_leechers").Text()); + + // grabs + var grabs = rowCq.Find("td.torrent_snatched").Text(); + release.Grabs = ParseUtil.CoerceInt(grabs); + + // freeleech + if (rowCq.Find("img[alt=\"Freeleech!\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + if (release.Category != null) + releases.Add(release); + } + } + } + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + // Add to the cache + lock (cache) + { + cache.Add(new CachedQueryResult(queryUrl, releases)); + } + + return releases.Select(s => (ReleaseInfo)s.Clone()); + } + } +} diff --git a/src/Jackett/Indexers/AnimeTorrents.cs b/src/Jackett/Indexers/AnimeTorrents.cs index 42f4a5bb..b2e16664 100644 --- a/src/Jackett/Indexers/AnimeTorrents.cs +++ b/src/Jackett/Indexers/AnimeTorrents.cs @@ -146,16 +146,16 @@ namespace Jackett.Indexers release.PublishDate = DateTime.ParseExact(dateString, "dd MMM yy", CultureInfo.InvariantCulture); var qLink = qRow.Find("td:eq(2) a"); - if (qLink.Length != 0) // newbie users don't see DL links - { - release.Link = new Uri(qLink.Attr("href")); + if (qLink.Length != 0) // newbie users don't see DL links + { + release.Link = new Uri(qLink.Attr("href")); } - else - { - // use comments link as placeholder - // null causes errors during export to torznab - // skipping the release prevents newbie users from adding the tracker (empty result) - release.Link = release.Comments; + else + { + // use comments link as placeholder + // null causes errors during export to torznab + // skipping the release prevents newbie users from adding the tracker (empty result) + release.Link = release.Comments; } var sizeStr = qRow.Find("td:eq(5)").Text(); @@ -176,26 +176,26 @@ namespace Jackett.Indexers release.Category = MapTrackerCatToNewznab(rCat); - if (qRow.Find("img[alt=\"Gold Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[alt=\"Silver Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; + if (qRow.Find("img[alt=\"Gold Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[alt=\"Silver Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; else release.DownloadVolumeFactor = 1; var ULFactorImg = qRow.Find("img[alt*=\"x Multiplier Torrent\"]"); - if (ULFactorImg.Length >= 1) - { - release.UploadVolumeFactor = ParseUtil.CoerceDouble(ULFactorImg.Attr("alt").Split('x')[0]); - } - else - { - release.UploadVolumeFactor = 1; - } - - qTitleLink.Remove(); - release.Description = qRow.Find("td:eq(1)").Text(); - + if (ULFactorImg.Length >= 1) + { + release.UploadVolumeFactor = ParseUtil.CoerceDouble(ULFactorImg.Attr("alt").Split('x')[0]); + } + else + { + release.UploadVolumeFactor = 1; + } + + qTitleLink.Remove(); + release.Description = qRow.Find("td:eq(1)").Text(); + releases.Add(release); } } diff --git a/src/Jackett/Indexers/BB.cs b/src/Jackett/Indexers/BB.cs index 2f93a46d..f115acaa 100644 --- a/src/Jackett/Indexers/BB.cs +++ b/src/Jackett/Indexers/BB.cs @@ -15,7 +15,7 @@ using System.Threading.Tasks; using System.Web; using Jackett.Models.IndexerConfig; using System.Collections.Specialized; - + namespace Jackett.Indexers { // To comply with the rules for this tracker, only the acronym is used and no publicly displayed URLs to the site. @@ -95,10 +95,10 @@ namespace Jackett.Indexers var searchString = query.GetQueryString(); var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("action", "basic"); - + var queryCollection = new NameValueCollection(); + + queryCollection.Add("action", "basic"); + if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("searchstr", searchString); @@ -114,10 +114,10 @@ namespace Jackett.Indexers var results = await RequestStringWithCookiesAndRetry(searchUrl); // Occasionally the cookies become invalid, login again if that happens - if (results.IsRedirect) - { - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl); + if (results.IsRedirect) + { + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl); } try @@ -155,10 +155,10 @@ namespace Jackett.Indexers release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text().Trim()) + release.Seeders; var grabs = qRow.Find("td:nth-child(6)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - if (qRow.Find("strong:contains(\"Freeleech!\")").Length >= 1) - release.DownloadVolumeFactor = 0; + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (qRow.Find("strong:contains(\"Freeleech!\")").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/BJShare.cs b/src/Jackett/Indexers/BJShare.cs index c742bf26..95824477 100644 --- a/src/Jackett/Indexers/BJShare.cs +++ b/src/Jackett/Indexers/BJShare.cs @@ -10,11 +10,11 @@ using System; using System.Text; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using AngleSharp.Parser.Html; -using AngleSharp.Dom; -using System.Text.RegularExpressions; - +using System.Collections.Specialized; +using AngleSharp.Parser.Html; +using AngleSharp.Dom; +using System.Text.RegularExpressions; + namespace Jackett.Indexers { public class BJShare : BaseIndexer, IIndexer @@ -39,7 +39,7 @@ namespace Jackett.Indexers logger: l, p: ps, configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { + { Encoding = Encoding.GetEncoding("UTF-8"); Language = "pt-br"; Type = "private"; @@ -63,8 +63,8 @@ namespace Jackett.Indexers AddCategoryMapping(11, TorznabCatType.Other); // Video-Aula AddCategoryMapping(6, TorznabCatType.TV); // Vídeos de TV AddCategoryMapping(4, TorznabCatType.Other); // Jogos - AddCategoryMapping(199, TorznabCatType.XXX); // Filmes Adultos - AddCategoryMapping(200, TorznabCatType.XXX); // Jogos Adultos + AddCategoryMapping(199, TorznabCatType.XXX); // Filmes Adultos + AddCategoryMapping(200, TorznabCatType.XXX); // Jogos Adultos AddCategoryMapping(201, TorznabCatType.XXXImageset); // Fotos Adultas } @@ -80,241 +80,241 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } - private string StripSearchString(string term) - { - // Search does not support searching with episode numbers so strip it if we have one - // Ww AND filter the result later to archive the proper result - term = Regex.Replace(term, @"[S|E]\d\d", string.Empty); - return term.Trim(); + private string StripSearchString(string term) + { + // Search does not support searching with episode numbers so strip it if we have one + // Ww AND filter the result later to archive the proper result + term = Regex.Replace(term, @"[S|E]\d\d", string.Empty); + return term.Trim(); } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - // if the search string is empty use the "last 24h torrents" view - if (string.IsNullOrWhiteSpace(searchString)) - { + var searchString = query.GetQueryString(); + + // if the search string is empty use the "last 24h torrents" view + if (string.IsNullOrWhiteSpace(searchString)) + { var results = await RequestStringWithCookies(TodayUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + foreach (var Row in Rows) { - try + try { var release = new ReleaseInfo(); - release.MinimumRatio = 1; + release.MinimumRatio = 1; release.MinimumSeedTime = 0; - - var qDetailsLink = Row.QuerySelector("a.BJinfoBox"); - var qTitle = qDetailsLink.QuerySelector("font"); - release.Title = qTitle.TextContent; - - var qBJinfoBox = qDetailsLink.QuerySelector("span"); - var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); - var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); - var qSeeders = Row.QuerySelector("td:nth-child(4)"); - var qLeechers = Row.QuerySelector("td:nth-child(5)"); - var qFreeLeech = Row.QuerySelector("font[color=\"green\"]:contains(Free)"); - - release.Description = ""; - foreach (var Child in qBJinfoBox.ChildNodes) - { - var type = Child.NodeType; - if (type != NodeType.Text) - continue; - - var line = Child.TextContent; - if (line.StartsWith("Tamanho:")) - { - string Size = line.Substring("Tamanho: ".Length); ; - release.Size = ReleaseInfo.GetBytes(Size); - } - else if (line.StartsWith("Lançado em: ")) - { - string PublishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", ""); - PublishDateStr += " +0"; - var PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(PublishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - release.PublishDate = PublishDate.ToLocalTime(); - } - else - { - release.Description += line + "\n"; - } - } - - - var catStr = qCatLink.GetAttribute("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); - release.Guid = release.Link; - - release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); - release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; - - - if (qFreeLeech != null) - release.DownloadVolumeFactor = 0; + + var qDetailsLink = Row.QuerySelector("a.BJinfoBox"); + var qTitle = qDetailsLink.QuerySelector("font"); + release.Title = qTitle.TextContent; + + var qBJinfoBox = qDetailsLink.QuerySelector("span"); + var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); + var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); + var qSeeders = Row.QuerySelector("td:nth-child(4)"); + var qLeechers = Row.QuerySelector("td:nth-child(5)"); + var qFreeLeech = Row.QuerySelector("font[color=\"green\"]:contains(Free)"); + + release.Description = ""; + foreach (var Child in qBJinfoBox.ChildNodes) + { + var type = Child.NodeType; + if (type != NodeType.Text) + continue; + + var line = Child.TextContent; + if (line.StartsWith("Tamanho:")) + { + string Size = line.Substring("Tamanho: ".Length); ; + release.Size = ReleaseInfo.GetBytes(Size); + } + else if (line.StartsWith("Lançado em: ")) + { + string PublishDateStr = line.Substring("Lançado em: ".Length).Replace("às ", ""); + PublishDateStr += " +0"; + var PublishDate = DateTime.SpecifyKind(DateTime.ParseExact(PublishDateStr, "dd/MM/yyyy HH:mm z", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + release.PublishDate = PublishDate.ToLocalTime(); + } + else + { + release.Description += line + "\n"; + } + } + + + var catStr = qCatLink.GetAttribute("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); + release.Guid = release.Link; + + release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); + release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; + + + if (qFreeLeech != null) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); + releases.Add(release); } - } + catch (Exception ex) + { + logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); + } + } } catch (Exception ex) { OnParseError(results.Content, ex); - } + } } - else // use search + else // use search { - var searchUrl = BrowseUrl; - - var queryCollection = new NameValueCollection(); - queryCollection.Add("searchstr", StripSearchString(searchString)); - queryCollection.Add("order_by", "time"); - queryCollection.Add("order_way", "desc"); - queryCollection.Add("group_results", "1"); - queryCollection.Add("action", "basic"); - queryCollection.Add("searchsubmit", "1"); - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("filter_cat["+cat+"]", "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - + var searchUrl = BrowseUrl; + + var queryCollection = new NameValueCollection(); + queryCollection.Add("searchstr", StripSearchString(searchString)); + queryCollection.Add("order_by", "time"); + queryCollection.Add("order_way", "desc"); + queryCollection.Add("group_results", "1"); + queryCollection.Add("action", "basic"); + queryCollection.Add("searchsubmit", "1"); + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("filter_cat["+cat+"]", "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + var results = await RequestStringWithCookies(searchUrl); try { string RowsSelector = "table.torrent_table > tbody > tr:not(tr.colhead)"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - - ICollection<int> GroupCategory = null; - string GroupTitle = null; - string GroupYearStr = null; - Nullable<DateTime> GroupPublishDate = null; - - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + + ICollection<int> GroupCategory = null; + string GroupTitle = null; + string GroupYearStr = null; + Nullable<DateTime> GroupPublishDate = null; + + foreach (var Row in Rows) { - try - { - var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); - string Title = qDetailsLink.TextContent; - ICollection<int> Category = null; - string YearStr = null; - Nullable<DateTime> YearPublishDate = null; - - if (Row.ClassList.Contains("group") || Row.ClassList.Contains("torrent")) // group/ungrouped headers - { - var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); - string CategoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0]; - Category = MapTrackerCatToNewznab(CategoryStr); - YearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']'); - YearPublishDate = DateTime.SpecifyKind(DateTime.ParseExact(YearStr, "yyyy", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - if (Row.ClassList.Contains("group")) // group headers - { - GroupCategory = Category; - GroupTitle = Title; - GroupYearStr = YearStr; - GroupPublishDate = YearPublishDate; - continue; - } - } - + try + { + var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); + string Title = qDetailsLink.TextContent; + ICollection<int> Category = null; + string YearStr = null; + Nullable<DateTime> YearPublishDate = null; + + if (Row.ClassList.Contains("group") || Row.ClassList.Contains("torrent")) // group/ungrouped headers + { + var qCatLink = Row.QuerySelector("a[href^=\"/torrents.php?filter_cat\"]"); + string CategoryStr = qCatLink.GetAttribute("href").Split('=')[1].Split('&')[0]; + Category = MapTrackerCatToNewznab(CategoryStr); + YearStr = qDetailsLink.NextSibling.TextContent.Trim().TrimStart('[').TrimEnd(']'); + YearPublishDate = DateTime.SpecifyKind(DateTime.ParseExact(YearStr, "yyyy", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + if (Row.ClassList.Contains("group")) // group headers + { + GroupCategory = Category; + GroupTitle = Title; + GroupYearStr = YearStr; + GroupPublishDate = YearPublishDate; + continue; + } + } + var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 0; - - var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); - var qSize = Row.QuerySelector("td:nth-last-child(4)"); - var qSeeders = Row.QuerySelector("td:nth-last-child(3)"); - var qLeechers = Row.QuerySelector("td:nth-last-child(2)"); - var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]"); - - if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group - { - release.Description = qDetailsLink.TextContent; - release.Title = GroupTitle + " " + GroupYearStr; - release.PublishDate = GroupPublishDate.Value; - release.Category = GroupCategory; - } - else if (Row.ClassList.Contains("torrent")) // standalone/un grouped torrents - { - var qDescription = Row.QuerySelector("div.torrent_info"); - release.Description = qDescription.TextContent; - release.Title = Title + " " + YearStr; - release.PublishDate = YearPublishDate.Value; - release.Category = Category; - } - - release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag - release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it - - // check for previously stripped search terms - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var Size = qSize.TextContent; - release.Size = ReleaseInfo.GetBytes(Size); - - release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); - release.Guid = release.Link; - - release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); - release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; - - if (qFreeLeech != null) - release.DownloadVolumeFactor = 0; + release.MinimumRatio = 1; + release.MinimumSeedTime = 0; + + var qDLLink = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); + var qSize = Row.QuerySelector("td:nth-last-child(4)"); + var qSeeders = Row.QuerySelector("td:nth-last-child(3)"); + var qLeechers = Row.QuerySelector("td:nth-last-child(2)"); + var qFreeLeech = Row.QuerySelector("strong[title=\"Free\"]"); + + if (Row.ClassList.Contains("group_torrent")) // torrents belonging to a group + { + release.Description = qDetailsLink.TextContent; + release.Title = GroupTitle + " " + GroupYearStr; + release.PublishDate = GroupPublishDate.Value; + release.Category = GroupCategory; + } + else if (Row.ClassList.Contains("torrent")) // standalone/un grouped torrents + { + var qDescription = Row.QuerySelector("div.torrent_info"); + release.Description = qDescription.TextContent; + release.Title = Title + " " + YearStr; + release.PublishDate = YearPublishDate.Value; + release.Category = Category; + } + + release.Description = release.Description.Replace(" / Free", ""); // Remove Free Tag + release.Title += " " + release.Description; // add year and Description to the release Title to add some meaning to it + + // check for previously stripped search terms + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var Size = qSize.TextContent; + release.Size = ReleaseInfo.GetBytes(Size); + + release.Link = new Uri(SiteLink + qDLLink.GetAttribute("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); + release.Guid = release.Link; + + release.Seeders = ParseUtil.CoerceInt(qSeeders.TextContent); + release.Peers = ParseUtil.CoerceInt(qLeechers.TextContent) + release.Seeders; + + if (qFreeLeech != null) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); + releases.Add(release); } - } + catch (Exception ex) + { + logger.Error(string.Format("{0}: Error while parsing row '{1}': {2}", ID, Row.OuterHtml, ex.Message)); + } + } } catch (Exception ex) { OnParseError(results.Content, ex); - } + } } return releases; diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs index d35f10ce..3faca56d 100644 --- a/src/Jackett/Indexers/BaseIndexer.cs +++ b/src/Jackett/Indexers/BaseIndexer.cs @@ -1,645 +1,645 @@ -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.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using AutoMapper; -using System.Threading; -using Jackett.Models.IndexerConfig; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public abstract class BaseIndexer - { - public string SiteLink { get; protected set; } - public string DefaultSiteLink { get; protected set; } - public string[] AlternativeSiteLinks { get; protected set; } = new string[] { }; - public string DisplayDescription { get; protected set; } - public string DisplayName { get; protected set; } - public string Language { get; protected set; } - public Encoding Encoding { get; protected set; } - public string Type { get; protected set; } - public string ID { get { return GetIndexerID(GetType()); } } - - public bool IsConfigured { get; protected set; } - public TorznabCapabilities TorznabCaps { get; protected set; } - protected Logger logger; - protected IIndexerManagerService indexerService; - protected static List<CachedQueryResult> cache = new List<CachedQueryResult>(); - protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0); - protected IWebClient webclient; - protected IProtectionService protectionService; - protected readonly string downloadUrlBase = ""; - - protected string CookieHeader - { - get { return configData.CookieHeader.Value; } - set { configData.CookieHeader.Value = value; } - } - - public string LastError - { - get { return configData.LastError.Value; } - set - { - bool SaveNeeded = configData.LastError.Value != value && IsConfigured; - configData.LastError.Value = value; - if (SaveNeeded) - SaveConfig(); - } - } - - protected ConfigurationData configData; - - private List<CategoryMapping> categoryMapping = new List<CategoryMapping>(); - - // standard constructor used by most indexers - public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null, string downloadBase = null) - : this(manager, client, logger, p) - { - if (!link.EndsWith("/")) - throw new Exception("Site link must end with a slash."); - - DisplayName = name; - DisplayDescription = description; - SiteLink = link; - DefaultSiteLink = link; - this.downloadUrlBase = downloadBase; - this.configData = configData; - LoadValuesFromJson(null); - - if (caps == null) - caps = TorznabUtil.CreateDefaultTorznabTVCaps(); - TorznabCaps = caps; - - } - - // minimal constructor used by e.g. cardigann generic indexer - public BaseIndexer(IIndexerManagerService manager, IWebClient client, Logger logger, IProtectionService p) - { - this.logger = logger; - indexerService = manager; - webclient = client; - protectionService = p; - } - - public IEnumerable<ReleaseInfo> CleanLinks(IEnumerable<ReleaseInfo> releases) - { - if (string.IsNullOrEmpty(downloadUrlBase)) - return releases; - foreach (var release in releases) - { - if (release.Link.ToString().StartsWith(downloadUrlBase)) - { - release.Link = new Uri(release.Link.ToString().Substring(downloadUrlBase.Length), UriKind.Relative); - } - } - - return releases; - } - - public Uri UncleanLink(Uri link) - { - if (string.IsNullOrWhiteSpace(downloadUrlBase)) - { - return link; - } - - if (link.ToString().StartsWith(downloadUrlBase)) - { - return link; - } - - return new Uri(downloadUrlBase + link.ToString(), UriKind.RelativeOrAbsolute); - } - - protected ICollection<int> MapTrackerCatToNewznab(string input) - { - var cats = new List<int>(); - if (null != input) - { - var mapping = categoryMapping.Where(m => m.TrackerCategory != null && m.TrackerCategory.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault(); - if (mapping != null) - { - cats.Add(mapping.NewzNabCategory); - } - - // 1:1 category mapping - try - { - var trackerCategoryInt = int.Parse(input); - cats.Add(trackerCategoryInt + 100000); - } - catch (FormatException) - { - // input is not an integer, continue - } - } - return cats; - } - - protected ICollection<int> MapTrackerCatDescToNewznab(string input) - { - var cats = new List<int>(); - if (null != input) - { - var mapping = categoryMapping.Where(m => m.TrackerCategoryDesc != null && m.TrackerCategoryDesc.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault(); - if (mapping != null) - { - cats.Add(mapping.NewzNabCategory); - - if (mapping.TrackerCategory != null) - { - // 1:1 category mapping - try - { - var trackerCategoryInt = int.Parse(mapping.TrackerCategory); - cats.Add(trackerCategoryInt + 100000); - } - catch (FormatException) - { - // mapping.TrackerCategory is not an integer, continue - } - } - } - } - return cats; - } - - public static string GetIndexerID(Type type) - { - return StringUtil.StripNonAlphaNumeric(type.Name.ToLowerInvariant()); - } - - public virtual Task<ConfigurationData> GetConfigurationForSetup() - { - return Task.FromResult<ConfigurationData>(configData); - } - - public virtual void ResetBaseConfig() - { - CookieHeader = string.Empty; - IsConfigured = false; - } - - public virtual void SaveConfig() - { - indexerService.SaveConfig(this as IIndexer, configData.ToJson(protectionService, forDisplay: false)); - } - - protected void OnParseError(string results, Exception ex) - { - var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), DisplayName); - var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5)); - var fileContents = string.Format("{0}{1}{2}", ex, spacing, results); - logger.Error(fileName + fileContents); - throw ex; - } - - protected void CleanCache() - { - foreach (var expired in cache.Where(i => DateTime.Now - i.Created > cacheTime).ToList()) - { - cache.Remove(expired); - } - } - - protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) - { - var byteResult = new WebClientByteResult(); - // Map to byte - Mapper.Map(response, byteResult); - await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); - // Map to string - Mapper.Map(byteResult, response); - } - - protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) - { - // Follow up to 5 redirects - for (int i = 0; i < 5; i++) - { - if (!response.IsRedirect) - break; - await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); - if (accumulateCookies) - { - CookieHeader = ResolveCookies((CookieHeader != null && CookieHeader != ""? CookieHeader + " " : "") + (overrideCookies != null && overrideCookies != "" ? overrideCookies + " " : "") + response.Cookies); - overrideCookies = response.Cookies = CookieHeader; - } - if (overrideCookies != null && response.Cookies == null) - { - response.Cookies = overrideCookies; - } - } - } - - private String ResolveCookies(String incomingCookies = "") - { - var redirRequestCookies = (CookieHeader != null && CookieHeader != "" ? CookieHeader + " " : "") + incomingCookies; - System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\\,;\s]+)=([^=\\,;\s]*)"); - Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>(); - var matches = expression.Match(redirRequestCookies); - while (matches.Success) - { - if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value; - matches = matches.NextMatch(); - } - return string.Join("; ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray()); - - } - - // Update CookieHeader with new cookies and save the config if something changed (e.g. a new CloudFlare clearance cookie was issued) - protected void UpdateCookieHeader(string newCookies, string cookieOverride = null) - { - string newCookieHeader = ResolveCookies((cookieOverride != null && cookieOverride != "" ? cookieOverride + " " : "") + newCookies); - if (CookieHeader != newCookieHeader) - { - logger.Debug(string.Format("updating Cookies {0} => {1}", CookieHeader, newCookieHeader)); - CookieHeader = newCookieHeader; - if (IsConfigured) - SaveConfig(); - } - } - - private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) - { - if (incomingResponse.IsRedirect) - { - var redirRequestCookies = ""; - if (accumulateCookies) - { - redirRequestCookies = ResolveCookies((CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null ? overrideCookies : "")); - } else - { - redirRequestCookies = (overrideCookies != null ? overrideCookies : ""); - } - // Do redirect - var redirectedResponse = await webclient.GetBytes(new WebRequest() - { - Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo, - Referer = referrer, - Cookies = redirRequestCookies, - Encoding = Encoding - }); - Mapper.Map(redirectedResponse, incomingResponse); - } - } - - - protected void LoadLegacyCookieConfig(JToken jsonConfig) - { - string legacyCookieHeader = (string)jsonConfig["cookie_header"]; - if (!string.IsNullOrEmpty(legacyCookieHeader)) - { - CookieHeader = legacyCookieHeader; - } - else - { - // Legacy cookie key - var jcookies = jsonConfig["cookies"]; - if (jcookies is JArray) - { - var array = (JArray)jcookies; - legacyCookieHeader = string.Empty; - for (int i = 0; i < array.Count; i++) - { - if (i != 0) - legacyCookieHeader += "; "; - legacyCookieHeader += array[i]; - } - CookieHeader = legacyCookieHeader; - } - else if (jcookies != null) - { - CookieHeader = (string)jcookies; - } - } - } - - virtual public void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) - { - IProtectionService ps = null; - if (useProtectionService) - ps = protectionService; - configData.LoadValuesFromJson(jsonConfig, ps); - if (string.IsNullOrWhiteSpace(configData.SiteLink.Value)) - { - configData.SiteLink.Value = DefaultSiteLink; - } - if (!configData.SiteLink.Value.EndsWith("/")) - configData.SiteLink.Value += "/"; - - var match = Regex.Match(configData.SiteLink.Value, "^https?:\\/\\/[\\w\\-\\/\\.]+$"); - if (!match.Success) - { - throw new Exception(string.Format("\"{0}\" is not a valid URL.", configData.SiteLink.Value)); - } - - SiteLink = configData.SiteLink.Value; - } - - public virtual void LoadFromSavedConfiguration(JToken jsonConfig) - { - if (jsonConfig is JArray) - { - LoadValuesFromJson(jsonConfig, true); - IsConfigured = true; - } - // read and upgrade old settings file format - else if (jsonConfig is Object) - { - LoadLegacyCookieConfig(jsonConfig); - SaveConfig(); - IsConfigured = true; - } - } - - public async virtual Task<byte[]> Download(Uri link) - { - return await Download(link, RequestType.GET); - } - - public async virtual Task<byte[]> Download(Uri link, RequestType method = RequestType.GET) - { - // do some extra escaping, needed for HD-Torrents - var requestLink = link.ToString() - .Replace("(", "%28") - .Replace(")", "%29") - .Replace("'", "%27"); - var response = await RequestBytesWithCookiesAndRetry(requestLink, null, method, requestLink); - if (response.Status != System.Net.HttpStatusCode.OK && response.Status != System.Net.HttpStatusCode.Continue && response.Status != System.Net.HttpStatusCode.PartialContent) - { - logger.Error("Failed download cookies: " + this.CookieHeader); - if (response.Content != null) - logger.Error("Failed download response:\n" + Encoding.UTF8.GetString(response.Content)); - throw new Exception($"Remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => "+response.RedirectingTo : "")); - } - - return response.Content; - } - - protected async Task<WebClientByteResult> RequestBytesWithCookiesAndRetry(string url, string cookieOverride = null, RequestType method = RequestType.GET, string referer = null, IEnumerable<KeyValuePair<string, string>> data = null) - { - Exception lastException = null; - for (int i = 0; i < 3; i++) - { - try - { - return await RequestBytesWithCookies(url, cookieOverride, method, referer, data); - } - catch (Exception e) - { - logger.Error(e, string.Format("On attempt {0} downloading from {1}: {2}", (i + 1), DisplayName, e.Message)); - lastException = e; - } - await Task.Delay(500); - } - - throw lastException; - } - - protected async Task<WebClientStringResult> RequestStringWithCookies(string url, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null) - { - var request = new Utils.Clients.WebRequest() - { - Url = url, - Type = RequestType.GET, - Cookies = CookieHeader, - Referer = referer, - Headers = headers, - Encoding = Encoding - }; - - if (cookieOverride != null) - request.Cookies = cookieOverride; - WebClientStringResult result = await webclient.GetString(request); - UpdateCookieHeader(result.Cookies, cookieOverride); - return result; - } - - protected async Task<WebClientStringResult> RequestStringWithCookiesAndRetry(string url, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null) - { - Exception lastException = null; - for (int i = 0; i < 3; i++) - { - try - { - return await RequestStringWithCookies(url, cookieOverride, referer, headers); - } - catch (Exception e) - { - logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message)); - lastException = e; - } - await Task.Delay(500); - } - - throw lastException; - } - - protected async Task<WebClientByteResult> RequestBytesWithCookies(string url, string cookieOverride = null, RequestType method = RequestType.GET, string referer = null, IEnumerable<KeyValuePair<string, string>> data = null, Dictionary<string, string> headers = null) - { - var request = new Utils.Clients.WebRequest() - { - Url = url, - Type = method, - Cookies = cookieOverride ?? CookieHeader, - PostData = data, - Referer = referer, - Headers = headers, - Encoding = Encoding - }; - - if (cookieOverride != null) - request.Cookies = cookieOverride; - return await webclient.GetBytes(request); - } - - protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null) - { - var request = new Utils.Clients.WebRequest() - { - Url = url, - Type = RequestType.POST, - Cookies = cookieOverride ?? CookieHeader, - PostData = data, - Referer = referer, - Headers = headers, - RawBody = rawbody, - Encoding = Encoding - }; - - if (emulateBrowser.HasValue) - request.EmulateBrowser = emulateBrowser.Value; - WebClientStringResult result = await webclient.GetString(request); - UpdateCookieHeader(result.Cookies, cookieOverride); - return result; - } - - protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null) - { - Exception lastException = null; - for (int i = 0; i < 3; i++) - { - try - { - return await PostDataWithCookies(url, data, cookieOverride, referer, headers, rawbody, emulateBrowser); - } - catch (Exception e) - { - logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message)); - lastException = e; - } - await Task.Delay(500); - } - - throw lastException; - } - - protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, IEnumerable<KeyValuePair<string, string>> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer = null, bool accumulateCookies = false) - { - var request = new Utils.Clients.WebRequest() - { - Url = url, - Type = RequestType.POST, - Cookies = cookies, - Referer = referer, - PostData = data, - Encoding = Encoding - }; - var response = await webclient.GetString(request); - if (accumulateCookies) - { - response.Cookies = ResolveCookies((request.Cookies == null ? "" : request.Cookies + " ") + response.Cookies); - } - var firstCallCookies = response.Cookies; - - if (response.IsRedirect) - { - await FollowIfRedirect(response, request.Url, redirectUrlOverride, response.Cookies, accumulateCookies); - } - - if (returnCookiesFromFirstCall) - { - response.Cookies = ResolveCookies(firstCallCookies + (accumulateCookies ? " " + response.Cookies : "")); - } - - return response; - } - - protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError) - { - if (isLoggedin) - { - CookieHeader = cookies; - SaveConfig(); - IsConfigured = true; - } - else - { - await onError(); - } - } - - public virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results) - { - foreach (var result in results) - { - if (query.Categories.Length == 0 || result.Category == null || result.Category.Count() == 0 || query.Categories.Intersect(result.Category).Any() || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category)) - { - yield return result; - } - } - } - - protected List<string> GetAllTrackerCategories() - { - return categoryMapping.Select(x => x.TrackerCategory).ToList(); - } - - protected void AddCategoryMapping(string trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) - { - categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, newznabCategory.ID)); - if (!TorznabCaps.Categories.Contains(newznabCategory)) - { - TorznabCaps.Categories.Add(newznabCategory); - if (TorznabCatType.Movies.Contains(newznabCategory)) - TorznabCaps.MovieSearchAvailable = true; - } - - // add 1:1 categories - if (trackerCategoryDesc != null && trackerCategory != null) - { - try - { - var trackerCategoryInt = int.Parse(trackerCategory); - var CustomCat = new TorznabCategory(trackerCategoryInt + 100000, trackerCategoryDesc); - if (!TorznabCaps.Categories.Contains(CustomCat)) - TorznabCaps.Categories.Add(CustomCat); - } - catch (FormatException) - { - // trackerCategory is not an integer, continue - } - } - } - - protected void AddCategoryMapping(int trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) - { - AddCategoryMapping(trackerCategory.ToString(), newznabCategory, trackerCategoryDesc); - } - - protected void AddMultiCategoryMapping(TorznabCategory newznabCategory, params int[] trackerCategories) - { - foreach (var trackerCat in trackerCategories) - { - AddCategoryMapping(trackerCat, newznabCategory); - } - } - - protected virtual List<string> MapTorznabCapsToTrackers(TorznabQuery query, bool mapChildrenCatsToParent = false) - { - var result = new List<string>(); - foreach (var cat in query.Categories) - { - // use 1:1 mapping to tracker categories for newznab categories >= 100000 - if (cat >= 100000) - { - result.Add((cat - 100000).ToString()); - continue; - } - - var queryCats = new List<int> { cat }; - var newznabCat = TorznabCatType.AllCats.FirstOrDefault(c => c.ID == cat); - if (newznabCat != null) - { - queryCats.AddRange(newznabCat.SubCategories.Select(c => c.ID)); - } - - if (mapChildrenCatsToParent) - { - var parentNewznabCat = TorznabCatType.AllCats.FirstOrDefault(c => c.SubCategories.Contains(newznabCat)); - if (parentNewznabCat != null) - { - queryCats.Add(parentNewznabCat.ID); - } - } - - foreach (var mapping in categoryMapping.Where(c => queryCats.Contains(c.NewzNabCategory))) - { - result.Add(mapping.TrackerCategory); - } - } - - return result.Distinct().ToList(); - } - } -} +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.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using AutoMapper; +using System.Threading; +using Jackett.Models.IndexerConfig; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public abstract class BaseIndexer + { + public string SiteLink { get; protected set; } + public string DefaultSiteLink { get; protected set; } + public string[] AlternativeSiteLinks { get; protected set; } = new string[] { }; + public string DisplayDescription { get; protected set; } + public string DisplayName { get; protected set; } + public string Language { get; protected set; } + public Encoding Encoding { get; protected set; } + public string Type { get; protected set; } + public string ID { get { return GetIndexerID(GetType()); } } + + public bool IsConfigured { get; protected set; } + public TorznabCapabilities TorznabCaps { get; protected set; } + protected Logger logger; + protected IIndexerManagerService indexerService; + protected static List<CachedQueryResult> cache = new List<CachedQueryResult>(); + protected static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0); + protected IWebClient webclient; + protected IProtectionService protectionService; + protected readonly string downloadUrlBase = ""; + + protected string CookieHeader + { + get { return configData.CookieHeader.Value; } + set { configData.CookieHeader.Value = value; } + } + + public string LastError + { + get { return configData.LastError.Value; } + set + { + bool SaveNeeded = configData.LastError.Value != value && IsConfigured; + configData.LastError.Value = value; + if (SaveNeeded) + SaveConfig(); + } + } + + protected ConfigurationData configData; + + private List<CategoryMapping> categoryMapping = new List<CategoryMapping>(); + + // standard constructor used by most indexers + public BaseIndexer(string name, string link, string description, IIndexerManagerService manager, IWebClient client, Logger logger, ConfigurationData configData, IProtectionService p, TorznabCapabilities caps = null, string downloadBase = null) + : this(manager, client, logger, p) + { + if (!link.EndsWith("/")) + throw new Exception("Site link must end with a slash."); + + DisplayName = name; + DisplayDescription = description; + SiteLink = link; + DefaultSiteLink = link; + this.downloadUrlBase = downloadBase; + this.configData = configData; + LoadValuesFromJson(null); + + if (caps == null) + caps = TorznabUtil.CreateDefaultTorznabTVCaps(); + TorznabCaps = caps; + + } + + // minimal constructor used by e.g. cardigann generic indexer + public BaseIndexer(IIndexerManagerService manager, IWebClient client, Logger logger, IProtectionService p) + { + this.logger = logger; + indexerService = manager; + webclient = client; + protectionService = p; + } + + public IEnumerable<ReleaseInfo> CleanLinks(IEnumerable<ReleaseInfo> releases) + { + if (string.IsNullOrEmpty(downloadUrlBase)) + return releases; + foreach (var release in releases) + { + if (release.Link.ToString().StartsWith(downloadUrlBase)) + { + release.Link = new Uri(release.Link.ToString().Substring(downloadUrlBase.Length), UriKind.Relative); + } + } + + return releases; + } + + public Uri UncleanLink(Uri link) + { + if (string.IsNullOrWhiteSpace(downloadUrlBase)) + { + return link; + } + + if (link.ToString().StartsWith(downloadUrlBase)) + { + return link; + } + + return new Uri(downloadUrlBase + link.ToString(), UriKind.RelativeOrAbsolute); + } + + protected ICollection<int> MapTrackerCatToNewznab(string input) + { + var cats = new List<int>(); + if (null != input) + { + var mapping = categoryMapping.Where(m => m.TrackerCategory != null && m.TrackerCategory.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault(); + if (mapping != null) + { + cats.Add(mapping.NewzNabCategory); + } + + // 1:1 category mapping + try + { + var trackerCategoryInt = int.Parse(input); + cats.Add(trackerCategoryInt + 100000); + } + catch (FormatException) + { + // input is not an integer, continue + } + } + return cats; + } + + protected ICollection<int> MapTrackerCatDescToNewznab(string input) + { + var cats = new List<int>(); + if (null != input) + { + var mapping = categoryMapping.Where(m => m.TrackerCategoryDesc != null && m.TrackerCategoryDesc.ToLowerInvariant() == input.ToLowerInvariant()).FirstOrDefault(); + if (mapping != null) + { + cats.Add(mapping.NewzNabCategory); + + if (mapping.TrackerCategory != null) + { + // 1:1 category mapping + try + { + var trackerCategoryInt = int.Parse(mapping.TrackerCategory); + cats.Add(trackerCategoryInt + 100000); + } + catch (FormatException) + { + // mapping.TrackerCategory is not an integer, continue + } + } + } + } + return cats; + } + + public static string GetIndexerID(Type type) + { + return StringUtil.StripNonAlphaNumeric(type.Name.ToLowerInvariant()); + } + + public virtual Task<ConfigurationData> GetConfigurationForSetup() + { + return Task.FromResult<ConfigurationData>(configData); + } + + public virtual void ResetBaseConfig() + { + CookieHeader = string.Empty; + IsConfigured = false; + } + + public virtual void SaveConfig() + { + indexerService.SaveConfig(this as IIndexer, configData.ToJson(protectionService, forDisplay: false)); + } + + protected void OnParseError(string results, Exception ex) + { + var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), DisplayName); + var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5)); + var fileContents = string.Format("{0}{1}{2}", ex, spacing, results); + logger.Error(fileName + fileContents); + throw ex; + } + + protected void CleanCache() + { + foreach (var expired in cache.Where(i => DateTime.Now - i.Created > cacheTime).ToList()) + { + cache.Remove(expired); + } + } + + protected async Task FollowIfRedirect(WebClientStringResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) + { + var byteResult = new WebClientByteResult(); + // Map to byte + Mapper.Map(response, byteResult); + await FollowIfRedirect(byteResult, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); + // Map to string + Mapper.Map(byteResult, response); + } + + protected async Task FollowIfRedirect(WebClientByteResult response, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) + { + // Follow up to 5 redirects + for (int i = 0; i < 5; i++) + { + if (!response.IsRedirect) + break; + await DoFollowIfRedirect(response, referrer, overrideRedirectUrl, overrideCookies, accumulateCookies); + if (accumulateCookies) + { + CookieHeader = ResolveCookies((CookieHeader != null && CookieHeader != ""? CookieHeader + " " : "") + (overrideCookies != null && overrideCookies != "" ? overrideCookies + " " : "") + response.Cookies); + overrideCookies = response.Cookies = CookieHeader; + } + if (overrideCookies != null && response.Cookies == null) + { + response.Cookies = overrideCookies; + } + } + } + + private String ResolveCookies(String incomingCookies = "") + { + var redirRequestCookies = (CookieHeader != null && CookieHeader != "" ? CookieHeader + " " : "") + incomingCookies; + System.Text.RegularExpressions.Regex expression = new System.Text.RegularExpressions.Regex(@"([^\\,;\s]+)=([^=\\,;\s]*)"); + Dictionary<string, string> cookieDIctionary = new Dictionary<string, string>(); + var matches = expression.Match(redirRequestCookies); + while (matches.Success) + { + if (matches.Groups.Count > 2) cookieDIctionary[matches.Groups[1].Value] = matches.Groups[2].Value; + matches = matches.NextMatch(); + } + return string.Join("; ", cookieDIctionary.Select(kv => kv.Key.ToString() + "=" + kv.Value.ToString()).ToArray()); + + } + + // Update CookieHeader with new cookies and save the config if something changed (e.g. a new CloudFlare clearance cookie was issued) + protected void UpdateCookieHeader(string newCookies, string cookieOverride = null) + { + string newCookieHeader = ResolveCookies((cookieOverride != null && cookieOverride != "" ? cookieOverride + " " : "") + newCookies); + if (CookieHeader != newCookieHeader) + { + logger.Debug(string.Format("updating Cookies {0} => {1}", CookieHeader, newCookieHeader)); + CookieHeader = newCookieHeader; + if (IsConfigured) + SaveConfig(); + } + } + + private async Task DoFollowIfRedirect(WebClientByteResult incomingResponse, string referrer = null, string overrideRedirectUrl = null, string overrideCookies = null, bool accumulateCookies = false) + { + if (incomingResponse.IsRedirect) + { + var redirRequestCookies = ""; + if (accumulateCookies) + { + redirRequestCookies = ResolveCookies((CookieHeader != "" ? CookieHeader + " " : "") + (overrideCookies != null ? overrideCookies : "")); + } else + { + redirRequestCookies = (overrideCookies != null ? overrideCookies : ""); + } + // Do redirect + var redirectedResponse = await webclient.GetBytes(new WebRequest() + { + Url = overrideRedirectUrl ?? incomingResponse.RedirectingTo, + Referer = referrer, + Cookies = redirRequestCookies, + Encoding = Encoding + }); + Mapper.Map(redirectedResponse, incomingResponse); + } + } + + + protected void LoadLegacyCookieConfig(JToken jsonConfig) + { + string legacyCookieHeader = (string)jsonConfig["cookie_header"]; + if (!string.IsNullOrEmpty(legacyCookieHeader)) + { + CookieHeader = legacyCookieHeader; + } + else + { + // Legacy cookie key + var jcookies = jsonConfig["cookies"]; + if (jcookies is JArray) + { + var array = (JArray)jcookies; + legacyCookieHeader = string.Empty; + for (int i = 0; i < array.Count; i++) + { + if (i != 0) + legacyCookieHeader += "; "; + legacyCookieHeader += array[i]; + } + CookieHeader = legacyCookieHeader; + } + else if (jcookies != null) + { + CookieHeader = (string)jcookies; + } + } + } + + virtual public void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) + { + IProtectionService ps = null; + if (useProtectionService) + ps = protectionService; + configData.LoadValuesFromJson(jsonConfig, ps); + if (string.IsNullOrWhiteSpace(configData.SiteLink.Value)) + { + configData.SiteLink.Value = DefaultSiteLink; + } + if (!configData.SiteLink.Value.EndsWith("/")) + configData.SiteLink.Value += "/"; + + var match = Regex.Match(configData.SiteLink.Value, "^https?:\\/\\/[\\w\\-\\/\\.]+$"); + if (!match.Success) + { + throw new Exception(string.Format("\"{0}\" is not a valid URL.", configData.SiteLink.Value)); + } + + SiteLink = configData.SiteLink.Value; + } + + public virtual void LoadFromSavedConfiguration(JToken jsonConfig) + { + if (jsonConfig is JArray) + { + LoadValuesFromJson(jsonConfig, true); + IsConfigured = true; + } + // read and upgrade old settings file format + else if (jsonConfig is Object) + { + LoadLegacyCookieConfig(jsonConfig); + SaveConfig(); + IsConfigured = true; + } + } + + public async virtual Task<byte[]> Download(Uri link) + { + return await Download(link, RequestType.GET); + } + + public async virtual Task<byte[]> Download(Uri link, RequestType method = RequestType.GET) + { + // do some extra escaping, needed for HD-Torrents + var requestLink = link.ToString() + .Replace("(", "%28") + .Replace(")", "%29") + .Replace("'", "%27"); + var response = await RequestBytesWithCookiesAndRetry(requestLink, null, method, requestLink); + if (response.Status != System.Net.HttpStatusCode.OK && response.Status != System.Net.HttpStatusCode.Continue && response.Status != System.Net.HttpStatusCode.PartialContent) + { + logger.Error("Failed download cookies: " + this.CookieHeader); + if (response.Content != null) + logger.Error("Failed download response:\n" + Encoding.UTF8.GetString(response.Content)); + throw new Exception($"Remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => "+response.RedirectingTo : "")); + } + + return response.Content; + } + + protected async Task<WebClientByteResult> RequestBytesWithCookiesAndRetry(string url, string cookieOverride = null, RequestType method = RequestType.GET, string referer = null, IEnumerable<KeyValuePair<string, string>> data = null) + { + Exception lastException = null; + for (int i = 0; i < 3; i++) + { + try + { + return await RequestBytesWithCookies(url, cookieOverride, method, referer, data); + } + catch (Exception e) + { + logger.Error(e, string.Format("On attempt {0} downloading from {1}: {2}", (i + 1), DisplayName, e.Message)); + lastException = e; + } + await Task.Delay(500); + } + + throw lastException; + } + + protected async Task<WebClientStringResult> RequestStringWithCookies(string url, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null) + { + var request = new Utils.Clients.WebRequest() + { + Url = url, + Type = RequestType.GET, + Cookies = CookieHeader, + Referer = referer, + Headers = headers, + Encoding = Encoding + }; + + if (cookieOverride != null) + request.Cookies = cookieOverride; + WebClientStringResult result = await webclient.GetString(request); + UpdateCookieHeader(result.Cookies, cookieOverride); + return result; + } + + protected async Task<WebClientStringResult> RequestStringWithCookiesAndRetry(string url, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null) + { + Exception lastException = null; + for (int i = 0; i < 3; i++) + { + try + { + return await RequestStringWithCookies(url, cookieOverride, referer, headers); + } + catch (Exception e) + { + logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message)); + lastException = e; + } + await Task.Delay(500); + } + + throw lastException; + } + + protected async Task<WebClientByteResult> RequestBytesWithCookies(string url, string cookieOverride = null, RequestType method = RequestType.GET, string referer = null, IEnumerable<KeyValuePair<string, string>> data = null, Dictionary<string, string> headers = null) + { + var request = new Utils.Clients.WebRequest() + { + Url = url, + Type = method, + Cookies = cookieOverride ?? CookieHeader, + PostData = data, + Referer = referer, + Headers = headers, + Encoding = Encoding + }; + + if (cookieOverride != null) + request.Cookies = cookieOverride; + return await webclient.GetBytes(request); + } + + protected async Task<WebClientStringResult> PostDataWithCookies(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null) + { + var request = new Utils.Clients.WebRequest() + { + Url = url, + Type = RequestType.POST, + Cookies = cookieOverride ?? CookieHeader, + PostData = data, + Referer = referer, + Headers = headers, + RawBody = rawbody, + Encoding = Encoding + }; + + if (emulateBrowser.HasValue) + request.EmulateBrowser = emulateBrowser.Value; + WebClientStringResult result = await webclient.GetString(request); + UpdateCookieHeader(result.Cookies, cookieOverride); + return result; + } + + protected async Task<WebClientStringResult> PostDataWithCookiesAndRetry(string url, IEnumerable<KeyValuePair<string, string>> data, string cookieOverride = null, string referer = null, Dictionary<string, string> headers = null, string rawbody = null, bool? emulateBrowser = null) + { + Exception lastException = null; + for (int i = 0; i < 3; i++) + { + try + { + return await PostDataWithCookies(url, data, cookieOverride, referer, headers, rawbody, emulateBrowser); + } + catch (Exception e) + { + logger.Error(string.Format("On attempt {0} checking for results from {1}: {2}", (i + 1), DisplayName, e.Message)); + lastException = e; + } + await Task.Delay(500); + } + + throw lastException; + } + + protected async Task<WebClientStringResult> RequestLoginAndFollowRedirect(string url, IEnumerable<KeyValuePair<string, string>> data, string cookies, bool returnCookiesFromFirstCall, string redirectUrlOverride = null, string referer = null, bool accumulateCookies = false) + { + var request = new Utils.Clients.WebRequest() + { + Url = url, + Type = RequestType.POST, + Cookies = cookies, + Referer = referer, + PostData = data, + Encoding = Encoding + }; + var response = await webclient.GetString(request); + if (accumulateCookies) + { + response.Cookies = ResolveCookies((request.Cookies == null ? "" : request.Cookies + " ") + response.Cookies); + } + var firstCallCookies = response.Cookies; + + if (response.IsRedirect) + { + await FollowIfRedirect(response, request.Url, redirectUrlOverride, response.Cookies, accumulateCookies); + } + + if (returnCookiesFromFirstCall) + { + response.Cookies = ResolveCookies(firstCallCookies + (accumulateCookies ? " " + response.Cookies : "")); + } + + return response; + } + + protected async Task ConfigureIfOK(string cookies, bool isLoggedin, Func<Task> onError) + { + if (isLoggedin) + { + CookieHeader = cookies; + SaveConfig(); + IsConfigured = true; + } + else + { + await onError(); + } + } + + public virtual IEnumerable<ReleaseInfo> FilterResults(TorznabQuery query, IEnumerable<ReleaseInfo> results) + { + foreach (var result in results) + { + if (query.Categories.Length == 0 || result.Category == null || result.Category.Count() == 0 || query.Categories.Intersect(result.Category).Any() || TorznabCatType.QueryContainsParentCategory(query.Categories, result.Category)) + { + yield return result; + } + } + } + + protected List<string> GetAllTrackerCategories() + { + return categoryMapping.Select(x => x.TrackerCategory).ToList(); + } + + protected void AddCategoryMapping(string trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) + { + categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, newznabCategory.ID)); + if (!TorznabCaps.Categories.Contains(newznabCategory)) + { + TorznabCaps.Categories.Add(newznabCategory); + if (TorznabCatType.Movies.Contains(newznabCategory)) + TorznabCaps.MovieSearchAvailable = true; + } + + // add 1:1 categories + if (trackerCategoryDesc != null && trackerCategory != null) + { + try + { + var trackerCategoryInt = int.Parse(trackerCategory); + var CustomCat = new TorznabCategory(trackerCategoryInt + 100000, trackerCategoryDesc); + if (!TorznabCaps.Categories.Contains(CustomCat)) + TorznabCaps.Categories.Add(CustomCat); + } + catch (FormatException) + { + // trackerCategory is not an integer, continue + } + } + } + + protected void AddCategoryMapping(int trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) + { + AddCategoryMapping(trackerCategory.ToString(), newznabCategory, trackerCategoryDesc); + } + + protected void AddMultiCategoryMapping(TorznabCategory newznabCategory, params int[] trackerCategories) + { + foreach (var trackerCat in trackerCategories) + { + AddCategoryMapping(trackerCat, newznabCategory); + } + } + + protected virtual List<string> MapTorznabCapsToTrackers(TorznabQuery query, bool mapChildrenCatsToParent = false) + { + var result = new List<string>(); + foreach (var cat in query.Categories) + { + // use 1:1 mapping to tracker categories for newznab categories >= 100000 + if (cat >= 100000) + { + result.Add((cat - 100000).ToString()); + continue; + } + + var queryCats = new List<int> { cat }; + var newznabCat = TorznabCatType.AllCats.FirstOrDefault(c => c.ID == cat); + if (newznabCat != null) + { + queryCats.AddRange(newznabCat.SubCategories.Select(c => c.ID)); + } + + if (mapChildrenCatsToParent) + { + var parentNewznabCat = TorznabCatType.AllCats.FirstOrDefault(c => c.SubCategories.Contains(newznabCat)); + if (parentNewznabCat != null) + { + queryCats.Add(parentNewznabCat.ID); + } + } + + foreach (var mapping in categoryMapping.Where(c => queryCats.Contains(c.NewzNabCategory))) + { + result.Add(mapping.TrackerCategory); + } + } + + return result.Distinct().ToList(); + } + } +} diff --git a/src/Jackett/Indexers/BestFriends.cs b/src/Jackett/Indexers/BestFriends.cs index 0ce02cc5..d6e98687 100644 --- a/src/Jackett/Indexers/BestFriends.cs +++ b/src/Jackett/Indexers/BestFriends.cs @@ -10,9 +10,9 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; - +using System.Collections.Specialized; +using System.Text; + namespace Jackett.Indexers { public class BestFriends : BaseIndexer, IIndexer @@ -42,49 +42,49 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - AddCategoryMapping(18, TorznabCatType.TVAnime); // Anime - AddCategoryMapping(8, TorznabCatType.PCMac); // Appz MAC - AddCategoryMapping(9, TorznabCatType.PC); // Appz other - AddCategoryMapping(7, TorznabCatType.PC); // Appz Windows - AddCategoryMapping(23, TorznabCatType.TVDocumentary); // Dokumentationen - AddCategoryMapping(32, TorznabCatType.Movies3D); // DVD 3D - AddCategoryMapping(15, TorznabCatType.Books); // eBooks - AddCategoryMapping(12, TorznabCatType.PCGames); // Games PC - AddCategoryMapping(37, TorznabCatType.PCPhoneOther); // Handy_Mobile - AddCategoryMapping(24, TorznabCatType.TVHD); // HDTV - AddCategoryMapping(22, TorznabCatType.AudioAudiobook); // Hörbücher - AddCategoryMapping(1, TorznabCatType.MoviesHD); // Movies 1080p/1080i - AddCategoryMapping(31, TorznabCatType.Movies3D); // Movies 3D - AddCategoryMapping(2, TorznabCatType.MoviesHD); // Movies 720p/720i - AddCategoryMapping(21, TorznabCatType.MoviesBluRay); // Movies BluRay - AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movies DVD/HDDVD - AddCategoryMapping(6, TorznabCatType.MoviesSD); // Movies M/SVCD/Other - AddCategoryMapping(4, TorznabCatType.MoviesSD); // Movies XVID/DIVX/h.264 - AddCategoryMapping(10, TorznabCatType.Audio); // Music - AddCategoryMapping(25, TorznabCatType.AudioVideo); // Musikvideo - AddCategoryMapping(29, TorznabCatType.ConsoleNDS); // Nintendo DS - AddCategoryMapping(16, TorznabCatType.Other); // other - AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Playstation - AddCategoryMapping(28, TorznabCatType.TVHD); // Serien HD - AddCategoryMapping(11, TorznabCatType.TVSD); // Serien XviD - AddCategoryMapping(33, TorznabCatType.Other); // Specials - AddCategoryMapping(30, TorznabCatType.TVSport); // Sport - AddCategoryMapping(19, TorznabCatType.TVOTHER); // TVRip - AddCategoryMapping(38, TorznabCatType.TVDocumentary); // US Dokus - AddCategoryMapping(20, TorznabCatType.MoviesForeign); // US Movies - AddCategoryMapping(14, TorznabCatType.TVFOREIGN); // US Serien - AddCategoryMapping(36, TorznabCatType.Other); // Wallpaper - AddCategoryMapping(26, TorznabCatType.ConsoleWii); // Wii - AddCategoryMapping(27, TorznabCatType.ConsoleXbox360); // Xbox 360 + AddCategoryMapping(18, TorznabCatType.TVAnime); // Anime + AddCategoryMapping(8, TorznabCatType.PCMac); // Appz MAC + AddCategoryMapping(9, TorznabCatType.PC); // Appz other + AddCategoryMapping(7, TorznabCatType.PC); // Appz Windows + AddCategoryMapping(23, TorznabCatType.TVDocumentary); // Dokumentationen + AddCategoryMapping(32, TorznabCatType.Movies3D); // DVD 3D + AddCategoryMapping(15, TorznabCatType.Books); // eBooks + AddCategoryMapping(12, TorznabCatType.PCGames); // Games PC + AddCategoryMapping(37, TorznabCatType.PCPhoneOther); // Handy_Mobile + AddCategoryMapping(24, TorznabCatType.TVHD); // HDTV + AddCategoryMapping(22, TorznabCatType.AudioAudiobook); // Hörbücher + AddCategoryMapping(1, TorznabCatType.MoviesHD); // Movies 1080p/1080i + AddCategoryMapping(31, TorznabCatType.Movies3D); // Movies 3D + AddCategoryMapping(2, TorznabCatType.MoviesHD); // Movies 720p/720i + AddCategoryMapping(21, TorznabCatType.MoviesBluRay); // Movies BluRay + AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movies DVD/HDDVD + AddCategoryMapping(6, TorznabCatType.MoviesSD); // Movies M/SVCD/Other + AddCategoryMapping(4, TorznabCatType.MoviesSD); // Movies XVID/DIVX/h.264 + AddCategoryMapping(10, TorznabCatType.Audio); // Music + AddCategoryMapping(25, TorznabCatType.AudioVideo); // Musikvideo + AddCategoryMapping(29, TorznabCatType.ConsoleNDS); // Nintendo DS + AddCategoryMapping(16, TorznabCatType.Other); // other + AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Playstation + AddCategoryMapping(28, TorznabCatType.TVHD); // Serien HD + AddCategoryMapping(11, TorznabCatType.TVSD); // Serien XviD + AddCategoryMapping(33, TorznabCatType.Other); // Specials + AddCategoryMapping(30, TorznabCatType.TVSport); // Sport + AddCategoryMapping(19, TorznabCatType.TVOTHER); // TVRip + AddCategoryMapping(38, TorznabCatType.TVDocumentary); // US Dokus + AddCategoryMapping(20, TorznabCatType.MoviesForeign); // US Movies + AddCategoryMapping(14, TorznabCatType.TVFOREIGN); // US Serien + AddCategoryMapping(36, TorznabCatType.Other); // Wallpaper + AddCategoryMapping(26, TorznabCatType.ConsoleWii); // Wii + AddCategoryMapping(27, TorznabCatType.ConsoleXbox360); // Xbox 360 AddCategoryMapping(3, TorznabCatType.XXX); // XXX } public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - CQ dom = loginPage.Content; - CQ qCaptchaImg = dom.Find("td.tablea > img").First(); - + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + CQ dom = loginPage.Content; + CQ qCaptchaImg = dom.Find("td.tablea > img").First(); + var CaptchaUrl = SiteLink + qCaptchaImg.Attr("src"); var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies); configData.CaptchaImage.Value = captchaImage.Content; @@ -99,15 +99,15 @@ namespace Jackett.Indexers var pairs1 = new Dictionary<string, string> { { "proofcode", configData.CaptchaText.Value } - }; - var cookies = configData.CaptchaCookie.Value; + }; + var cookies = configData.CaptchaCookie.Value; var result1 = await RequestLoginAndFollowRedirect(LoginUrl, pairs1, cookies, true, null, LoginUrl, true); - if(result1.Content == null || !result1.Content.Contains("takelogin.php")) - { - CQ dom = result1.Content; - var errorMessage = dom["#login_error"].Text().Trim(); - errorMessage = result1.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + if(result1.Content == null || !result1.Content.Contains("takelogin.php")) + { + CQ dom = result1.Content; + var errorMessage = dom["#login_error"].Text().Trim(); + errorMessage = result1.Content; + throw new ExceptionWithConfigData(errorMessage, configData); } var pairs2 = new Dictionary<string, string> @@ -129,33 +129,33 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("showsearch", "1"); - queryCollection.Add("incldead", "1"); - queryCollection.Add("blah", "0"); - queryCollection.Add("orderby", "added"); - queryCollection.Add("sort", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "1"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("blah", "0"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); @@ -168,55 +168,55 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 0.75; + release.MinimumRatio = 0.75; release.MinimumSeedTime = 0; - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - release.Title = qDetailsLink.Attr("title"); - - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - - // use negative indexes as if a user has "Wartezeit" there's an extra column after the title - var qSeeders = qRow.Find("td:nth-last-child(4)"); - var qLeechers = qRow.Find("td:nth-last-child(3)"); - var qDateStr = qRow.Find("td:nth-last-child(7)"); - var qSize = qRow.Find("td:nth-last-child(6)"); - - var torrentId = qDetailsLink.Attr("href").Replace("&hit=1", "").Split('=')[1]; - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + "download.php?torrent="+torrentId); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(",", ".")); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Attr("title"); + + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + + // use negative indexes as if a user has "Wartezeit" there's an extra column after the title + var qSeeders = qRow.Find("td:nth-last-child(4)"); + var qLeechers = qRow.Find("td:nth-last-child(3)"); + var qDateStr = qRow.Find("td:nth-last-child(7)"); + var qSize = qRow.Find("td:nth-last-child(6)"); + + var torrentId = qDetailsLink.Attr("href").Replace("&hit=1", "").Split('=')[1]; + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + "download.php?torrent="+torrentId); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(",", ".")); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text(); var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyyHH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); - release.PublishDate = pubDateUtc; - + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + release.PublishDate = pubDateUtc; + var files = qRow.Find("td:nth-last-child(9)").Text(); release.Files = ParseUtil.CoerceInt(files); var grabs = qRow.Find("td:nth-last-child(5)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("font[color=\"red\"]:contains(OnlyUp)").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("font[color=\"red\"]:contains(OnlyUp)").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/BeyondHD.cs b/src/Jackett/Indexers/BeyondHD.cs index e5f59385..3c92bec0 100644 --- a/src/Jackett/Indexers/BeyondHD.cs +++ b/src/Jackett/Indexers/BeyondHD.cs @@ -107,8 +107,8 @@ namespace Jackett.Indexers var queryCollection = new NameValueCollection(); if (!string.IsNullOrWhiteSpace(searchString)) - { - Regex ReplaceRegex = new Regex("[^a-zA-Z0-9]+"); + { + Regex ReplaceRegex = new Regex("[^a-zA-Z0-9]+"); searchString = "%" + ReplaceRegex.Replace(searchString, "%") + "%"; searchString = Regex.Replace(searchString, @"(%\d{3,4})[ip](%)", "$1$2"); // remove i/p from resolution tags (see #835) queryCollection.Add("search", searchString); @@ -164,7 +164,7 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(9) > a").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - release.DownloadVolumeFactor = 0; // ratioless + release.DownloadVolumeFactor = 0; // ratioless release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/BitCityReloaded.cs b/src/Jackett/Indexers/BitCityReloaded.cs index f2ed81fe..96072a86 100644 --- a/src/Jackett/Indexers/BitCityReloaded.cs +++ b/src/Jackett/Indexers/BitCityReloaded.cs @@ -12,8 +12,8 @@ using System; using System.Text; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - +using System.Collections.Specialized; + namespace Jackett.Indexers { public class BitCityReloaded : BaseIndexer, IIndexer @@ -43,43 +43,43 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show a reasonable amount (it looks like there's no maximum)."; + this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show a reasonable amount (it looks like there's no maximum)."; this.configData.DisplayText.Name = "Notice"; - AddCategoryMapping(1, TorznabCatType.Other); // Anderes - AddCategoryMapping(2, TorznabCatType.TVAnime); // Anime - AddCategoryMapping(34, TorznabCatType.PC); // Appz/Linux - AddCategoryMapping(35, TorznabCatType.PCMac); // Appz/Mac - AddCategoryMapping(36, TorznabCatType.PC); // Appz/Other - AddCategoryMapping(20, TorznabCatType.PC); // Appz/Win - AddCategoryMapping(3, TorznabCatType.TVDocumentary); // Doku/Alle Formate - AddCategoryMapping(4, TorznabCatType.Books); // EBooks - AddCategoryMapping(12, TorznabCatType.ConsolePS4); // Games PS / PSX - AddCategoryMapping(11, TorznabCatType.ConsoleNDS); // Games/Nintendo DS - AddCategoryMapping(10, TorznabCatType.PCGames); // Games/PC - AddCategoryMapping(13, TorznabCatType.ConsoleWii); // Games/Wii - AddCategoryMapping(14, TorznabCatType.ConsoleXbox); // Games/Xbox & 360 - AddCategoryMapping(15, TorznabCatType.PCPhoneOther); // Handy & PDA - AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // Hörspiel/Hörbuch - AddCategoryMapping(30, TorznabCatType.Other); // International - AddCategoryMapping(17, TorznabCatType.Other); // MegaPack - AddCategoryMapping(43, TorznabCatType.Movies3D); // Movie/3D - AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movie/DVD/R - AddCategoryMapping(6, TorznabCatType.MoviesHD); // Movie/HD 1080p - AddCategoryMapping(7, TorznabCatType.MoviesHD); // Movie/HD 720p - AddCategoryMapping(32, TorznabCatType.MoviesOther); // Movie/TVRip - AddCategoryMapping(9, TorznabCatType.MoviesOther); // Movie/XviD,DivX,h264 - AddCategoryMapping(26, TorznabCatType.XXX); // Movie/XXX - AddCategoryMapping(41, TorznabCatType.XXXOther); // Movie/XXX/Other - AddCategoryMapping(42, TorznabCatType.XXXPacks); // Movie/XXX/Pack - AddCategoryMapping(45, TorznabCatType.MoviesHD); // Movies/4K - AddCategoryMapping(33, TorznabCatType.MoviesBluRay); // Movies/BluRay - AddCategoryMapping(18, TorznabCatType.Audio); // Musik - AddCategoryMapping(19, TorznabCatType.AudioVideo); // Musik Videos - AddCategoryMapping(44, TorznabCatType.TVOTHER); // Serie/DVD/R - AddCategoryMapping(22, TorznabCatType.TVHD); // Serie/HDTV - AddCategoryMapping(38, TorznabCatType.TV); // Serie/Pack - AddCategoryMapping(23, TorznabCatType.TVOTHER); // Serie/XviD,DivX,h264 + AddCategoryMapping(1, TorznabCatType.Other); // Anderes + AddCategoryMapping(2, TorznabCatType.TVAnime); // Anime + AddCategoryMapping(34, TorznabCatType.PC); // Appz/Linux + AddCategoryMapping(35, TorznabCatType.PCMac); // Appz/Mac + AddCategoryMapping(36, TorznabCatType.PC); // Appz/Other + AddCategoryMapping(20, TorznabCatType.PC); // Appz/Win + AddCategoryMapping(3, TorznabCatType.TVDocumentary); // Doku/Alle Formate + AddCategoryMapping(4, TorznabCatType.Books); // EBooks + AddCategoryMapping(12, TorznabCatType.ConsolePS4); // Games PS / PSX + AddCategoryMapping(11, TorznabCatType.ConsoleNDS); // Games/Nintendo DS + AddCategoryMapping(10, TorznabCatType.PCGames); // Games/PC + AddCategoryMapping(13, TorznabCatType.ConsoleWii); // Games/Wii + AddCategoryMapping(14, TorznabCatType.ConsoleXbox); // Games/Xbox & 360 + AddCategoryMapping(15, TorznabCatType.PCPhoneOther); // Handy & PDA + AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // Hörspiel/Hörbuch + AddCategoryMapping(30, TorznabCatType.Other); // International + AddCategoryMapping(17, TorznabCatType.Other); // MegaPack + AddCategoryMapping(43, TorznabCatType.Movies3D); // Movie/3D + AddCategoryMapping(5, TorznabCatType.MoviesDVD); // Movie/DVD/R + AddCategoryMapping(6, TorznabCatType.MoviesHD); // Movie/HD 1080p + AddCategoryMapping(7, TorznabCatType.MoviesHD); // Movie/HD 720p + AddCategoryMapping(32, TorznabCatType.MoviesOther); // Movie/TVRip + AddCategoryMapping(9, TorznabCatType.MoviesOther); // Movie/XviD,DivX,h264 + AddCategoryMapping(26, TorznabCatType.XXX); // Movie/XXX + AddCategoryMapping(41, TorznabCatType.XXXOther); // Movie/XXX/Other + AddCategoryMapping(42, TorznabCatType.XXXPacks); // Movie/XXX/Pack + AddCategoryMapping(45, TorznabCatType.MoviesHD); // Movies/4K + AddCategoryMapping(33, TorznabCatType.MoviesBluRay); // Movies/BluRay + AddCategoryMapping(18, TorznabCatType.Audio); // Musik + AddCategoryMapping(19, TorznabCatType.AudioVideo); // Musik Videos + AddCategoryMapping(44, TorznabCatType.TVOTHER); // Serie/DVD/R + AddCategoryMapping(22, TorznabCatType.TVHD); // Serie/HDTV + AddCategoryMapping(38, TorznabCatType.TV); // Serie/Pack + AddCategoryMapping(23, TorznabCatType.TVOTHER); // Serie/XviD,DivX,h264 AddCategoryMapping(25, TorznabCatType.TVSport); // Sport } @@ -107,25 +107,25 @@ namespace Jackett.Indexers { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("showsearch", "0"); - queryCollection.Add("incldead", "1"); - queryCollection.Add("blah", "0"); - queryCollection.Add("team", "0"); - queryCollection.Add("orderby", "added"); - queryCollection.Add("sort", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "0"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("blah", "0"); + queryCollection.Add("team", "0"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); @@ -138,7 +138,7 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 0.7; + release.MinimumRatio = 0.7; release.MinimumSeedTime = 48 * 60 * 60; release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 1; @@ -146,21 +146,21 @@ namespace Jackett.Indexers var qRow = row.Cq(); var flagImgs = qRow.Find("table tbody tr: eq(0) td > img"); List<string> flags = new List<string>(); - flagImgs.Each(flagImg => { - var flag = flagImg.GetAttribute("src").Replace("pic/torrent_", "").Replace(".gif", "").ToUpper(); - if (flag == "OU") - release.DownloadVolumeFactor = 0; - else - flags.Add(flag); - }); - + flagImgs.Each(flagImg => { + var flag = flagImg.GetAttribute("src").Replace("pic/torrent_", "").Replace(".gif", "").ToUpper(); + if (flag == "OU") + release.DownloadVolumeFactor = 0; + else + flags.Add(flag); + }); + var titleLink = qRow.Find("table tbody tr:eq(0) td a:has(b)").First(); - var DLLink = qRow.Find("td.tableb > a:has(img[title=\"Torrent herunterladen\"])").First(); - release.Comments = new Uri(SiteLink + titleLink.Attr("href").Replace("&hit=1", "")); + var DLLink = qRow.Find("td.tableb > a:has(img[title=\"Torrent herunterladen\"])").First(); + release.Comments = new Uri(SiteLink + titleLink.Attr("href").Replace("&hit=1", "")); release.Link = new Uri(SiteLink + DLLink.Attr("href")); release.Title = titleLink.Text().Trim(); - if (!query.MatchQueryStringAND(release.Title)) + if (!query.MatchQueryStringAND(release.Title)) continue; release.Description = String.Join(", ", flags); @@ -168,7 +168,7 @@ namespace Jackett.Indexers var dateStr = qRow.Find("table tbody tr:eq(1) td:eq(4)").Html().Replace(" ", " ").Trim(); var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc.ToLocalTime(); var sizeStr = qRow.Find("table tbody tr:eq(1) td b").First().Text().Trim(); diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs index 3f01cad7..c707b778 100644 --- a/src/Jackett/Indexers/BitMeTV.cs +++ b/src/Jackett/Indexers/BitMeTV.cs @@ -138,7 +138,7 @@ namespace Jackett.Indexers var grabs = row.Cq().Find("td:nth-child(8)").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - release.DownloadVolumeFactor = 1; + release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/BitSoup.cs b/src/Jackett/Indexers/BitSoup.cs index 544be375..89448976 100644 --- a/src/Jackett/Indexers/BitSoup.cs +++ b/src/Jackett/Indexers/BitSoup.cs @@ -1,232 +1,232 @@ -using CsQuery; -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.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public class BitSoup : BaseIndexer, IIndexer - { - private string BrowseUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "takelogin.php"; } } - private string LoginReferer { get { return SiteLink + "login.php"; } } - public new string[] AlternativeSiteLinks { get; protected set; } = new string[] { "https://www.bitsoup.me/", "https://www.bitsoup.org/" }; - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public BitSoup(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "BitSoup", - description: "SoupieBits", - link: "https://www.bitsoup.me/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.UTF8; - Language = "en-us"; - Type = "private"; - - //AddCategoryMapping("624", TorznabCatType.Console); - //AddCategoryMapping("307", TorznabCatType.ConsoleNDS); - //AddCategoryMapping("308", TorznabCatType.ConsolePSP); - AddCategoryMapping("35", TorznabCatType.ConsoleWii); - //AddCategoryMapping("309", TorznabCatType.ConsoleXbox); - AddCategoryMapping("12", TorznabCatType.ConsoleXbox360); - //AddCategoryMapping("305", TorznabCatType.ConsoleWiiwareVC); - //AddCategoryMapping("309", TorznabCatType.ConsoleXBOX360DLC); - AddCategoryMapping("38", TorznabCatType.ConsolePS3); - //AddCategoryMapping("239", TorznabCatType.ConsoleOther); - //AddCategoryMapping("245", TorznabCatType.ConsoleOther); - //AddCategoryMapping("246", TorznabCatType.ConsoleOther); - //AddCategoryMapping("626", TorznabCatType.ConsoleOther); - //AddCategoryMapping("628", TorznabCatType.ConsoleOther); - //AddCategoryMapping("630", TorznabCatType.ConsoleOther); - //AddCategoryMapping("307", TorznabCatType.Console3DS); - //AddCategoryMapping("308", TorznabCatType.ConsolePSVita); - //AddCategoryMapping("307", TorznabCatType.ConsoleWiiU); - //AddCategoryMapping("309", TorznabCatType.ConsoleXboxOne); - //AddCategoryMapping("308", TorznabCatType.ConsolePS4); - //AddCategoryMapping("631", TorznabCatType.Movies); - //AddCategoryMapping("631", TorznabCatType.MoviesForeign); - //AddCategoryMapping("455", TorznabCatType.MoviesOther); - //AddCategoryMapping("633", TorznabCatType.MoviesOther); - AddCategoryMapping("19", TorznabCatType.MoviesSD); - AddCategoryMapping("41", TorznabCatType.MoviesHD); - AddCategoryMapping("17", TorznabCatType.Movies3D); - AddCategoryMapping("80", TorznabCatType.MoviesBluRay); - AddCategoryMapping("20", TorznabCatType.MoviesDVD); - //AddCategoryMapping("631", TorznabCatType.MoviesWEBDL); - AddCategoryMapping("6", TorznabCatType.Audio); - //AddCategoryMapping("623", TorznabCatType.AudioMP3); - AddCategoryMapping("29", TorznabCatType.AudioVideo); - //AddCategoryMapping("402", TorznabCatType.AudioVideo); - AddCategoryMapping("5", TorznabCatType.AudioAudiobook); - //AddCategoryMapping("1", TorznabCatType.AudioLossless); - //AddCategoryMapping("403", TorznabCatType.AudioOther); - //AddCategoryMapping("642", TorznabCatType.AudioOther); - //AddCategoryMapping("1", TorznabCatType.AudioForeign); - //AddCategoryMapping("233", TorznabCatType.PC); - //AddCategoryMapping("236", TorznabCatType.PC); - //AddCategoryMapping("1", TorznabCatType.PC0day); - AddCategoryMapping("1", TorznabCatType.PCISO); - //AddCategoryMapping("235", TorznabCatType.PCMac); - //AddCategoryMapping("627", TorznabCatType.PCPhoneOther); - AddCategoryMapping("21", TorznabCatType.PCGames); - AddCategoryMapping("4", TorznabCatType.PCGames); - //AddCategoryMapping("625", TorznabCatType.PCPhoneIOS); - //AddCategoryMapping("625", TorznabCatType.PCPhoneAndroid); - AddCategoryMapping("45", TorznabCatType.TV); - //AddCategoryMapping("433", TorznabCatType.TV); - //AddCategoryMapping("639", TorznabCatType.TVWEBDL); - //AddCategoryMapping("433", TorznabCatType.TVWEBDL); - //AddCategoryMapping("639", TorznabCatType.TVFOREIGN); - //AddCategoryMapping("433", TorznabCatType.TVFOREIGN); - AddCategoryMapping("7", TorznabCatType.TVSD); - AddCategoryMapping("49", TorznabCatType.TVSD); - AddCategoryMapping("42", TorznabCatType.TVHD); - //AddCategoryMapping("433", TorznabCatType.TVHD); - //AddCategoryMapping("635", TorznabCatType.TVOTHER); - //AddCategoryMapping("636", TorznabCatType.TVSport); - AddCategoryMapping("23", TorznabCatType.TVAnime); - //AddCategoryMapping("634", TorznabCatType.TVDocumentary); - AddCategoryMapping("9", TorznabCatType.XXX); - //AddCategoryMapping("1", TorznabCatType.XXXDVD); - //AddCategoryMapping("1", TorznabCatType.XXXWMV); - //AddCategoryMapping("1", TorznabCatType.XXXXviD); - //AddCategoryMapping("1", TorznabCatType.XXXx264); - //AddCategoryMapping("1", TorznabCatType.XXXOther); - //AddCategoryMapping("1", TorznabCatType.XXXImageset); - //AddCategoryMapping("1", TorznabCatType.XXXPacks); - //AddCategoryMapping("340", TorznabCatType.Other); - //AddCategoryMapping("342", TorznabCatType.Other); - //AddCategoryMapping("344", TorznabCatType.Other); - //AddCategoryMapping("391", TorznabCatType.Other); - //AddCategoryMapping("392", TorznabCatType.Other); - //AddCategoryMapping("393", TorznabCatType.Other); - //AddCategoryMapping("394", TorznabCatType.Other); - //AddCategoryMapping("234", TorznabCatType.Other); - //AddCategoryMapping("638", TorznabCatType.Other); - //AddCategoryMapping("629", TorznabCatType.Other); - //AddCategoryMapping("1", TorznabCatType.OtherMisc); - //AddCategoryMapping("1", TorznabCatType.OtherHashed); - //AddCategoryMapping("408", TorznabCatType.Books); - AddCategoryMapping("24", TorznabCatType.BooksEbook); - //AddCategoryMapping("406", TorznabCatType.BooksComics); - //AddCategoryMapping("407", TorznabCatType.BooksComics); - //AddCategoryMapping("409", TorznabCatType.BooksComics); - //AddCategoryMapping("410", TorznabCatType.BooksMagazines); - //AddCategoryMapping("1", TorznabCatType.BooksTechnical); - //AddCategoryMapping("1", TorznabCatType.BooksOther); - //AddCategoryMapping("1", TorznabCatType.BooksForeign); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - - }; - - var loginPage = await RequestStringWithCookies(SiteLink, string.Empty); - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginReferer, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["body > table.statusbar1 > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td"].First(); - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var trackerCats = MapTorznabCapsToTrackers(query); - var queryCollection = new NameValueCollection(); - - - queryCollection.Add("search", string.IsNullOrWhiteSpace(searchString) ? "" : searchString); - if (trackerCats.Count > 1) - { - for (var ct = 0; ct < trackerCats.Count; ct++) queryCollection.Add("cat" + (ct + 1), trackerCats.ElementAt(ct)); - } - else - { - queryCollection.Add("cat", (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0")); - } - //queryCollection.Add("cat", (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0")); - searchUrl += "?" + queryCollection.GetQueryString(); - await ProcessPage(releases, searchUrl); - - return releases; - } - - private async Task ProcessPage(List<ReleaseInfo> releases, string searchUrl) - { - var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); - var results = response.Content; - try - { - CQ dom = results; - - var rows = dom["table.koptekst tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - - release.Title = row.Cq().Find("td:eq(1) a").First().Text().Trim(); - release.Comments = new Uri(SiteLink + row.Cq().Find("td:eq(1) a").First().Attr("href")); - - release.Link = new Uri(SiteLink + row.Cq().Find("td:eq(2) a").First().Attr("href")); - release.Guid = release.Link; - release.Description = release.Title; - var cat = row.Cq().Find("td:eq(0) a").First().Attr("href").Substring(15); - release.Category = MapTrackerCatToNewznab(cat); - - var added = row.Cq().Find("td:eq(7)").First().Text().Trim(); - release.PublishDate = DateTime.ParseExact(added, "yyyy-MM-ddH:mm:ss", CultureInfo.InvariantCulture); - - var sizeStr = row.Cq().Find("td:eq(8)").First().Text().Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(row.Cq().Find("td:eq(10)").First().Text().Trim()); - release.Peers = ParseUtil.CoerceInt(row.Cq().Find("td:eq(11)").First().Text().Trim()) + release.Seeders; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results, ex); - } - } - } +using CsQuery; +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.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class BitSoup : BaseIndexer, IIndexer + { + private string BrowseUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + private string LoginReferer { get { return SiteLink + "login.php"; } } + public new string[] AlternativeSiteLinks { get; protected set; } = new string[] { "https://www.bitsoup.me/", "https://www.bitsoup.org/" }; + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public BitSoup(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "BitSoup", + description: "SoupieBits", + link: "https://www.bitsoup.me/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.UTF8; + Language = "en-us"; + Type = "private"; + + //AddCategoryMapping("624", TorznabCatType.Console); + //AddCategoryMapping("307", TorznabCatType.ConsoleNDS); + //AddCategoryMapping("308", TorznabCatType.ConsolePSP); + AddCategoryMapping("35", TorznabCatType.ConsoleWii); + //AddCategoryMapping("309", TorznabCatType.ConsoleXbox); + AddCategoryMapping("12", TorznabCatType.ConsoleXbox360); + //AddCategoryMapping("305", TorznabCatType.ConsoleWiiwareVC); + //AddCategoryMapping("309", TorznabCatType.ConsoleXBOX360DLC); + AddCategoryMapping("38", TorznabCatType.ConsolePS3); + //AddCategoryMapping("239", TorznabCatType.ConsoleOther); + //AddCategoryMapping("245", TorznabCatType.ConsoleOther); + //AddCategoryMapping("246", TorznabCatType.ConsoleOther); + //AddCategoryMapping("626", TorznabCatType.ConsoleOther); + //AddCategoryMapping("628", TorznabCatType.ConsoleOther); + //AddCategoryMapping("630", TorznabCatType.ConsoleOther); + //AddCategoryMapping("307", TorznabCatType.Console3DS); + //AddCategoryMapping("308", TorznabCatType.ConsolePSVita); + //AddCategoryMapping("307", TorznabCatType.ConsoleWiiU); + //AddCategoryMapping("309", TorznabCatType.ConsoleXboxOne); + //AddCategoryMapping("308", TorznabCatType.ConsolePS4); + //AddCategoryMapping("631", TorznabCatType.Movies); + //AddCategoryMapping("631", TorznabCatType.MoviesForeign); + //AddCategoryMapping("455", TorznabCatType.MoviesOther); + //AddCategoryMapping("633", TorznabCatType.MoviesOther); + AddCategoryMapping("19", TorznabCatType.MoviesSD); + AddCategoryMapping("41", TorznabCatType.MoviesHD); + AddCategoryMapping("17", TorznabCatType.Movies3D); + AddCategoryMapping("80", TorznabCatType.MoviesBluRay); + AddCategoryMapping("20", TorznabCatType.MoviesDVD); + //AddCategoryMapping("631", TorznabCatType.MoviesWEBDL); + AddCategoryMapping("6", TorznabCatType.Audio); + //AddCategoryMapping("623", TorznabCatType.AudioMP3); + AddCategoryMapping("29", TorznabCatType.AudioVideo); + //AddCategoryMapping("402", TorznabCatType.AudioVideo); + AddCategoryMapping("5", TorznabCatType.AudioAudiobook); + //AddCategoryMapping("1", TorznabCatType.AudioLossless); + //AddCategoryMapping("403", TorznabCatType.AudioOther); + //AddCategoryMapping("642", TorznabCatType.AudioOther); + //AddCategoryMapping("1", TorznabCatType.AudioForeign); + //AddCategoryMapping("233", TorznabCatType.PC); + //AddCategoryMapping("236", TorznabCatType.PC); + //AddCategoryMapping("1", TorznabCatType.PC0day); + AddCategoryMapping("1", TorznabCatType.PCISO); + //AddCategoryMapping("235", TorznabCatType.PCMac); + //AddCategoryMapping("627", TorznabCatType.PCPhoneOther); + AddCategoryMapping("21", TorznabCatType.PCGames); + AddCategoryMapping("4", TorznabCatType.PCGames); + //AddCategoryMapping("625", TorznabCatType.PCPhoneIOS); + //AddCategoryMapping("625", TorznabCatType.PCPhoneAndroid); + AddCategoryMapping("45", TorznabCatType.TV); + //AddCategoryMapping("433", TorznabCatType.TV); + //AddCategoryMapping("639", TorznabCatType.TVWEBDL); + //AddCategoryMapping("433", TorznabCatType.TVWEBDL); + //AddCategoryMapping("639", TorznabCatType.TVFOREIGN); + //AddCategoryMapping("433", TorznabCatType.TVFOREIGN); + AddCategoryMapping("7", TorznabCatType.TVSD); + AddCategoryMapping("49", TorznabCatType.TVSD); + AddCategoryMapping("42", TorznabCatType.TVHD); + //AddCategoryMapping("433", TorznabCatType.TVHD); + //AddCategoryMapping("635", TorznabCatType.TVOTHER); + //AddCategoryMapping("636", TorznabCatType.TVSport); + AddCategoryMapping("23", TorznabCatType.TVAnime); + //AddCategoryMapping("634", TorznabCatType.TVDocumentary); + AddCategoryMapping("9", TorznabCatType.XXX); + //AddCategoryMapping("1", TorznabCatType.XXXDVD); + //AddCategoryMapping("1", TorznabCatType.XXXWMV); + //AddCategoryMapping("1", TorznabCatType.XXXXviD); + //AddCategoryMapping("1", TorznabCatType.XXXx264); + //AddCategoryMapping("1", TorznabCatType.XXXOther); + //AddCategoryMapping("1", TorznabCatType.XXXImageset); + //AddCategoryMapping("1", TorznabCatType.XXXPacks); + //AddCategoryMapping("340", TorznabCatType.Other); + //AddCategoryMapping("342", TorznabCatType.Other); + //AddCategoryMapping("344", TorznabCatType.Other); + //AddCategoryMapping("391", TorznabCatType.Other); + //AddCategoryMapping("392", TorznabCatType.Other); + //AddCategoryMapping("393", TorznabCatType.Other); + //AddCategoryMapping("394", TorznabCatType.Other); + //AddCategoryMapping("234", TorznabCatType.Other); + //AddCategoryMapping("638", TorznabCatType.Other); + //AddCategoryMapping("629", TorznabCatType.Other); + //AddCategoryMapping("1", TorznabCatType.OtherMisc); + //AddCategoryMapping("1", TorznabCatType.OtherHashed); + //AddCategoryMapping("408", TorznabCatType.Books); + AddCategoryMapping("24", TorznabCatType.BooksEbook); + //AddCategoryMapping("406", TorznabCatType.BooksComics); + //AddCategoryMapping("407", TorznabCatType.BooksComics); + //AddCategoryMapping("409", TorznabCatType.BooksComics); + //AddCategoryMapping("410", TorznabCatType.BooksMagazines); + //AddCategoryMapping("1", TorznabCatType.BooksTechnical); + //AddCategoryMapping("1", TorznabCatType.BooksOther); + //AddCategoryMapping("1", TorznabCatType.BooksForeign); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + + }; + + var loginPage = await RequestStringWithCookies(SiteLink, string.Empty); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, null, LoginReferer, true); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["body > table.statusbar1 > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td"].First(); + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var trackerCats = MapTorznabCapsToTrackers(query); + var queryCollection = new NameValueCollection(); + + + queryCollection.Add("search", string.IsNullOrWhiteSpace(searchString) ? "" : searchString); + if (trackerCats.Count > 1) + { + for (var ct = 0; ct < trackerCats.Count; ct++) queryCollection.Add("cat" + (ct + 1), trackerCats.ElementAt(ct)); + } + else + { + queryCollection.Add("cat", (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0")); + } + //queryCollection.Add("cat", (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0")); + searchUrl += "?" + queryCollection.GetQueryString(); + await ProcessPage(releases, searchUrl); + + return releases; + } + + private async Task ProcessPage(List<ReleaseInfo> releases, string searchUrl) + { + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + var results = response.Content; + try + { + CQ dom = results; + + var rows = dom["table.koptekst tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + + release.Title = row.Cq().Find("td:eq(1) a").First().Text().Trim(); + release.Comments = new Uri(SiteLink + row.Cq().Find("td:eq(1) a").First().Attr("href")); + + release.Link = new Uri(SiteLink + row.Cq().Find("td:eq(2) a").First().Attr("href")); + release.Guid = release.Link; + release.Description = release.Title; + var cat = row.Cq().Find("td:eq(0) a").First().Attr("href").Substring(15); + release.Category = MapTrackerCatToNewznab(cat); + + var added = row.Cq().Find("td:eq(7)").First().Text().Trim(); + release.PublishDate = DateTime.ParseExact(added, "yyyy-MM-ddH:mm:ss", CultureInfo.InvariantCulture); + + var sizeStr = row.Cq().Find("td:eq(8)").First().Text().Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(row.Cq().Find("td:eq(10)").First().Text().Trim()); + release.Peers = ParseUtil.CoerceInt(row.Cq().Find("td:eq(11)").First().Text().Trim()) + release.Seeders; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/BroadcastTheNet.cs b/src/Jackett/Indexers/BroadcastTheNet.cs index 51b63b13..7387d052 100644 --- a/src/Jackett/Indexers/BroadcastTheNet.cs +++ b/src/Jackett/Indexers/BroadcastTheNet.cs @@ -1,177 +1,177 @@ -using CsQuery; -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.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; -using System.Dynamic; -using Newtonsoft.Json; - -namespace Jackett.Indexers -{ - public class BroadcastTheNet : BaseIndexer, IIndexer - { - string APIBASE = "https://api.broadcasthe.net"; - - new ConfigurationDataAPIKey configData - { - get { return (ConfigurationDataAPIKey)base.configData; } - set { base.configData = value; } - } - - public BroadcastTheNet(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "BroadcastTheNet", - description: "Needs no description..", - link: "https://broadcasthe.net/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataAPIKey()) - { - Encoding = Encoding.UTF8; - Language = "en-us"; - Type = "private"; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - IsConfigured = false; - try - { - var results = await PerformQuery(new TorznabQuery()); - if (results.Count() == 0) - throw new Exception("Testing returned no results!"); - IsConfigured = true; - SaveConfig(); - } - catch(Exception e) - { - throw new ExceptionWithConfigData(e.Message, configData); - } - - return IndexerConfigurationStatus.Completed; - } - - - private string JsonRPCRequest(string method, JArray parameters) - { - dynamic request = new JObject(); - request["jsonrpc"] = "2.0"; - request["method"] = method; - request["params"] = parameters; - request["id"] = Guid.NewGuid().ToString().Substring(0, 8); - return request.ToString(); - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var searchString = query.GetQueryString(); - var releases = new List<ReleaseInfo>(); - - var parameters = new JArray(); - parameters.Add(new JValue(configData.Key.Value)); - parameters.Add(new JValue(searchString.Trim())); - parameters.Add(new JValue(100)); - parameters.Add(new JValue(0)); - var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary<string, string>() - { - { "Accept", "application/json-rpc, application/json"}, - {"Content-Type", "application/json-rpc"} - }, JsonRPCRequest("getTorrents", parameters),false); - - try - { - var btnResponse = JsonConvert.DeserializeObject<BTNRPCResponse>(response.Content); - - if (btnResponse != null && btnResponse.Result != null) - { - foreach (var itemKey in btnResponse.Result.Torrents) - { - var btnResult = itemKey.Value; - var item = new ReleaseInfo(); - if (!string.IsNullOrEmpty(btnResult.SeriesBanner)) - item.BannerUrl = new Uri(btnResult.SeriesBanner); - item.Category = new List<int> { TorznabCatType.TV.ID }; - item.Comments = new Uri($"https://broadcasthe.net/torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}"); - item.Description = btnResult.ReleaseName; - item.Guid = new Uri(btnResult.DownloadURL); - if (!string.IsNullOrWhiteSpace(btnResult.ImdbID)) - item.Imdb = ParseUtil.CoerceLong(btnResult.ImdbID); - item.Link = new Uri(btnResult.DownloadURL); - item.MinimumRatio = 1; - item.PublishDate = DateTimeUtil.UnixTimestampToDateTime(btnResult.Time); - item.RageID = btnResult.TvrageID; - item.Seeders = btnResult.Seeders; - item.Peers = btnResult.Seeders + btnResult.Leechers; - item.Size = btnResult.Size; - item.TVDBId = btnResult.TvdbID; - item.Title = btnResult.ReleaseName; - releases.Add(item); - } - } - - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - return releases; - } - - - public class BTNRPCResponse - { - public string Id { get; set; } - public BTNResultPage Result { get; set; } - } - - public class BTNResultPage - { - public Dictionary<int, BTNResultItem> Torrents { get; set; } - } - - public class BTNResultItem - { - public int TorrentID { get; set; } - public string DownloadURL { get; set; } - public string GroupName { get; set; } - public int GroupID { get; set; } - public int SeriesID { get; set; } - public string Series { get; set; } - public string SeriesBanner { get; set; } - public string SeriesPoster { get; set; } - public string YoutubeTrailer { get; set; } - public string Category { get; set; } - public int? Snatched { get; set; } - public int? Seeders { get; set; } - public int? Leechers { get; set; } - public string Source { get; set; } - public string Container { get; set; } - public string Codec { get; set; } - public string Resolution { get; set; } - public string Origin { get; set; } - public string ReleaseName { get; set; } - public long Size { get; set; } - public long Time { get; set; } - public int? TvdbID { get; set; } - public int? TvrageID { get; set; } - public string ImdbID { get; set; } - public string InfoHash { get; set; } - } - } -} +using CsQuery; +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.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using System.Dynamic; +using Newtonsoft.Json; + +namespace Jackett.Indexers +{ + public class BroadcastTheNet : BaseIndexer, IIndexer + { + string APIBASE = "https://api.broadcasthe.net"; + + new ConfigurationDataAPIKey configData + { + get { return (ConfigurationDataAPIKey)base.configData; } + set { base.configData = value; } + } + + public BroadcastTheNet(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "BroadcastTheNet", + description: "Needs no description..", + link: "https://broadcasthe.net/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataAPIKey()) + { + Encoding = Encoding.UTF8; + Language = "en-us"; + Type = "private"; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + IsConfigured = false; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (results.Count() == 0) + throw new Exception("Testing returned no results!"); + IsConfigured = true; + SaveConfig(); + } + catch(Exception e) + { + throw new ExceptionWithConfigData(e.Message, configData); + } + + return IndexerConfigurationStatus.Completed; + } + + + private string JsonRPCRequest(string method, JArray parameters) + { + dynamic request = new JObject(); + request["jsonrpc"] = "2.0"; + request["method"] = method; + request["params"] = parameters; + request["id"] = Guid.NewGuid().ToString().Substring(0, 8); + return request.ToString(); + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var searchString = query.GetQueryString(); + var releases = new List<ReleaseInfo>(); + + var parameters = new JArray(); + parameters.Add(new JValue(configData.Key.Value)); + parameters.Add(new JValue(searchString.Trim())); + parameters.Add(new JValue(100)); + parameters.Add(new JValue(0)); + var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary<string, string>() + { + { "Accept", "application/json-rpc, application/json"}, + {"Content-Type", "application/json-rpc"} + }, JsonRPCRequest("getTorrents", parameters),false); + + try + { + var btnResponse = JsonConvert.DeserializeObject<BTNRPCResponse>(response.Content); + + if (btnResponse != null && btnResponse.Result != null) + { + foreach (var itemKey in btnResponse.Result.Torrents) + { + var btnResult = itemKey.Value; + var item = new ReleaseInfo(); + if (!string.IsNullOrEmpty(btnResult.SeriesBanner)) + item.BannerUrl = new Uri(btnResult.SeriesBanner); + item.Category = new List<int> { TorznabCatType.TV.ID }; + item.Comments = new Uri($"https://broadcasthe.net/torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}"); + item.Description = btnResult.ReleaseName; + item.Guid = new Uri(btnResult.DownloadURL); + if (!string.IsNullOrWhiteSpace(btnResult.ImdbID)) + item.Imdb = ParseUtil.CoerceLong(btnResult.ImdbID); + item.Link = new Uri(btnResult.DownloadURL); + item.MinimumRatio = 1; + item.PublishDate = DateTimeUtil.UnixTimestampToDateTime(btnResult.Time); + item.RageID = btnResult.TvrageID; + item.Seeders = btnResult.Seeders; + item.Peers = btnResult.Seeders + btnResult.Leechers; + item.Size = btnResult.Size; + item.TVDBId = btnResult.TvdbID; + item.Title = btnResult.ReleaseName; + releases.Add(item); + } + } + + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + return releases; + } + + + public class BTNRPCResponse + { + public string Id { get; set; } + public BTNResultPage Result { get; set; } + } + + public class BTNResultPage + { + public Dictionary<int, BTNResultItem> Torrents { get; set; } + } + + public class BTNResultItem + { + public int TorrentID { get; set; } + public string DownloadURL { get; set; } + public string GroupName { get; set; } + public int GroupID { get; set; } + public int SeriesID { get; set; } + public string Series { get; set; } + public string SeriesBanner { get; set; } + public string SeriesPoster { get; set; } + public string YoutubeTrailer { get; set; } + public string Category { get; set; } + public int? Snatched { get; set; } + public int? Seeders { get; set; } + public int? Leechers { get; set; } + public string Source { get; set; } + public string Container { get; set; } + public string Codec { get; set; } + public string Resolution { get; set; } + public string Origin { get; set; } + public string ReleaseName { get; set; } + public long Size { get; set; } + public long Time { get; set; } + public int? TvdbID { get; set; } + public int? TvrageID { get; set; } + public string ImdbID { get; set; } + public string InfoHash { get; set; } + } + } +} diff --git a/src/Jackett/Indexers/CardigannIndexer.cs b/src/Jackett/Indexers/CardigannIndexer.cs index 8b341e99..33ad8541 100644 --- a/src/Jackett/Indexers/CardigannIndexer.cs +++ b/src/Jackett/Indexers/CardigannIndexer.cs @@ -8,232 +8,232 @@ using Newtonsoft.Json.Linq; using System.Collections.Generic; using System; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.NamingConventions; -using static Jackett.Models.IndexerConfig.ConfigurationData; -using AngleSharp.Parser.Html; -using System.Text.RegularExpressions; -using System.Web; -using AngleSharp.Dom; -using AngleSharp.Dom.Html; -using System.Linq; - +using System.Collections.Specialized; +using System.Text; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; +using static Jackett.Models.IndexerConfig.ConfigurationData; +using AngleSharp.Parser.Html; +using System.Text.RegularExpressions; +using System.Web; +using AngleSharp.Dom; +using AngleSharp.Dom.Html; +using System.Linq; + namespace Jackett.Indexers { public class CardigannIndexer : BaseIndexer, IIndexer { - public string DefinitionString { get; protected set; } - protected IndexerDefinition Definition; - public new string ID { get { return (Definition != null ? Definition.Site : GetIndexerID(GetType())); } } - + public string DefinitionString { get; protected set; } + protected IndexerDefinition Definition; + public new string ID { get { return (Definition != null ? Definition.Site : GetIndexerID(GetType())); } } + protected WebClientStringResult landingResult; - protected IHtmlDocument landingResultDocument; - + protected IHtmlDocument landingResultDocument; + new ConfigurationData configData { get { return (ConfigurationData)base.configData; } set { base.configData = value; } - } - - // A Dictionary allowing the same key multiple times - public class KeyValuePairList : List<KeyValuePair<string, selectorBlock>>, IDictionary<string, selectorBlock> - { - public selectorBlock this[string key] - { - get - { - throw new NotImplementedException(); - } - - set - { - base.Add(new KeyValuePair<string, selectorBlock>(key, value)); - } - } - - public ICollection<string> Keys - { - get - { - throw new NotImplementedException(); - } - } - - public ICollection<selectorBlock> Values - { - get - { - throw new NotImplementedException(); - } - } - - public void Add(string key, selectorBlock value) - { - base.Add(new KeyValuePair<string, selectorBlock>(key, value)); - } - - public bool ContainsKey(string key) - { - throw new NotImplementedException(); - } - - public bool Remove(string key) - { - throw new NotImplementedException(); - } - - public bool TryGetValue(string key, out selectorBlock value) - { - throw new NotImplementedException(); - } - } - + } + + // A Dictionary allowing the same key multiple times + public class KeyValuePairList : List<KeyValuePair<string, selectorBlock>>, IDictionary<string, selectorBlock> + { + public selectorBlock this[string key] + { + get + { + throw new NotImplementedException(); + } + + set + { + base.Add(new KeyValuePair<string, selectorBlock>(key, value)); + } + } + + public ICollection<string> Keys + { + get + { + throw new NotImplementedException(); + } + } + + public ICollection<selectorBlock> Values + { + get + { + throw new NotImplementedException(); + } + } + + public void Add(string key, selectorBlock value) + { + base.Add(new KeyValuePair<string, selectorBlock>(key, value)); + } + + public bool ContainsKey(string key) + { + throw new NotImplementedException(); + } + + public bool Remove(string key) + { + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out selectorBlock value) + { + throw new NotImplementedException(); + } + } + // Cardigann yaml classes public class IndexerDefinition { - public string Site { get; set; } - public List<settingsField> Settings { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Type { get; set; } - public string Language { get; set; } - public string Encoding { get; set; } - public List<string> Links { get; set; } - public List<string> Certificates { get; set; } - public capabilitiesBlock Caps { get; set; } - public loginBlock Login { get; set; } - public ratioBlock Ratio { get; set; } - public searchBlock Search { get; set; } - public downloadBlock Download { get; set; } - // IndexerDefinitionStats not needed/implemented - } - public class settingsField - { - public string Name { get; set; } - public string Type { get; set; } - public string Label { get; set; } + public string Site { get; set; } + public List<settingsField> Settings { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Type { get; set; } + public string Language { get; set; } + public string Encoding { get; set; } + public List<string> Links { get; set; } + public List<string> Certificates { get; set; } + public capabilitiesBlock Caps { get; set; } + public loginBlock Login { get; set; } + public ratioBlock Ratio { get; set; } + public searchBlock Search { get; set; } + public downloadBlock Download { get; set; } + // IndexerDefinitionStats not needed/implemented + } + public class settingsField + { + public string Name { get; set; } + public string Type { get; set; } + public string Label { get; set; } + } + + public class CategorymappingBlock + { + public string id { get; set; } + public string cat { get; set; } + public string desc { get; set; } + } + + public class capabilitiesBlock + { + public Dictionary<string, string> Categories { get; set; } + public List<CategorymappingBlock> Categorymappings { get; set; } + public Dictionary<string, List<string>> Modes { get; set; } + } + + public class captchaBlock + { + public string Type { get; set; } + public string Image { get; set; } + public string Input { get; set; } + } + + public class loginBlock + { + public string Path { get; set; } + public string Submitpath { get; set; } + public List<string> Cookies { get; set; } + public string Method { get; set; } + public string Form { get; set; } + public bool Selectors { get; set; } = false; + public Dictionary<string, string> Inputs { get; set; } + public Dictionary<string, selectorBlock> Selectorinputs { get; set; } + public Dictionary<string, selectorBlock> Getselectorinputs { get; set; } + public List<errorBlock> Error { get; set; } + public pageTestBlock Test { get; set; } + public captchaBlock Captcha { get; set; } + } + + public class errorBlock + { + public string Path { get; set; } + public string Selector { get; set; } + public selectorBlock Message { get; set; } } - public class CategorymappingBlock - { - public string id { get; set; } - public string cat { get; set; } - public string desc { get; set; } + public class selectorBlock + { + public string Selector { get; set; } + public bool Optional { get; set; } = false; + public string Text { get; set; } + public string Attribute { get; set; } + public string Remove { get; set; } + public List<filterBlock> Filters { get; set; } + public Dictionary<string, string> Case { get; set; } } - public class capabilitiesBlock - { - public Dictionary<string, string> Categories { get; set; } - public List<CategorymappingBlock> Categorymappings { get; set; } - public Dictionary<string, List<string>> Modes { get; set; } - } - - public class captchaBlock - { - public string Type { get; set; } - public string Image { get; set; } - public string Input { get; set; } - } - - public class loginBlock - { - public string Path { get; set; } - public string Submitpath { get; set; } - public List<string> Cookies { get; set; } - public string Method { get; set; } - public string Form { get; set; } - public bool Selectors { get; set; } = false; - public Dictionary<string, string> Inputs { get; set; } - public Dictionary<string, selectorBlock> Selectorinputs { get; set; } - public Dictionary<string, selectorBlock> Getselectorinputs { get; set; } - public List<errorBlock> Error { get; set; } - public pageTestBlock Test { get; set; } - public captchaBlock Captcha { get; set; } - } - - public class errorBlock - { - public string Path { get; set; } - public string Selector { get; set; } - public selectorBlock Message { get; set; } - } - - public class selectorBlock - { - public string Selector { get; set; } - public bool Optional { get; set; } = false; - public string Text { get; set; } - public string Attribute { get; set; } - public string Remove { get; set; } - public List<filterBlock> Filters { get; set; } - public Dictionary<string, string> Case { get; set; } - } - - public class filterBlock - { - public string Name { get; set; } - public dynamic Args { get; set; } - } - - public class pageTestBlock - { - public string Path { get; set; } - public string Selector { get; set; } - } - - public class ratioBlock : selectorBlock - { - public string Path { get; set; } - } - - public class searchBlock - { - public string Path { get; set; } - public List<searchPathBlock> Paths { get; set; } - public List<filterBlock> Keywordsfilters { get; set; } - public Dictionary<string, string> Inputs { get; set; } - public List<errorBlock> Error { get; set; } - public rowsBlock Rows { get; set; } - public KeyValuePairList Fields { get; set; } - } - - public class rowsBlock : selectorBlock - { - public int After { get; set; } - //public string Remove { get; set; } // already inherited - public selectorBlock Dateheaders { get; set; } - } - - public class searchPathBlock : requestBlock - { - public List<string> Categories { get; set; } - public bool Inheritinputs { get; set; } = true; - } - - public class requestBlock - { - public string Path { get; set; } - public string Method { get; set; } - public Dictionary<string, string> Inputs { get; set; } - } - - public class downloadBlock - { - public string Selector { get; set; } - public string Method { get; set; } - public requestBlock Before { get; set; } - } - - protected readonly string[] OptionalFileds = new string[] { "imdb", "rageid", "tvdbid", "banner" }; - + public class filterBlock + { + public string Name { get; set; } + public dynamic Args { get; set; } + } + + public class pageTestBlock + { + public string Path { get; set; } + public string Selector { get; set; } + } + + public class ratioBlock : selectorBlock + { + public string Path { get; set; } + } + + public class searchBlock + { + public string Path { get; set; } + public List<searchPathBlock> Paths { get; set; } + public List<filterBlock> Keywordsfilters { get; set; } + public Dictionary<string, string> Inputs { get; set; } + public List<errorBlock> Error { get; set; } + public rowsBlock Rows { get; set; } + public KeyValuePairList Fields { get; set; } + } + + public class rowsBlock : selectorBlock + { + public int After { get; set; } + //public string Remove { get; set; } // already inherited + public selectorBlock Dateheaders { get; set; } + } + + public class searchPathBlock : requestBlock + { + public List<string> Categories { get; set; } + public bool Inheritinputs { get; set; } = true; + } + + public class requestBlock + { + public string Path { get; set; } + public string Method { get; set; } + public Dictionary<string, string> Inputs { get; set; } + } + + public class downloadBlock + { + public string Selector { get; set; } + public string Method { get; set; } + public requestBlock Before { get; set; } + } + + protected readonly string[] OptionalFileds = new string[] { "imdb", "rageid", "tvdbid", "banner" }; + public CardigannIndexer(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) : base(manager: i, client: wc, logger: l, p: ps) { - } + } public CardigannIndexer(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps, string DefinitionString) : base(manager: i, @@ -244,665 +244,665 @@ namespace Jackett.Indexers Init(DefinitionString); } - protected void Init(string DefinitionString) - { - this.DefinitionString = DefinitionString; - var deserializer = new DeserializerBuilder() - .WithNamingConvention(new CamelCaseNamingConvention()) - .IgnoreUnmatchedProperties() - .Build(); + protected void Init(string DefinitionString) + { + this.DefinitionString = DefinitionString; + var deserializer = new DeserializerBuilder() + .WithNamingConvention(new CamelCaseNamingConvention()) + .IgnoreUnmatchedProperties() + .Build(); Definition = deserializer.Deserialize<IndexerDefinition>(DefinitionString); // Add default data if necessary - if (Definition.Settings == null) + if (Definition.Settings == null) { Definition.Settings = new List<settingsField>(); - Definition.Settings.Add(new settingsField { Name = "username", Label = "Username", Type = "text" }); - Definition.Settings.Add(new settingsField { Name = "password", Label = "Password", Type = "password" }); + Definition.Settings.Add(new settingsField { Name = "username", Label = "Username", Type = "text" }); + Definition.Settings.Add(new settingsField { Name = "password", Label = "Password", Type = "password" }); } - if (Definition.Encoding == null) + if (Definition.Encoding == null) Definition.Encoding = "UTF-8"; if (Definition.Login != null && Definition.Login.Method == null) - Definition.Login.Method = "form"; - - if (Definition.Search.Paths == null) - { - Definition.Search.Paths = new List<searchPathBlock>(); - } - - // convert definitions with a single search Path to a Paths entry - if (Definition.Search.Path != null) - { - var legacySearchPath = new searchPathBlock(); - legacySearchPath.Path = Definition.Search.Path; - legacySearchPath.Inheritinputs = true; - Definition.Search.Paths.Add(legacySearchPath); - } - - // init missing mandatory attributes - DisplayName = Definition.Name; - DisplayDescription = Definition.Description; - if (Definition.Links.Count > 1) - AlternativeSiteLinks = Definition.Links.ToArray(); - DefaultSiteLink = Definition.Links[0]; - Encoding = Encoding.GetEncoding(Definition.Encoding); - if (!DefaultSiteLink.EndsWith("/")) - DefaultSiteLink += "/"; - Language = Definition.Language; - Type = Definition.Type; - TorznabCaps = new TorznabCapabilities(); - - TorznabCaps.SupportsImdbSearch = Definition.Caps.Modes.Where(c => c.Key == "movie-search" && c.Value.Contains("imdbid")).Any(); - - // init config Data + Definition.Login.Method = "form"; + + if (Definition.Search.Paths == null) + { + Definition.Search.Paths = new List<searchPathBlock>(); + } + + // convert definitions with a single search Path to a Paths entry + if (Definition.Search.Path != null) + { + var legacySearchPath = new searchPathBlock(); + legacySearchPath.Path = Definition.Search.Path; + legacySearchPath.Inheritinputs = true; + Definition.Search.Paths.Add(legacySearchPath); + } + + // init missing mandatory attributes + DisplayName = Definition.Name; + DisplayDescription = Definition.Description; + if (Definition.Links.Count > 1) + AlternativeSiteLinks = Definition.Links.ToArray(); + DefaultSiteLink = Definition.Links[0]; + Encoding = Encoding.GetEncoding(Definition.Encoding); + if (!DefaultSiteLink.EndsWith("/")) + DefaultSiteLink += "/"; + Language = Definition.Language; + Type = Definition.Type; + TorznabCaps = new TorznabCapabilities(); + + TorznabCaps.SupportsImdbSearch = Definition.Caps.Modes.Where(c => c.Key == "movie-search" && c.Value.Contains("imdbid")).Any(); + + // init config Data configData = new ConfigurationData(); - foreach (var Setting in Definition.Settings) - { - Item item; - if (Setting.Type != null && Setting.Type == "checkbox") - { - item = new BoolItem() { Value = false }; - } - else if(Setting.Type != null && Setting.Type == "password") - { - item = new StringItem(); - } - else - { - item = new StringItem(); - } - item.Name = Setting.Label; - configData.AddDynamic(Setting.Name, item); + foreach (var Setting in Definition.Settings) + { + Item item; + if (Setting.Type != null && Setting.Type == "checkbox") + { + item = new BoolItem() { Value = false }; + } + else if(Setting.Type != null && Setting.Type == "password") + { + item = new StringItem(); + } + else + { + item = new StringItem(); + } + item.Name = Setting.Label; + configData.AddDynamic(Setting.Name, item); } - if (Definition.Caps.Categories != null) + if (Definition.Caps.Categories != null) { - foreach (var Category in Definition.Caps.Categories) - { - var cat = TorznabCatType.GetCatByName(Category.Value); - if (cat == null) - { - logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", ID, Category.Key, Category.Value)); - continue; - } - AddCategoryMapping(Category.Key, cat); - } - } - - if (Definition.Caps.Categorymappings != null) - { - foreach (var Categorymapping in Definition.Caps.Categorymappings) - { - TorznabCategory TorznabCat = null; - - if (Categorymapping.cat != null) - { - TorznabCat = TorznabCatType.GetCatByName(Categorymapping.cat); - if (TorznabCat == null) - { - logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", ID, Categorymapping.id, Categorymapping.cat)); - continue; - } - } - AddCategoryMapping(Categorymapping.id, TorznabCat, Categorymapping.desc); - } - } - LoadValuesFromJson(null); + foreach (var Category in Definition.Caps.Categories) + { + var cat = TorznabCatType.GetCatByName(Category.Value); + if (cat == null) + { + logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", ID, Category.Key, Category.Value)); + continue; + } + AddCategoryMapping(Category.Key, cat); + } + } + + if (Definition.Caps.Categorymappings != null) + { + foreach (var Categorymapping in Definition.Caps.Categorymappings) + { + TorznabCategory TorznabCat = null; + + if (Categorymapping.cat != null) + { + TorznabCat = TorznabCatType.GetCatByName(Categorymapping.cat); + if (TorznabCat == null) + { + logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", ID, Categorymapping.id, Categorymapping.cat)); + continue; + } + } + AddCategoryMapping(Categorymapping.id, TorznabCat, Categorymapping.desc); + } + } + LoadValuesFromJson(null); } - public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) - { - base.LoadValuesFromJson(jsonConfig, useProtectionService); - - // add self signed cert to trusted certs - if (Definition.Certificates != null) - { - foreach (var certificateHash in Definition.Certificates) - webclient.AddTrustedCertificate(new Uri(SiteLink).Host, certificateHash); - } + public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) + { + base.LoadValuesFromJson(jsonConfig, useProtectionService); + + // add self signed cert to trusted certs + if (Definition.Certificates != null) + { + foreach (var certificateHash in Definition.Certificates) + webclient.AddTrustedCertificate(new Uri(SiteLink).Host, certificateHash); + } + } + + protected Dictionary<string, object> getTemplateVariablesFromConfigData() + { + Dictionary<string, object> variables = new Dictionary<string, object>(); + + foreach (settingsField Setting in Definition.Settings) + { + string value; + var item = configData.GetDynamic(Setting.Name); + if (item.GetType() == typeof(BoolItem)) + { + value = (((BoolItem)item).Value == true ? "true" : ""); + } + else + { + value = ((StringItem)item).Value; + } + variables[".Config."+Setting.Name] = value; + } + return variables; } - protected Dictionary<string, object> getTemplateVariablesFromConfigData() - { - Dictionary<string, object> variables = new Dictionary<string, object>(); - - foreach (settingsField Setting in Definition.Settings) - { - string value; - var item = configData.GetDynamic(Setting.Name); - if (item.GetType() == typeof(BoolItem)) - { - value = (((BoolItem)item).Value == true ? "true" : ""); - } - else - { - value = ((StringItem)item).Value; - } - variables[".Config."+Setting.Name] = value; - } - return variables; - } - - // A very bad implementation of the golang template/text templating engine. + // A very bad implementation of the golang template/text templating engine. // But it should work for most basic constucts used by Cardigann definitions. protected delegate string TemplateTextModifier(string str); - protected string applyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) - { - if (variables == null) - { - variables = getTemplateVariablesFromConfigData(); - } - - // handle re_replace expression - // Example: {{ re_replace .Query.Keywords "[^a-zA-Z0-9]+" "%" }} - Regex ReReplaceRegex = new Regex(@"{{\s*re_replace\s+(\..+?)\s+""(.+)""\s+""(.+?)""\s*}}"); - var ReReplaceRegexMatches = ReReplaceRegex.Match(template); - - while (ReReplaceRegexMatches.Success) - { - string all = ReReplaceRegexMatches.Groups[0].Value; - string variable = ReReplaceRegexMatches.Groups[1].Value; - string regexp = ReReplaceRegexMatches.Groups[2].Value; - string newvalue = ReReplaceRegexMatches.Groups[3].Value; - - Regex ReplaceRegex = new Regex(regexp); - var input = (string)variables[variable]; - var expanded = ReplaceRegex.Replace(input, newvalue); - - if (modifier != null) - expanded = modifier(expanded); - - template = template.Replace(all, expanded); - ReReplaceRegexMatches = ReReplaceRegexMatches.NextMatch(); - } - - // handle if ... else ... expression - Regex IfElseRegex = new Regex(@"{{\s*if\s*(.+?)\s*}}(.*?){{\s*else\s*}}(.*?){{\s*end\s*}}"); - var IfElseRegexMatches = IfElseRegex.Match(template); - - while (IfElseRegexMatches.Success) - { - string conditionResult = null; - - string all = IfElseRegexMatches.Groups[0].Value; - string condition = IfElseRegexMatches.Groups[1].Value; - string onTrue = IfElseRegexMatches.Groups[2].Value; - string onFalse = IfElseRegexMatches.Groups[3].Value; - - if (condition.StartsWith(".")) - { - string value = (string)variables[condition]; - if (!string.IsNullOrWhiteSpace(value)) - { - conditionResult = onTrue; - } - else - { - conditionResult = onFalse; - } - } - else - { - throw new NotImplementedException("CardigannIndexer: Condition operation '" + condition + "' not implemented"); - } - template = template.Replace(all, conditionResult); - IfElseRegexMatches = IfElseRegexMatches.NextMatch(); - } - - // handle range expression - Regex RangeRegex = new Regex(@"{{\s*range\s*(.+?)\s*}}(.*?){{\.}}(.*?){{end}}"); - var RangeRegexMatches = RangeRegex.Match(template); - - while (RangeRegexMatches.Success) - { - string expanded = string.Empty; - - string all = RangeRegexMatches.Groups[0].Value; - string variable = RangeRegexMatches.Groups[1].Value; - string prefix = RangeRegexMatches.Groups[2].Value; - string postfix = RangeRegexMatches.Groups[3].Value; - - foreach (string value in (List<string>)variables[variable]) - { - var newvalue = value; - if (modifier != null) - newvalue = modifier(newvalue); - expanded += prefix + newvalue + postfix; - } - template = template.Replace(all, expanded); - RangeRegexMatches = RangeRegexMatches.NextMatch(); - } - - // handle simple variables - Regex VariablesRegEx = new Regex(@"{{\s*(\..+?)\s*}}"); - var VariablesRegExMatches = VariablesRegEx.Match(template); - - while (VariablesRegExMatches.Success) - { - string expanded = string.Empty; - - string all = VariablesRegExMatches.Groups[0].Value; - string variable = VariablesRegExMatches.Groups[1].Value; - - string value = (string)variables[variable]; - if (modifier != null) - value = modifier(value); - template = template.Replace(all, value); - VariablesRegExMatches = VariablesRegExMatches.NextMatch(); - } - - return template; - } - - protected bool checkForError(WebClientStringResult loginResult, IList<errorBlock> errorBlocks) - { - if (errorBlocks == null) - return true; // no error - - var ResultParser = new HtmlParser(); - var ResultDocument = ResultParser.Parse(loginResult.Content); - foreach (errorBlock error in errorBlocks) - { - var selection = ResultDocument.QuerySelector(error.Selector); - if (selection != null) - { - string errorMessage = selection.TextContent; - if (error.Message != null) - { - errorMessage = handleSelector(error.Message, ResultDocument.FirstElementChild); - } - throw new ExceptionWithConfigData(string.Format("Error: {0}", errorMessage.Trim()), configData); - } - } - return true; // no error + protected string applyGoTemplateText(string template, Dictionary<string, object> variables = null, TemplateTextModifier modifier = null) + { + if (variables == null) + { + variables = getTemplateVariablesFromConfigData(); + } + + // handle re_replace expression + // Example: {{ re_replace .Query.Keywords "[^a-zA-Z0-9]+" "%" }} + Regex ReReplaceRegex = new Regex(@"{{\s*re_replace\s+(\..+?)\s+""(.+)""\s+""(.+?)""\s*}}"); + var ReReplaceRegexMatches = ReReplaceRegex.Match(template); + + while (ReReplaceRegexMatches.Success) + { + string all = ReReplaceRegexMatches.Groups[0].Value; + string variable = ReReplaceRegexMatches.Groups[1].Value; + string regexp = ReReplaceRegexMatches.Groups[2].Value; + string newvalue = ReReplaceRegexMatches.Groups[3].Value; + + Regex ReplaceRegex = new Regex(regexp); + var input = (string)variables[variable]; + var expanded = ReplaceRegex.Replace(input, newvalue); + + if (modifier != null) + expanded = modifier(expanded); + + template = template.Replace(all, expanded); + ReReplaceRegexMatches = ReReplaceRegexMatches.NextMatch(); + } + + // handle if ... else ... expression + Regex IfElseRegex = new Regex(@"{{\s*if\s*(.+?)\s*}}(.*?){{\s*else\s*}}(.*?){{\s*end\s*}}"); + var IfElseRegexMatches = IfElseRegex.Match(template); + + while (IfElseRegexMatches.Success) + { + string conditionResult = null; + + string all = IfElseRegexMatches.Groups[0].Value; + string condition = IfElseRegexMatches.Groups[1].Value; + string onTrue = IfElseRegexMatches.Groups[2].Value; + string onFalse = IfElseRegexMatches.Groups[3].Value; + + if (condition.StartsWith(".")) + { + string value = (string)variables[condition]; + if (!string.IsNullOrWhiteSpace(value)) + { + conditionResult = onTrue; + } + else + { + conditionResult = onFalse; + } + } + else + { + throw new NotImplementedException("CardigannIndexer: Condition operation '" + condition + "' not implemented"); + } + template = template.Replace(all, conditionResult); + IfElseRegexMatches = IfElseRegexMatches.NextMatch(); + } + + // handle range expression + Regex RangeRegex = new Regex(@"{{\s*range\s*(.+?)\s*}}(.*?){{\.}}(.*?){{end}}"); + var RangeRegexMatches = RangeRegex.Match(template); + + while (RangeRegexMatches.Success) + { + string expanded = string.Empty; + + string all = RangeRegexMatches.Groups[0].Value; + string variable = RangeRegexMatches.Groups[1].Value; + string prefix = RangeRegexMatches.Groups[2].Value; + string postfix = RangeRegexMatches.Groups[3].Value; + + foreach (string value in (List<string>)variables[variable]) + { + var newvalue = value; + if (modifier != null) + newvalue = modifier(newvalue); + expanded += prefix + newvalue + postfix; + } + template = template.Replace(all, expanded); + RangeRegexMatches = RangeRegexMatches.NextMatch(); + } + + // handle simple variables + Regex VariablesRegEx = new Regex(@"{{\s*(\..+?)\s*}}"); + var VariablesRegExMatches = VariablesRegEx.Match(template); + + while (VariablesRegExMatches.Success) + { + string expanded = string.Empty; + + string all = VariablesRegExMatches.Groups[0].Value; + string variable = VariablesRegExMatches.Groups[1].Value; + + string value = (string)variables[variable]; + if (modifier != null) + value = modifier(value); + template = template.Replace(all, value); + VariablesRegExMatches = VariablesRegExMatches.NextMatch(); + } + + return template; + } + + protected bool checkForError(WebClientStringResult loginResult, IList<errorBlock> errorBlocks) + { + if (errorBlocks == null) + return true; // no error + + var ResultParser = new HtmlParser(); + var ResultDocument = ResultParser.Parse(loginResult.Content); + foreach (errorBlock error in errorBlocks) + { + var selection = ResultDocument.QuerySelector(error.Selector); + if (selection != null) + { + string errorMessage = selection.TextContent; + if (error.Message != null) + { + errorMessage = handleSelector(error.Message, ResultDocument.FirstElementChild); + } + throw new ExceptionWithConfigData(string.Format("Error: {0}", errorMessage.Trim()), configData); + } + } + return true; // no error } - protected async Task<bool> DoLogin() - { + protected async Task<bool> DoLogin() + { var Login = Definition.Login; if (Login == null) return true; - if (Login.Method == "post") - { + if (Login.Method == "post") + { var pairs = new Dictionary<string, string>(); - foreach (var Input in Definition.Login.Inputs) - { - var value = applyGoTemplateText(Input.Value); - pairs.Add(Input.Key, value); + foreach (var Input in Definition.Login.Inputs) + { + var value = applyGoTemplateText(Input.Value); + pairs.Add(Input.Key, value); } var LoginUrl = resolvePath(Login.Path).ToString(); configData.CookieHeader.Value = null; var loginResult = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink, true); configData.CookieHeader.Value = loginResult.Cookies; - + checkForError(loginResult, Definition.Login.Error); - } - else if (Login.Method == "form") - { - var LoginUrl = resolvePath(Login.Path).ToString(); - - var queryCollection = new NameValueCollection(); - var pairs = new Dictionary<string, string>(); - - var CaptchaConfigItem = (RecaptchaItem)configData.GetDynamic("Captcha"); - - if (CaptchaConfigItem != null) - { - if (!string.IsNullOrWhiteSpace(CaptchaConfigItem.Cookie)) - { - // for remote users just set the cookie and return - CookieHeader = CaptchaConfigItem.Cookie; - return true; - } - - var CloudFlareCaptchaChallenge = landingResultDocument.QuerySelector("script[src=\"/cdn-cgi/scripts/cf.challenge.js\"]"); - if (CloudFlareCaptchaChallenge != null) - { - var CloudFlareQueryCollection = new NameValueCollection(); - CloudFlareQueryCollection["id"] = CloudFlareCaptchaChallenge.GetAttribute("data-ray"); - - CloudFlareQueryCollection["g-recaptcha-response"] = CaptchaConfigItem.Value; - var ClearanceUrl = resolvePath("/cdn-cgi/l/chk_captcha?" + CloudFlareQueryCollection.GetQueryString()); - - var ClearanceResult = await RequestStringWithCookies(ClearanceUrl.ToString(), null, SiteLink); - - if (ClearanceResult.IsRedirect) // clearance successfull - { - // request real login page again - landingResult = await RequestStringWithCookies(LoginUrl, null, SiteLink); - var htmlParser = new HtmlParser(); - landingResultDocument = htmlParser.Parse(landingResult.Content); - } - else - { - throw new ExceptionWithConfigData(string.Format("Login failed: Cloudflare clearance failed using cookies {0}: {1}", CookieHeader, ClearanceResult.Content), configData); - } - } - else - { - pairs.Add("g-recaptcha-response", CaptchaConfigItem.Value); - } - } - - var FormSelector = Login.Form; - if (FormSelector == null) - FormSelector = "form"; - - // landingResultDocument might not be initiated if the login is caused by a relogin during a query - if (landingResultDocument == null) - { - var ConfigurationResult = await GetConfigurationForSetup(true); - if (ConfigurationResult == null) // got captcha - { - return false; - } - } - - var form = landingResultDocument.QuerySelector(FormSelector); - if (form == null) - { - throw new ExceptionWithConfigData(string.Format("Login failed: No form found on {0} using form selector {1}", LoginUrl, FormSelector), configData); - } - - var inputs = form.QuerySelectorAll("input"); - if (inputs == null) - { - throw new ExceptionWithConfigData(string.Format("Login failed: No inputs found on {0} using form selector {1}", LoginUrl, FormSelector), configData); - } - - var submitUrlstr = form.GetAttribute("action"); - if (Login.Submitpath != null) - submitUrlstr = Login.Submitpath; - - foreach (var input in inputs) - { - var name = input.GetAttribute("name"); - if (name == null) - continue; - - var value = input.GetAttribute("value"); - if (value == null) - value = ""; - - pairs[name] = value; - } + } + else if (Login.Method == "form") + { + var LoginUrl = resolvePath(Login.Path).ToString(); + + var queryCollection = new NameValueCollection(); + var pairs = new Dictionary<string, string>(); + + var CaptchaConfigItem = (RecaptchaItem)configData.GetDynamic("Captcha"); + + if (CaptchaConfigItem != null) + { + if (!string.IsNullOrWhiteSpace(CaptchaConfigItem.Cookie)) + { + // for remote users just set the cookie and return + CookieHeader = CaptchaConfigItem.Cookie; + return true; + } + + var CloudFlareCaptchaChallenge = landingResultDocument.QuerySelector("script[src=\"/cdn-cgi/scripts/cf.challenge.js\"]"); + if (CloudFlareCaptchaChallenge != null) + { + var CloudFlareQueryCollection = new NameValueCollection(); + CloudFlareQueryCollection["id"] = CloudFlareCaptchaChallenge.GetAttribute("data-ray"); + + CloudFlareQueryCollection["g-recaptcha-response"] = CaptchaConfigItem.Value; + var ClearanceUrl = resolvePath("/cdn-cgi/l/chk_captcha?" + CloudFlareQueryCollection.GetQueryString()); + + var ClearanceResult = await RequestStringWithCookies(ClearanceUrl.ToString(), null, SiteLink); + + if (ClearanceResult.IsRedirect) // clearance successfull + { + // request real login page again + landingResult = await RequestStringWithCookies(LoginUrl, null, SiteLink); + var htmlParser = new HtmlParser(); + landingResultDocument = htmlParser.Parse(landingResult.Content); + } + else + { + throw new ExceptionWithConfigData(string.Format("Login failed: Cloudflare clearance failed using cookies {0}: {1}", CookieHeader, ClearanceResult.Content), configData); + } + } + else + { + pairs.Add("g-recaptcha-response", CaptchaConfigItem.Value); + } + } + + var FormSelector = Login.Form; + if (FormSelector == null) + FormSelector = "form"; + + // landingResultDocument might not be initiated if the login is caused by a relogin during a query + if (landingResultDocument == null) + { + var ConfigurationResult = await GetConfigurationForSetup(true); + if (ConfigurationResult == null) // got captcha + { + return false; + } + } + + var form = landingResultDocument.QuerySelector(FormSelector); + if (form == null) + { + throw new ExceptionWithConfigData(string.Format("Login failed: No form found on {0} using form selector {1}", LoginUrl, FormSelector), configData); + } + + var inputs = form.QuerySelectorAll("input"); + if (inputs == null) + { + throw new ExceptionWithConfigData(string.Format("Login failed: No inputs found on {0} using form selector {1}", LoginUrl, FormSelector), configData); + } + + var submitUrlstr = form.GetAttribute("action"); + if (Login.Submitpath != null) + submitUrlstr = Login.Submitpath; + + foreach (var input in inputs) + { + var name = input.GetAttribute("name"); + if (name == null) + continue; + + var value = input.GetAttribute("value"); + if (value == null) + value = ""; + + pairs[name] = value; + } - foreach (var Input in Definition.Login.Inputs) - { - var value = applyGoTemplateText(Input.Value); - var input = Input.Key; - if (Login.Selectors) - { - var inputElement = landingResultDocument.QuerySelector(Input.Key); - if (inputElement == null) - throw new ExceptionWithConfigData(string.Format("Login failed: No input found using selector {0}", Input.Key), configData); - input = inputElement.GetAttribute("name"); - } - pairs[input] = value; - } - - // selector inputs - if (Login.Selectorinputs != null) - { - foreach (var Selectorinput in Login.Selectorinputs) - { - string value = null; - try - { - value = handleSelector(Selectorinput.Value, landingResultDocument.FirstElementChild); - pairs[Selectorinput.Key] = value; - } - catch (Exception ex) - { - throw new Exception(string.Format("Error while parsing selector input={0}, selector={1}, value={2}: {3}", Selectorinput.Key, Selectorinput.Value.Selector, value, ex.Message)); - } - } - } - - // getselector inputs - if (Login.Getselectorinputs != null) - { - foreach (var Selectorinput in Login.Getselectorinputs) - { - string value = null; - try - { - value = handleSelector(Selectorinput.Value, landingResultDocument.FirstElementChild); - queryCollection[Selectorinput.Key] = value; - } - catch (Exception ex) - { - throw new Exception(string.Format("Error while parsing get selector input={0}, selector={1}, value={2}: {3}", Selectorinput.Key, Selectorinput.Value.Selector, value, ex.Message)); - } - } - } - if (queryCollection.Count > 0) - submitUrlstr += "?" + queryCollection.GetQueryString(); - var submitUrl = resolvePath(submitUrlstr, new Uri(LoginUrl)); - - // automatically solve simpleCaptchas, if used - var simpleCaptchaPresent = landingResultDocument.QuerySelector("script[src*=\"simpleCaptcha\"]"); - if(simpleCaptchaPresent != null) - { - var captchaUrl = resolvePath("simpleCaptcha.php?numImages=1"); - var simpleCaptchaResult = await RequestStringWithCookies(captchaUrl.ToString(), null, LoginUrl); - var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); - var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); - pairs["captchaSelection"] = captchaSelection; - pairs["submitme"] = "X"; - } - - if (Login.Captcha != null) - { - var Captcha = Login.Captcha; - if (Captcha.Type == "image") - { - var CaptchaText = (StringItem)configData.GetDynamic("CaptchaText"); - if (CaptchaText != null) - { - var input = Captcha.Input; - if (Login.Selectors) - { - var inputElement = landingResultDocument.QuerySelector(Captcha.Input); - if (inputElement == null) - throw new ExceptionWithConfigData(string.Format("Login failed: No captcha input found using {0}", Captcha.Input), configData); - input = inputElement.GetAttribute("name"); - } - pairs[input] = CaptchaText.Value; - } - } - } - - // clear landingResults/Document, otherwise we might use an old version for a new relogin (if GetConfigurationForSetup() wasn't called before) - landingResult = null; - landingResultDocument = null; - - WebClientStringResult loginResult = null; - var enctype = form.GetAttribute("enctype"); - if (enctype == "multipart/form-data") - { - var headers = new Dictionary<string, string>(); - var boundary = "---------------------------" + (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString().Replace(".", ""); - var bodyParts = new List<string>(); - - foreach (var pair in pairs) - { - var part = "--" + boundary + "\r\n" + - "Content-Disposition: form-data; name=\"" + pair.Key + "\"\r\n" + - "\r\n" + - pair.Value; - bodyParts.Add(part); - } - - bodyParts.Add("--" + boundary + "--"); - - headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary); - var body = string.Join("\r\n", bodyParts); - loginResult = await PostDataWithCookies(submitUrl.ToString(), pairs, configData.CookieHeader.Value, SiteLink, headers, body); - } else { - loginResult = await RequestLoginAndFollowRedirect(submitUrl.ToString(), pairs, configData.CookieHeader.Value, true, null, LoginUrl, true); - } - + foreach (var Input in Definition.Login.Inputs) + { + var value = applyGoTemplateText(Input.Value); + var input = Input.Key; + if (Login.Selectors) + { + var inputElement = landingResultDocument.QuerySelector(Input.Key); + if (inputElement == null) + throw new ExceptionWithConfigData(string.Format("Login failed: No input found using selector {0}", Input.Key), configData); + input = inputElement.GetAttribute("name"); + } + pairs[input] = value; + } + + // selector inputs + if (Login.Selectorinputs != null) + { + foreach (var Selectorinput in Login.Selectorinputs) + { + string value = null; + try + { + value = handleSelector(Selectorinput.Value, landingResultDocument.FirstElementChild); + pairs[Selectorinput.Key] = value; + } + catch (Exception ex) + { + throw new Exception(string.Format("Error while parsing selector input={0}, selector={1}, value={2}: {3}", Selectorinput.Key, Selectorinput.Value.Selector, value, ex.Message)); + } + } + } + + // getselector inputs + if (Login.Getselectorinputs != null) + { + foreach (var Selectorinput in Login.Getselectorinputs) + { + string value = null; + try + { + value = handleSelector(Selectorinput.Value, landingResultDocument.FirstElementChild); + queryCollection[Selectorinput.Key] = value; + } + catch (Exception ex) + { + throw new Exception(string.Format("Error while parsing get selector input={0}, selector={1}, value={2}: {3}", Selectorinput.Key, Selectorinput.Value.Selector, value, ex.Message)); + } + } + } + if (queryCollection.Count > 0) + submitUrlstr += "?" + queryCollection.GetQueryString(); + var submitUrl = resolvePath(submitUrlstr, new Uri(LoginUrl)); + + // automatically solve simpleCaptchas, if used + var simpleCaptchaPresent = landingResultDocument.QuerySelector("script[src*=\"simpleCaptcha\"]"); + if(simpleCaptchaPresent != null) + { + var captchaUrl = resolvePath("simpleCaptcha.php?numImages=1"); + var simpleCaptchaResult = await RequestStringWithCookies(captchaUrl.ToString(), null, LoginUrl); + var simpleCaptchaJSON = JObject.Parse(simpleCaptchaResult.Content); + var captchaSelection = simpleCaptchaJSON["images"][0]["hash"].ToString(); + pairs["captchaSelection"] = captchaSelection; + pairs["submitme"] = "X"; + } + + if (Login.Captcha != null) + { + var Captcha = Login.Captcha; + if (Captcha.Type == "image") + { + var CaptchaText = (StringItem)configData.GetDynamic("CaptchaText"); + if (CaptchaText != null) + { + var input = Captcha.Input; + if (Login.Selectors) + { + var inputElement = landingResultDocument.QuerySelector(Captcha.Input); + if (inputElement == null) + throw new ExceptionWithConfigData(string.Format("Login failed: No captcha input found using {0}", Captcha.Input), configData); + input = inputElement.GetAttribute("name"); + } + pairs[input] = CaptchaText.Value; + } + } + } + + // clear landingResults/Document, otherwise we might use an old version for a new relogin (if GetConfigurationForSetup() wasn't called before) + landingResult = null; + landingResultDocument = null; + + WebClientStringResult loginResult = null; + var enctype = form.GetAttribute("enctype"); + if (enctype == "multipart/form-data") + { + var headers = new Dictionary<string, string>(); + var boundary = "---------------------------" + (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString().Replace(".", ""); + var bodyParts = new List<string>(); + + foreach (var pair in pairs) + { + var part = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"" + pair.Key + "\"\r\n" + + "\r\n" + + pair.Value; + bodyParts.Add(part); + } + + bodyParts.Add("--" + boundary + "--"); + + headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary); + var body = string.Join("\r\n", bodyParts); + loginResult = await PostDataWithCookies(submitUrl.ToString(), pairs, configData.CookieHeader.Value, SiteLink, headers, body); + } else { + loginResult = await RequestLoginAndFollowRedirect(submitUrl.ToString(), pairs, configData.CookieHeader.Value, true, null, LoginUrl, true); + } + configData.CookieHeader.Value = loginResult.Cookies; checkForError(loginResult, Definition.Login.Error); - } - else if (Login.Method == "cookie") - { - configData.CookieHeader.Value = ((StringItem)configData.GetDynamic("cookie")).Value; - } - else if (Login.Method == "get") - { - var queryCollection = new NameValueCollection(); - foreach (var Input in Definition.Login.Inputs) - { - var value = applyGoTemplateText(Input.Value); - queryCollection.Add(Input.Key, value); - } - - var LoginUrl = resolvePath(Login.Path + "?" + queryCollection.GetQueryString()).ToString(); - configData.CookieHeader.Value = null; - var loginResult = await RequestStringWithCookies(LoginUrl, null, SiteLink); - configData.CookieHeader.Value = loginResult.Cookies; - - checkForError(loginResult, Definition.Login.Error); - } - else - { - throw new NotImplementedException("Login method " + Definition.Login.Method + " not implemented"); - } - logger.Debug(string.Format("CardigannIndexer ({0}): Cookies after login: {1}", ID, CookieHeader)); - return true; + } + else if (Login.Method == "cookie") + { + configData.CookieHeader.Value = ((StringItem)configData.GetDynamic("cookie")).Value; + } + else if (Login.Method == "get") + { + var queryCollection = new NameValueCollection(); + foreach (var Input in Definition.Login.Inputs) + { + var value = applyGoTemplateText(Input.Value); + queryCollection.Add(Input.Key, value); + } + + var LoginUrl = resolvePath(Login.Path + "?" + queryCollection.GetQueryString()).ToString(); + configData.CookieHeader.Value = null; + var loginResult = await RequestStringWithCookies(LoginUrl, null, SiteLink); + configData.CookieHeader.Value = loginResult.Cookies; + + checkForError(loginResult, Definition.Login.Error); + } + else + { + throw new NotImplementedException("Login method " + Definition.Login.Method + " not implemented"); + } + logger.Debug(string.Format("CardigannIndexer ({0}): Cookies after login: {1}", ID, CookieHeader)); + return true; } - protected async Task<bool> TestLogin() - { - var Login = Definition.Login; - + protected async Task<bool> TestLogin() + { + var Login = Definition.Login; + if (Login == null || Login.Test == null) - return false; - + return false; + // test if login was successful var LoginTestUrl = resolvePath(Login.Test.Path).ToString(); var testResult = await RequestStringWithCookies(LoginTestUrl); - if (testResult.IsRedirect) - { - throw new ExceptionWithConfigData("Login Failed, got redirected", configData); + if (testResult.IsRedirect) + { + throw new ExceptionWithConfigData("Login Failed, got redirected", configData); } - - if (Login.Test.Selector != null) - { - var testResultParser = new HtmlParser(); - var testResultDocument = testResultParser.Parse(testResult.Content); + + if (Login.Test.Selector != null) + { + var testResultParser = new HtmlParser(); + var testResultDocument = testResultParser.Parse(testResult.Content); var selection = testResultDocument.QuerySelectorAll(Login.Test.Selector); - if (selection.Length == 0) - { - throw new ExceptionWithConfigData(string.Format("Login failed: Selector \"{0}\" didn't match", Login.Test.Selector), configData); - } - } - return true; + if (selection.Length == 0) + { + throw new ExceptionWithConfigData(string.Format("Login failed: Selector \"{0}\" didn't match", Login.Test.Selector), configData); + } + } + return true; } - protected bool CheckIfLoginIsNeeded(WebClientStringResult Result, IHtmlDocument document) - { - if (Result.IsRedirect) - { - return true; + protected bool CheckIfLoginIsNeeded(WebClientStringResult Result, IHtmlDocument document) + { + if (Result.IsRedirect) + { + return true; } - - if (Definition.Login == null || Definition.Login.Test == null) - return false; - - if (Definition.Login.Test.Selector != null) - { + + if (Definition.Login == null || Definition.Login.Test == null) + return false; + + if (Definition.Login.Test.Selector != null) + { var selection = document.QuerySelectorAll(Definition.Login.Test.Selector); - if (selection.Length == 0) - { - return true; - } - } - return false; - } - + if (selection.Length == 0) + { + return true; + } + } + return false; + } + public override async Task<ConfigurationData> GetConfigurationForSetup() - { - return await GetConfigurationForSetup(false); - } - + { + return await GetConfigurationForSetup(false); + } + public async Task<ConfigurationData> GetConfigurationForSetup(bool automaticlogin) - { + { var Login = Definition.Login; if (Login == null || Login.Method != "form") return configData; - var LoginUrl = resolvePath(Login.Path); - - configData.CookieHeader.Value = null; - if (Login.Cookies != null) - configData.CookieHeader.Value = String.Join("; ", Login.Cookies); - landingResult = await RequestStringWithCookies(LoginUrl.AbsoluteUri, null, SiteLink); - - var htmlParser = new HtmlParser(); - landingResultDocument = htmlParser.Parse(landingResult.Content); - - var hasCaptcha = false; - - var grecaptcha = landingResultDocument.QuerySelector(".g-recaptcha"); - if (grecaptcha != null) - { - hasCaptcha = true; - var CaptchaItem = new RecaptchaItem(); - CaptchaItem.Name = "Captcha"; - CaptchaItem.Version = "2"; - CaptchaItem.SiteKey = grecaptcha.GetAttribute("data-sitekey"); - if (CaptchaItem.SiteKey == null) // some sites don't store the sitekey in the .g-recaptcha div (e.g. cloudflare captcha challenge page) - CaptchaItem.SiteKey = landingResultDocument.QuerySelector("[data-sitekey]").GetAttribute("data-sitekey"); - - configData.AddDynamic("Captcha", CaptchaItem); + var LoginUrl = resolvePath(Login.Path); + + configData.CookieHeader.Value = null; + if (Login.Cookies != null) + configData.CookieHeader.Value = String.Join("; ", Login.Cookies); + landingResult = await RequestStringWithCookies(LoginUrl.AbsoluteUri, null, SiteLink); + + var htmlParser = new HtmlParser(); + landingResultDocument = htmlParser.Parse(landingResult.Content); + + var hasCaptcha = false; + + var grecaptcha = landingResultDocument.QuerySelector(".g-recaptcha"); + if (grecaptcha != null) + { + hasCaptcha = true; + var CaptchaItem = new RecaptchaItem(); + CaptchaItem.Name = "Captcha"; + CaptchaItem.Version = "2"; + CaptchaItem.SiteKey = grecaptcha.GetAttribute("data-sitekey"); + if (CaptchaItem.SiteKey == null) // some sites don't store the sitekey in the .g-recaptcha div (e.g. cloudflare captcha challenge page) + CaptchaItem.SiteKey = landingResultDocument.QuerySelector("[data-sitekey]").GetAttribute("data-sitekey"); + + configData.AddDynamic("Captcha", CaptchaItem); } - if (Login.Captcha != null) - { - var Captcha = Login.Captcha; - if (Captcha.Type == "image") - { - var captchaElement = landingResultDocument.QuerySelector(Captcha.Image); - if (captchaElement != null) { - hasCaptcha = true; - - var CaptchaUrl = resolvePath(captchaElement.GetAttribute("src"), LoginUrl); - var captchaImageData = await RequestBytesWithCookies(CaptchaUrl.ToString(), landingResult.Cookies, RequestType.GET, LoginUrl.AbsoluteUri); - var CaptchaImage = new ImageItem { Name = "Captcha Image" }; - var CaptchaText = new StringItem { Name = "Captcha Text" }; - - CaptchaImage.Value = captchaImageData.Content; - - configData.AddDynamic("CaptchaImage", CaptchaImage); - configData.AddDynamic("CaptchaText", CaptchaText); - } - else - { - logger.Debug(string.Format("CardigannIndexer ({0}): No captcha image found", ID)); - } - } - else - { - throw new NotImplementedException(string.Format("Captcha type \"{0}\" is not implemented", Captcha.Type)); - } + if (Login.Captcha != null) + { + var Captcha = Login.Captcha; + if (Captcha.Type == "image") + { + var captchaElement = landingResultDocument.QuerySelector(Captcha.Image); + if (captchaElement != null) { + hasCaptcha = true; + + var CaptchaUrl = resolvePath(captchaElement.GetAttribute("src"), LoginUrl); + var captchaImageData = await RequestBytesWithCookies(CaptchaUrl.ToString(), landingResult.Cookies, RequestType.GET, LoginUrl.AbsoluteUri); + var CaptchaImage = new ImageItem { Name = "Captcha Image" }; + var CaptchaText = new StringItem { Name = "Captcha Text" }; + + CaptchaImage.Value = captchaImageData.Content; + + configData.AddDynamic("CaptchaImage", CaptchaImage); + configData.AddDynamic("CaptchaText", CaptchaText); + } + else + { + logger.Debug(string.Format("CardigannIndexer ({0}): No captcha image found", ID)); + } + } + else + { + throw new NotImplementedException(string.Format("Captcha type \"{0}\" is not implemented", Captcha.Type)); + } } - if (hasCaptcha && automaticlogin) - { - configData.LastError.Value = "Got captcha during automatic login, please reconfigure manually"; - logger.Error(string.Format("CardigannIndexer ({0}): Found captcha during automatic login, aborting", ID)); - return null; + if (hasCaptcha && automaticlogin) + { + configData.LastError.Value = "Got captcha during automatic login, please reconfigure manually"; + logger.Error(string.Format("CardigannIndexer ({0}): Found captcha during automatic login, aborting", ID)); + return null; } return configData; @@ -915,190 +915,190 @@ namespace Jackett.Indexers await DoLogin(); await TestLogin(); - SaveConfig(); - IsConfigured = true; - return IndexerConfigurationStatus.Completed; + SaveConfig(); + IsConfigured = true; + return IndexerConfigurationStatus.Completed; } - protected string applyFilters(string Data, List<filterBlock> Filters, Dictionary<string, object> variables = null) - { - if (Filters == null) - return Data; - - foreach(filterBlock Filter in Filters) - { - switch (Filter.Name) - { - case "querystring": - var param = (string)Filter.Args; - Data = ParseUtil.GetArgumentFromQueryString(Data, param); - break; - case "timeparse": - case "dateparse": - var layout = (string)Filter.Args; - try - { - var Date = DateTimeUtil.ParseDateTimeGoLang(Data, layout); - Data = Date.ToString(DateTimeUtil.RFC1123ZPattern); - } - catch (FormatException ex) - { - logger.Debug(ex.Message); - } - break; - case "regexp": - var pattern = (string)Filter.Args; - var Regexp = new Regex(pattern); - var Match = Regexp.Match(Data); - Data = Match.Groups[1].Value; - break; - case "re_replace": - var regexpreplace_pattern = (string)Filter.Args[0]; - var regexpreplace_replacement = (string)Filter.Args[1]; - regexpreplace_replacement = applyGoTemplateText(regexpreplace_replacement, variables); - Regex regexpreplace_regex = new Regex(regexpreplace_pattern); - Data = regexpreplace_regex.Replace(Data, regexpreplace_replacement); - break; - case "split": - var sep = (string)Filter.Args[0]; - var pos = (string)Filter.Args[1]; - var posInt = int.Parse(pos); - var strParts = Data.Split(sep[0]); - if (posInt < 0) - { - posInt += strParts.Length; - } - Data = strParts[posInt]; - break; - case "replace": - var from = (string)Filter.Args[0]; - var to = (string)Filter.Args[1]; - to = applyGoTemplateText(to, variables); - Data = Data.Replace(from, to); - break; - case "trim": - var cutset = (string)Filter.Args; - if (cutset != null) - Data = Data.Trim(cutset[0]); - else - Data = Data.Trim(); - break; - case "prepend": - var prependstr = (string)Filter.Args; - Data = applyGoTemplateText(prependstr, variables) + Data; - break; - case "append": - var str = (string)Filter.Args; - Data += applyGoTemplateText(str, variables); - break; - case "tolower": - Data = Data.ToLower(); - break; - case "toupper": - Data = Data.ToUpper(); - break; - case "urldecode": - Data = HttpUtility.UrlDecode(Data, Encoding); - break; - case "timeago": - case "reltime": - Data = DateTimeUtil.FromTimeAgo(Data).ToString(DateTimeUtil.RFC1123ZPattern); - break; - case "fuzzytime": - var timestr = (string)Filter.Args; - Data = DateTimeUtil.FromUnknown(timestr).ToString(DateTimeUtil.RFC1123ZPattern); - break; - case "hexdump": - // this is mainly for debugging invisible special char related issues - var HexData = string.Join("", Data.Select(c => c + "(" + ((int)c).ToString("X2") + ")")); - logger.Info(string.Format("CardigannIndexer ({0}): strdump: {1}", ID, HexData)); - break; - case "strdump": - // for debugging - var DebugData = Data.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\xA0", "\\xA0"); - logger.Info(string.Format("CardigannIndexer ({0}): strdump: {1}", ID, DebugData)); - break; - default: - break; - } - } - return Data; + protected string applyFilters(string Data, List<filterBlock> Filters, Dictionary<string, object> variables = null) + { + if (Filters == null) + return Data; + + foreach(filterBlock Filter in Filters) + { + switch (Filter.Name) + { + case "querystring": + var param = (string)Filter.Args; + Data = ParseUtil.GetArgumentFromQueryString(Data, param); + break; + case "timeparse": + case "dateparse": + var layout = (string)Filter.Args; + try + { + var Date = DateTimeUtil.ParseDateTimeGoLang(Data, layout); + Data = Date.ToString(DateTimeUtil.RFC1123ZPattern); + } + catch (FormatException ex) + { + logger.Debug(ex.Message); + } + break; + case "regexp": + var pattern = (string)Filter.Args; + var Regexp = new Regex(pattern); + var Match = Regexp.Match(Data); + Data = Match.Groups[1].Value; + break; + case "re_replace": + var regexpreplace_pattern = (string)Filter.Args[0]; + var regexpreplace_replacement = (string)Filter.Args[1]; + regexpreplace_replacement = applyGoTemplateText(regexpreplace_replacement, variables); + Regex regexpreplace_regex = new Regex(regexpreplace_pattern); + Data = regexpreplace_regex.Replace(Data, regexpreplace_replacement); + break; + case "split": + var sep = (string)Filter.Args[0]; + var pos = (string)Filter.Args[1]; + var posInt = int.Parse(pos); + var strParts = Data.Split(sep[0]); + if (posInt < 0) + { + posInt += strParts.Length; + } + Data = strParts[posInt]; + break; + case "replace": + var from = (string)Filter.Args[0]; + var to = (string)Filter.Args[1]; + to = applyGoTemplateText(to, variables); + Data = Data.Replace(from, to); + break; + case "trim": + var cutset = (string)Filter.Args; + if (cutset != null) + Data = Data.Trim(cutset[0]); + else + Data = Data.Trim(); + break; + case "prepend": + var prependstr = (string)Filter.Args; + Data = applyGoTemplateText(prependstr, variables) + Data; + break; + case "append": + var str = (string)Filter.Args; + Data += applyGoTemplateText(str, variables); + break; + case "tolower": + Data = Data.ToLower(); + break; + case "toupper": + Data = Data.ToUpper(); + break; + case "urldecode": + Data = HttpUtility.UrlDecode(Data, Encoding); + break; + case "timeago": + case "reltime": + Data = DateTimeUtil.FromTimeAgo(Data).ToString(DateTimeUtil.RFC1123ZPattern); + break; + case "fuzzytime": + var timestr = (string)Filter.Args; + Data = DateTimeUtil.FromUnknown(timestr).ToString(DateTimeUtil.RFC1123ZPattern); + break; + case "hexdump": + // this is mainly for debugging invisible special char related issues + var HexData = string.Join("", Data.Select(c => c + "(" + ((int)c).ToString("X2") + ")")); + logger.Info(string.Format("CardigannIndexer ({0}): strdump: {1}", ID, HexData)); + break; + case "strdump": + // for debugging + var DebugData = Data.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\xA0", "\\xA0"); + logger.Info(string.Format("CardigannIndexer ({0}): strdump: {1}", ID, DebugData)); + break; + default: + break; + } + } + return Data; } - protected IElement QuerySelector(IElement Element, string Selector) - { - // AngleSharp doesn't support the :root pseudo selector, so we check for it manually - if (Selector.StartsWith(":root")) - { - Selector = Selector.Substring(5); - while (Element.ParentElement != null) - { - Element = Element.ParentElement; - } - } - return Element.QuerySelector(Selector); + protected IElement QuerySelector(IElement Element, string Selector) + { + // AngleSharp doesn't support the :root pseudo selector, so we check for it manually + if (Selector.StartsWith(":root")) + { + Selector = Selector.Substring(5); + while (Element.ParentElement != null) + { + Element = Element.ParentElement; + } + } + return Element.QuerySelector(Selector); } - protected string handleSelector(selectorBlock Selector, IElement Dom, Dictionary<string, object> variables = null) - { - if (Selector.Text != null) - { - return applyFilters(applyGoTemplateText(Selector.Text, variables), Selector.Filters, variables); - } - - IElement selection = Dom; - string value = null; - - if (Selector.Selector != null) - { - selection = QuerySelector(Dom, Selector.Selector); - if (selection == null) - { - throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", Selector.Selector, Dom.ToHtmlPretty())); - } - } - - if (Selector.Remove != null) - { - foreach(var i in selection.QuerySelectorAll(Selector.Remove)) - { - i.Remove(); - } - } - - if (Selector.Case != null) - { - foreach(var Case in Selector.Case) - { - if (selection.Matches(Case.Key) || QuerySelector(selection, Case.Key) != null) - { - value = Case.Value; - break; - } - } - if(value == null) - throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", Selector.Case), selection.ToHtmlPretty())); - } - else if (Selector.Attribute != null) - { - value = selection.GetAttribute(Selector.Attribute); - if (value == null) - throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", Selector.Attribute, selection.ToHtmlPretty())); - } - else - { - value = selection.TextContent; - } - - return applyFilters(ParseUtil.NormalizeSpace(value), Selector.Filters, variables); + protected string handleSelector(selectorBlock Selector, IElement Dom, Dictionary<string, object> variables = null) + { + if (Selector.Text != null) + { + return applyFilters(applyGoTemplateText(Selector.Text, variables), Selector.Filters, variables); + } + + IElement selection = Dom; + string value = null; + + if (Selector.Selector != null) + { + selection = QuerySelector(Dom, Selector.Selector); + if (selection == null) + { + throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", Selector.Selector, Dom.ToHtmlPretty())); + } + } + + if (Selector.Remove != null) + { + foreach(var i in selection.QuerySelectorAll(Selector.Remove)) + { + i.Remove(); + } + } + + if (Selector.Case != null) + { + foreach(var Case in Selector.Case) + { + if (selection.Matches(Case.Key) || QuerySelector(selection, Case.Key) != null) + { + value = Case.Value; + break; + } + } + if(value == null) + throw new Exception(string.Format("None of the case selectors \"{0}\" matched {1}", string.Join(",", Selector.Case), selection.ToHtmlPretty())); + } + else if (Selector.Attribute != null) + { + value = selection.GetAttribute(Selector.Attribute); + if (value == null) + throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", Selector.Attribute, selection.ToHtmlPretty())); + } + else + { + value = selection.TextContent; + } + + return applyFilters(ParseUtil.NormalizeSpace(value), Selector.Filters, variables); } - protected Uri resolvePath(string path, Uri currentUrl = null) - { - if (currentUrl == null) - currentUrl = new Uri(SiteLink); - - return new Uri(currentUrl, path); + protected Uri resolvePath(string path, Uri currentUrl = null) + { + if (currentUrl == null) + currentUrl = new Uri(SiteLink); + + return new Uri(currentUrl, path); } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) @@ -1108,511 +1108,511 @@ namespace Jackett.Indexers searchBlock Search = Definition.Search; // init template context - var variables = getTemplateVariablesFromConfigData(); - - variables[".Query.Type"] = query.QueryType; - variables[".Query.Q"] = query.SearchTerm; - variables[".Query.Series"] = null; - variables[".Query.Ep"] = query.Episode; - variables[".Query.Season"] = query.Season; - variables[".Query.Movie"] = null; - variables[".Query.Year"] = null; - variables[".Query.Limit"] = query.Limit; - variables[".Query.Offset"] = query.Offset; - variables[".Query.Extended"] = query.Extended; - variables[".Query.Categories"] = query.Categories; - variables[".Query.APIKey"] = query.ApiKey; - variables[".Query.TVDBID"] = null; - variables[".Query.TVRageID"] = query.RageID; - variables[".Query.IMDBID"] = query.ImdbID; - variables[".Query.IMDBIDShort"] = query.ImdbIDShort; - variables[".Query.TVMazeID"] = null; - variables[".Query.TraktID"] = null; - - variables[".Query.Episode"] = query.GetEpisodeSearchString(); - - var mappedCategories = MapTorznabCapsToTrackers(query); - variables[".Categories"] = mappedCategories; - - var KeywordTokens = new List<string>(); - var KeywordTokenKeys = new List<string> { "Q", "Series", "Movie", "Year" }; - foreach (var key in KeywordTokenKeys) - { - var Value = (string)variables[".Query." + key]; - if (!string.IsNullOrWhiteSpace(Value)) - KeywordTokens.Add(Value); - } - - if (!string.IsNullOrWhiteSpace((string)variables[".Query.Episode"])) - KeywordTokens.Add((string)variables[".Query.Episode"]); - variables[".Query.Keywords"] = string.Join(" ", KeywordTokens); - variables[".Keywords"] = applyFilters((string)variables[".Query.Keywords"], Search.Keywordsfilters); - - // TODO: prepare queries first and then send them parallel - var SearchPaths = Search.Paths; - foreach (var SearchPath in SearchPaths) - { - // skip path if categories don't match - if (SearchPath.Categories != null && mappedCategories.Count > 0) - { - var invertMatch = (SearchPath.Categories[0] == "!"); - var hasIntersect = mappedCategories.Intersect(SearchPath.Categories).Any(); - if (invertMatch) - hasIntersect = !hasIntersect; - if (!hasIntersect) - continue; - } - - // build search URL - // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround - var searchUrl = resolvePath(applyGoTemplateText(SearchPath.Path, variables, HttpUtility.UrlEncode).Replace("+", "%20")).AbsoluteUri; - var queryCollection = new List<KeyValuePair<string, string>>(); - RequestType method = RequestType.GET; - - if (String.Equals(SearchPath.Method, "post", StringComparison.OrdinalIgnoreCase)) - { - method = RequestType.POST; - } - - var InputsList = new List<Dictionary<string, string>>(); - if (SearchPath.Inheritinputs) - InputsList.Add(Search.Inputs); - InputsList.Add(SearchPath.Inputs); - - foreach (var Inputs in InputsList) - { - if (Inputs != null) - { - foreach (var Input in Inputs) - { - if (Input.Key == "$raw") - { - var rawStr = applyGoTemplateText(Input.Value, variables, HttpUtility.UrlEncode); - foreach (string part in rawStr.Split('&')) - { - var parts = part.Split(new char[] { '=' }, 2); - var key = parts[0]; - if (key.Length == 0) - continue; - var value = ""; - if (parts.Count() == 2) - value = parts[1]; - queryCollection.Add(key, value); - } - } - else - queryCollection.Add(Input.Key, applyGoTemplateText(Input.Value, variables)); - } - } - } - - if (method == RequestType.GET) - { - if (queryCollection.Count > 0) - searchUrl += "?" + queryCollection.GetQueryString(Encoding); - } - - // send HTTP request - WebClientStringResult response = null; - if (method == RequestType.POST) + var variables = getTemplateVariablesFromConfigData(); + + variables[".Query.Type"] = query.QueryType; + variables[".Query.Q"] = query.SearchTerm; + variables[".Query.Series"] = null; + variables[".Query.Ep"] = query.Episode; + variables[".Query.Season"] = query.Season; + variables[".Query.Movie"] = null; + variables[".Query.Year"] = null; + variables[".Query.Limit"] = query.Limit; + variables[".Query.Offset"] = query.Offset; + variables[".Query.Extended"] = query.Extended; + variables[".Query.Categories"] = query.Categories; + variables[".Query.APIKey"] = query.ApiKey; + variables[".Query.TVDBID"] = null; + variables[".Query.TVRageID"] = query.RageID; + variables[".Query.IMDBID"] = query.ImdbID; + variables[".Query.IMDBIDShort"] = query.ImdbIDShort; + variables[".Query.TVMazeID"] = null; + variables[".Query.TraktID"] = null; + + variables[".Query.Episode"] = query.GetEpisodeSearchString(); + + var mappedCategories = MapTorznabCapsToTrackers(query); + variables[".Categories"] = mappedCategories; + + var KeywordTokens = new List<string>(); + var KeywordTokenKeys = new List<string> { "Q", "Series", "Movie", "Year" }; + foreach (var key in KeywordTokenKeys) + { + var Value = (string)variables[".Query." + key]; + if (!string.IsNullOrWhiteSpace(Value)) + KeywordTokens.Add(Value); + } + + if (!string.IsNullOrWhiteSpace((string)variables[".Query.Episode"])) + KeywordTokens.Add((string)variables[".Query.Episode"]); + variables[".Query.Keywords"] = string.Join(" ", KeywordTokens); + variables[".Keywords"] = applyFilters((string)variables[".Query.Keywords"], Search.Keywordsfilters); + + // TODO: prepare queries first and then send them parallel + var SearchPaths = Search.Paths; + foreach (var SearchPath in SearchPaths) + { + // skip path if categories don't match + if (SearchPath.Categories != null && mappedCategories.Count > 0) + { + var invertMatch = (SearchPath.Categories[0] == "!"); + var hasIntersect = mappedCategories.Intersect(SearchPath.Categories).Any(); + if (invertMatch) + hasIntersect = !hasIntersect; + if (!hasIntersect) + continue; + } + + // build search URL + // HttpUtility.UrlPathEncode seems to only encode spaces, we use UrlEncode and replace + with %20 as a workaround + var searchUrl = resolvePath(applyGoTemplateText(SearchPath.Path, variables, HttpUtility.UrlEncode).Replace("+", "%20")).AbsoluteUri; + var queryCollection = new List<KeyValuePair<string, string>>(); + RequestType method = RequestType.GET; + + if (String.Equals(SearchPath.Method, "post", StringComparison.OrdinalIgnoreCase)) + { + method = RequestType.POST; + } + + var InputsList = new List<Dictionary<string, string>>(); + if (SearchPath.Inheritinputs) + InputsList.Add(Search.Inputs); + InputsList.Add(SearchPath.Inputs); + + foreach (var Inputs in InputsList) + { + if (Inputs != null) + { + foreach (var Input in Inputs) + { + if (Input.Key == "$raw") + { + var rawStr = applyGoTemplateText(Input.Value, variables, HttpUtility.UrlEncode); + foreach (string part in rawStr.Split('&')) + { + var parts = part.Split(new char[] { '=' }, 2); + var key = parts[0]; + if (key.Length == 0) + continue; + var value = ""; + if (parts.Count() == 2) + value = parts[1]; + queryCollection.Add(key, value); + } + } + else + queryCollection.Add(Input.Key, applyGoTemplateText(Input.Value, variables)); + } + } + } + + if (method == RequestType.GET) + { + if (queryCollection.Count > 0) + searchUrl += "?" + queryCollection.GetQueryString(Encoding); + } + + // send HTTP request + WebClientStringResult response = null; + if (method == RequestType.POST) response = await PostDataWithCookies(searchUrl, queryCollection); else response = await RequestStringWithCookies(searchUrl); var results = response.Content; try { - var SearchResultParser = new HtmlParser(); - var SearchResultDocument = SearchResultParser.Parse(results); - - // check if we need to login again - var loginNeeded = CheckIfLoginIsNeeded(response, SearchResultDocument); - if (loginNeeded) - { - logger.Info(string.Format("CardigannIndexer ({0}): Relogin required", ID)); - var LoginResult = await DoLogin(); - if (!LoginResult) - throw new Exception(string.Format("Relogin failed")); - await TestLogin(); - if (method == RequestType.POST) - response = await PostDataWithCookies(searchUrl, queryCollection); - else - response = await RequestStringWithCookies(searchUrl); - results = response.Content; - SearchResultDocument = SearchResultParser.Parse(results); - } - - checkForError(response, Definition.Search.Error); - - - var RowsDom = SearchResultDocument.QuerySelectorAll(Search.Rows.Selector); - List<IElement> Rows = new List<IElement>(); - foreach (var RowDom in RowsDom) - { - Rows.Add(RowDom); - } - - // merge following rows for After selector - var After = Definition.Search.Rows.After; - if (After > 0) - { - for (int i = 0; i < Rows.Count; i += 1) - { - var CurrentRow = Rows[i]; - for (int j = 0; j < After; j += 1) - { - var MergeRowIndex = i + j + 1; - var MergeRow = Rows[MergeRowIndex]; - List<INode> MergeNodes = new List<INode>(); - foreach (var node in MergeRow.ChildNodes) - { - MergeNodes.Add(node); - } - CurrentRow.Append(MergeNodes.ToArray()); - } - Rows.RemoveRange(i + 1, After); - } - } - - foreach (var Row in Rows) + var SearchResultParser = new HtmlParser(); + var SearchResultDocument = SearchResultParser.Parse(results); + + // check if we need to login again + var loginNeeded = CheckIfLoginIsNeeded(response, SearchResultDocument); + if (loginNeeded) + { + logger.Info(string.Format("CardigannIndexer ({0}): Relogin required", ID)); + var LoginResult = await DoLogin(); + if (!LoginResult) + throw new Exception(string.Format("Relogin failed")); + await TestLogin(); + if (method == RequestType.POST) + response = await PostDataWithCookies(searchUrl, queryCollection); + else + response = await RequestStringWithCookies(searchUrl); + results = response.Content; + SearchResultDocument = SearchResultParser.Parse(results); + } + + checkForError(response, Definition.Search.Error); + + + var RowsDom = SearchResultDocument.QuerySelectorAll(Search.Rows.Selector); + List<IElement> Rows = new List<IElement>(); + foreach (var RowDom in RowsDom) + { + Rows.Add(RowDom); + } + + // merge following rows for After selector + var After = Definition.Search.Rows.After; + if (After > 0) + { + for (int i = 0; i < Rows.Count; i += 1) + { + var CurrentRow = Rows[i]; + for (int j = 0; j < After; j += 1) + { + var MergeRowIndex = i + j + 1; + var MergeRow = Rows[MergeRowIndex]; + List<INode> MergeNodes = new List<INode>(); + foreach (var node in MergeRow.ChildNodes) + { + MergeNodes.Add(node); + } + CurrentRow.Append(MergeNodes.ToArray()); + } + Rows.RemoveRange(i + 1, After); + } + } + + foreach (var Row in Rows) { - try - { + try + { var release = new ReleaseInfo(); - release.MinimumRatio = 1; + release.MinimumRatio = 1; release.MinimumSeedTime = 48 * 60 * 60; // Parse fields - foreach (var Field in Search.Fields) - { - var FieldParts = Field.Key.Split('|'); - var FieldName = FieldParts[0]; - var FieldModifiers = new List<string>(); - for (var i = 1; i < FieldParts.Length; i++) - FieldModifiers.Add(FieldParts[i]); - - string value = null; - var variablesKey = ".Result." + FieldName; - try - { - value = handleSelector(Field.Value, Row, variables); - switch (FieldName) - { + foreach (var Field in Search.Fields) + { + var FieldParts = Field.Key.Split('|'); + var FieldName = FieldParts[0]; + var FieldModifiers = new List<string>(); + for (var i = 1; i < FieldParts.Length; i++) + FieldModifiers.Add(FieldParts[i]); + + string value = null; + var variablesKey = ".Result." + FieldName; + try + { + value = handleSelector(Field.Value, Row, variables); + switch (FieldName) + { case "download": - if (string.IsNullOrEmpty(value)) - { - value = null; - release.Link = null; - break; + if (string.IsNullOrEmpty(value)) + { + value = null; + release.Link = null; + break; + } + if (value.StartsWith("magnet:")) + { + release.MagnetUri = new Uri(value); + //release.Link = release.MagnetUri; + value = release.MagnetUri.ToString(); + } + else + { + release.Link = resolvePath(value); + value = release.Link.ToString(); } - if (value.StartsWith("magnet:")) - { - release.MagnetUri = new Uri(value); - //release.Link = release.MagnetUri; - value = release.MagnetUri.ToString(); - } - else - { - release.Link = resolvePath(value); - value = release.Link.ToString(); - } - break; - case "magnet": - release.MagnetUri = new Uri(value); - value = release.MagnetUri.ToString(); - break; + break; + case "magnet": + release.MagnetUri = new Uri(value); + value = release.MagnetUri.ToString(); + break; case "details": - var url = resolvePath(value); - release.Guid = url; - release.Comments = url; - if (release.Guid == null) - release.Guid = url; - value = url.ToString(); - break; + var url = resolvePath(value); + release.Guid = url; + release.Comments = url; + if (release.Guid == null) + release.Guid = url; + value = url.ToString(); + break; case "comments": - var CommentsUrl = resolvePath(value); - if (release.Comments == null) - release.Comments = CommentsUrl; - if (release.Guid == null) - release.Guid = CommentsUrl; - value = CommentsUrl.ToString(); - break; + var CommentsUrl = resolvePath(value); + if (release.Comments == null) + release.Comments = CommentsUrl; + if (release.Guid == null) + release.Guid = CommentsUrl; + value = CommentsUrl.ToString(); + break; case "title": if (FieldModifiers.Contains("append")) release.Title += value; else - release.Title = value; - value = release.Title; - break; + release.Title = value; + value = release.Title; + break; case "description": if (FieldModifiers.Contains("append")) release.Description += value; else release.Description = value; value = release.Description; - break; + break; case "category": - release.Category = MapTrackerCatToNewznab(value); - value = release.Category.ToString(); - break; + release.Category = MapTrackerCatToNewznab(value); + value = release.Category.ToString(); + break; case "size": - release.Size = ReleaseInfo.GetBytes(value); - value = release.Size.ToString(); - break; + release.Size = ReleaseInfo.GetBytes(value); + value = release.Size.ToString(); + break; case "leechers": var Leechers = ParseUtil.CoerceInt(value); - if (release.Peers == null) - release.Peers = Leechers; - else - release.Peers += Leechers; - value = Leechers.ToString(); - break; + if (release.Peers == null) + release.Peers = Leechers; + else + release.Peers += Leechers; + value = Leechers.ToString(); + break; case "seeders": - release.Seeders = ParseUtil.CoerceInt(value); - if (release.Peers == null) - release.Peers = release.Seeders; - else - release.Peers += release.Seeders; - value = release.Seeders.ToString(); - break; + release.Seeders = ParseUtil.CoerceInt(value); + if (release.Peers == null) + release.Peers = release.Seeders; + else + release.Peers += release.Seeders; + value = release.Seeders.ToString(); + break; case "date": - release.PublishDate = DateTimeUtil.FromUnknown(value); - value = release.PublishDate.ToString(DateTimeUtil.RFC1123ZPattern); - break; + release.PublishDate = DateTimeUtil.FromUnknown(value); + value = release.PublishDate.ToString(DateTimeUtil.RFC1123ZPattern); + break; case "files": - release.Files = ParseUtil.CoerceLong(value); - value = release.Files.ToString(); - break; + release.Files = ParseUtil.CoerceLong(value); + value = release.Files.ToString(); + break; case "grabs": - release.Grabs = ParseUtil.CoerceLong(value); - value = release.Grabs.ToString(); - break; + release.Grabs = ParseUtil.CoerceLong(value); + value = release.Grabs.ToString(); + break; case "downloadvolumefactor": - release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.DownloadVolumeFactor.ToString(); - break; + release.DownloadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.DownloadVolumeFactor.ToString(); + break; case "uploadvolumefactor": - release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); - value = release.UploadVolumeFactor.ToString(); - break; + release.UploadVolumeFactor = ParseUtil.CoerceDouble(value); + value = release.UploadVolumeFactor.ToString(); + break; case "minimumratio": - release.MinimumRatio = ParseUtil.CoerceDouble(value); - value = release.MinimumRatio.ToString(); - break; + release.MinimumRatio = ParseUtil.CoerceDouble(value); + value = release.MinimumRatio.ToString(); + break; case "minimumseedtime": - release.MinimumSeedTime = ParseUtil.CoerceLong(value); - value = release.MinimumSeedTime.ToString(); - break; + release.MinimumSeedTime = ParseUtil.CoerceLong(value); + value = release.MinimumSeedTime.ToString(); + break; case "imdb": - release.Imdb = ParseUtil.GetLongFromString(value); - value = release.Imdb.ToString(); - break; + release.Imdb = ParseUtil.GetLongFromString(value); + value = release.Imdb.ToString(); + break; case "rageid": - Regex RageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var RageIDMatch = RageIDRegEx.Match(value); - var RageID = RageIDMatch.Groups[1].Value; - release.RageID = ParseUtil.CoerceLong(RageID); - value = release.RageID.ToString(); - break; + Regex RageIDRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var RageIDMatch = RageIDRegEx.Match(value); + var RageID = RageIDMatch.Groups[1].Value; + release.RageID = ParseUtil.CoerceLong(RageID); + value = release.RageID.ToString(); + break; case "tvdbid": - Regex TVDBIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var TVDBIdMatch = TVDBIdRegEx.Match(value); - var TVDBId = TVDBIdMatch.Groups[1].Value; - release.TVDBId = ParseUtil.CoerceLong(TVDBId); - value = release.TVDBId.ToString(); - break; + Regex TVDBIdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var TVDBIdMatch = TVDBIdRegEx.Match(value); + var TVDBId = TVDBIdMatch.Groups[1].Value; + release.TVDBId = ParseUtil.CoerceLong(TVDBId); + value = release.TVDBId.ToString(); + break; case "banner": if(!string.IsNullOrWhiteSpace(value)) { - var bannerurl = resolvePath(value); - release.BannerUrl = bannerurl; - } - value = release.BannerUrl.ToString(); - break; - default: - break; - } - variables[variablesKey] = value; - } - catch (Exception ex) - { - if (!variables.ContainsKey(variablesKey)) - variables[variablesKey] = null; - if (OptionalFileds.Contains(Field.Key) || FieldModifiers.Contains("optional") || Field.Value.Optional) - continue; - throw new Exception(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", Field.Key, Field.Value.Selector, (value == null ? "<null>" : value), ex.Message)); - } - } - - var Filters = Definition.Search.Rows.Filters; - var SkipRelease = false; - if (Filters != null) - { - foreach (filterBlock Filter in Filters) - { - switch (Filter.Name) - { - case "andmatch": - int CharacterLimit = -1; - if (Filter.Args != null) - CharacterLimit = int.Parse(Filter.Args); - - if (query.ImdbID != null && TorznabCaps.SupportsImdbSearch) - break; // skip andmatch filter for imdb searches - - if (!query.MatchQueryStringAND(release.Title, CharacterLimit)) - { - logger.Debug(string.Format("CardigannIndexer ({0}): skipping {1} (andmatch filter)", ID, release.Title)); - SkipRelease = true; - } - break; - case "strdump": - // for debugging - logger.Info(string.Format("CardigannIndexer ({0}): row strdump: {1}", ID, Row.ToHtmlPretty())); - break; - default: - logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", ID, Filter.Name)); - break; - } - } - } - - if (SkipRelease) - continue; - - // if DateHeaders is set go through the previous rows and look for the header selector - var DateHeaders = Definition.Search.Rows.Dateheaders; - if (release.PublishDate == DateTime.MinValue && DateHeaders != null) - { - var PrevRow = Row.PreviousElementSibling; - string value = null; - while (PrevRow != null) - { - try - { - value = handleSelector(DateHeaders, PrevRow); - break; - } - catch (Exception) - { - // do nothing - } - PrevRow = PrevRow.PreviousElementSibling; - } - - if (value == null && DateHeaders.Optional == false) - throw new Exception(string.Format("No date header row found for {0}", release.ToString())); - if (value != null) - release.PublishDate = DateTimeUtil.FromUnknown(value); - } - - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", ID, Row.ToHtmlPretty(), ex)); - } + var bannerurl = resolvePath(value); + release.BannerUrl = bannerurl; + } + value = release.BannerUrl.ToString(); + break; + default: + break; + } + variables[variablesKey] = value; + } + catch (Exception ex) + { + if (!variables.ContainsKey(variablesKey)) + variables[variablesKey] = null; + if (OptionalFileds.Contains(Field.Key) || FieldModifiers.Contains("optional") || Field.Value.Optional) + continue; + throw new Exception(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", Field.Key, Field.Value.Selector, (value == null ? "<null>" : value), ex.Message)); + } + } + + var Filters = Definition.Search.Rows.Filters; + var SkipRelease = false; + if (Filters != null) + { + foreach (filterBlock Filter in Filters) + { + switch (Filter.Name) + { + case "andmatch": + int CharacterLimit = -1; + if (Filter.Args != null) + CharacterLimit = int.Parse(Filter.Args); + + if (query.ImdbID != null && TorznabCaps.SupportsImdbSearch) + break; // skip andmatch filter for imdb searches + + if (!query.MatchQueryStringAND(release.Title, CharacterLimit)) + { + logger.Debug(string.Format("CardigannIndexer ({0}): skipping {1} (andmatch filter)", ID, release.Title)); + SkipRelease = true; + } + break; + case "strdump": + // for debugging + logger.Info(string.Format("CardigannIndexer ({0}): row strdump: {1}", ID, Row.ToHtmlPretty())); + break; + default: + logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", ID, Filter.Name)); + break; + } + } + } + + if (SkipRelease) + continue; + + // if DateHeaders is set go through the previous rows and look for the header selector + var DateHeaders = Definition.Search.Rows.Dateheaders; + if (release.PublishDate == DateTime.MinValue && DateHeaders != null) + { + var PrevRow = Row.PreviousElementSibling; + string value = null; + while (PrevRow != null) + { + try + { + value = handleSelector(DateHeaders, PrevRow); + break; + } + catch (Exception) + { + // do nothing + } + PrevRow = PrevRow.PreviousElementSibling; + } + + if (value == null && DateHeaders.Optional == false) + throw new Exception(string.Format("No date header row found for {0}", release.ToString())); + if (value != null) + release.PublishDate = DateTimeUtil.FromUnknown(value); + } + + releases.Add(release); + } + catch (Exception ex) + { + logger.Error(string.Format("CardigannIndexer ({0}): Error while parsing row '{1}':\n\n{2}", ID, Row.ToHtmlPretty(), ex)); + } } } catch (Exception ex) { OnParseError(results, ex); - } + } } return releases; } - protected async Task<WebClientByteResult> handleRequest(requestBlock request, Dictionary<string, object> variables = null, string referer = null) - { - var requestLinkStr = resolvePath(applyGoTemplateText(request.Path, variables)).ToString(); - - Dictionary<string, string> pairs = null; - var queryCollection = new NameValueCollection(); - - RequestType method = RequestType.GET; - if (String.Equals(request.Method, "post", StringComparison.OrdinalIgnoreCase)) - { - method = RequestType.POST; - pairs = new Dictionary<string, string>(); - } - - foreach (var Input in request.Inputs) - { - var value = applyGoTemplateText(Input.Value, variables); - if (method == RequestType.GET) - queryCollection.Add(Input.Key, value); - else if (method == RequestType.POST) - pairs.Add(Input.Key, value); - } - - if (queryCollection.Count > 0) - { - if (!requestLinkStr.Contains("?")) - requestLinkStr += "?" + queryCollection.GetQueryString(Encoding).Substring(1); - else - requestLinkStr += queryCollection.GetQueryString(Encoding); - } - - var response = await RequestBytesWithCookiesAndRetry(requestLinkStr, null, method, referer, pairs); - logger.Debug($"CardigannIndexer ({ID}): handleRequest() remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => " + response.RedirectingTo : "")); - return response; + protected async Task<WebClientByteResult> handleRequest(requestBlock request, Dictionary<string, object> variables = null, string referer = null) + { + var requestLinkStr = resolvePath(applyGoTemplateText(request.Path, variables)).ToString(); + + Dictionary<string, string> pairs = null; + var queryCollection = new NameValueCollection(); + + RequestType method = RequestType.GET; + if (String.Equals(request.Method, "post", StringComparison.OrdinalIgnoreCase)) + { + method = RequestType.POST; + pairs = new Dictionary<string, string>(); + } + + foreach (var Input in request.Inputs) + { + var value = applyGoTemplateText(Input.Value, variables); + if (method == RequestType.GET) + queryCollection.Add(Input.Key, value); + else if (method == RequestType.POST) + pairs.Add(Input.Key, value); + } + + if (queryCollection.Count > 0) + { + if (!requestLinkStr.Contains("?")) + requestLinkStr += "?" + queryCollection.GetQueryString(Encoding).Substring(1); + else + requestLinkStr += queryCollection.GetQueryString(Encoding); + } + + var response = await RequestBytesWithCookiesAndRetry(requestLinkStr, null, method, referer, pairs); + logger.Debug($"CardigannIndexer ({ID}): handleRequest() remote server returned {response.Status.ToString()}" + (response.IsRedirect ? " => " + response.RedirectingTo : "")); + return response; } - protected IDictionary<string, object> AddTemplateVariablesFromUri(IDictionary<string, object> variables, Uri uri, string prefix = "") - { - variables[prefix + ".AbsoluteUri"] = uri.AbsoluteUri; - variables[prefix + ".AbsolutePath"] = uri.AbsolutePath; - variables[prefix + ".Scheme"] = uri.Scheme; - variables[prefix + ".Host"] = uri.Host; - variables[prefix + ".Port"] = uri.Port.ToString(); - variables[prefix + ".PathAndQuery"] = uri.PathAndQuery; - variables[prefix + ".Query"] = uri.Query; - var queryString = HttpUtility.ParseQueryString(uri.Query); - foreach (string key in queryString.Keys) - { - variables[prefix + ".Query." + key] = queryString.Get(key); - } - return variables; + protected IDictionary<string, object> AddTemplateVariablesFromUri(IDictionary<string, object> variables, Uri uri, string prefix = "") + { + variables[prefix + ".AbsoluteUri"] = uri.AbsoluteUri; + variables[prefix + ".AbsolutePath"] = uri.AbsolutePath; + variables[prefix + ".Scheme"] = uri.Scheme; + variables[prefix + ".Host"] = uri.Host; + variables[prefix + ".Port"] = uri.Port.ToString(); + variables[prefix + ".PathAndQuery"] = uri.PathAndQuery; + variables[prefix + ".Query"] = uri.Query; + var queryString = HttpUtility.ParseQueryString(uri.Query); + foreach (string key in queryString.Keys) + { + variables[prefix + ".Query." + key] = queryString.Get(key); + } + return variables; } - public override async Task<byte[]> Download(Uri link) - { - var method = RequestType.GET; - if (Definition.Download != null) - { - var Download = Definition.Download; - if (Download.Before != null) - { - var beforeVariables = getTemplateVariablesFromConfigData(); - AddTemplateVariablesFromUri(beforeVariables, link, ".DownloadUri"); - var beforeresult = await handleRequest(Download.Before, beforeVariables, link.ToString()); - } - if (Download.Method != null) - { - if (Download.Method == "post") - method = RequestType.POST; - } - if (Download.Selector != null) - { - var response = await RequestStringWithCookies(link.ToString()); - if (response.IsRedirect) - response = await RequestStringWithCookies(response.RedirectingTo); - var results = response.Content; - var SearchResultParser = new HtmlParser(); - var SearchResultDocument = SearchResultParser.Parse(results); - var DlUri = SearchResultDocument.QuerySelector(Download.Selector); - if (DlUri != null) - { - logger.Debug(string.Format("CardigannIndexer ({0}): Download selector {1} matched:{2}", ID, Download.Selector, DlUri.ToHtmlPretty())); - var href = DlUri.GetAttribute("href"); - link = resolvePath(href); - } - else - { - logger.Error(string.Format("CardigannIndexer ({0}): Download selector {1} didn't match:\n{2}", ID, Download.Selector, results)); - throw new Exception(string.Format("Download selector {0} didn't match", Download.Selector)); - } - } - } - return await base.Download(link, method); + public override async Task<byte[]> Download(Uri link) + { + var method = RequestType.GET; + if (Definition.Download != null) + { + var Download = Definition.Download; + if (Download.Before != null) + { + var beforeVariables = getTemplateVariablesFromConfigData(); + AddTemplateVariablesFromUri(beforeVariables, link, ".DownloadUri"); + var beforeresult = await handleRequest(Download.Before, beforeVariables, link.ToString()); + } + if (Download.Method != null) + { + if (Download.Method == "post") + method = RequestType.POST; + } + if (Download.Selector != null) + { + var response = await RequestStringWithCookies(link.ToString()); + if (response.IsRedirect) + response = await RequestStringWithCookies(response.RedirectingTo); + var results = response.Content; + var SearchResultParser = new HtmlParser(); + var SearchResultDocument = SearchResultParser.Parse(results); + var DlUri = SearchResultDocument.QuerySelector(Download.Selector); + if (DlUri != null) + { + logger.Debug(string.Format("CardigannIndexer ({0}): Download selector {1} matched:{2}", ID, Download.Selector, DlUri.ToHtmlPretty())); + var href = DlUri.GetAttribute("href"); + link = resolvePath(href); + } + else + { + logger.Error(string.Format("CardigannIndexer ({0}): Download selector {1} didn't match:\n{2}", ID, Download.Selector, results)); + throw new Exception(string.Format("Download selector {0} didn't match", Download.Selector)); + } + } + } + return await base.Download(link, method); } } } diff --git a/src/Jackett/Indexers/DanishBits.cs b/src/Jackett/Indexers/DanishBits.cs index 316501eb..a6f9a834 100644 --- a/src/Jackett/Indexers/DanishBits.cs +++ b/src/Jackett/Indexers/DanishBits.cs @@ -14,8 +14,8 @@ using System.Threading.Tasks; using System.Web; using CsQuery.ExtensionMethods; using Jackett.Models.IndexerConfig; -using Jackett.Utils; - +using Jackett.Utils; + namespace Jackett.Indexers { public class DanishBits : BaseIndexer, IIndexer @@ -274,15 +274,15 @@ namespace Jackett.Indexers var Grabs = qRow.Find("td:nth-child(6)"); release.Grabs = ParseUtil.CoerceLong(Grabs.Text()); - if (qRow.Find("span.freeleech, img[src=\"/static/common/torrents/gratis.png\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("span.freeleech, img[src=\"/static/common/torrents/gratis.png\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - - if (qRow.Find("img[src=\"/static/common/torrents/toxupload.png\"]").Length >= 1) - release.UploadVolumeFactor = 2; + release.DownloadVolumeFactor = 1; + + if (qRow.Find("img[src=\"/static/common/torrents/toxupload.png\"]").Length >= 1) + release.UploadVolumeFactor = 2; else - release.UploadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); } diff --git a/src/Jackett/Indexers/Demonoid.cs b/src/Jackett/Indexers/Demonoid.cs index 785965b4..2725bd91 100644 --- a/src/Jackett/Indexers/Demonoid.cs +++ b/src/Jackett/Indexers/Demonoid.cs @@ -1,173 +1,173 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Models.IndexerConfig; -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.Text; -using System.Threading.Tasks; -using System.Web; - -namespace Jackett.Indexers -{ - public class Demonoid : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "account_handler.php"; } } - private string SearchUrl { get { return SiteLink + "files/?category={0}&subcategory=All&quality=All&seeded=2&to=1&query={1}&external=2"; } } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public Demonoid(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "Demonoid", - description: "Demonoid", - link: "https://www.demonoid.pw/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(5, TorznabCatType.PC0day, "Applications"); - AddCategoryMapping(17, TorznabCatType.AudioAudiobook, "Audio Books"); - AddCategoryMapping(11, TorznabCatType.Books, "Books"); - AddCategoryMapping(10, TorznabCatType.BooksComics, "Comics"); - AddCategoryMapping(4, TorznabCatType.PCGames, "Games"); - AddCategoryMapping(9, TorznabCatType.TVAnime, "Japanese Anime"); - AddCategoryMapping(6, TorznabCatType.Other, "Miscellaneous"); - AddCategoryMapping(1, TorznabCatType.Movies, "Movies"); - AddCategoryMapping(2, TorznabCatType.Audio, "Music"); - AddCategoryMapping(13, TorznabCatType.AudioVideo, "Music Videos"); - AddCategoryMapping(8, TorznabCatType.Other, "Pictures"); - AddCategoryMapping(3, TorznabCatType.TV, "TV"); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "nickname", configData.Username.Value }, - { "password", configData.Password.Value }, - { "returnpath", "/" }, - { "withq", "0" }, - { "Submit", "Submit" } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, SiteLink); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Cookies.Contains("uid="), () => - { - CQ dom = result.Content; - string errorMessage = dom["form[id='bb_code_form']"].Parent().Find("font[class='red']").Text(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var trackerCats = MapTorznabCapsToTrackers(query); - var cat = (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0"); - var episodeSearchUrl = string.Format(SearchUrl, cat, HttpUtility.UrlEncode(query.GetQueryString())); - var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); - - - if (results.Content.Contains("No torrents found")) - { - return releases; - } - - try - { - CQ dom = results.Content; - var rows = dom[".ctable_content_no_pad > table > tbody > tr"].ToArray(); - DateTime lastDateTime = default(DateTime); - for (var i = 0; i < rows.Length; i++) - { - var rowA = rows[i]; - var rAlign = rowA.Attributes["align"]; - if (rAlign == "right" || rAlign == "center") - continue; - if (rAlign == "left") - { - // ex: "Monday, Jun 01, 2015", "Monday, Aug 03, 2015" - var dateStr = rowA.Cq().Text().Trim().Replace("Added on ", ""); - if (dateStr.ToLowerInvariant().Contains("today")) - lastDateTime = DateTime.Now; - else - lastDateTime = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dddd, MMM dd, yyyy", CultureInfo.InvariantCulture), DateTimeKind.Utc).ToLocalTime(); - continue; - } - if (rowA.ChildElements.Count() < 2) - continue; - - var rowB = rows[++i]; - - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - release.PublishDate = lastDateTime; - - var catUrl = rowA.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href"); - var catId = HttpUtility.ParseQueryString(catUrl).Get("category"); - release.Category = MapTrackerCatToNewznab(catId); - - var qLink = rowA.ChildElements.ElementAt(1).FirstElementChild.Cq(); - release.Title = qLink.Text().Trim(); - release.Description = rowB.ChildElements.ElementAt(0).Cq().Text(); - - if (release.Category != null && release.Category.Contains(TorznabCatType.Audio.ID)) - { - if (release.Description.Contains("Lossless")) - release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; - else if (release.Description.Contains("MP3")) - release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; - else - release.Category = new List<int> { TorznabCatType.AudioOther.ID }; - } - - release.Comments = new Uri(SiteLink + qLink.Attr("href")); - release.Guid = release.Comments; - - var qDownload = rowB.ChildElements.ElementAt(2).ChildElements.ElementAt(0).Cq(); - release.Link = new Uri(SiteLink + qDownload.Attr("href")); - - var sizeStr = rowB.ChildElements.ElementAt(3).Cq().Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()); - release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders; - +using CsQuery; +using Jackett.Models; +using Jackett.Models.IndexerConfig; +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.Text; +using System.Threading.Tasks; +using System.Web; + +namespace Jackett.Indexers +{ + public class Demonoid : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "account_handler.php"; } } + private string SearchUrl { get { return SiteLink + "files/?category={0}&subcategory=All&quality=All&seeded=2&to=1&query={1}&external=2"; } } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public Demonoid(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "Demonoid", + description: "Demonoid", + link: "https://www.demonoid.pw/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(5, TorznabCatType.PC0day, "Applications"); + AddCategoryMapping(17, TorznabCatType.AudioAudiobook, "Audio Books"); + AddCategoryMapping(11, TorznabCatType.Books, "Books"); + AddCategoryMapping(10, TorznabCatType.BooksComics, "Comics"); + AddCategoryMapping(4, TorznabCatType.PCGames, "Games"); + AddCategoryMapping(9, TorznabCatType.TVAnime, "Japanese Anime"); + AddCategoryMapping(6, TorznabCatType.Other, "Miscellaneous"); + AddCategoryMapping(1, TorznabCatType.Movies, "Movies"); + AddCategoryMapping(2, TorznabCatType.Audio, "Music"); + AddCategoryMapping(13, TorznabCatType.AudioVideo, "Music Videos"); + AddCategoryMapping(8, TorznabCatType.Other, "Pictures"); + AddCategoryMapping(3, TorznabCatType.TV, "TV"); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "nickname", configData.Username.Value }, + { "password", configData.Password.Value }, + { "returnpath", "/" }, + { "withq", "0" }, + { "Submit", "Submit" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, SiteLink); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Cookies.Contains("uid="), () => + { + CQ dom = result.Content; + string errorMessage = dom["form[id='bb_code_form']"].Parent().Find("font[class='red']").Text(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var trackerCats = MapTorznabCapsToTrackers(query); + var cat = (trackerCats.Count == 1 ? trackerCats.ElementAt(0) : "0"); + var episodeSearchUrl = string.Format(SearchUrl, cat, HttpUtility.UrlEncode(query.GetQueryString())); + var results = await RequestStringWithCookiesAndRetry(episodeSearchUrl); + + + if (results.Content.Contains("No torrents found")) + { + return releases; + } + + try + { + CQ dom = results.Content; + var rows = dom[".ctable_content_no_pad > table > tbody > tr"].ToArray(); + DateTime lastDateTime = default(DateTime); + for (var i = 0; i < rows.Length; i++) + { + var rowA = rows[i]; + var rAlign = rowA.Attributes["align"]; + if (rAlign == "right" || rAlign == "center") + continue; + if (rAlign == "left") + { + // ex: "Monday, Jun 01, 2015", "Monday, Aug 03, 2015" + var dateStr = rowA.Cq().Text().Trim().Replace("Added on ", ""); + if (dateStr.ToLowerInvariant().Contains("today")) + lastDateTime = DateTime.Now; + else + lastDateTime = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dddd, MMM dd, yyyy", CultureInfo.InvariantCulture), DateTimeKind.Utc).ToLocalTime(); + continue; + } + if (rowA.ChildElements.Count() < 2) + continue; + + var rowB = rows[++i]; + + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + release.PublishDate = lastDateTime; + + var catUrl = rowA.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href"); + var catId = HttpUtility.ParseQueryString(catUrl).Get("category"); + release.Category = MapTrackerCatToNewznab(catId); + + var qLink = rowA.ChildElements.ElementAt(1).FirstElementChild.Cq(); + release.Title = qLink.Text().Trim(); + release.Description = rowB.ChildElements.ElementAt(0).Cq().Text(); + + if (release.Category != null && release.Category.Contains(TorznabCatType.Audio.ID)) + { + if (release.Description.Contains("Lossless")) + release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; + else if (release.Description.Contains("MP3")) + release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; + else + release.Category = new List<int> { TorznabCatType.AudioOther.ID }; + } + + release.Comments = new Uri(SiteLink + qLink.Attr("href")); + release.Guid = release.Comments; + + var qDownload = rowB.ChildElements.ElementAt(2).ChildElements.ElementAt(0).Cq(); + release.Link = new Uri(SiteLink + qDownload.Attr("href")); + + var sizeStr = rowB.ChildElements.ElementAt(3).Cq().Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(rowB.ChildElements.ElementAt(6).Cq().Text()) + release.Seeders; + var grabs = rowB.Cq().Find("td:nth-child(6)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - release.DownloadVolumeFactor = 0; // ratioless - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - return releases; - } - } -} + release.Grabs = ParseUtil.CoerceInt(grabs); + + release.DownloadVolumeFactor = 0; // ratioless + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + return releases; + } + } +} diff --git a/src/Jackett/Indexers/DigitalHive.cs b/src/Jackett/Indexers/DigitalHive.cs index 570925c4..e9689e5e 100644 --- a/src/Jackett/Indexers/DigitalHive.cs +++ b/src/Jackett/Indexers/DigitalHive.cs @@ -1,234 +1,234 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text.RegularExpressions; -using System.IO; - -namespace Jackett.Indexers -{ - public class DigitalHive : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "login.php?returnto=%2F"; } } - private string AjaxLoginUrl { get { return SiteLink + "takelogin.php"; } } - - new ConfigurationDataRecaptchaLogin configData - { - get { return (ConfigurationDataRecaptchaLogin)base.configData; } - set { base.configData = value; } - } - - public DigitalHive(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "DigitalHive", - description: "DigitalHive is one of the oldest general trackers", - link: "https://www.digitalhive.org/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataRecaptchaLogin()) - { - Encoding = Encoding.GetEncoding("iso-8859-1"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(0, TorznabCatType.Other); - AddCategoryMapping(48, TorznabCatType.Other); // 0Day - AddCategoryMapping(56, TorznabCatType.XXXImageset); // 0Day-Imagesets - AddCategoryMapping(6, TorznabCatType.Audio); // 0Day-Music - AddCategoryMapping(51, TorznabCatType.XXX); // 0Day-XXX - AddCategoryMapping(2, TorznabCatType.TVAnime); // Anime - AddCategoryMapping(59, TorznabCatType.MoviesBluRay); // BluRay - AddCategoryMapping(40, TorznabCatType.TVDocumentary); // Documentary - AddCategoryMapping(20, TorznabCatType.MoviesDVD); // DVD-R - AddCategoryMapping(25, TorznabCatType.BooksEbook); // Ebooks - AddCategoryMapping(38, TorznabCatType.PCPhoneIOS); // HandHeld - AddCategoryMapping(38, TorznabCatType.PCPhoneAndroid); // HandHeld - AddCategoryMapping(38, TorznabCatType.PCPhoneOther); // HandHeld - AddCategoryMapping(37, TorznabCatType.Other); // Kids Stuff - AddCategoryMapping(23, TorznabCatType.PC); // Linux - AddCategoryMapping(24, TorznabCatType.PCMac); // Mac - AddCategoryMapping(22, TorznabCatType.OtherMisc); // Misc - AddCategoryMapping(35, TorznabCatType.MoviesOther); // Movie Pack - AddCategoryMapping(36, TorznabCatType.MoviesHD); // Movie-HD - AddCategoryMapping(19, TorznabCatType.MoviesSD); // Movie-SD - AddCategoryMapping(50, TorznabCatType.Audio); // Music - AddCategoryMapping(53, TorznabCatType.AudioLossless); // Music-FLAC - AddCategoryMapping(49, TorznabCatType.AudioVideo); // MVID - AddCategoryMapping(1, TorznabCatType.PC); // PC Apps - AddCategoryMapping(4, TorznabCatType.PCGames); // PC Games - AddCategoryMapping(17, TorznabCatType.ConsolePS3); // Playstation - AddCategoryMapping(17, TorznabCatType.ConsolePS4); // Playstation - AddCategoryMapping(17, TorznabCatType.ConsolePSVita); // Playstation - AddCategoryMapping(17, TorznabCatType.ConsolePSP); // Playstation - AddCategoryMapping(28, TorznabCatType.ConsolePSP); // PSP - AddCategoryMapping(34, TorznabCatType.TVOTHER); // TV Pack - AddCategoryMapping(32, TorznabCatType.TVHD); // TV-HD - AddCategoryMapping(55, TorznabCatType.TVOTHER); // TV-HDRip - AddCategoryMapping(7, TorznabCatType.TVSD); // TV-SD - AddCategoryMapping(57, TorznabCatType.TVOTHER); // TV-SDRip - AddCategoryMapping(33, TorznabCatType.ConsoleWii); // WII - AddCategoryMapping(33, TorznabCatType.ConsoleWiiU); // WII - AddCategoryMapping(45, TorznabCatType.ConsoleXbox); // XBox - AddCategoryMapping(45, TorznabCatType.ConsoleXbox360); // XBox - AddCategoryMapping(45, TorznabCatType.ConsoleXBOX360DLC); // XBox - AddCategoryMapping(45, TorznabCatType.ConsoleXboxOne); // XBox - AddCategoryMapping(9, TorznabCatType.XXX); // XXX - AddCategoryMapping(52, TorznabCatType.XXXOther); // XXX-ISO - } - - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, configData.CookieHeader.Value); - CQ cq = loginPage.Content; - string recaptchaSiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); - var result = this.configData; - result.CookieHeader.Value = loginPage.Cookies; - result.Captcha.SiteKey = recaptchaSiteKey; - result.Captcha.Version = "2"; - return result; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "returnto" , "/" }, - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "g-recaptcha-response", configData.Captcha.Value } - }; - - if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) - { - // Cookie was manually supplied - CookieHeader = configData.Captcha.Cookie; - try - { - var results = await PerformQuery(new TorznabQuery()); - if (!results.Any()) - { - throw new Exception("Your cookie did not work"); - } - - SaveConfig(); - IsConfigured = true; - return IndexerConfigurationStatus.Completed; - } - catch (Exception e) - { - IsConfigured = false; - throw new Exception("Your cookie did not work: " + e.Message); - } - } - - var result = await RequestLoginAndFollowRedirect(AjaxLoginUrl, pairs, configData.CookieHeader.Value, true, SiteLink, LoginUrl); - - await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var queryCollection = new NameValueCollection(); - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - queryCollection.Add("blah", "0"); - - var results = await RequestStringWithCookiesAndRetry(searchUrl + "?" + queryCollection.GetQueryString()); - if (results.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl + "?" + queryCollection.GetQueryString()); - } - try - { - releases.AddRange(contentToReleaseInfos(query, results.Content)); - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - - private IEnumerable<ReleaseInfo> contentToReleaseInfos(TorznabQuery query, CQ dom) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - // Doesn't handle pagination yet... - var rows = dom["div.panel-body > table.table > tbody > tr"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 259200; - - var qRow = row.Cq(); - release.Title = qRow.Find("td:nth-child(2) > a").First().Text().Trim(); - - if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) - continue; - - release.Guid = new Uri(SiteLink + qRow.Find("td:nth-child(2) > a").First().Attr("href")); - release.Comments = release.Guid; - release.Link = new Uri(SiteLink + qRow.Find("td:nth-child(3) > a").First().Attr("href")); - var pubDate = new StringReader(qRow.Find("td:nth-child(2) > span").First().Text()).ReadLine().Trim().Replace("Added: ", ""); - release.PublishDate = DateTime.Parse(pubDate).ToLocalTime(); - release.Category = MapTrackerCatToNewznab(qRow.Find("td:nth-child(1) > a").First().Attr("href").Split('=')[1]); - release.Size = ReleaseInfo.GetBytes(qRow.Find("td:nth-child(7)").First().Text()); - release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").First().Text()); - release.Peers = ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").First().Text()) + release.Seeders; - - var files = row.Cq().Find("td:nth-child(5)").Text(); - release.Files = ParseUtil.CoerceInt(files); - - var grabs = row.Cq().Find("td:nth-child(8)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - if (row.Cq().Find("i.fa-star").Any()) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - - return releases; - } - } +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Text.RegularExpressions; +using System.IO; + +namespace Jackett.Indexers +{ + public class DigitalHive : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "login.php?returnto=%2F"; } } + private string AjaxLoginUrl { get { return SiteLink + "takelogin.php"; } } + + new ConfigurationDataRecaptchaLogin configData + { + get { return (ConfigurationDataRecaptchaLogin)base.configData; } + set { base.configData = value; } + } + + public DigitalHive(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "DigitalHive", + description: "DigitalHive is one of the oldest general trackers", + link: "https://www.digitalhive.org/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataRecaptchaLogin()) + { + Encoding = Encoding.GetEncoding("iso-8859-1"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(0, TorznabCatType.Other); + AddCategoryMapping(48, TorznabCatType.Other); // 0Day + AddCategoryMapping(56, TorznabCatType.XXXImageset); // 0Day-Imagesets + AddCategoryMapping(6, TorznabCatType.Audio); // 0Day-Music + AddCategoryMapping(51, TorznabCatType.XXX); // 0Day-XXX + AddCategoryMapping(2, TorznabCatType.TVAnime); // Anime + AddCategoryMapping(59, TorznabCatType.MoviesBluRay); // BluRay + AddCategoryMapping(40, TorznabCatType.TVDocumentary); // Documentary + AddCategoryMapping(20, TorznabCatType.MoviesDVD); // DVD-R + AddCategoryMapping(25, TorznabCatType.BooksEbook); // Ebooks + AddCategoryMapping(38, TorznabCatType.PCPhoneIOS); // HandHeld + AddCategoryMapping(38, TorznabCatType.PCPhoneAndroid); // HandHeld + AddCategoryMapping(38, TorznabCatType.PCPhoneOther); // HandHeld + AddCategoryMapping(37, TorznabCatType.Other); // Kids Stuff + AddCategoryMapping(23, TorznabCatType.PC); // Linux + AddCategoryMapping(24, TorznabCatType.PCMac); // Mac + AddCategoryMapping(22, TorznabCatType.OtherMisc); // Misc + AddCategoryMapping(35, TorznabCatType.MoviesOther); // Movie Pack + AddCategoryMapping(36, TorznabCatType.MoviesHD); // Movie-HD + AddCategoryMapping(19, TorznabCatType.MoviesSD); // Movie-SD + AddCategoryMapping(50, TorznabCatType.Audio); // Music + AddCategoryMapping(53, TorznabCatType.AudioLossless); // Music-FLAC + AddCategoryMapping(49, TorznabCatType.AudioVideo); // MVID + AddCategoryMapping(1, TorznabCatType.PC); // PC Apps + AddCategoryMapping(4, TorznabCatType.PCGames); // PC Games + AddCategoryMapping(17, TorznabCatType.ConsolePS3); // Playstation + AddCategoryMapping(17, TorznabCatType.ConsolePS4); // Playstation + AddCategoryMapping(17, TorznabCatType.ConsolePSVita); // Playstation + AddCategoryMapping(17, TorznabCatType.ConsolePSP); // Playstation + AddCategoryMapping(28, TorznabCatType.ConsolePSP); // PSP + AddCategoryMapping(34, TorznabCatType.TVOTHER); // TV Pack + AddCategoryMapping(32, TorznabCatType.TVHD); // TV-HD + AddCategoryMapping(55, TorznabCatType.TVOTHER); // TV-HDRip + AddCategoryMapping(7, TorznabCatType.TVSD); // TV-SD + AddCategoryMapping(57, TorznabCatType.TVOTHER); // TV-SDRip + AddCategoryMapping(33, TorznabCatType.ConsoleWii); // WII + AddCategoryMapping(33, TorznabCatType.ConsoleWiiU); // WII + AddCategoryMapping(45, TorznabCatType.ConsoleXbox); // XBox + AddCategoryMapping(45, TorznabCatType.ConsoleXbox360); // XBox + AddCategoryMapping(45, TorznabCatType.ConsoleXBOX360DLC); // XBox + AddCategoryMapping(45, TorznabCatType.ConsoleXboxOne); // XBox + AddCategoryMapping(9, TorznabCatType.XXX); // XXX + AddCategoryMapping(52, TorznabCatType.XXXOther); // XXX-ISO + } + + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, configData.CookieHeader.Value); + CQ cq = loginPage.Content; + string recaptchaSiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); + var result = this.configData; + result.CookieHeader.Value = loginPage.Cookies; + result.Captcha.SiteKey = recaptchaSiteKey; + result.Captcha.Version = "2"; + return result; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "returnto" , "/" }, + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "g-recaptcha-response", configData.Captcha.Value } + }; + + if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) + { + // Cookie was manually supplied + CookieHeader = configData.Captcha.Cookie; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (!results.Any()) + { + throw new Exception("Your cookie did not work"); + } + + SaveConfig(); + IsConfigured = true; + return IndexerConfigurationStatus.Completed; + } + catch (Exception e) + { + IsConfigured = false; + throw new Exception("Your cookie did not work: " + e.Message); + } + } + + var result = await RequestLoginAndFollowRedirect(AjaxLoginUrl, pairs, configData.CookieHeader.Value, true, SiteLink, LoginUrl); + + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var queryCollection = new NameValueCollection(); + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + queryCollection.Add("blah", "0"); + + var results = await RequestStringWithCookiesAndRetry(searchUrl + "?" + queryCollection.GetQueryString()); + if (results.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl + "?" + queryCollection.GetQueryString()); + } + try + { + releases.AddRange(contentToReleaseInfos(query, results.Content)); + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + + private IEnumerable<ReleaseInfo> contentToReleaseInfos(TorznabQuery query, CQ dom) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + // Doesn't handle pagination yet... + var rows = dom["div.panel-body > table.table > tbody > tr"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 259200; + + var qRow = row.Cq(); + release.Title = qRow.Find("td:nth-child(2) > a").First().Text().Trim(); + + if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) + continue; + + release.Guid = new Uri(SiteLink + qRow.Find("td:nth-child(2) > a").First().Attr("href")); + release.Comments = release.Guid; + release.Link = new Uri(SiteLink + qRow.Find("td:nth-child(3) > a").First().Attr("href")); + var pubDate = new StringReader(qRow.Find("td:nth-child(2) > span").First().Text()).ReadLine().Trim().Replace("Added: ", ""); + release.PublishDate = DateTime.Parse(pubDate).ToLocalTime(); + release.Category = MapTrackerCatToNewznab(qRow.Find("td:nth-child(1) > a").First().Attr("href").Split('=')[1]); + release.Size = ReleaseInfo.GetBytes(qRow.Find("td:nth-child(7)").First().Text()); + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:nth-child(9)").First().Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find("td:nth-child(10)").First().Text()) + release.Seeders; + + var files = row.Cq().Find("td:nth-child(5)").Text(); + release.Files = ParseUtil.CoerceInt(files); + + var grabs = row.Cq().Find("td:nth-child(8)").Text(); + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (row.Cq().Find("i.fa-star").Any()) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + + return releases; + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/EliteTracker.cs b/src/Jackett/Indexers/EliteTracker.cs index d0b5aa99..e469798c 100644 --- a/src/Jackett/Indexers/EliteTracker.cs +++ b/src/Jackett/Indexers/EliteTracker.cs @@ -1,34 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -using AngleSharp.Parser.Html; -using Newtonsoft.Json.Linq; -using NLog; - -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; - -namespace Jackett.Indexers -{ - class EliteTracker : BaseIndexer, IIndexer - { +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using AngleSharp.Parser.Html; +using Newtonsoft.Json.Linq; +using NLog; + +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; + +namespace Jackett.Indexers +{ + class EliteTracker : BaseIndexer, IIndexer + { string LoginUrl { get { return SiteLink + "takelogin.php"; } } - string BrowseUrl { get { return SiteLink + "browse.php"; } } - + string BrowseUrl { get { return SiteLink + "browse.php"; } } + new ConfigurationDataBasicLogin configData { get { return (ConfigurationDataBasicLogin)base.configData; } set { base.configData = value; } - } - + } + public EliteTracker(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) : base(name: "Elite-Tracker", description: "French Torrent Tracker", @@ -39,235 +39,235 @@ namespace Jackett.Indexers client: webClient, configData: new ConfigurationDataBasicLogin() ) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "fr-fr"; - Type = "private"; - - AddCategoryMapping(27, TorznabCatType.TVAnime, "Animation/Animes"); - AddCategoryMapping(63, TorznabCatType.TVAnime, "Animes DVD"); - AddCategoryMapping(56, TorznabCatType.TVAnime, "Animes HD"); - AddCategoryMapping(59, TorznabCatType.TVAnime, "Animes Serie"); - - AddCategoryMapping(3, TorznabCatType.PC0day, "APPLICATION"); - AddCategoryMapping(74, TorznabCatType.PCPhoneAndroid, "ANDROID"); - AddCategoryMapping(57, TorznabCatType.PCPhoneIOS, "IPHONE"); - AddCategoryMapping(6, TorznabCatType.PC0day, "LINUX"); - AddCategoryMapping(5, TorznabCatType.PCMac, "MAC"); - AddCategoryMapping(4, TorznabCatType.PC0day, "WINDOWS"); - - AddCategoryMapping(38, TorznabCatType.TVDocumentary, "DOCUMENTAIRES"); - - AddCategoryMapping(34, TorznabCatType.Books, "EBOOKS"); - - AddCategoryMapping(7, TorznabCatType.Movies, "FILMS"); - AddCategoryMapping(11, TorznabCatType.MoviesDVD, "DVD"); - AddCategoryMapping(10, TorznabCatType.MoviesSD, "DVD-RIP/BD-RIP"); - AddCategoryMapping(53, TorznabCatType.MoviesSD, "DVD-SCREENER"); - AddCategoryMapping(9, TorznabCatType.MoviesDVD, "R5"); - AddCategoryMapping(8, TorznabCatType.MoviesSD, "SCREENER"); - AddCategoryMapping(40, TorznabCatType.Movies, "VO"); - AddCategoryMapping(39, TorznabCatType.Movies, "VOSTFR"); - AddCategoryMapping(48, TorznabCatType.MoviesHD, "HD"); - AddCategoryMapping(51, TorznabCatType.MoviesHD, "1080P"); - AddCategoryMapping(70, TorznabCatType.Movies3D, "3D"); - AddCategoryMapping(50, TorznabCatType.MoviesHD, "720P"); - AddCategoryMapping(49, TorznabCatType.MoviesBluRay, "BluRay"); - AddCategoryMapping(78, TorznabCatType.MoviesHD, "M - HD"); - - AddCategoryMapping(15, TorznabCatType.Console, "JEUX VIDEO"); - AddCategoryMapping(76, TorznabCatType.Console3DS, "3DS"); - AddCategoryMapping(18, TorznabCatType.ConsoleNDS, "DS"); - AddCategoryMapping(55, TorznabCatType.PCPhoneIOS, "IPHONE"); - AddCategoryMapping(80, TorznabCatType.PCGames, "LINUX"); - AddCategoryMapping(79, TorznabCatType.PCMac, "OSX"); - AddCategoryMapping(22, TorznabCatType.PCGames, "PC"); - AddCategoryMapping(66, TorznabCatType.ConsolePS3, "PS2"); - AddCategoryMapping(58, TorznabCatType.ConsolePS3, "PS3"); - AddCategoryMapping(81, TorznabCatType.ConsolePS4, "PS4"); - AddCategoryMapping(20, TorznabCatType.ConsolePSP, "PSP"); - AddCategoryMapping(75, TorznabCatType.ConsolePS3, "PSX"); - AddCategoryMapping(19, TorznabCatType.ConsoleWii, "WII"); - AddCategoryMapping(83, TorznabCatType.ConsoleWiiU, "WiiU"); - AddCategoryMapping(16, TorznabCatType.ConsoleXbox, "XBOX"); - AddCategoryMapping(82, TorznabCatType.ConsoleXboxOne, "XBOX ONE"); - AddCategoryMapping(17, TorznabCatType.ConsoleXbox360, "XBOX360"); - AddCategoryMapping(44, TorznabCatType.ConsoleXbox360, "XBOX360.E"); - AddCategoryMapping(54, TorznabCatType.ConsoleXbox360, "XBOX360.JTAG"); - AddCategoryMapping(43, TorznabCatType.ConsoleXbox360, "XBOX360.NTSC"); - - AddCategoryMapping(23, TorznabCatType.Audio, "MUSIQUES"); - AddCategoryMapping(26, TorznabCatType.Audio, "CLIP/CONCERT"); - AddCategoryMapping(61, TorznabCatType.AudioLossless, "FLAC"); - AddCategoryMapping(60, TorznabCatType.AudioMP3, "MP3"); - - AddCategoryMapping(30, TorznabCatType.TV, "SERIES"); - AddCategoryMapping(73, TorznabCatType.TV, "Pack TV"); - AddCategoryMapping(31, TorznabCatType.TV, "Series FR"); - AddCategoryMapping(32, TorznabCatType.TV, "Series VO"); - AddCategoryMapping(33, TorznabCatType.TV, "Series VO-STFR"); - AddCategoryMapping(77, TorznabCatType.TVSD, "Series.DVD"); - AddCategoryMapping(67, TorznabCatType.TVHD, "Series.FR.HD"); - AddCategoryMapping(68, TorznabCatType.TVHD, "Series.VO.HD"); - AddCategoryMapping(69, TorznabCatType.TVHD, "Series.VOSTFR.HD"); - - AddCategoryMapping(47, TorznabCatType.TV, "SPECTACLES/EMISSIONS"); - AddCategoryMapping(71, TorznabCatType.TV, "Emissions"); - AddCategoryMapping(72, TorznabCatType.TV, "Spectacles"); - - AddCategoryMapping(35, TorznabCatType.TVSport, "SPORT"); - AddCategoryMapping(36, TorznabCatType.TVSport, "CATCH"); - AddCategoryMapping(65, TorznabCatType.TVSport, "UFC"); - - AddCategoryMapping(37, TorznabCatType.XXX, "XXX"); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "fr-fr"; + Type = "private"; + + AddCategoryMapping(27, TorznabCatType.TVAnime, "Animation/Animes"); + AddCategoryMapping(63, TorznabCatType.TVAnime, "Animes DVD"); + AddCategoryMapping(56, TorznabCatType.TVAnime, "Animes HD"); + AddCategoryMapping(59, TorznabCatType.TVAnime, "Animes Serie"); + + AddCategoryMapping(3, TorznabCatType.PC0day, "APPLICATION"); + AddCategoryMapping(74, TorznabCatType.PCPhoneAndroid, "ANDROID"); + AddCategoryMapping(57, TorznabCatType.PCPhoneIOS, "IPHONE"); + AddCategoryMapping(6, TorznabCatType.PC0day, "LINUX"); + AddCategoryMapping(5, TorznabCatType.PCMac, "MAC"); + AddCategoryMapping(4, TorznabCatType.PC0day, "WINDOWS"); + + AddCategoryMapping(38, TorznabCatType.TVDocumentary, "DOCUMENTAIRES"); + + AddCategoryMapping(34, TorznabCatType.Books, "EBOOKS"); + + AddCategoryMapping(7, TorznabCatType.Movies, "FILMS"); + AddCategoryMapping(11, TorznabCatType.MoviesDVD, "DVD"); + AddCategoryMapping(10, TorznabCatType.MoviesSD, "DVD-RIP/BD-RIP"); + AddCategoryMapping(53, TorznabCatType.MoviesSD, "DVD-SCREENER"); + AddCategoryMapping(9, TorznabCatType.MoviesDVD, "R5"); + AddCategoryMapping(8, TorznabCatType.MoviesSD, "SCREENER"); + AddCategoryMapping(40, TorznabCatType.Movies, "VO"); + AddCategoryMapping(39, TorznabCatType.Movies, "VOSTFR"); + AddCategoryMapping(48, TorznabCatType.MoviesHD, "HD"); + AddCategoryMapping(51, TorznabCatType.MoviesHD, "1080P"); + AddCategoryMapping(70, TorznabCatType.Movies3D, "3D"); + AddCategoryMapping(50, TorznabCatType.MoviesHD, "720P"); + AddCategoryMapping(49, TorznabCatType.MoviesBluRay, "BluRay"); + AddCategoryMapping(78, TorznabCatType.MoviesHD, "M - HD"); + + AddCategoryMapping(15, TorznabCatType.Console, "JEUX VIDEO"); + AddCategoryMapping(76, TorznabCatType.Console3DS, "3DS"); + AddCategoryMapping(18, TorznabCatType.ConsoleNDS, "DS"); + AddCategoryMapping(55, TorznabCatType.PCPhoneIOS, "IPHONE"); + AddCategoryMapping(80, TorznabCatType.PCGames, "LINUX"); + AddCategoryMapping(79, TorznabCatType.PCMac, "OSX"); + AddCategoryMapping(22, TorznabCatType.PCGames, "PC"); + AddCategoryMapping(66, TorznabCatType.ConsolePS3, "PS2"); + AddCategoryMapping(58, TorznabCatType.ConsolePS3, "PS3"); + AddCategoryMapping(81, TorznabCatType.ConsolePS4, "PS4"); + AddCategoryMapping(20, TorznabCatType.ConsolePSP, "PSP"); + AddCategoryMapping(75, TorznabCatType.ConsolePS3, "PSX"); + AddCategoryMapping(19, TorznabCatType.ConsoleWii, "WII"); + AddCategoryMapping(83, TorznabCatType.ConsoleWiiU, "WiiU"); + AddCategoryMapping(16, TorznabCatType.ConsoleXbox, "XBOX"); + AddCategoryMapping(82, TorznabCatType.ConsoleXboxOne, "XBOX ONE"); + AddCategoryMapping(17, TorznabCatType.ConsoleXbox360, "XBOX360"); + AddCategoryMapping(44, TorznabCatType.ConsoleXbox360, "XBOX360.E"); + AddCategoryMapping(54, TorznabCatType.ConsoleXbox360, "XBOX360.JTAG"); + AddCategoryMapping(43, TorznabCatType.ConsoleXbox360, "XBOX360.NTSC"); + + AddCategoryMapping(23, TorznabCatType.Audio, "MUSIQUES"); + AddCategoryMapping(26, TorznabCatType.Audio, "CLIP/CONCERT"); + AddCategoryMapping(61, TorznabCatType.AudioLossless, "FLAC"); + AddCategoryMapping(60, TorznabCatType.AudioMP3, "MP3"); + + AddCategoryMapping(30, TorznabCatType.TV, "SERIES"); + AddCategoryMapping(73, TorznabCatType.TV, "Pack TV"); + AddCategoryMapping(31, TorznabCatType.TV, "Series FR"); + AddCategoryMapping(32, TorznabCatType.TV, "Series VO"); + AddCategoryMapping(33, TorznabCatType.TV, "Series VO-STFR"); + AddCategoryMapping(77, TorznabCatType.TVSD, "Series.DVD"); + AddCategoryMapping(67, TorznabCatType.TVHD, "Series.FR.HD"); + AddCategoryMapping(68, TorznabCatType.TVHD, "Series.VO.HD"); + AddCategoryMapping(69, TorznabCatType.TVHD, "Series.VOSTFR.HD"); + + AddCategoryMapping(47, TorznabCatType.TV, "SPECTACLES/EMISSIONS"); + AddCategoryMapping(71, TorznabCatType.TV, "Emissions"); + AddCategoryMapping(72, TorznabCatType.TV, "Spectacles"); + + AddCategoryMapping(35, TorznabCatType.TVSport, "SPORT"); + AddCategoryMapping(36, TorznabCatType.TVSport, "CATCH"); + AddCategoryMapping(65, TorznabCatType.TVSport, "UFC"); + + AddCategoryMapping(37, TorznabCatType.XXX, "XXX"); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { configData.LoadValuesFromJson(configJson); var pairs = new Dictionary<string, string> { { "username", configData.Username.Value }, { "password", configData.Password.Value } - }; - - var result = await PostDataWithCookies(LoginUrl, pairs); - - await ConfigureIfOK(result.Cookies, result.Cookies != null, () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - var queryCollection = new Dictionary<string, string>(); - queryCollection.Add("search_type", "t_name"); - queryCollection.Add("do", "search"); - queryCollection.Add("keywords", searchString); - queryCollection.Add("category", "0"); // multi cat search not supported - - var results = await PostDataWithCookies(BrowseUrl, queryCollection); - if (results.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - results = await PostDataWithCookies(BrowseUrl, queryCollection); - } - + }; + + var result = await PostDataWithCookies(LoginUrl, pairs); + + await ConfigureIfOK(result.Cookies, result.Cookies != null, () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + + var queryCollection = new Dictionary<string, string>(); + queryCollection.Add("search_type", "t_name"); + queryCollection.Add("do", "search"); + queryCollection.Add("keywords", searchString); + queryCollection.Add("category", "0"); // multi cat search not supported + + var results = await PostDataWithCookies(BrowseUrl, queryCollection); + if (results.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + results = await PostDataWithCookies(BrowseUrl, queryCollection); + } + try { var RowsSelector = "table[id='sortabletable'] > tbody > tr"; - var SearchResultParser = new HtmlParser(); - var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - var lastDate = DateTime.Now; - - foreach (var Row in Rows.Skip(1)) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 0; + var SearchResultParser = new HtmlParser(); + var SearchResultDocument = SearchResultParser.Parse(results.Content); + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + var lastDate = DateTime.Now; + + foreach (var Row in Rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 0; var category = Row.QuerySelector("td:nth-child(1) > a"); - var title = Row.QuerySelector("td:nth-child(2) a"); - var added = Row.QuerySelector("td:nth-child(2) > div:has(span[style=\"float: right;\"])"); - if (added == null) // not a torrent line - continue; - var pretime = added.QuerySelector("font.mkprettytime"); - var tooltip = Row.QuerySelector("td:nth-child(2) > div.tooltip-content"); - - var link = Row.QuerySelector("td:nth-child(3)").QuerySelector("a"); - var comments = Row.QuerySelector("td:nth-child(2)").QuerySelector("a"); - var Size = Row.QuerySelector("td:nth-child(5)"); - var Grabs = Row.QuerySelector("td:nth-child(6)").QuerySelector("a"); - var Seeders = Row.QuerySelector("td:nth-child(7)").QuerySelector("a"); - var Leechers = Row.QuerySelector("td:nth-child(8)").QuerySelector("a"); - - var categoryIdparts = category.GetAttribute("href").Split('-'); - var categoryId = categoryIdparts[categoryIdparts.Length-1].Replace(".ts", ""); - - release.Title = title.TextContent; - release.Category = MapTrackerCatToNewznab(categoryId); - release.Link = new Uri(link.GetAttribute("href")); - release.Comments = new Uri(comments.GetAttribute("href")); - release.Guid = release.Link; - release.Size = ReleaseInfo.GetBytes(Size.TextContent); - release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); - release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; - release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); - - if (added.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null) - release.DownloadVolumeFactor = 0; - else if (added.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null) - release.DownloadVolumeFactor = 0.5; - else - release.DownloadVolumeFactor = 1; - - if (added.QuerySelector("img[alt^=\"TORRENT X2\"]") != null) - release.UploadVolumeFactor = 2; - else - release.UploadVolumeFactor = 1; - - if (tooltip != null) - { - var banner = tooltip.QuerySelector("img"); - if (banner != null) - { - release.BannerUrl = new Uri(banner.GetAttribute("src")); - banner.Remove(); - } - - tooltip.QuerySelector("div:contains(\"Total Hits: \")").Remove(); - - var longtitle = tooltip.QuerySelectorAll("div").First(); - release.Title = longtitle.TextContent; - longtitle.Remove(); - - var desc = tooltip.TextContent.Trim(); - if (!string.IsNullOrWhiteSpace(desc)) - release.Description = desc; - } - - // if even the tooltip title is shortened we use the URL - if (release.Title.EndsWith("...")) - { - var tregex = new Regex(@"/([^/]+)-s-\d+\.ts"); - var tmatch = tregex.Match(release.Comments.ToString()); - release.Title = tmatch.Groups[1].Value; - } - - if (pretime != null) - { - if (release.Description == null) - release.Description = pretime.TextContent; - else - release.Description += "<br>\n" + pretime.TextContent; - release.PublishDate = lastDate; - } - else - { - release.PublishDate = DateTime.ParseExact(added.TextContent.Trim(), "dd.M.yyyy HH:mm", CultureInfo.InvariantCulture); - lastDate = release.PublishDate; - } - + var title = Row.QuerySelector("td:nth-child(2) a"); + var added = Row.QuerySelector("td:nth-child(2) > div:has(span[style=\"float: right;\"])"); + if (added == null) // not a torrent line + continue; + var pretime = added.QuerySelector("font.mkprettytime"); + var tooltip = Row.QuerySelector("td:nth-child(2) > div.tooltip-content"); + + var link = Row.QuerySelector("td:nth-child(3)").QuerySelector("a"); + var comments = Row.QuerySelector("td:nth-child(2)").QuerySelector("a"); + var Size = Row.QuerySelector("td:nth-child(5)"); + var Grabs = Row.QuerySelector("td:nth-child(6)").QuerySelector("a"); + var Seeders = Row.QuerySelector("td:nth-child(7)").QuerySelector("a"); + var Leechers = Row.QuerySelector("td:nth-child(8)").QuerySelector("a"); + + var categoryIdparts = category.GetAttribute("href").Split('-'); + var categoryId = categoryIdparts[categoryIdparts.Length-1].Replace(".ts", ""); + + release.Title = title.TextContent; + release.Category = MapTrackerCatToNewznab(categoryId); + release.Link = new Uri(link.GetAttribute("href")); + release.Comments = new Uri(comments.GetAttribute("href")); + release.Guid = release.Link; + release.Size = ReleaseInfo.GetBytes(Size.TextContent); + release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); + release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; + release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); + + if (added.QuerySelector("img[alt^=\"TORRENT GRATUIT\"]") != null) + release.DownloadVolumeFactor = 0; + else if (added.QuerySelector("img[alt^=\"TORRENT SILVER\"]") != null) + release.DownloadVolumeFactor = 0.5; + else + release.DownloadVolumeFactor = 1; + + if (added.QuerySelector("img[alt^=\"TORRENT X2\"]") != null) + release.UploadVolumeFactor = 2; + else + release.UploadVolumeFactor = 1; + + if (tooltip != null) + { + var banner = tooltip.QuerySelector("img"); + if (banner != null) + { + release.BannerUrl = new Uri(banner.GetAttribute("src")); + banner.Remove(); + } + + tooltip.QuerySelector("div:contains(\"Total Hits: \")").Remove(); + + var longtitle = tooltip.QuerySelectorAll("div").First(); + release.Title = longtitle.TextContent; + longtitle.Remove(); + + var desc = tooltip.TextContent.Trim(); + if (!string.IsNullOrWhiteSpace(desc)) + release.Description = desc; + } + + // if even the tooltip title is shortened we use the URL + if (release.Title.EndsWith("...")) + { + var tregex = new Regex(@"/([^/]+)-s-\d+\.ts"); + var tmatch = tregex.Match(release.Comments.ToString()); + release.Title = tmatch.Groups[1].Value; + } + + if (pretime != null) + { + if (release.Description == null) + release.Description = pretime.TextContent; + else + release.Description += "<br>\n" + pretime.TextContent; + release.PublishDate = lastDate; + } + else + { + release.PublishDate = DateTime.ParseExact(added.TextContent.Trim(), "dd.M.yyyy HH:mm", CultureInfo.InvariantCulture); + lastDate = release.PublishDate; + } + releases.Add(release); - } + } } catch (Exception ex) - { - OnParseError(results.Content, ex); + { + OnParseError(results.Content, ex); } - return releases; - } - - } -} + return releases; + } + + } +} diff --git a/src/Jackett/Indexers/FileList.cs b/src/Jackett/Indexers/FileList.cs index a0cd20d5..ecb6cae4 100644 --- a/src/Jackett/Indexers/FileList.cs +++ b/src/Jackett/Indexers/FileList.cs @@ -1,196 +1,196 @@ -using CsQuery; -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.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; -using Jackett.Models.IndexerConfig.Bespoke; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public class FileList : BaseIndexer, IIndexer - { - string LoginUrl { get { return SiteLink + "takelogin.php"; } } - string BrowseUrl { get { return SiteLink + "browse.php"; } } - - new ConfigurationDataFileList configData - { - get { return (ConfigurationDataFileList)base.configData; } - set { base.configData = value; } - } - - public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "FileList", - description: "The best Romanian site.", - link: "http://filelist.ro/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataFileList()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "ro-ro"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(24, TorznabCatType.TVAnime); //Anime - AddCategoryMapping(11, TorznabCatType.Audio); //Audio - AddCategoryMapping(18, TorznabCatType.Other); //Misc - AddCategoryMapping(16, TorznabCatType.Books); //Docs - AddCategoryMapping(25, TorznabCatType.Movies3D); //Movies 3D - AddCategoryMapping(20, TorznabCatType.MoviesBluRay); // Movies Blu-Ray - AddCategoryMapping(2, TorznabCatType.MoviesDVD); //Movies DVD - AddCategoryMapping(3, TorznabCatType.MoviesForeign); //Movies DVD-RO - AddCategoryMapping(4, TorznabCatType.MoviesHD); //Movies HD - AddCategoryMapping(19, TorznabCatType.MoviesForeign); //Movies HD-RO - AddCategoryMapping(1, TorznabCatType.MoviesSD); //Movies SD - AddCategoryMapping(10, TorznabCatType.Console); //Console Games - AddCategoryMapping(9, TorznabCatType.PCGames); //PC Games - AddCategoryMapping(17, TorznabCatType.PC); //Linux - AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile - AddCategoryMapping(8, TorznabCatType.PC); //Software - AddCategoryMapping(21, TorznabCatType.TVHD); //TV HD - AddCategoryMapping(23, TorznabCatType.TVSD); //TV SD - AddCategoryMapping(13, TorznabCatType.TVSport); //Sport - AddCategoryMapping(14, TorznabCatType.TV); //TV - AddCategoryMapping(12, TorznabCatType.AudioVideo); //Music Video - AddCategoryMapping(7, TorznabCatType.XXX); //XXX - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var errorMessage = dom[".main"].Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchUrl = BrowseUrl; - var searchString = query.GetQueryString(); - - var cats = MapTorznabCapsToTrackers(query); - string cat = "0"; - if (cats.Count == 1) - { - cat = cats[0]; - } - - var queryCollection = new NameValueCollection(); - - if (query.ImdbID != null) - { - queryCollection.Add("search", query.ImdbID); - } - else if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - queryCollection.Add("cat", cat); - queryCollection.Add("searchin", "0"); - queryCollection.Add("sort", "0"); - - searchUrl += "?" + queryCollection.GetQueryString(); - - var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); - var results = response.Content; - try - { - CQ dom = results; - var globalFreeLeech = dom.Find("div.globalFreeLeech").Any(); - var rows = dom[".torrentrow"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First(); - release.Title = qRow.Find(".torrenttable:eq(1) b").Text(); - - if (query.ImdbID == null && !query.MatchQueryStringAND(release.Title)) - continue; - - release.Description = qRow.Find(".torrenttable:eq(1) > span > font.small").First().Text(); - - var tooltip = qTitleLink.Attr("title"); - if (!string.IsNullOrEmpty(tooltip)) - { - var ImgRegexp = new Regex("src='(.*?)'"); - var ImgRegexpMatch = ImgRegexp.Match(tooltip); - if (ImgRegexpMatch.Success) - release.BannerUrl = new Uri(ImgRegexpMatch.Groups[1].Value); - } - - release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); - release.Comments = release.Guid; - - //22:05:3716/02/2013 - var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim()+" +0200"; - release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy zzz", CultureInfo.InvariantCulture); - - var qLink = qRow.Find("a[href^=\"download.php?id=\"]").First(); - release.Link = new Uri(SiteLink + qLink.Attr("href")); - - var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders; - - var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15); - release.Category = MapTrackerCatToNewznab(catId); - - var grabs = qRow.Find(".torrenttable:eq(7)").First().Get(0).FirstChild; - release.Grabs = ParseUtil.CoerceLong(catId); - - if (globalFreeLeech || row.Cq().Find("img[alt=\"FreeLeech\"]").Any()) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - // Skip Romanian releases - if (release.Category.Contains(TorznabCatType.MoviesForeign.ID) && !configData.IncludeRomanianReleases.Value) - continue; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results, ex); - } - - return releases; - } - } -} +using CsQuery; +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.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using Jackett.Models.IndexerConfig.Bespoke; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class FileList : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "takelogin.php"; } } + string BrowseUrl { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataFileList configData + { + get { return (ConfigurationDataFileList)base.configData; } + set { base.configData = value; } + } + + public FileList(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "FileList", + description: "The best Romanian site.", + link: "http://filelist.ro/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataFileList()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "ro-ro"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(24, TorznabCatType.TVAnime); //Anime + AddCategoryMapping(11, TorznabCatType.Audio); //Audio + AddCategoryMapping(18, TorznabCatType.Other); //Misc + AddCategoryMapping(16, TorznabCatType.Books); //Docs + AddCategoryMapping(25, TorznabCatType.Movies3D); //Movies 3D + AddCategoryMapping(20, TorznabCatType.MoviesBluRay); // Movies Blu-Ray + AddCategoryMapping(2, TorznabCatType.MoviesDVD); //Movies DVD + AddCategoryMapping(3, TorznabCatType.MoviesForeign); //Movies DVD-RO + AddCategoryMapping(4, TorznabCatType.MoviesHD); //Movies HD + AddCategoryMapping(19, TorznabCatType.MoviesForeign); //Movies HD-RO + AddCategoryMapping(1, TorznabCatType.MoviesSD); //Movies SD + AddCategoryMapping(10, TorznabCatType.Console); //Console Games + AddCategoryMapping(9, TorznabCatType.PCGames); //PC Games + AddCategoryMapping(17, TorznabCatType.PC); //Linux + AddCategoryMapping(22, TorznabCatType.PCPhoneOther); //Apps/mobile + AddCategoryMapping(8, TorznabCatType.PC); //Software + AddCategoryMapping(21, TorznabCatType.TVHD); //TV HD + AddCategoryMapping(23, TorznabCatType.TVSD); //TV SD + AddCategoryMapping(13, TorznabCatType.TVSport); //Sport + AddCategoryMapping(14, TorznabCatType.TV); //TV + AddCategoryMapping(12, TorznabCatType.AudioVideo); //Music Video + AddCategoryMapping(7, TorznabCatType.XXX); //XXX + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom[".main"].Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchUrl = BrowseUrl; + var searchString = query.GetQueryString(); + + var cats = MapTorznabCapsToTrackers(query); + string cat = "0"; + if (cats.Count == 1) + { + cat = cats[0]; + } + + var queryCollection = new NameValueCollection(); + + if (query.ImdbID != null) + { + queryCollection.Add("search", query.ImdbID); + } + else if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + queryCollection.Add("cat", cat); + queryCollection.Add("searchin", "0"); + queryCollection.Add("sort", "0"); + + searchUrl += "?" + queryCollection.GetQueryString(); + + var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + var results = response.Content; + try + { + CQ dom = results; + var globalFreeLeech = dom.Find("div.globalFreeLeech").Any(); + var rows = dom[".torrentrow"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + var qTitleLink = qRow.Find(".torrenttable:eq(1) a").First(); + release.Title = qRow.Find(".torrenttable:eq(1) b").Text(); + + if (query.ImdbID == null && !query.MatchQueryStringAND(release.Title)) + continue; + + release.Description = qRow.Find(".torrenttable:eq(1) > span > font.small").First().Text(); + + var tooltip = qTitleLink.Attr("title"); + if (!string.IsNullOrEmpty(tooltip)) + { + var ImgRegexp = new Regex("src='(.*?)'"); + var ImgRegexpMatch = ImgRegexp.Match(tooltip); + if (ImgRegexpMatch.Success) + release.BannerUrl = new Uri(ImgRegexpMatch.Groups[1].Value); + } + + release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); + release.Comments = release.Guid; + + //22:05:3716/02/2013 + var dateStr = qRow.Find(".torrenttable:eq(5)").Text().Trim()+" +0200"; + release.PublishDate = DateTime.ParseExact(dateStr, "H:mm:ssdd/MM/yyyy zzz", CultureInfo.InvariantCulture); + + var qLink = qRow.Find("a[href^=\"download.php?id=\"]").First(); + release.Link = new Uri(SiteLink + qLink.Attr("href")); + + var sizeStr = qRow.Find(".torrenttable:eq(6)").Text().Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(8)").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".torrenttable:eq(9)").Text().Trim()) + release.Seeders; + + var catId = qRow.Find(".torrenttable:eq(0) a").First().Attr("href").Substring(15); + release.Category = MapTrackerCatToNewznab(catId); + + var grabs = qRow.Find(".torrenttable:eq(7)").First().Get(0).FirstChild; + release.Grabs = ParseUtil.CoerceLong(catId); + + if (globalFreeLeech || row.Cq().Find("img[alt=\"FreeLeech\"]").Any()) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + // Skip Romanian releases + if (release.Category.Contains(TorznabCatType.MoviesForeign.ID) && !configData.IncludeRomanianReleases.Value) + continue; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs index cfdb9e79..976ef216 100644 --- a/src/Jackett/Indexers/Freshon.cs +++ b/src/Jackett/Indexers/Freshon.cs @@ -18,8 +18,8 @@ using System.Threading.Tasks; using System.Web; using System.Web.UI.WebControls; using Jackett.Models.IndexerConfig; -using System.Text.RegularExpressions; - +using System.Text.RegularExpressions; + namespace Jackett.Indexers { public class Freshon : BaseIndexer, IIndexer @@ -108,7 +108,7 @@ namespace Jackett.Indexers release.MinimumRatio = 1; release.MinimumSeedTime = 172800; release.Title = qLink.Attr("title"); - if (!query.MatchQueryStringAND(release.Title)) + if (!query.MatchQueryStringAND(release.Title)) continue; release.Description = release.Title; @@ -133,22 +133,22 @@ namespace Jackett.Indexers { pubDateRomania = DateTime.SpecifyKind(DateTime.ParseExact(dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); } DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(pubDateRomania, romaniaTz); - release.PublishDate = pubDateUtc.ToLocalTime(); - - try - { - var grabs = Regex.Match(row.Cq().Find("td.table_snatch").Text().Trim(), @"(^\d*).*").Value[0].ToString(); - release.Grabs = ParseUtil.CoerceInt(grabs); + release.PublishDate = pubDateUtc.ToLocalTime(); + + try + { + var grabs = Regex.Match(row.Cq().Find("td.table_snatch").Text().Trim(), @"(^\d*).*").Value[0].ToString(); + release.Grabs = ParseUtil.CoerceInt(grabs); } catch - { - release.Grabs = 1; + { + release.Grabs = 1; } - if (row.Cq().Find("img[alt=\"100% Free\"]").Any()) - release.DownloadVolumeFactor = 0; - else if (row.Cq().Find("img[alt=\"50% Free\"]").Any()) - release.DownloadVolumeFactor = 0.5; + if (row.Cq().Find("img[alt=\"100% Free\"]").Any()) + release.DownloadVolumeFactor = 0; + else if (row.Cq().Find("img[alt=\"50% Free\"]").Any()) + release.DownloadVolumeFactor = 0.5; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/FunFile.cs b/src/Jackett/Indexers/FunFile.cs index 372adf66..fa791dd5 100644 --- a/src/Jackett/Indexers/FunFile.cs +++ b/src/Jackett/Indexers/FunFile.cs @@ -1,147 +1,147 @@ -using CsQuery; -using Jackett.Models; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Text; -using System.Collections.Generic; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - -namespace Jackett.Indexers -{ - public class FunFile : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "takelogin.php"; } } - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public FunFile(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "FunFile", - description: "A general tracker", - link: "https://www.funfile.org/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("iso-8859-1"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(44, TorznabCatType.TVAnime); // Anime - AddCategoryMapping(22, TorznabCatType.PC); // Applications - AddCategoryMapping(43, TorznabCatType.AudioAudiobook); // Audio Books - AddCategoryMapping(27, TorznabCatType.Books); // Ebook - AddCategoryMapping(4, TorznabCatType.PCGames); // Games - AddCategoryMapping(40, TorznabCatType.OtherMisc); // Miscellaneous - AddCategoryMapping(19, TorznabCatType.Movies); // Movies - AddCategoryMapping(6, TorznabCatType.Audio); // Music - AddCategoryMapping(31, TorznabCatType.PCPhoneOther); // Portable - AddCategoryMapping(7, TorznabCatType.TV); // TV - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "login", "Login" }, - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var errorMessage = dom["td.mf_content"].Html(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("incldead", "1"); - queryCollection.Add("showspam", "1"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - var cats = MapTorznabCapsToTrackers(query); - string cat = "0"; - if (cats.Count == 1) - { - cat = cats[0]; - } - queryCollection.Add("cat", cat); - - searchUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - +using CsQuery; +using Jackett.Models; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Text; +using System.Collections.Generic; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + public class FunFile : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public FunFile(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "FunFile", + description: "A general tracker", + link: "https://www.funfile.org/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("iso-8859-1"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(44, TorznabCatType.TVAnime); // Anime + AddCategoryMapping(22, TorznabCatType.PC); // Applications + AddCategoryMapping(43, TorznabCatType.AudioAudiobook); // Audio Books + AddCategoryMapping(27, TorznabCatType.Books); // Ebook + AddCategoryMapping(4, TorznabCatType.PCGames); // Games + AddCategoryMapping(40, TorznabCatType.OtherMisc); // Miscellaneous + AddCategoryMapping(19, TorznabCatType.Movies); // Movies + AddCategoryMapping(6, TorznabCatType.Audio); // Music + AddCategoryMapping(31, TorznabCatType.PCPhoneOther); // Portable + AddCategoryMapping(7, TorznabCatType.TV); // TV + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "login", "Login" }, + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom["td.mf_content"].Html(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("incldead", "1"); + queryCollection.Add("showspam", "1"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + var cats = MapTorznabCapsToTrackers(query); + string cat = "0"; + if (cats.Count == 1) + { + cat = cats[0]; + } + queryCollection.Add("cat", cat); + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + // Occasionally the cookies become invalid, login again if that happens - if (results.IsRedirect) - { - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl); - } - - try - { - CQ dom = results.Content; - var rows = dom["table[cellpadding=2] > tbody > tr:has(td.row3)"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 48 * 60 * 60; - - var qRow = row.Cq(); - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - var qSeeders = qRow.Find("td:eq(9)"); - var qLeechers = qRow.Find("td:eq(10)"); - var qDownloadLink = qRow.Find("a[href^=download.php]").First(); - var qTimeAgo = qRow.Find("td:eq(5)"); - var qSize = qRow.Find("td:eq(7)"); - - var catStr = qCatLink.Attr("href").Split('=')[1].Split('&')[0]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); - release.Title = qDetailsLink.Attr("title").Trim(); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); - release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; - - var dateStr = qTimeAgo.Text(); - release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); - + if (results.IsRedirect) + { + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl); + } + + try + { + CQ dom = results.Content; + var rows = dom["table[cellpadding=2] > tbody > tr:has(td.row3)"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 48 * 60 * 60; + + var qRow = row.Cq(); + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + var qSeeders = qRow.Find("td:eq(9)"); + var qLeechers = qRow.Find("td:eq(10)"); + var qDownloadLink = qRow.Find("a[href^=download.php]").First(); + var qTimeAgo = qRow.Find("td:eq(5)"); + var qSize = qRow.Find("td:eq(7)"); + + var catStr = qCatLink.Attr("href").Split('=')[1].Split('&')[0]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); + release.Title = qDetailsLink.Attr("title").Trim(); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var dateStr = qTimeAgo.Text(); + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + var files = qRow.Find("td:nth-child(4)").Text(); release.Files = ParseUtil.CoerceInt(files); @@ -151,18 +151,18 @@ namespace Jackett.Indexers var ka = qRow.Next(); var DLFactor = ka.Find("table > tbody > tr:nth-child(3) > td:nth-child(2)").Text().Replace("X", ""); var ULFactor = ka.Find("table > tbody > tr:nth-child(3) > td:nth-child(1)").Text().Replace("X", ""); - release.DownloadVolumeFactor = ParseUtil.CoerceDouble(DLFactor); - release.UploadVolumeFactor = ParseUtil.CoerceDouble(ULFactor); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} + release.DownloadVolumeFactor = ParseUtil.CoerceDouble(DLFactor); + release.UploadVolumeFactor = ParseUtil.CoerceDouble(ULFactor); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Fuzer.cs b/src/Jackett/Indexers/Fuzer.cs index 5a75d801..4776fee1 100644 --- a/src/Jackett/Indexers/Fuzer.cs +++ b/src/Jackett/Indexers/Fuzer.cs @@ -247,8 +247,8 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(6)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[src=\"/images/FL.png\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("img[src=\"/images/FL.png\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/GFTracker.cs b/src/Jackett/Indexers/GFTracker.cs index 1ac2c259..6d95725d 100644 --- a/src/Jackett/Indexers/GFTracker.cs +++ b/src/Jackett/Indexers/GFTracker.cs @@ -49,36 +49,36 @@ namespace Jackett.Indexers Language = "en-us"; Type = "private"; - AddCategoryMapping(2, TorznabCatType.PC0day, "0DAY"); - AddCategoryMapping(16, TorznabCatType.TVAnime, "Anime"); - AddCategoryMapping(1, TorznabCatType.PC0day, "APPS"); - AddCategoryMapping(9, TorznabCatType.Other, "E-Learning"); - AddCategoryMapping(35, TorznabCatType.TVFOREIGN, "Foreign"); - AddCategoryMapping(32, TorznabCatType.ConsoleNDS, "Games/NDS"); - AddCategoryMapping(6, TorznabCatType.PCGames, "Games/PC"); - AddCategoryMapping(36, TorznabCatType.ConsolePS4, "Games/Playstation"); - AddCategoryMapping(29, TorznabCatType.ConsolePSP, "Games/PSP"); - AddCategoryMapping(23, TorznabCatType.ConsoleWii, "Games/WII"); - AddCategoryMapping(12, TorznabCatType.ConsoleXbox, "Games/XBOX"); - AddCategoryMapping(11, TorznabCatType.Other, "Misc"); - AddCategoryMapping(48, TorznabCatType.MoviesBluRay, "Movies/BLURAY"); - AddCategoryMapping(8, TorznabCatType.MoviesDVD, "Movies/DVDR"); - AddCategoryMapping(18, TorznabCatType.MoviesHD, "Movies/X264-HD"); - AddCategoryMapping(49, TorznabCatType.MoviesSD, "Movies/X264-SD"); - AddCategoryMapping(7, TorznabCatType.MoviesSD, "Movies/XVID"); - AddCategoryMapping(38, TorznabCatType.AudioOther, "Music/DVDR"); - AddCategoryMapping(46, TorznabCatType.AudioLossless, "Music/FLAC"); - AddCategoryMapping(5, TorznabCatType.AudioMP3, "Music/MP3"); - AddCategoryMapping(13, TorznabCatType.AudioVideo, "Music/Vids"); - AddCategoryMapping(26, TorznabCatType.TVHD, "TV/BLURAY"); - AddCategoryMapping(37, TorznabCatType.TVSD, "TV/DVDR"); - AddCategoryMapping(19, TorznabCatType.TVSD, "TV/DVDRIP"); - AddCategoryMapping(47, TorznabCatType.TVSD, "TV/SD"); - AddCategoryMapping(17, TorznabCatType.TVHD, "TV/X264"); - AddCategoryMapping(4, TorznabCatType.TVSD, "TV/XVID"); - AddCategoryMapping(22, TorznabCatType.XXX, "XXX/0DAY"); - AddCategoryMapping(25, TorznabCatType.XXXDVD, "XXX/DVDR"); - AddCategoryMapping(20, TorznabCatType.XXX, "XXX/HD"); + AddCategoryMapping(2, TorznabCatType.PC0day, "0DAY"); + AddCategoryMapping(16, TorznabCatType.TVAnime, "Anime"); + AddCategoryMapping(1, TorznabCatType.PC0day, "APPS"); + AddCategoryMapping(9, TorznabCatType.Other, "E-Learning"); + AddCategoryMapping(35, TorznabCatType.TVFOREIGN, "Foreign"); + AddCategoryMapping(32, TorznabCatType.ConsoleNDS, "Games/NDS"); + AddCategoryMapping(6, TorznabCatType.PCGames, "Games/PC"); + AddCategoryMapping(36, TorznabCatType.ConsolePS4, "Games/Playstation"); + AddCategoryMapping(29, TorznabCatType.ConsolePSP, "Games/PSP"); + AddCategoryMapping(23, TorznabCatType.ConsoleWii, "Games/WII"); + AddCategoryMapping(12, TorznabCatType.ConsoleXbox, "Games/XBOX"); + AddCategoryMapping(11, TorznabCatType.Other, "Misc"); + AddCategoryMapping(48, TorznabCatType.MoviesBluRay, "Movies/BLURAY"); + AddCategoryMapping(8, TorznabCatType.MoviesDVD, "Movies/DVDR"); + AddCategoryMapping(18, TorznabCatType.MoviesHD, "Movies/X264-HD"); + AddCategoryMapping(49, TorznabCatType.MoviesSD, "Movies/X264-SD"); + AddCategoryMapping(7, TorznabCatType.MoviesSD, "Movies/XVID"); + AddCategoryMapping(38, TorznabCatType.AudioOther, "Music/DVDR"); + AddCategoryMapping(46, TorznabCatType.AudioLossless, "Music/FLAC"); + AddCategoryMapping(5, TorznabCatType.AudioMP3, "Music/MP3"); + AddCategoryMapping(13, TorznabCatType.AudioVideo, "Music/Vids"); + AddCategoryMapping(26, TorznabCatType.TVHD, "TV/BLURAY"); + AddCategoryMapping(37, TorznabCatType.TVSD, "TV/DVDR"); + AddCategoryMapping(19, TorznabCatType.TVSD, "TV/DVDRIP"); + AddCategoryMapping(47, TorznabCatType.TVSD, "TV/SD"); + AddCategoryMapping(17, TorznabCatType.TVHD, "TV/X264"); + AddCategoryMapping(4, TorznabCatType.TVSD, "TV/XVID"); + AddCategoryMapping(22, TorznabCatType.XXX, "XXX/0DAY"); + AddCategoryMapping(25, TorznabCatType.XXXDVD, "XXX/DVDR"); + AddCategoryMapping(20, TorznabCatType.XXX, "XXX/HD"); AddCategoryMapping(3, TorznabCatType.XXXXviD, "XXX/XVID"); } @@ -138,8 +138,8 @@ namespace Jackett.Indexers var response = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CookieHeader.Value, true, SearchUrl, StartPageUrl); UpdateCookieHeader(response.Cookies); - UpdateCookieHeader("mybbuser=;"); // add dummy cookie, otherwise we get logged out after each request - + UpdateCookieHeader("mybbuser=;"); // add dummy cookie, otherwise we get logged out after each request + await ConfigureIfOK(configData.CookieHeader.Value, response.Content != null && response.Content.Contains("logout.php"), () => { CQ dom = response.Content; @@ -159,7 +159,7 @@ namespace Jackett.Indexers var searchString = query.GetQueryString(); // search in normal + gems view - foreach (var view in new string[] {"0", "1"}) + foreach (var view in new string[] {"0", "1"}) { var queryCollection = new NameValueCollection(); @@ -178,12 +178,12 @@ namespace Jackett.Indexers var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString(); - var results = await RequestStringWithCookiesAndRetry(searchUrl); - if (results.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl); + var results = await RequestStringWithCookiesAndRetry(searchUrl); + if (results.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl); } try @@ -238,7 +238,7 @@ namespace Jackett.Indexers catch (Exception ex) { OnParseError(results.Content, ex); - } + } } return releases; diff --git a/src/Jackett/Indexers/GhostCity.cs b/src/Jackett/Indexers/GhostCity.cs index e0784e93..8d4af82d 100644 --- a/src/Jackett/Indexers/GhostCity.cs +++ b/src/Jackett/Indexers/GhostCity.cs @@ -1,184 +1,184 @@ -using CsQuery; -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.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; - -namespace Jackett.Indexers -{ - public class GhostCity : BaseIndexer, IIndexer - { - string LoginUrl { get { return SiteLink + "takelogin.php"; } } - string BrowsePage { get { return SiteLink + "browse.php"; } } - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public GhostCity(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "Ghost City", - description: "A German general tracker", - link: "http://ghostcity.dyndns.info/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "de-de"; - Type = "private"; - - this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; - this.configData.DisplayText.Name = "Notice"; - AddMultiCategoryMapping(TorznabCatType.TVAnime, 8, 34, 35, 36); - AddMultiCategoryMapping(TorznabCatType.TVDocumentary, 12, 44, 106, 45, 46, 47); - AddMultiCategoryMapping(TorznabCatType.Console, 92, 93, 95, 96, 97); - AddMultiCategoryMapping(TorznabCatType.ConsoleNDS, 92); - AddMultiCategoryMapping(TorznabCatType.ConsolePS3, 95); - AddMultiCategoryMapping(TorznabCatType.ConsolePS4, 95); - AddMultiCategoryMapping(TorznabCatType.ConsolePS4, 95); - AddMultiCategoryMapping(TorznabCatType.ConsolePSP, 95); - AddMultiCategoryMapping(TorznabCatType.ConsoleXbox, 97); - AddMultiCategoryMapping(TorznabCatType.ConsoleXbox360, 97); - AddMultiCategoryMapping(TorznabCatType.ConsoleXBOX360DLC, 97); - AddMultiCategoryMapping(TorznabCatType.ConsoleXboxOne, 97); - AddMultiCategoryMapping(TorznabCatType.ConsoleWii, 96); - AddMultiCategoryMapping(TorznabCatType.PC, 20, 94, 40); - AddMultiCategoryMapping(TorznabCatType.PCGames, 94); - AddMultiCategoryMapping(TorznabCatType.PCMac, 39); - AddMultiCategoryMapping(TorznabCatType.PCPhoneOther, 37, 38); - AddMultiCategoryMapping(TorznabCatType.TVSport, 22, 98, 99, 100, 101); - AddMultiCategoryMapping(TorznabCatType.Movies, 68, 69, 70, 102, 104, 103, 72, 71, 73, 74, 75, 77, 78, 79); - AddMultiCategoryMapping(TorznabCatType.MoviesSD, 68, 69, 102, 104, 103, 72, 71, 73, 74); - AddMultiCategoryMapping(TorznabCatType.MoviesHD, 75, 76, 77, 78, 79); - AddMultiCategoryMapping(TorznabCatType.MoviesOther, 73); - AddMultiCategoryMapping(TorznabCatType.MoviesBluRay, 70); - AddMultiCategoryMapping(TorznabCatType.MoviesDVD, 102, 104, 103, 72, 71); - AddMultiCategoryMapping(TorznabCatType.Movies3D, 69); - AddMultiCategoryMapping(TorznabCatType.AudioVideo, 109); - AddMultiCategoryMapping(TorznabCatType.TV, 8, 34, 35, 36, 23, 90, 88, 107, 89); - AddMultiCategoryMapping(TorznabCatType.TVHD, 107); - AddMultiCategoryMapping(TorznabCatType.TVSD, 89); - AddMultiCategoryMapping(TorznabCatType.XXX, 25); - AddMultiCategoryMapping(TorznabCatType.TVDocumentary, 88); - AddMultiCategoryMapping(TorznabCatType.AudioAudiobook, 84); - AddMultiCategoryMapping(TorznabCatType.BooksEbook, 83); - AddMultiCategoryMapping(TorznabCatType.BooksMagazines, 85); - AddMultiCategoryMapping(TorznabCatType.BooksOther, 108); - AddMultiCategoryMapping(TorznabCatType.Other, 3, 93, 24); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value } - }; - - var result1 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink); - CQ result1Dom = result1.Content; - var link = result1Dom[".trow2 a"].First(); - var result2 = await RequestStringWithCookies(link.Attr("href"), result1.Cookies); - CQ result2Dom = result2.Content; - - await ConfigureIfOK(result1.Cookies, result2.Content.Contains("/logout.php"), () => - { - var errorMessage = "Login failed."; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowsePage; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("do", "search"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("keywords", searchString); - } - - queryCollection.Add("search_type", "t_name"); - - // FIXME: Tracker doesn't support multi category search - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("category", cat); - } - - if (queryCollection.Count > 0) - { - searchUrl += "?" + queryCollection.GetQueryString(); - } - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - - try - { - CQ dom = results.Content; - - var rows = dom["#sortabletable tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - release.Title = qRow.Find(".tooltip-content div").First().Text(); - if (string.IsNullOrWhiteSpace(release.Title)) - continue; - release.Description = qRow.Find(".tooltip-content div").Get(1).InnerText.Trim(); - - var qLink = row.Cq().Find("td:eq(2) a:eq(0)"); - release.Link = new Uri(qLink.Attr("href")); - release.Guid = release.Link; - release.Comments = new Uri(qRow.Find(".tooltip-target a").First().Attr("href")); - - var dateString = qRow.Find("td:eq(1) div").Last().Children().Remove().End().Text().Trim(); - release.PublishDate = DateTime.ParseExact(dateString, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture); - - var sizeStr = qRow.Find("td:eq(4)").Text().Trim(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text().Trim()); - release.Peers = ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()) + release.Seeders; - - var catLink = row.Cq().Find("td:eq(0) a").First().Attr("href"); - var catSplit = catLink.IndexOf("category="); - if (catSplit > -1) - { - catLink = catLink.Substring(catSplit + 9); - } - - release.Category = MapTrackerCatToNewznab(catLink); - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} +using CsQuery; +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.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; + +namespace Jackett.Indexers +{ + public class GhostCity : BaseIndexer, IIndexer + { + string LoginUrl { get { return SiteLink + "takelogin.php"; } } + string BrowsePage { get { return SiteLink + "browse.php"; } } + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public GhostCity(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "Ghost City", + description: "A German general tracker", + link: "http://ghostcity.dyndns.info/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "de-de"; + Type = "private"; + + this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; + this.configData.DisplayText.Name = "Notice"; + AddMultiCategoryMapping(TorznabCatType.TVAnime, 8, 34, 35, 36); + AddMultiCategoryMapping(TorznabCatType.TVDocumentary, 12, 44, 106, 45, 46, 47); + AddMultiCategoryMapping(TorznabCatType.Console, 92, 93, 95, 96, 97); + AddMultiCategoryMapping(TorznabCatType.ConsoleNDS, 92); + AddMultiCategoryMapping(TorznabCatType.ConsolePS3, 95); + AddMultiCategoryMapping(TorznabCatType.ConsolePS4, 95); + AddMultiCategoryMapping(TorznabCatType.ConsolePS4, 95); + AddMultiCategoryMapping(TorznabCatType.ConsolePSP, 95); + AddMultiCategoryMapping(TorznabCatType.ConsoleXbox, 97); + AddMultiCategoryMapping(TorznabCatType.ConsoleXbox360, 97); + AddMultiCategoryMapping(TorznabCatType.ConsoleXBOX360DLC, 97); + AddMultiCategoryMapping(TorznabCatType.ConsoleXboxOne, 97); + AddMultiCategoryMapping(TorznabCatType.ConsoleWii, 96); + AddMultiCategoryMapping(TorznabCatType.PC, 20, 94, 40); + AddMultiCategoryMapping(TorznabCatType.PCGames, 94); + AddMultiCategoryMapping(TorznabCatType.PCMac, 39); + AddMultiCategoryMapping(TorznabCatType.PCPhoneOther, 37, 38); + AddMultiCategoryMapping(TorznabCatType.TVSport, 22, 98, 99, 100, 101); + AddMultiCategoryMapping(TorznabCatType.Movies, 68, 69, 70, 102, 104, 103, 72, 71, 73, 74, 75, 77, 78, 79); + AddMultiCategoryMapping(TorznabCatType.MoviesSD, 68, 69, 102, 104, 103, 72, 71, 73, 74); + AddMultiCategoryMapping(TorznabCatType.MoviesHD, 75, 76, 77, 78, 79); + AddMultiCategoryMapping(TorznabCatType.MoviesOther, 73); + AddMultiCategoryMapping(TorznabCatType.MoviesBluRay, 70); + AddMultiCategoryMapping(TorznabCatType.MoviesDVD, 102, 104, 103, 72, 71); + AddMultiCategoryMapping(TorznabCatType.Movies3D, 69); + AddMultiCategoryMapping(TorznabCatType.AudioVideo, 109); + AddMultiCategoryMapping(TorznabCatType.TV, 8, 34, 35, 36, 23, 90, 88, 107, 89); + AddMultiCategoryMapping(TorznabCatType.TVHD, 107); + AddMultiCategoryMapping(TorznabCatType.TVSD, 89); + AddMultiCategoryMapping(TorznabCatType.XXX, 25); + AddMultiCategoryMapping(TorznabCatType.TVDocumentary, 88); + AddMultiCategoryMapping(TorznabCatType.AudioAudiobook, 84); + AddMultiCategoryMapping(TorznabCatType.BooksEbook, 83); + AddMultiCategoryMapping(TorznabCatType.BooksMagazines, 85); + AddMultiCategoryMapping(TorznabCatType.BooksOther, 108); + AddMultiCategoryMapping(TorznabCatType.Other, 3, 93, 24); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var result1 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink); + CQ result1Dom = result1.Content; + var link = result1Dom[".trow2 a"].First(); + var result2 = await RequestStringWithCookies(link.Attr("href"), result1.Cookies); + CQ result2Dom = result2.Content; + + await ConfigureIfOK(result1.Cookies, result2.Content.Contains("/logout.php"), () => + { + var errorMessage = "Login failed."; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var searchUrl = BrowsePage; + var queryCollection = new NameValueCollection(); + + queryCollection.Add("do", "search"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("keywords", searchString); + } + + queryCollection.Add("search_type", "t_name"); + + // FIXME: Tracker doesn't support multi category search + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("category", cat); + } + + if (queryCollection.Count > 0) + { + searchUrl += "?" + queryCollection.GetQueryString(); + } + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + + try + { + CQ dom = results.Content; + + var rows = dom["#sortabletable tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + release.Title = qRow.Find(".tooltip-content div").First().Text(); + if (string.IsNullOrWhiteSpace(release.Title)) + continue; + release.Description = qRow.Find(".tooltip-content div").Get(1).InnerText.Trim(); + + var qLink = row.Cq().Find("td:eq(2) a:eq(0)"); + release.Link = new Uri(qLink.Attr("href")); + release.Guid = release.Link; + release.Comments = new Uri(qRow.Find(".tooltip-target a").First().Attr("href")); + + var dateString = qRow.Find("td:eq(1) div").Last().Children().Remove().End().Text().Trim(); + release.PublishDate = DateTime.ParseExact(dateString, "dd-MM-yyyy HH:mm", CultureInfo.InvariantCulture); + + var sizeStr = qRow.Find("td:eq(4)").Text().Trim(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text().Trim()); + release.Peers = ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()) + release.Seeders; + + var catLink = row.Cq().Find("td:eq(0) a").First().Attr("href"); + var catSplit = catLink.IndexOf("category="); + if (catSplit > -1) + { + catLink = catLink.Substring(catSplit + 9); + } + + release.Category = MapTrackerCatToNewznab(catLink); + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/HD4Free.cs b/src/Jackett/Indexers/HD4Free.cs index 0ca5fa83..027d8646 100644 --- a/src/Jackett/Indexers/HD4Free.cs +++ b/src/Jackett/Indexers/HD4Free.cs @@ -1,367 +1,367 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; - -using AngleSharp.Parser.Html; - -namespace Jackett.Indexers -{ - public class HD4Free : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "ajax/initial_recall.php"; } } - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } } - - new ConfigurationDataRecaptchaLogin configData - { - get { return (ConfigurationDataRecaptchaLogin)base.configData; } - set { base.configData = value; } - } - - public HD4Free(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "HD4Free", - description: "A HD trackers", - link: "https://hd4free.xyz/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataRecaptchaLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(42, TorznabCatType.MoviesSD); // LEGi0N 480p - AddCategoryMapping(17, TorznabCatType.MoviesHD); // LEGi0N 720p - AddCategoryMapping(16, TorznabCatType.MoviesHD); // LEGi0N 1080p - AddCategoryMapping(84, TorznabCatType.Movies3D); // LEGi0N 3D 1080p - AddCategoryMapping(31, TorznabCatType.MoviesOther); // LEGi0N REMUX - AddCategoryMapping(70, TorznabCatType.MoviesBluRay); // LEGi0N BD BD25 & BD50 - AddCategoryMapping(55, TorznabCatType.Movies); // LEGi0N Movie/TV PACKS - AddCategoryMapping(60, TorznabCatType.Other); // shadz shack - AddCategoryMapping(85, TorznabCatType.MoviesHD); // MarGe 720p - AddCategoryMapping(86, TorznabCatType.MoviesHD); // MarGe 1080p - AddCategoryMapping(73, TorznabCatType.MoviesBluRay); // GF44 BD-50 - AddCategoryMapping(74, TorznabCatType.MoviesBluRay); // GF44 BD-25 - AddCategoryMapping(88, TorznabCatType.MoviesBluRay); // taterzero BD50 - AddCategoryMapping(89, TorznabCatType.MoviesBluRay); // taterzero BD25 - AddCategoryMapping(90, TorznabCatType.Movies3D); // taterzero 3D BD - AddCategoryMapping(39, TorznabCatType.MoviesBluRay); // Bluray REMUX - AddCategoryMapping(38, TorznabCatType.MoviesBluRay); // Bluray - AddCategoryMapping(75, TorznabCatType.MoviesBluRay); // Bluray 25 - AddCategoryMapping(36, TorznabCatType.MoviesHD); // Encodes 720p - AddCategoryMapping(35, TorznabCatType.MoviesHD); // Encodes 1080p - AddCategoryMapping(45, TorznabCatType.Movies3D); // 1080p 3D Encodes - AddCategoryMapping(77, TorznabCatType.MoviesHD); // WEB-DL 720p - AddCategoryMapping(78, TorznabCatType.MoviesHD); // WEB-DL 1080p - AddCategoryMapping(83, TorznabCatType.MoviesDVD); // DVD 5/9's - AddCategoryMapping(47, TorznabCatType.Movies); // General x264 - AddCategoryMapping(58, TorznabCatType.Movies); // General XViD - AddCategoryMapping(66, TorznabCatType.Movies); // x265 HEVC - AddCategoryMapping(34, TorznabCatType.MoviesHD); // 4K - AddCategoryMapping(61, TorznabCatType.Movies); // MOViE PACKS - AddCategoryMapping(44, TorznabCatType.TVHD); // HDTV 720p - AddCategoryMapping(43, TorznabCatType.TVHD); // HDTV 1080p - AddCategoryMapping(41, TorznabCatType.TVHD); // WEB-DL 720p TV - AddCategoryMapping(40, TorznabCatType.TVHD); // WEB-DL 1080p TV - AddCategoryMapping(52, TorznabCatType.TVHD); // 720p TV BluRay - AddCategoryMapping(53, TorznabCatType.TVHD); // 1080p TV BluRay - AddCategoryMapping(62, TorznabCatType.TVHD); // HDTV Packs - AddCategoryMapping(82, TorznabCatType.TVSD); // SDTV TV PACKS - AddCategoryMapping(63, TorznabCatType.PC0day); // Apps Windows - AddCategoryMapping(57, TorznabCatType.PCMac); // Appz Mac - AddCategoryMapping(72, TorznabCatType.AudioAudiobook); // Audio Books - AddCategoryMapping(71, TorznabCatType.Books); // Ebooks - AddCategoryMapping(46, TorznabCatType.AudioLossless); // FLAC/Lossless - AddCategoryMapping(81, TorznabCatType.AudioMP3); // MP3 Music - AddCategoryMapping(87, TorznabCatType.AudioVideo); // HD MUSiC ViDEOS - AddCategoryMapping(32, TorznabCatType.Other); // Covers And Artwork - AddCategoryMapping(50, TorznabCatType.XXX); // Porn XXX - } - - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, configData.CookieHeader.Value); - CQ cq = loginPage.Content; - string recaptchaSiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); - var result = this.configData; - result.CookieHeader.Value = loginPage.Cookies; - result.Captcha.SiteKey = recaptchaSiteKey; - result.Captcha.Version = "2"; - return result; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "returnto" , "/" }, - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "g-recaptcha-response", configData.Captcha.Value }, - { "submitme", "Login" } - }; - - if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) - { - // Cookie was manually supplied - CookieHeader = configData.Captcha.Cookie; - try - { - var results = await PerformQuery(new TorznabQuery()); - if (!results.Any()) - { - throw new Exception("Your cookie did not work"); - } - - SaveConfig(); - IsConfigured = true; - return IndexerConfigurationStatus.Completed; - } - catch (Exception e) - { - IsConfigured = false; - throw new Exception("Your cookie did not work: " + e.Message); - } - } - - var result = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, SiteLink, LoginUrl); - - await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["table.main > tbody > tr > td > table > tbody > tr > td"]; - var errorMessage = messageEl.Text().Trim(); - if (string.IsNullOrWhiteSpace(errorMessage)) - errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var pairs = new Dictionary<string, string>(); - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - - pairs.Add("draw", "1"); - pairs.Add("columns[0][data]", ""); - pairs.Add("columns[0][name]", ""); - pairs.Add("columns[0][searchable]", "false"); - pairs.Add("columns[0][orderable]", "false"); - pairs.Add("columns[0][search][value]", ""); - pairs.Add("columns[0][search][regex]", "false"); - pairs.Add("columns[1][data]", "id"); - pairs.Add("columns[1][name]", ""); - pairs.Add("columns[1][searchable]", "false"); - pairs.Add("columns[1][orderable]", "true"); - pairs.Add("columns[1][search][value]", ""); - pairs.Add("columns[1][search][regex]", "false"); - pairs.Add("columns[2][data]", "cat"); - pairs.Add("columns[2][name]", ""); - pairs.Add("columns[2][searchable]", "false"); - pairs.Add("columns[2][orderable]", "true"); - pairs.Add("columns[2][search][value]", ""); - pairs.Add("columns[2][search][regex]", "false"); - pairs.Add("columns[3][data]", "name"); - pairs.Add("columns[3][name]", ""); - pairs.Add("columns[3][searchable]", "true"); - pairs.Add("columns[3][orderable]", "true"); - pairs.Add("columns[3][search][value]", ""); - pairs.Add("columns[3][search][regex]", "false"); - pairs.Add("columns[4][data]", "username"); - pairs.Add("columns[4][name]", ""); - pairs.Add("columns[4][searchable]", "true"); - pairs.Add("columns[4][orderable]", "true"); - pairs.Add("columns[4][search][value]", ""); - pairs.Add("columns[4][search][regex]", "false"); - pairs.Add("columns[5][data]", "cat-image"); - pairs.Add("columns[5][name]", ""); - pairs.Add("columns[5][searchable]", "false"); - pairs.Add("columns[5][orderable]", "true"); - pairs.Add("columns[5][search][value]", ""); - pairs.Add("columns[5][search][regex]", "false"); - pairs.Add("columns[6][data]", "cat-name"); - pairs.Add("columns[6][name]", ""); - pairs.Add("columns[6][searchable]", "false"); - pairs.Add("columns[6][orderable]", "true"); - pairs.Add("columns[6][search][value]", ""); - pairs.Add("columns[6][search][regex]", "false"); - pairs.Add("columns[7][data]", "imdbid"); - pairs.Add("columns[7][name]", ""); - pairs.Add("columns[7][searchable]", "true"); - pairs.Add("columns[7][orderable]", "true"); - pairs.Add("columns[7][search][value]", ""); - pairs.Add("columns[7][search][regex]", "false"); - pairs.Add("columns[8][data]", "genre"); - pairs.Add("columns[8][name]", ""); - pairs.Add("columns[8][searchable]", "false"); - pairs.Add("columns[8][orderable]", "true"); - pairs.Add("columns[8][search][value]", ""); - pairs.Add("columns[8][search][regex]", "false"); - pairs.Add("columns[9][data]", "added"); - pairs.Add("columns[9][name]", ""); - pairs.Add("columns[9][searchable]", "false"); - pairs.Add("columns[9][orderable]", "true"); - pairs.Add("columns[9][search][value]", ""); - pairs.Add("columns[9][search][regex]", "false"); - pairs.Add("columns[10][data]", "size"); - pairs.Add("columns[10][name]", ""); - pairs.Add("columns[10][searchable]", "false"); - pairs.Add("columns[10][orderable]", "true"); - pairs.Add("columns[10][search][value]", ""); - pairs.Add("columns[10][search][regex]", "false"); - pairs.Add("columns[11][data]", "rating"); - pairs.Add("columns[11][name]", ""); - pairs.Add("columns[11][searchable]", "false"); - pairs.Add("columns[11][orderable]", "true"); - pairs.Add("columns[11][search][value]", ""); - pairs.Add("columns[11][search][regex]", "false"); - pairs.Add("columns[12][data]", "comments"); - pairs.Add("columns[12][name]", ""); - pairs.Add("columns[12][searchable]", "false"); - pairs.Add("columns[12][orderable]", "true"); - pairs.Add("columns[12][search][value]", ""); - pairs.Add("columns[12][search][regex]", "false"); - pairs.Add("columns[13][data]", "numfiles"); - pairs.Add("columns[13][name]", ""); - pairs.Add("columns[13][searchable]", "false"); - pairs.Add("columns[13][orderable]", "true"); - pairs.Add("columns[13][search][value]", ""); - pairs.Add("columns[13][search][regex]", "false"); - pairs.Add("columns[14][data]", "seeders"); - pairs.Add("columns[14][name]", ""); - pairs.Add("columns[14][searchable]", "false"); - pairs.Add("columns[14][orderable]", "true"); - pairs.Add("columns[14][search][value]", ""); - pairs.Add("columns[14][search][regex]", "false"); - pairs.Add("columns[15][data]", "leechers"); - pairs.Add("columns[15][name]", ""); - pairs.Add("columns[15][searchable]", "false"); - pairs.Add("columns[15][orderable]", "true"); - pairs.Add("columns[15][search][value]", ""); - pairs.Add("columns[15][search][regex]", "false"); - pairs.Add("columns[16][data]", "to_go"); - pairs.Add("columns[16][name]", ""); - pairs.Add("columns[16][searchable]", "false"); - pairs.Add("columns[16][orderable]", "true"); - pairs.Add("columns[16][search][value]", ""); - pairs.Add("columns[16][search][regex]", "false"); - pairs.Add("columns[17][data]", "genre"); - pairs.Add("columns[17][name]", ""); - pairs.Add("columns[17][searchable]", "true"); - pairs.Add("columns[17][orderable]", "true"); - pairs.Add("columns[17][search][value]", ""); - pairs.Add("columns[17][search][regex]", "false"); - pairs.Add("order[0][column]", "9"); - pairs.Add("order[0][dir]", "desc"); - pairs.Add("start", "0"); - pairs.Add("length", "100"); - pairs.Add("visible", "1"); - pairs.Add("uid", "-1"); - pairs.Add("genre", ""); - - pairs.Add("cats", string.Join(",+", MapTorznabCapsToTrackers(query))); - - if (query.ImdbID != null) - { - pairs.Add("search[value]", query.ImdbID); - pairs.Add("search[regex]", "false"); - } - else if (!string.IsNullOrWhiteSpace(searchString)) - { - pairs.Add("search[value]", searchString); - pairs.Add("search[regex]", "false"); - } - - var results = await PostDataWithCookiesAndRetry(searchUrl, pairs); - - try - { - var json = JObject.Parse(results.Content); - foreach (var row in json["data"]) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 24 * 60 * 60; - - var hParser = new HtmlParser(); - var hName = hParser.Parse(row["name"].ToString()); - var hComments = hParser.Parse(row["comments"].ToString()); - var hNumfiles = hParser.Parse(row["numfiles"].ToString()); - var hSeeders = hParser.Parse(row["seeders"].ToString()); - var hLeechers = hParser.Parse(row["leechers"].ToString()); - - var hDetailsLink = hName.QuerySelector("a[href^=\"details.php?id=\"]"); - var hCommentsLink = hComments.QuerySelector("a"); - var hDownloadLink = hName.QuerySelector("a[title=\"Download Torrent\"]"); - - release.Title = hDetailsLink.TextContent; - if (query.ImdbID == null && !query.MatchQueryStringAND(release.Title)) - continue; - - release.Comments = new Uri(SiteLink + hCommentsLink.GetAttribute("href")); - release.Link = new Uri(SiteLink + hDownloadLink.GetAttribute("href")); - release.Guid = release.Link; - - release.Description = row["genre"].ToString(); - - var poster = row["poster"].ToString(); - if(!string.IsNullOrWhiteSpace(poster)) - { - var posterurl = poster; - if (!poster.StartsWith("http")) - posterurl = SiteLink + poster; - release.BannerUrl = new Uri(posterurl); - } - - release.Size = ReleaseInfo.GetBytes(row["size"].ToString()); - var imdbId = row["imdbid"].ToString(); - if (imdbId.StartsWith("tt")) - release.Imdb = ParseUtil.CoerceLong(imdbId.Substring(2)); - - var added = row["added"].ToString().Replace("<br>", " "); - release.PublishDate = DateTimeUtil.FromUnknown(added); - - var catid = row["catid"].ToString(); - release.Category = MapTrackerCatToNewznab(catid); - - release.Seeders = ParseUtil.CoerceInt(hSeeders.QuerySelector("a").TextContent); - release.Peers = ParseUtil.CoerceInt(hLeechers.QuerySelector("a").TextContent) + release.Seeders; - - release.Files = ParseUtil.CoerceInt(hNumfiles.QuerySelector("a").TextContent); - - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - releases.Add(release); - - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; + +using AngleSharp.Parser.Html; + +namespace Jackett.Indexers +{ + public class HD4Free : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "ajax/initial_recall.php"; } } + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string TakeLoginUrl { get { return SiteLink + "takelogin.php"; } } + + new ConfigurationDataRecaptchaLogin configData + { + get { return (ConfigurationDataRecaptchaLogin)base.configData; } + set { base.configData = value; } + } + + public HD4Free(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "HD4Free", + description: "A HD trackers", + link: "https://hd4free.xyz/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataRecaptchaLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(42, TorznabCatType.MoviesSD); // LEGi0N 480p + AddCategoryMapping(17, TorznabCatType.MoviesHD); // LEGi0N 720p + AddCategoryMapping(16, TorznabCatType.MoviesHD); // LEGi0N 1080p + AddCategoryMapping(84, TorznabCatType.Movies3D); // LEGi0N 3D 1080p + AddCategoryMapping(31, TorznabCatType.MoviesOther); // LEGi0N REMUX + AddCategoryMapping(70, TorznabCatType.MoviesBluRay); // LEGi0N BD BD25 & BD50 + AddCategoryMapping(55, TorznabCatType.Movies); // LEGi0N Movie/TV PACKS + AddCategoryMapping(60, TorznabCatType.Other); // shadz shack + AddCategoryMapping(85, TorznabCatType.MoviesHD); // MarGe 720p + AddCategoryMapping(86, TorznabCatType.MoviesHD); // MarGe 1080p + AddCategoryMapping(73, TorznabCatType.MoviesBluRay); // GF44 BD-50 + AddCategoryMapping(74, TorznabCatType.MoviesBluRay); // GF44 BD-25 + AddCategoryMapping(88, TorznabCatType.MoviesBluRay); // taterzero BD50 + AddCategoryMapping(89, TorznabCatType.MoviesBluRay); // taterzero BD25 + AddCategoryMapping(90, TorznabCatType.Movies3D); // taterzero 3D BD + AddCategoryMapping(39, TorznabCatType.MoviesBluRay); // Bluray REMUX + AddCategoryMapping(38, TorznabCatType.MoviesBluRay); // Bluray + AddCategoryMapping(75, TorznabCatType.MoviesBluRay); // Bluray 25 + AddCategoryMapping(36, TorznabCatType.MoviesHD); // Encodes 720p + AddCategoryMapping(35, TorznabCatType.MoviesHD); // Encodes 1080p + AddCategoryMapping(45, TorznabCatType.Movies3D); // 1080p 3D Encodes + AddCategoryMapping(77, TorznabCatType.MoviesHD); // WEB-DL 720p + AddCategoryMapping(78, TorznabCatType.MoviesHD); // WEB-DL 1080p + AddCategoryMapping(83, TorznabCatType.MoviesDVD); // DVD 5/9's + AddCategoryMapping(47, TorznabCatType.Movies); // General x264 + AddCategoryMapping(58, TorznabCatType.Movies); // General XViD + AddCategoryMapping(66, TorznabCatType.Movies); // x265 HEVC + AddCategoryMapping(34, TorznabCatType.MoviesHD); // 4K + AddCategoryMapping(61, TorznabCatType.Movies); // MOViE PACKS + AddCategoryMapping(44, TorznabCatType.TVHD); // HDTV 720p + AddCategoryMapping(43, TorznabCatType.TVHD); // HDTV 1080p + AddCategoryMapping(41, TorznabCatType.TVHD); // WEB-DL 720p TV + AddCategoryMapping(40, TorznabCatType.TVHD); // WEB-DL 1080p TV + AddCategoryMapping(52, TorznabCatType.TVHD); // 720p TV BluRay + AddCategoryMapping(53, TorznabCatType.TVHD); // 1080p TV BluRay + AddCategoryMapping(62, TorznabCatType.TVHD); // HDTV Packs + AddCategoryMapping(82, TorznabCatType.TVSD); // SDTV TV PACKS + AddCategoryMapping(63, TorznabCatType.PC0day); // Apps Windows + AddCategoryMapping(57, TorznabCatType.PCMac); // Appz Mac + AddCategoryMapping(72, TorznabCatType.AudioAudiobook); // Audio Books + AddCategoryMapping(71, TorznabCatType.Books); // Ebooks + AddCategoryMapping(46, TorznabCatType.AudioLossless); // FLAC/Lossless + AddCategoryMapping(81, TorznabCatType.AudioMP3); // MP3 Music + AddCategoryMapping(87, TorznabCatType.AudioVideo); // HD MUSiC ViDEOS + AddCategoryMapping(32, TorznabCatType.Other); // Covers And Artwork + AddCategoryMapping(50, TorznabCatType.XXX); // Porn XXX + } + + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, configData.CookieHeader.Value); + CQ cq = loginPage.Content; + string recaptchaSiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); + var result = this.configData; + result.CookieHeader.Value = loginPage.Cookies; + result.Captcha.SiteKey = recaptchaSiteKey; + result.Captcha.Version = "2"; + return result; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "returnto" , "/" }, + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "g-recaptcha-response", configData.Captcha.Value }, + { "submitme", "Login" } + }; + + if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) + { + // Cookie was manually supplied + CookieHeader = configData.Captcha.Cookie; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (!results.Any()) + { + throw new Exception("Your cookie did not work"); + } + + SaveConfig(); + IsConfigured = true; + return IndexerConfigurationStatus.Completed; + } + catch (Exception e) + { + IsConfigured = false; + throw new Exception("Your cookie did not work: " + e.Message); + } + } + + var result = await RequestLoginAndFollowRedirect(TakeLoginUrl, pairs, null, true, SiteLink, LoginUrl); + + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["table.main > tbody > tr > td > table > tbody > tr > td"]; + var errorMessage = messageEl.Text().Trim(); + if (string.IsNullOrWhiteSpace(errorMessage)) + errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var pairs = new Dictionary<string, string>(); + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + + pairs.Add("draw", "1"); + pairs.Add("columns[0][data]", ""); + pairs.Add("columns[0][name]", ""); + pairs.Add("columns[0][searchable]", "false"); + pairs.Add("columns[0][orderable]", "false"); + pairs.Add("columns[0][search][value]", ""); + pairs.Add("columns[0][search][regex]", "false"); + pairs.Add("columns[1][data]", "id"); + pairs.Add("columns[1][name]", ""); + pairs.Add("columns[1][searchable]", "false"); + pairs.Add("columns[1][orderable]", "true"); + pairs.Add("columns[1][search][value]", ""); + pairs.Add("columns[1][search][regex]", "false"); + pairs.Add("columns[2][data]", "cat"); + pairs.Add("columns[2][name]", ""); + pairs.Add("columns[2][searchable]", "false"); + pairs.Add("columns[2][orderable]", "true"); + pairs.Add("columns[2][search][value]", ""); + pairs.Add("columns[2][search][regex]", "false"); + pairs.Add("columns[3][data]", "name"); + pairs.Add("columns[3][name]", ""); + pairs.Add("columns[3][searchable]", "true"); + pairs.Add("columns[3][orderable]", "true"); + pairs.Add("columns[3][search][value]", ""); + pairs.Add("columns[3][search][regex]", "false"); + pairs.Add("columns[4][data]", "username"); + pairs.Add("columns[4][name]", ""); + pairs.Add("columns[4][searchable]", "true"); + pairs.Add("columns[4][orderable]", "true"); + pairs.Add("columns[4][search][value]", ""); + pairs.Add("columns[4][search][regex]", "false"); + pairs.Add("columns[5][data]", "cat-image"); + pairs.Add("columns[5][name]", ""); + pairs.Add("columns[5][searchable]", "false"); + pairs.Add("columns[5][orderable]", "true"); + pairs.Add("columns[5][search][value]", ""); + pairs.Add("columns[5][search][regex]", "false"); + pairs.Add("columns[6][data]", "cat-name"); + pairs.Add("columns[6][name]", ""); + pairs.Add("columns[6][searchable]", "false"); + pairs.Add("columns[6][orderable]", "true"); + pairs.Add("columns[6][search][value]", ""); + pairs.Add("columns[6][search][regex]", "false"); + pairs.Add("columns[7][data]", "imdbid"); + pairs.Add("columns[7][name]", ""); + pairs.Add("columns[7][searchable]", "true"); + pairs.Add("columns[7][orderable]", "true"); + pairs.Add("columns[7][search][value]", ""); + pairs.Add("columns[7][search][regex]", "false"); + pairs.Add("columns[8][data]", "genre"); + pairs.Add("columns[8][name]", ""); + pairs.Add("columns[8][searchable]", "false"); + pairs.Add("columns[8][orderable]", "true"); + pairs.Add("columns[8][search][value]", ""); + pairs.Add("columns[8][search][regex]", "false"); + pairs.Add("columns[9][data]", "added"); + pairs.Add("columns[9][name]", ""); + pairs.Add("columns[9][searchable]", "false"); + pairs.Add("columns[9][orderable]", "true"); + pairs.Add("columns[9][search][value]", ""); + pairs.Add("columns[9][search][regex]", "false"); + pairs.Add("columns[10][data]", "size"); + pairs.Add("columns[10][name]", ""); + pairs.Add("columns[10][searchable]", "false"); + pairs.Add("columns[10][orderable]", "true"); + pairs.Add("columns[10][search][value]", ""); + pairs.Add("columns[10][search][regex]", "false"); + pairs.Add("columns[11][data]", "rating"); + pairs.Add("columns[11][name]", ""); + pairs.Add("columns[11][searchable]", "false"); + pairs.Add("columns[11][orderable]", "true"); + pairs.Add("columns[11][search][value]", ""); + pairs.Add("columns[11][search][regex]", "false"); + pairs.Add("columns[12][data]", "comments"); + pairs.Add("columns[12][name]", ""); + pairs.Add("columns[12][searchable]", "false"); + pairs.Add("columns[12][orderable]", "true"); + pairs.Add("columns[12][search][value]", ""); + pairs.Add("columns[12][search][regex]", "false"); + pairs.Add("columns[13][data]", "numfiles"); + pairs.Add("columns[13][name]", ""); + pairs.Add("columns[13][searchable]", "false"); + pairs.Add("columns[13][orderable]", "true"); + pairs.Add("columns[13][search][value]", ""); + pairs.Add("columns[13][search][regex]", "false"); + pairs.Add("columns[14][data]", "seeders"); + pairs.Add("columns[14][name]", ""); + pairs.Add("columns[14][searchable]", "false"); + pairs.Add("columns[14][orderable]", "true"); + pairs.Add("columns[14][search][value]", ""); + pairs.Add("columns[14][search][regex]", "false"); + pairs.Add("columns[15][data]", "leechers"); + pairs.Add("columns[15][name]", ""); + pairs.Add("columns[15][searchable]", "false"); + pairs.Add("columns[15][orderable]", "true"); + pairs.Add("columns[15][search][value]", ""); + pairs.Add("columns[15][search][regex]", "false"); + pairs.Add("columns[16][data]", "to_go"); + pairs.Add("columns[16][name]", ""); + pairs.Add("columns[16][searchable]", "false"); + pairs.Add("columns[16][orderable]", "true"); + pairs.Add("columns[16][search][value]", ""); + pairs.Add("columns[16][search][regex]", "false"); + pairs.Add("columns[17][data]", "genre"); + pairs.Add("columns[17][name]", ""); + pairs.Add("columns[17][searchable]", "true"); + pairs.Add("columns[17][orderable]", "true"); + pairs.Add("columns[17][search][value]", ""); + pairs.Add("columns[17][search][regex]", "false"); + pairs.Add("order[0][column]", "9"); + pairs.Add("order[0][dir]", "desc"); + pairs.Add("start", "0"); + pairs.Add("length", "100"); + pairs.Add("visible", "1"); + pairs.Add("uid", "-1"); + pairs.Add("genre", ""); + + pairs.Add("cats", string.Join(",+", MapTorznabCapsToTrackers(query))); + + if (query.ImdbID != null) + { + pairs.Add("search[value]", query.ImdbID); + pairs.Add("search[regex]", "false"); + } + else if (!string.IsNullOrWhiteSpace(searchString)) + { + pairs.Add("search[value]", searchString); + pairs.Add("search[regex]", "false"); + } + + var results = await PostDataWithCookiesAndRetry(searchUrl, pairs); + + try + { + var json = JObject.Parse(results.Content); + foreach (var row in json["data"]) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 24 * 60 * 60; + + var hParser = new HtmlParser(); + var hName = hParser.Parse(row["name"].ToString()); + var hComments = hParser.Parse(row["comments"].ToString()); + var hNumfiles = hParser.Parse(row["numfiles"].ToString()); + var hSeeders = hParser.Parse(row["seeders"].ToString()); + var hLeechers = hParser.Parse(row["leechers"].ToString()); + + var hDetailsLink = hName.QuerySelector("a[href^=\"details.php?id=\"]"); + var hCommentsLink = hComments.QuerySelector("a"); + var hDownloadLink = hName.QuerySelector("a[title=\"Download Torrent\"]"); + + release.Title = hDetailsLink.TextContent; + if (query.ImdbID == null && !query.MatchQueryStringAND(release.Title)) + continue; + + release.Comments = new Uri(SiteLink + hCommentsLink.GetAttribute("href")); + release.Link = new Uri(SiteLink + hDownloadLink.GetAttribute("href")); + release.Guid = release.Link; + + release.Description = row["genre"].ToString(); + + var poster = row["poster"].ToString(); + if(!string.IsNullOrWhiteSpace(poster)) + { + var posterurl = poster; + if (!poster.StartsWith("http")) + posterurl = SiteLink + poster; + release.BannerUrl = new Uri(posterurl); + } + + release.Size = ReleaseInfo.GetBytes(row["size"].ToString()); + var imdbId = row["imdbid"].ToString(); + if (imdbId.StartsWith("tt")) + release.Imdb = ParseUtil.CoerceLong(imdbId.Substring(2)); + + var added = row["added"].ToString().Replace("<br>", " "); + release.PublishDate = DateTimeUtil.FromUnknown(added); + + var catid = row["catid"].ToString(); + release.Category = MapTrackerCatToNewznab(catid); + + release.Seeders = ParseUtil.CoerceInt(hSeeders.QuerySelector("a").TextContent); + release.Peers = ParseUtil.CoerceInt(hLeechers.QuerySelector("a").TextContent) + release.Seeders; + + release.Files = ParseUtil.CoerceInt(hNumfiles.QuerySelector("a").TextContent); + + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/HDOnly.cs b/src/Jackett/Indexers/HDOnly.cs index 93b2d98c..8277a806 100644 --- a/src/Jackett/Indexers/HDOnly.cs +++ b/src/Jackett/Indexers/HDOnly.cs @@ -2,11 +2,11 @@ using NLog; using Jackett.Services; using Jackett.Utils.Clients; -using Jackett.Indexers.Abstract; -using Newtonsoft.Json.Linq; -using System.Collections.Generic; -using System.Web; - +using Jackett.Indexers.Abstract; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Web; + namespace Jackett.Indexers { public class HDOnly : GazelleTracker, IIndexer @@ -28,36 +28,36 @@ namespace Jackett.Indexers AddCategoryMapping(null, TorznabCatType.TV, "Séries"); // releaseType mappings - AddCategoryMapping(1, TorznabCatType.Movies, "Film"); - AddCategoryMapping(3, TorznabCatType.TVAnime, "Dessin animé"); - AddCategoryMapping(5, TorznabCatType.TV, "Série"); - AddCategoryMapping(6, TorznabCatType.TVAnime, "Série Animée"); - AddCategoryMapping(7, TorznabCatType.MoviesOther, "Film d'animation"); - AddCategoryMapping(9, TorznabCatType.AudioVideo, "Concert"); - AddCategoryMapping(11, TorznabCatType.TVDocumentary, "Documentaire"); - AddCategoryMapping(13, TorznabCatType.MoviesOther, "Court-métrage"); - AddCategoryMapping(14, TorznabCatType.MoviesOther, "Clip"); - AddCategoryMapping(15, TorznabCatType.MoviesOther, "Démonstration"); - AddCategoryMapping(16, TorznabCatType.MoviesOther, "Bonus de BD"); - AddCategoryMapping(21, TorznabCatType.Other, "Autre"); + AddCategoryMapping(1, TorznabCatType.Movies, "Film"); + AddCategoryMapping(3, TorznabCatType.TVAnime, "Dessin animé"); + AddCategoryMapping(5, TorznabCatType.TV, "Série"); + AddCategoryMapping(6, TorznabCatType.TVAnime, "Série Animée"); + AddCategoryMapping(7, TorznabCatType.MoviesOther, "Film d'animation"); + AddCategoryMapping(9, TorznabCatType.AudioVideo, "Concert"); + AddCategoryMapping(11, TorznabCatType.TVDocumentary, "Documentaire"); + AddCategoryMapping(13, TorznabCatType.MoviesOther, "Court-métrage"); + AddCategoryMapping(14, TorznabCatType.MoviesOther, "Clip"); + AddCategoryMapping(15, TorznabCatType.MoviesOther, "Démonstration"); + AddCategoryMapping(16, TorznabCatType.MoviesOther, "Bonus de BD"); + AddCategoryMapping(21, TorznabCatType.Other, "Autre"); } - protected override bool ReleaseInfoPostParse(ReleaseInfo release, JObject torrent, JObject result) - { - // releaseType is used for categories - var category = (string)result["category"]; - if (category == null) - { - var releaseType = (string)result["releaseType"]; - release.Category = MapTrackerCatDescToNewznab(releaseType); - } - return true; + protected override bool ReleaseInfoPostParse(ReleaseInfo release, JObject torrent, JObject result) + { + // releaseType is used for categories + var category = (string)result["category"]; + if (category == null) + { + var releaseType = (string)result["releaseType"]; + release.Category = MapTrackerCatDescToNewznab(releaseType); + } + return true; } - protected override List<string> MapTorznabCapsToTrackers(TorznabQuery query, bool mapChildrenCatsToParent = false) - { - // don't use category filtering - return new List<string>(); + protected override List<string> MapTorznabCapsToTrackers(TorznabQuery query, bool mapChildrenCatsToParent = false) + { + // don't use category filtering + return new List<string>(); } } } \ No newline at end of file diff --git a/src/Jackett/Indexers/HDSpace.cs b/src/Jackett/Indexers/HDSpace.cs index 274dd60a..dc04d318 100644 --- a/src/Jackett/Indexers/HDSpace.cs +++ b/src/Jackett/Indexers/HDSpace.cs @@ -14,8 +14,8 @@ using System.Web; using System.Text.RegularExpressions; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - +using System.Collections.Specialized; + namespace Jackett.Indexers { public class HDSpace : BaseIndexer, IIndexer @@ -106,18 +106,18 @@ namespace Jackett.Indexers var searchString = query.GetQueryString(); var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("active", "0"); - queryCollection.Add("options", "0"); - queryCollection.Add("category", string.Join(";", MapTorznabCapsToTrackers(query))); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - searchUrl += queryCollection.GetQueryString(); - + var queryCollection = new NameValueCollection(); + queryCollection.Add("active", "0"); + queryCollection.Add("options", "0"); + queryCollection.Add("category", string.Join(";", MapTorznabCapsToTrackers(query))); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + searchUrl += queryCollection.GetQueryString(); + var response = await RequestStringWithCookiesAndRetry(searchUrl); var results = response.Content; @@ -164,12 +164,12 @@ namespace Jackett.Indexers grabs = grabs.Replace("---", "0"); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[title=\"FreeLeech\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[src=\"images/sf.png\"]").Length >= 1) // side freeleech - release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[title=\"Half FreeLeech\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; + if (qRow.Find("img[title=\"FreeLeech\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[src=\"images/sf.png\"]").Length >= 1) // side freeleech + release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[title=\"Half FreeLeech\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs index 9d91bf68..a270839f 100644 --- a/src/Jackett/Indexers/HDTorrents.cs +++ b/src/Jackett/Indexers/HDTorrents.cs @@ -48,34 +48,34 @@ namespace Jackett.Indexers TorznabCaps.SupportsImdbSearch = true; - TorznabCaps.Categories.Clear(); - - // Movie - AddCategoryMapping("1", TorznabCatType.MoviesHD, "Movie/Blu-Ray"); - AddCategoryMapping("2", TorznabCatType.MoviesHD, "Movie/Remux"); - AddCategoryMapping("5", TorznabCatType.MoviesHD, "Movie/1080p/i"); - AddCategoryMapping("3", TorznabCatType.MoviesHD, "Movie/720p"); - AddCategoryMapping("64", TorznabCatType.MoviesHD, "Movie/2160p"); - AddCategoryMapping("63", TorznabCatType.Audio, "Movie/Audio Track"); - // TV Show - AddCategoryMapping("59", TorznabCatType.TVHD, "TV Show/Blu-ray"); - AddCategoryMapping("60", TorznabCatType.TVHD, "TV Show/Remux"); - AddCategoryMapping("30", TorznabCatType.TVHD, "TV Show/1080p/i"); - AddCategoryMapping("38", TorznabCatType.TVHD, "TV Show/720p"); - AddCategoryMapping("65", TorznabCatType.TVHD, "TV Show/2160p"); - // Music - AddCategoryMapping("44", TorznabCatType.Audio, "Music/Album"); - AddCategoryMapping("61", TorznabCatType.AudioVideo, "Music/Blu-Ray"); - AddCategoryMapping("62", TorznabCatType.AudioVideo, "Music/Remux"); - AddCategoryMapping("57", TorznabCatType.AudioVideo, "Music/1080p/i"); - AddCategoryMapping("45", TorznabCatType.AudioVideo, "Music/720p"); - AddCategoryMapping("66", TorznabCatType.AudioVideo, "Music/2160p"); - // XXX - AddCategoryMapping("58", TorznabCatType.XXX, "XXX/Blu-ray"); - AddCategoryMapping("48", TorznabCatType.XXX, "XXX/1080p/i"); - AddCategoryMapping("47", TorznabCatType.XXX, "XXX/720p"); - AddCategoryMapping("67", TorznabCatType.XXX, "XXX/2160p"); - // 3D + TorznabCaps.Categories.Clear(); + + // Movie + AddCategoryMapping("1", TorznabCatType.MoviesHD, "Movie/Blu-Ray"); + AddCategoryMapping("2", TorznabCatType.MoviesHD, "Movie/Remux"); + AddCategoryMapping("5", TorznabCatType.MoviesHD, "Movie/1080p/i"); + AddCategoryMapping("3", TorznabCatType.MoviesHD, "Movie/720p"); + AddCategoryMapping("64", TorznabCatType.MoviesHD, "Movie/2160p"); + AddCategoryMapping("63", TorznabCatType.Audio, "Movie/Audio Track"); + // TV Show + AddCategoryMapping("59", TorznabCatType.TVHD, "TV Show/Blu-ray"); + AddCategoryMapping("60", TorznabCatType.TVHD, "TV Show/Remux"); + AddCategoryMapping("30", TorznabCatType.TVHD, "TV Show/1080p/i"); + AddCategoryMapping("38", TorznabCatType.TVHD, "TV Show/720p"); + AddCategoryMapping("65", TorznabCatType.TVHD, "TV Show/2160p"); + // Music + AddCategoryMapping("44", TorznabCatType.Audio, "Music/Album"); + AddCategoryMapping("61", TorznabCatType.AudioVideo, "Music/Blu-Ray"); + AddCategoryMapping("62", TorznabCatType.AudioVideo, "Music/Remux"); + AddCategoryMapping("57", TorznabCatType.AudioVideo, "Music/1080p/i"); + AddCategoryMapping("45", TorznabCatType.AudioVideo, "Music/720p"); + AddCategoryMapping("66", TorznabCatType.AudioVideo, "Music/2160p"); + // XXX + AddCategoryMapping("58", TorznabCatType.XXX, "XXX/Blu-ray"); + AddCategoryMapping("48", TorznabCatType.XXX, "XXX/1080p/i"); + AddCategoryMapping("47", TorznabCatType.XXX, "XXX/720p"); + AddCategoryMapping("67", TorznabCatType.XXX, "XXX/2160p"); + // 3D AddCategoryMapping("67", TorznabCatType.Movies3D, "3D"); } @@ -191,17 +191,17 @@ namespace Jackett.Indexers release.UploadVolumeFactor = 1; - if (qRow.Find("img[alt=\"Free Torrent\"]").Length >= 1) - { - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 0; + if (qRow.Find("img[alt=\"Free Torrent\"]").Length >= 1) + { + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 0; } - else if (qRow.Find("img[alt=\"Silver Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; - else if (qRow.Find("img[alt=\"Bronze Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.75; - else if (qRow.Find("img[alt=\"Blue Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.25; + else if (qRow.Find("img[alt=\"Silver Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; + else if (qRow.Find("img[alt=\"Bronze Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.75; + else if (qRow.Find("img[alt=\"Blue Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.25; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/Hardbay.cs b/src/Jackett/Indexers/Hardbay.cs index ea84d49f..2ceabe7d 100644 --- a/src/Jackett/Indexers/Hardbay.cs +++ b/src/Jackett/Indexers/Hardbay.cs @@ -1,147 +1,147 @@ -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.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using Newtonsoft.Json; -using System.Globalization; - -namespace Jackett.Indexers -{ - public class Hardbay : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } } - private string LoginUrl { get { return SiteLink + "api/v1/auth"; } } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public Hardbay(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "Hardbay", - description: null, - link: "https://hardbay.club/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(1, TorznabCatType.Audio); - AddCategoryMapping(2, TorznabCatType.AudioLossless); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var queryCollection = new NameValueCollection(); - +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.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using Newtonsoft.Json; +using System.Globalization; + +namespace Jackett.Indexers +{ + public class Hardbay : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } } + private string LoginUrl { get { return SiteLink + "api/v1/auth"; } } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public Hardbay(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "Hardbay", + description: null, + link: "https://hardbay.club/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(1, TorznabCatType.Audio); + AddCategoryMapping(2, TorznabCatType.AudioLossless); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var queryCollection = new NameValueCollection(); + queryCollection.Add("username", configData.Username.Value); - queryCollection.Add("password", configData.Password.Value); - - var loginUrl = LoginUrl + "?" + queryCollection.GetQueryString(); - var loginResult = await RequestStringWithCookies(loginUrl, null, SiteLink); - - await ConfigureIfOK(loginResult.Cookies, loginResult.Content.Contains("\"user\""), () => - { - throw new ExceptionWithConfigData(loginResult.Content, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - var queryCollection = new NameValueCollection(); - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - - queryCollection.Add("extendedSearch", "false"); - queryCollection.Add("hideOld", "false"); - queryCollection.Add("index", "0"); - queryCollection.Add("limit", "100"); - queryCollection.Add("order", "desc"); - queryCollection.Add("page", "search"); - queryCollection.Add("searchText", searchString); - queryCollection.Add("sort", "d"); - - /*foreach (var cat in MapTorznabCapsToTrackers(query)) - queryCollection.Add("categories[]", cat); - */ - - searchUrl += "?" + queryCollection.GetQueryString(); - var results = await RequestStringWithCookies(searchUrl, null, SiteLink); - - try - { - //var json = JArray.Parse(results.Content); - dynamic json = JsonConvert.DeserializeObject<dynamic>(results.Content); - foreach (var row in json) - { - var release = new ReleaseInfo(); - var descriptions = new List<string>(); - var tags = new List<string>(); - - release.MinimumRatio = 0.5; - release.MinimumSeedTime = 0; - release.Title = row.name; - release.Category = new List<int> { TorznabCatType.Audio.ID }; - release.Size = row.size; - release.Seeders = row.seeders; - release.Peers = row.leechers + release.Seeders; - release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); - release.Files = row.numfiles; - release.Grabs = row.times_completed; - - release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/"); - release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString()); - - if (row.frileech == 1) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 0.33; - release.UploadVolumeFactor = 1; - - if ((int)row.p2p == 1) - tags.Add("P2P"); - if ((int)row.pack == 1) - tags.Add("Pack"); - if ((int)row.reqid != 0) - tags.Add("Archive"); - if ((int)row.flac != 0) - { - tags.Add("FLAC"); - release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; - } - - if (tags.Count > 0) - descriptions.Add("Tags: " + string.Join(", ", tags)); - - release.Description = string.Join("<br>\n", descriptions); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } + queryCollection.Add("password", configData.Password.Value); + + var loginUrl = LoginUrl + "?" + queryCollection.GetQueryString(); + var loginResult = await RequestStringWithCookies(loginUrl, null, SiteLink); + + await ConfigureIfOK(loginResult.Cookies, loginResult.Content.Contains("\"user\""), () => + { + throw new ExceptionWithConfigData(loginResult.Content, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + var queryCollection = new NameValueCollection(); + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + + queryCollection.Add("extendedSearch", "false"); + queryCollection.Add("hideOld", "false"); + queryCollection.Add("index", "0"); + queryCollection.Add("limit", "100"); + queryCollection.Add("order", "desc"); + queryCollection.Add("page", "search"); + queryCollection.Add("searchText", searchString); + queryCollection.Add("sort", "d"); + + /*foreach (var cat in MapTorznabCapsToTrackers(query)) + queryCollection.Add("categories[]", cat); + */ + + searchUrl += "?" + queryCollection.GetQueryString(); + var results = await RequestStringWithCookies(searchUrl, null, SiteLink); + + try + { + //var json = JArray.Parse(results.Content); + dynamic json = JsonConvert.DeserializeObject<dynamic>(results.Content); + foreach (var row in json) + { + var release = new ReleaseInfo(); + var descriptions = new List<string>(); + var tags = new List<string>(); + + release.MinimumRatio = 0.5; + release.MinimumSeedTime = 0; + release.Title = row.name; + release.Category = new List<int> { TorznabCatType.Audio.ID }; + release.Size = row.size; + release.Seeders = row.seeders; + release.Peers = row.leechers + release.Seeders; + release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); + release.Files = row.numfiles; + release.Grabs = row.times_completed; + + release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/"); + release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString()); + + if (row.frileech == 1) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 0.33; + release.UploadVolumeFactor = 1; + + if ((int)row.p2p == 1) + tags.Add("P2P"); + if ((int)row.pack == 1) + tags.Add("Pack"); + if ((int)row.reqid != 0) + tags.Add("Archive"); + if ((int)row.flac != 0) + { + tags.Add("FLAC"); + release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; + } + + if (tags.Count > 0) + descriptions.Add("Tags: " + string.Join(", ", tags)); + + release.Description = string.Join("<br>\n", descriptions); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/Hebits.cs b/src/Jackett/Indexers/Hebits.cs index 6c434824..9716728e 100644 --- a/src/Jackett/Indexers/Hebits.cs +++ b/src/Jackett/Indexers/Hebits.cs @@ -12,8 +12,8 @@ using System.Threading.Tasks; using System.Web; using Jackett.Models.IndexerConfig; using System.Text.RegularExpressions; -using System.Text; - +using System.Text; + namespace Jackett.Indexers { public class Hebits : BaseIndexer, IIndexer @@ -146,15 +146,15 @@ namespace Jackett.Indexers var grabs = qRow.Find("div.bFinish").Get(0).LastChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[src=\"/pic/free.jpg\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("img[src=\"/pic/free.jpg\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; - if (qRow.Find("img[src=\"/pic/triple.jpg\"]").Length >= 1) + if (qRow.Find("img[src=\"/pic/triple.jpg\"]").Length >= 1) release.UploadVolumeFactor = 3; - else if (qRow.Find("img[src=\"/pic/double.jpg\"]").Length >= 1) - release.UploadVolumeFactor = 2; + else if (qRow.Find("img[src=\"/pic/double.jpg\"]").Length >= 1) + release.UploadVolumeFactor = 2; else release.UploadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/Hounddawgs.cs b/src/Jackett/Indexers/Hounddawgs.cs index 5b77aeaf..0c1d947b 100644 --- a/src/Jackett/Indexers/Hounddawgs.cs +++ b/src/Jackett/Indexers/Hounddawgs.cs @@ -18,9 +18,9 @@ using System.Threading.Tasks; using System.Web; using System.Web.UI.WebControls; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text.RegularExpressions; - +using System.Collections.Specialized; +using System.Text.RegularExpressions; + namespace Jackett.Indexers { public class Hounddawgs : BaseIndexer, IIndexer @@ -45,43 +45,43 @@ namespace Jackett.Indexers p: ps, configData: new NxtGnConfigurationData()) { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "da-dk"; - Type = "private"; - - AddCategoryMapping(68, TorznabCatType.Movies3D, "3D"); - AddCategoryMapping(80, TorznabCatType.PCPhoneAndroid, "Appz / Android"); - AddCategoryMapping(86, TorznabCatType.PC0day, "Appz / Div"); - AddCategoryMapping(71, TorznabCatType.PCPhoneIOS, "Appz / iOS"); - AddCategoryMapping(70, TorznabCatType.PCMac, "Appz / Mac"); - AddCategoryMapping(69, TorznabCatType.PC0day, "Appz / PC"); - AddCategoryMapping(72, TorznabCatType.AudioAudiobook, "Audio Books"); - AddCategoryMapping(82, TorznabCatType.MoviesBluRay, "BluRay/REMUX"); - AddCategoryMapping(78, TorznabCatType.Books, "Books"); - AddCategoryMapping(87, TorznabCatType.Other, "Cover"); - AddCategoryMapping(90, TorznabCatType.MoviesDVD, "DK DVDr"); - AddCategoryMapping(89, TorznabCatType.TVHD, "DK HD"); - AddCategoryMapping(91, TorznabCatType.TVSD, "DK SD"); - AddCategoryMapping(92, TorznabCatType.TVHD, "DK TV HD"); - AddCategoryMapping(93, TorznabCatType.TVSD, "DK TV SD"); - AddCategoryMapping(83, TorznabCatType.Other, "ELearning"); - AddCategoryMapping(84, TorznabCatType.Movies, "Film Boxset"); - AddCategoryMapping(81, TorznabCatType.MoviesSD, "Film CAM/TS"); - AddCategoryMapping(60, TorznabCatType.MoviesDVD, "Film DVDr"); - AddCategoryMapping(59, TorznabCatType.MoviesHD, "Film HD"); - AddCategoryMapping(73, TorznabCatType.MoviesSD, "Film SD"); - AddCategoryMapping(77, TorznabCatType.MoviesOther, "Film Tablet"); - AddCategoryMapping(61, TorznabCatType.Audio, "Musik"); - AddCategoryMapping(76, TorznabCatType.AudioVideo, "MusikVideo/Koncert"); - AddCategoryMapping(75, TorznabCatType.Console, "Spil / Konsol"); - AddCategoryMapping(79, TorznabCatType.PCMac, "Spil / Mac"); - AddCategoryMapping(64, TorznabCatType.PCGames, "Spil / PC"); - AddCategoryMapping(85, TorznabCatType.TV, "TV Boxset"); - AddCategoryMapping(58, TorznabCatType.TVSD, "TV DVDr"); - AddCategoryMapping(57, TorznabCatType.TVHD, "TV HD"); - AddCategoryMapping(74, TorznabCatType.TVSD, "TV SD"); - AddCategoryMapping(94, TorznabCatType.TVOTHER, "TV Tablet"); - AddCategoryMapping(67, TorznabCatType.XXX, "XXX"); + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "da-dk"; + Type = "private"; + + AddCategoryMapping(68, TorznabCatType.Movies3D, "3D"); + AddCategoryMapping(80, TorznabCatType.PCPhoneAndroid, "Appz / Android"); + AddCategoryMapping(86, TorznabCatType.PC0day, "Appz / Div"); + AddCategoryMapping(71, TorznabCatType.PCPhoneIOS, "Appz / iOS"); + AddCategoryMapping(70, TorznabCatType.PCMac, "Appz / Mac"); + AddCategoryMapping(69, TorznabCatType.PC0day, "Appz / PC"); + AddCategoryMapping(72, TorznabCatType.AudioAudiobook, "Audio Books"); + AddCategoryMapping(82, TorznabCatType.MoviesBluRay, "BluRay/REMUX"); + AddCategoryMapping(78, TorznabCatType.Books, "Books"); + AddCategoryMapping(87, TorznabCatType.Other, "Cover"); + AddCategoryMapping(90, TorznabCatType.MoviesDVD, "DK DVDr"); + AddCategoryMapping(89, TorznabCatType.TVHD, "DK HD"); + AddCategoryMapping(91, TorznabCatType.TVSD, "DK SD"); + AddCategoryMapping(92, TorznabCatType.TVHD, "DK TV HD"); + AddCategoryMapping(93, TorznabCatType.TVSD, "DK TV SD"); + AddCategoryMapping(83, TorznabCatType.Other, "ELearning"); + AddCategoryMapping(84, TorznabCatType.Movies, "Film Boxset"); + AddCategoryMapping(81, TorznabCatType.MoviesSD, "Film CAM/TS"); + AddCategoryMapping(60, TorznabCatType.MoviesDVD, "Film DVDr"); + AddCategoryMapping(59, TorznabCatType.MoviesHD, "Film HD"); + AddCategoryMapping(73, TorznabCatType.MoviesSD, "Film SD"); + AddCategoryMapping(77, TorznabCatType.MoviesOther, "Film Tablet"); + AddCategoryMapping(61, TorznabCatType.Audio, "Musik"); + AddCategoryMapping(76, TorznabCatType.AudioVideo, "MusikVideo/Koncert"); + AddCategoryMapping(75, TorznabCatType.Console, "Spil / Konsol"); + AddCategoryMapping(79, TorznabCatType.PCMac, "Spil / Mac"); + AddCategoryMapping(64, TorznabCatType.PCGames, "Spil / PC"); + AddCategoryMapping(85, TorznabCatType.TV, "TV Boxset"); + AddCategoryMapping(58, TorznabCatType.TVSD, "TV DVDr"); + AddCategoryMapping(57, TorznabCatType.TVHD, "TV HD"); + AddCategoryMapping(74, TorznabCatType.TVSD, "TV SD"); + AddCategoryMapping(94, TorznabCatType.TVOTHER, "TV Tablet"); + AddCategoryMapping(67, TorznabCatType.XXX, "XXX"); } public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) @@ -110,24 +110,24 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); + var searchString = query.GetQueryString(); var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("order_by", "time"); - queryCollection.Add("order_way", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("searchstr", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("filter_cat[" + cat + "]", "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); + var queryCollection = new NameValueCollection(); + + queryCollection.Add("order_by", "time"); + queryCollection.Add("order_way", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("searchstr", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("filter_cat[" + cat + "]", "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); var results = await RequestStringWithCookiesAndRetry(searchUrl); if (results.Content.Contains("Din søgning gav intet resultat.")) { @@ -141,16 +141,16 @@ namespace Jackett.Indexers foreach (var row in rows.Skip(1)) { - var qRow = row.Cq(); + var qRow = row.Cq(); var release = new ReleaseInfo(); release.MinimumRatio = 1; release.MinimumSeedTime = 172800; var qCat = row.ChildElements.ElementAt(0).ChildElements.ElementAt(0).Cq(); var catUrl = qCat.Attr("href"); - var cat = catUrl.Substring(catUrl.LastIndexOf('[') + 1).Trim(']'); - release.Category = MapTrackerCatToNewznab(cat); - + var cat = catUrl.Substring(catUrl.LastIndexOf('[') + 1).Trim(']'); + release.Category = MapTrackerCatToNewznab(cat); + var qAdded = row.ChildElements.ElementAt(4).ChildElements.ElementAt(0).Cq(); var addedStr = qAdded.Attr("title"); release.PublishDate = DateTime.ParseExact(addedStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture); @@ -160,22 +160,22 @@ namespace Jackett.Indexers var overlayHtml = Regex.Unescape(overlayHtmlEscaped); CQ qOverlay = overlayHtml; var title = qOverlay.Find("td.overlay > strong"); - var banner = qOverlay.Find("td.leftOverlay > img").Attr("src"); - var description = qOverlay.Find("td.rightOverlay"); - - foreach (var img in description.Find("img")) // convert relativ flag paths to full uri - img.SetAttribute("src", SiteLink + img.GetAttribute("src")); - - var descriptionDom = description.Get(0); - for (var i = 14; i > 0; i--) // remove size/seeders/leechers - descriptionDom.ChildNodes.RemoveAt(0); - - release.Description = descriptionDom.OuterHTML; + var banner = qOverlay.Find("td.leftOverlay > img").Attr("src"); + var description = qOverlay.Find("td.rightOverlay"); + + foreach (var img in description.Find("img")) // convert relativ flag paths to full uri + img.SetAttribute("src", SiteLink + img.GetAttribute("src")); + + var descriptionDom = description.Get(0); + for (var i = 14; i > 0; i--) // remove size/seeders/leechers + descriptionDom.ChildNodes.RemoveAt(0); + + release.Description = descriptionDom.OuterHTML; release.Title = title.Text(); if (!string.IsNullOrEmpty(banner) && banner != "/static/common/noartwork/noimage.png") release.BannerUrl = new Uri(banner); - var qLink = row.Cq().Find("a[href^=\"torrents.php?id=\"][onmouseover]"); + var qLink = row.Cq().Find("a[href^=\"torrents.php?id=\"][onmouseover]"); release.Comments = new Uri(SiteLink + qLink.Attr("href")); release.Guid = release.Comments; @@ -186,18 +186,18 @@ namespace Jackett.Indexers release.Size = ReleaseInfo.GetBytes(sizeStr); release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(6).Cq().Text()); - release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()) + release.Seeders; - + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()) + release.Seeders; + var files = row.Cq().Find("td:nth-child(4)").Text(); release.Files = ParseUtil.CoerceInt(files); - if (row.Cq().Find("img[src=\"/static//common/browse/freeleech.png\"]").Any()) - release.DownloadVolumeFactor = 0; + if (row.Cq().Find("img[src=\"/static//common/browse/freeleech.png\"]").Any()) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - + release.UploadVolumeFactor = 1; + releases.Add(release); } } diff --git a/src/Jackett/Indexers/HouseOfTorrents.cs b/src/Jackett/Indexers/HouseOfTorrents.cs index 8744163f..9c48d84b 100644 --- a/src/Jackett/Indexers/HouseOfTorrents.cs +++ b/src/Jackett/Indexers/HouseOfTorrents.cs @@ -1,237 +1,237 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Globalization; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public class HouseOfTorrents : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "takelogin.php"; } } - private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public HouseOfTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "House-of-Torrents", - description: "A general tracker", - link: "https://houseoftorrents.club/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(42, TorznabCatType.PCMac); // Applications/Mac - AddCategoryMapping(34, TorznabCatType.PC); // Applications/PC - AddCategoryMapping(66, TorznabCatType.MoviesForeign); // Foreign - AddCategoryMapping(38, TorznabCatType.MoviesForeign); // Foreign/French - AddCategoryMapping(39, TorznabCatType.MoviesForeign); // Foreign/German - AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Foreign/Spanish - AddCategoryMapping(41, TorznabCatType.MoviesForeign); // Foreign/Swedish - AddCategoryMapping(67, TorznabCatType.ConsoleNDS); // Games/Nintendo - AddCategoryMapping(9 , TorznabCatType.PCGames); // Games/PC - AddCategoryMapping(8, TorznabCatType.ConsolePS3); // Games/PS3 - AddCategoryMapping(30, TorznabCatType.ConsolePS4); // Games/PS4 - AddCategoryMapping(7, TorznabCatType.ConsolePSP); // Games/PSP - AddCategoryMapping(29, TorznabCatType.ConsoleWii); // Games/Wii - AddCategoryMapping(31, TorznabCatType.ConsoleXbox360); // Games/XBOX360 - AddCategoryMapping(32, TorznabCatType.ConsoleXboxOne); // Games/XBOXONE - AddCategoryMapping(71, TorznabCatType.PCPhoneAndroid); // Mobile/Android - AddCategoryMapping(72, TorznabCatType.PCPhoneIOS); // Mobile/iOS - AddCategoryMapping(47, TorznabCatType.Movies3D); // Movies/3D - AddCategoryMapping(43, TorznabCatType.MoviesBluRay); // Movies/Bluray - AddCategoryMapping(84, TorznabCatType.MoviesSD); // Movies/Cam - AddCategoryMapping(44, TorznabCatType.MoviesDVD); // Movies/DVD-R - AddCategoryMapping(45, TorznabCatType.Movies); // Movies/MP4 - AddCategoryMapping(69, TorznabCatType.Movies); // Movies/Packs - AddCategoryMapping(46, TorznabCatType.MoviesSD); // Movies/SD - AddCategoryMapping(11, TorznabCatType.MoviesHD); // Movies/x264 - AddCategoryMapping(83, TorznabCatType.MoviesHD); // Movies/x265 - AddCategoryMapping(10, TorznabCatType.MoviesOther); // Movies/XviD - AddCategoryMapping(36, TorznabCatType.AudioLossless); // Music/FLAC - AddCategoryMapping(12, TorznabCatType.AudioMP3); // Music/MP3 - AddCategoryMapping(79, TorznabCatType.Audio); // Music/Pack - AddCategoryMapping(28, TorznabCatType.AudioVideo); // Music/Video - AddCategoryMapping(49, TorznabCatType.TVAnime); // Others/Anime - AddCategoryMapping(80, TorznabCatType.AudioAudiobook); // Others/AudioBook - AddCategoryMapping(60, TorznabCatType.Other); // Others/Boxsets - AddCategoryMapping(65, TorznabCatType.TVDocumentary); // Others/Documentary - AddCategoryMapping(61, TorznabCatType.Books); // Others/E-Book - AddCategoryMapping(51, TorznabCatType.Other); // Others/RARFIX - AddCategoryMapping(74, TorznabCatType.TVSport); // Sports - AddCategoryMapping(75, TorznabCatType.TVSport); // Sports/Boxing - AddCategoryMapping(76, TorznabCatType.TVSport); // Sports/Racing - AddCategoryMapping(77, TorznabCatType.TVSport); // Sports/UFC - AddCategoryMapping(78, TorznabCatType.TVSport); // Sports/WWE - AddCategoryMapping(68, TorznabCatType.TV); // TV/Packs - AddCategoryMapping(53, TorznabCatType.TVSD); // TV/SD - AddCategoryMapping(54, TorznabCatType.TVHD); // TV/x264 - AddCategoryMapping(82, TorznabCatType.TVHD); // TV/x265 - AddCategoryMapping(55, TorznabCatType.TVOTHER); // Tv/XviD - AddCategoryMapping(63, TorznabCatType.XXX); // XXX - AddCategoryMapping(57, TorznabCatType.XXX); // XXX/0-DAY - AddCategoryMapping(58, TorznabCatType.XXXImageset); // XXX/IMAGESET - AddCategoryMapping(81, TorznabCatType.XXXPacks); // XXX/Pack - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - // reset cookies, if we send expired cookies for a new session their code seems to get confused - // Due to the session not getting initiated correctly it will result in errors like this: - // Notice: Undefined index: simpleCaptchaAnswer in /var/www/html/takelogin.php on line 17 - CookieHeader = null; - - var result1 = await RequestStringWithCookies(CaptchaUrl); - var json1 = JObject.Parse(result1.Content); - var captchaSelection = json1["images"][0]["hash"]; - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "captchaSelection", (string)captchaSelection }, - { "submitme", "X" } - }; - - var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); - - await ConfigureIfOK(result2.Cookies, result2.Content.Contains("logout.php"), () => - { - var errorMessage = result2.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("searchin", "title"); - queryCollection.Add("incldead", "1"); - if (!string.IsNullOrWhiteSpace(searchString)) - { - // use AND+wildcard operator to avoid getting to many useless results - var searchStringArray = Regex.Split(searchString.Trim(), "[ _.-]+", RegexOptions.Compiled).ToList(); - searchStringArray = searchStringArray.Where(x => x.Length >= 3).ToList(); // remove words with less than 3 characters - searchStringArray = searchStringArray.Select(x => "+" + x).ToList(); // add AND operators+wildcards - var searchStringFinal = String.Join("", searchStringArray); - queryCollection.Add("search", searchStringFinal); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - - if (results.IsRedirect) - { - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl); - } - - try - { - CQ dom = results.Content; - var rows = dom["table.tt > tbody > tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 60 * 60; - - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - release.Title = qDetailsLink.Text().Trim(); - - // HoT search returns should support AND search but it simply doesn't work, so we AND filter it manualy - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - var qSeeders = qRow.Find("td:eq(8)"); - var qLeechers = qRow.Find("td:eq(9)"); - var qDownloadLink = qRow.Find("a[href^=download.php]").First(); - var qTimeAgo = qRow.Find("td:eq(5)"); - var qSize = qRow.Find("td:eq(6)"); - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); - release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; - - var dateStr = qTimeAgo.Text(); - DateTime pubDateUtc; - var Timeparts = dateStr.Split(new char[] { ' ' }, 2)[1]; - if (dateStr.StartsWith("Today ")) - pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay; - else if (dateStr.StartsWith("Yesterday ")) - pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + - DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay - TimeSpan.FromDays(1); - else - pubDateUtc = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy hh:mm tt", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - release.PublishDate = pubDateUtc.ToLocalTime(); - +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class HouseOfTorrents : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public HouseOfTorrents(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "House-of-Torrents", + description: "A general tracker", + link: "https://houseoftorrents.club/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(42, TorznabCatType.PCMac); // Applications/Mac + AddCategoryMapping(34, TorznabCatType.PC); // Applications/PC + AddCategoryMapping(66, TorznabCatType.MoviesForeign); // Foreign + AddCategoryMapping(38, TorznabCatType.MoviesForeign); // Foreign/French + AddCategoryMapping(39, TorznabCatType.MoviesForeign); // Foreign/German + AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Foreign/Spanish + AddCategoryMapping(41, TorznabCatType.MoviesForeign); // Foreign/Swedish + AddCategoryMapping(67, TorznabCatType.ConsoleNDS); // Games/Nintendo + AddCategoryMapping(9 , TorznabCatType.PCGames); // Games/PC + AddCategoryMapping(8, TorznabCatType.ConsolePS3); // Games/PS3 + AddCategoryMapping(30, TorznabCatType.ConsolePS4); // Games/PS4 + AddCategoryMapping(7, TorznabCatType.ConsolePSP); // Games/PSP + AddCategoryMapping(29, TorznabCatType.ConsoleWii); // Games/Wii + AddCategoryMapping(31, TorznabCatType.ConsoleXbox360); // Games/XBOX360 + AddCategoryMapping(32, TorznabCatType.ConsoleXboxOne); // Games/XBOXONE + AddCategoryMapping(71, TorznabCatType.PCPhoneAndroid); // Mobile/Android + AddCategoryMapping(72, TorznabCatType.PCPhoneIOS); // Mobile/iOS + AddCategoryMapping(47, TorznabCatType.Movies3D); // Movies/3D + AddCategoryMapping(43, TorznabCatType.MoviesBluRay); // Movies/Bluray + AddCategoryMapping(84, TorznabCatType.MoviesSD); // Movies/Cam + AddCategoryMapping(44, TorznabCatType.MoviesDVD); // Movies/DVD-R + AddCategoryMapping(45, TorznabCatType.Movies); // Movies/MP4 + AddCategoryMapping(69, TorznabCatType.Movies); // Movies/Packs + AddCategoryMapping(46, TorznabCatType.MoviesSD); // Movies/SD + AddCategoryMapping(11, TorznabCatType.MoviesHD); // Movies/x264 + AddCategoryMapping(83, TorznabCatType.MoviesHD); // Movies/x265 + AddCategoryMapping(10, TorznabCatType.MoviesOther); // Movies/XviD + AddCategoryMapping(36, TorznabCatType.AudioLossless); // Music/FLAC + AddCategoryMapping(12, TorznabCatType.AudioMP3); // Music/MP3 + AddCategoryMapping(79, TorznabCatType.Audio); // Music/Pack + AddCategoryMapping(28, TorznabCatType.AudioVideo); // Music/Video + AddCategoryMapping(49, TorznabCatType.TVAnime); // Others/Anime + AddCategoryMapping(80, TorznabCatType.AudioAudiobook); // Others/AudioBook + AddCategoryMapping(60, TorznabCatType.Other); // Others/Boxsets + AddCategoryMapping(65, TorznabCatType.TVDocumentary); // Others/Documentary + AddCategoryMapping(61, TorznabCatType.Books); // Others/E-Book + AddCategoryMapping(51, TorznabCatType.Other); // Others/RARFIX + AddCategoryMapping(74, TorznabCatType.TVSport); // Sports + AddCategoryMapping(75, TorznabCatType.TVSport); // Sports/Boxing + AddCategoryMapping(76, TorznabCatType.TVSport); // Sports/Racing + AddCategoryMapping(77, TorznabCatType.TVSport); // Sports/UFC + AddCategoryMapping(78, TorznabCatType.TVSport); // Sports/WWE + AddCategoryMapping(68, TorznabCatType.TV); // TV/Packs + AddCategoryMapping(53, TorznabCatType.TVSD); // TV/SD + AddCategoryMapping(54, TorznabCatType.TVHD); // TV/x264 + AddCategoryMapping(82, TorznabCatType.TVHD); // TV/x265 + AddCategoryMapping(55, TorznabCatType.TVOTHER); // Tv/XviD + AddCategoryMapping(63, TorznabCatType.XXX); // XXX + AddCategoryMapping(57, TorznabCatType.XXX); // XXX/0-DAY + AddCategoryMapping(58, TorznabCatType.XXXImageset); // XXX/IMAGESET + AddCategoryMapping(81, TorznabCatType.XXXPacks); // XXX/Pack + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + // reset cookies, if we send expired cookies for a new session their code seems to get confused + // Due to the session not getting initiated correctly it will result in errors like this: + // Notice: Undefined index: simpleCaptchaAnswer in /var/www/html/takelogin.php on line 17 + CookieHeader = null; + + var result1 = await RequestStringWithCookies(CaptchaUrl); + var json1 = JObject.Parse(result1.Content); + var captchaSelection = json1["images"][0]["hash"]; + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "captchaSelection", (string)captchaSelection }, + { "submitme", "X" } + }; + + var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); + + await ConfigureIfOK(result2.Cookies, result2.Content.Contains("logout.php"), () => + { + var errorMessage = result2.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("searchin", "title"); + queryCollection.Add("incldead", "1"); + if (!string.IsNullOrWhiteSpace(searchString)) + { + // use AND+wildcard operator to avoid getting to many useless results + var searchStringArray = Regex.Split(searchString.Trim(), "[ _.-]+", RegexOptions.Compiled).ToList(); + searchStringArray = searchStringArray.Where(x => x.Length >= 3).ToList(); // remove words with less than 3 characters + searchStringArray = searchStringArray.Select(x => "+" + x).ToList(); // add AND operators+wildcards + var searchStringFinal = String.Join("", searchStringArray); + queryCollection.Add("search", searchStringFinal); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + + if (results.IsRedirect) + { + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl); + } + + try + { + CQ dom = results.Content; + var rows = dom["table.tt > tbody > tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Text().Trim(); + + // HoT search returns should support AND search but it simply doesn't work, so we AND filter it manualy + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qSeeders = qRow.Find("td:eq(8)"); + var qLeechers = qRow.Find("td:eq(9)"); + var qDownloadLink = qRow.Find("a[href^=download.php]").First(); + var qTimeAgo = qRow.Find("td:eq(5)"); + var qSize = qRow.Find("td:eq(6)"); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var dateStr = qTimeAgo.Text(); + DateTime pubDateUtc; + var Timeparts = dateStr.Split(new char[] { ' ' }, 2)[1]; + if (dateStr.StartsWith("Today ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay; + else if (dateStr.StartsWith("Yesterday ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay - TimeSpan.FromDays(1); + else + pubDateUtc = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy hh:mm tt", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + release.PublishDate = pubDateUtc.ToLocalTime(); + var files = qRow.Find("td:nth-child(4)").Text(); release.Files = ParseUtil.CoerceInt(files); var grabs = qRow.Find("td:nth-child(8) > a").Html(); release.Grabs = ParseUtil.CoerceInt(grabs.Split('<')[0]); - release.DownloadVolumeFactor = 0; // ratioless + release.DownloadVolumeFactor = 0; // ratioless - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/IIndexer.cs b/src/Jackett/Indexers/IIndexer.cs index 11ccf608..a9f97681 100644 --- a/src/Jackett/Indexers/IIndexer.cs +++ b/src/Jackett/Indexers/IIndexer.cs @@ -25,9 +25,9 @@ namespace Jackett.Indexers TorznabCapabilities TorznabCaps { get; } // Whether this indexer has been configured, verified and saved in the past and has the settings required for functioning - bool IsConfigured { get; } - - // Retrieved for starting setup for the indexer via web API + bool IsConfigured { get; } + + // Retrieved for starting setup for the indexer via web API Task<ConfigurationData> GetConfigurationForSetup(); // Called when web API wants to apply setup configuration via web API, usually this is where login and storing cookie happens diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index c132c2b5..0be5f894 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -21,8 +21,8 @@ namespace Jackett.Indexers { public class IPTorrents : BaseIndexer, IIndexer { - string LoginUrl { get { return SiteLink + "login.php"; } } - string TakeLoginUrl { get { return SiteLink + "take_login.php"; } } + string LoginUrl { get { return SiteLink + "login.php"; } } + string TakeLoginUrl { get { return SiteLink + "take_login.php"; } } private string BrowseUrl { get { return SiteLink + "t"; } } public new string[] AlternativeSiteLinks { get; protected set; } = new string[] { "https://ipt-update.com/", "https://iptorrents.com/", "https://iptorrents.eu/", "https://nemo.iptorrents.com/", "https://ipt.rocks/" }; @@ -47,94 +47,94 @@ namespace Jackett.Indexers Language = "en-us"; Type = "private"; - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(72, TorznabCatType.Movies, "Movies"); - AddCategoryMapping(87, TorznabCatType.Movies3D, "Movie/3D"); - AddCategoryMapping(77, TorznabCatType.MoviesSD, "Movie/480p"); - AddCategoryMapping(89, TorznabCatType.MoviesSD, "Movie/BD-R"); - AddCategoryMapping(90, TorznabCatType.MoviesSD, "Movie/BD-Rip"); - AddCategoryMapping(96, TorznabCatType.MoviesSD, "Movie/Cam"); - AddCategoryMapping(6, TorznabCatType.MoviesDVD, "Movie/DVD-R"); - AddCategoryMapping(48, TorznabCatType.MoviesBluRay, "Movie/HD/Bluray"); - AddCategoryMapping(54, TorznabCatType.Movies, "Movie/Kids"); - AddCategoryMapping(62, TorznabCatType.MoviesSD, "Movie/MP4"); - AddCategoryMapping(38, TorznabCatType.MoviesForeign, "Movie/Non-English"); - AddCategoryMapping(68, TorznabCatType.Movies, "Movie/Packs"); - AddCategoryMapping(20, TorznabCatType.MoviesHD, "Movie/Web-DL"); - AddCategoryMapping(7, TorznabCatType.MoviesSD, "Movie/Xvid"); - AddCategoryMapping(100, TorznabCatType.Movies, "Movie/x265"); - - AddCategoryMapping(73, TorznabCatType.TV, "TV"); - AddCategoryMapping(26, TorznabCatType.TVDocumentary, "Documentaries"); - AddCategoryMapping(55, TorznabCatType.TVSport, "Sports"); - AddCategoryMapping(78, TorznabCatType.TVSD, "TV/480p"); - AddCategoryMapping(23, TorznabCatType.TVHD, "TV/BD"); - AddCategoryMapping(24, TorznabCatType.TVSD, "TV/DVD-R"); - AddCategoryMapping(25, TorznabCatType.TVSD, "TV/DVD-Rip"); - AddCategoryMapping(66, TorznabCatType.TVSD, "TV/Mobile"); - AddCategoryMapping(82, TorznabCatType.TVFOREIGN, "TV/Non-English"); - AddCategoryMapping(65, TorznabCatType.TV, "TV/Packs"); - AddCategoryMapping(83, TorznabCatType.TVFOREIGN, "TV/Packs/Non-English"); - AddCategoryMapping(79, TorznabCatType.TVSD, "TV/SD/x264"); - AddCategoryMapping(22, TorznabCatType.TVWEBDL, "TV/Web-DL"); - AddCategoryMapping(5, TorznabCatType.TVHD, "TV/x264"); - AddCategoryMapping(99, TorznabCatType.TVHD, "TV/x265"); - AddCategoryMapping(4, TorznabCatType.TVSD, "TV/Xvid"); - - AddCategoryMapping(74, TorznabCatType.Console, "Games"); - AddCategoryMapping(2, TorznabCatType.ConsoleOther, "Games/Mixed"); - AddCategoryMapping(47, TorznabCatType.ConsoleNDS, "Games/Nintendo DS"); - AddCategoryMapping(43, TorznabCatType.PCISO, "Games/PC-ISO"); - AddCategoryMapping(45, TorznabCatType.PCGames, "Games/PC-Rip"); - AddCategoryMapping(39, TorznabCatType.ConsolePS3, "Games/PS2"); - AddCategoryMapping(71, TorznabCatType.ConsolePS3, "Games/PS3"); - AddCategoryMapping(40, TorznabCatType.ConsolePSP, "Games/PSP"); - AddCategoryMapping(50, TorznabCatType.ConsoleWii, "Games/Wii"); - AddCategoryMapping(44, TorznabCatType.ConsoleXbox360, "Games/Xbox-360"); - - AddCategoryMapping(75, TorznabCatType.Audio, "Music"); - AddCategoryMapping(3, TorznabCatType.AudioMP3, "Music/Audio"); - AddCategoryMapping(80, TorznabCatType.AudioLossless, "Music/Flac"); - AddCategoryMapping(93, TorznabCatType.Audio, "Music/Packs"); - AddCategoryMapping(37, TorznabCatType.AudioVideo, "Music/Video"); - AddCategoryMapping(21, TorznabCatType.AudioVideo, "Podcast"); - - AddCategoryMapping(76, TorznabCatType.Other, "Miscellaneous"); - AddCategoryMapping(60, TorznabCatType.TVAnime, "Anime"); - AddCategoryMapping(1, TorznabCatType.PC0day, "Appz"); - AddCategoryMapping(86, TorznabCatType.PC0day, "Appz/Non-English"); - AddCategoryMapping(64, TorznabCatType.AudioAudiobook, "AudioBook"); - AddCategoryMapping(35, TorznabCatType.Books, "Books"); - AddCategoryMapping(94, TorznabCatType.BooksComics, "Comics"); - AddCategoryMapping(95, TorznabCatType.BooksOther, "Educational"); - AddCategoryMapping(98, TorznabCatType.Other, "Fonts"); - AddCategoryMapping(69, TorznabCatType.PCMac, "Mac"); - AddCategoryMapping(92, TorznabCatType.BooksMagazines, "Magazines / Newspapers"); - AddCategoryMapping(58, TorznabCatType.PCPhoneOther, "Mobile"); - AddCategoryMapping(36, TorznabCatType.Other, "Pics/Wallpapers"); - - AddCategoryMapping(88, TorznabCatType.XXX, "XXX"); - AddCategoryMapping(85, TorznabCatType.XXXOther, "XXX/Magazines"); - AddCategoryMapping(8, TorznabCatType.XXX, "XXX/Movie"); - AddCategoryMapping(81, TorznabCatType.XXX, "XXX/Movie/0Day"); - AddCategoryMapping(91, TorznabCatType.XXXPacks, "XXX/Packs"); + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(72, TorznabCatType.Movies, "Movies"); + AddCategoryMapping(87, TorznabCatType.Movies3D, "Movie/3D"); + AddCategoryMapping(77, TorznabCatType.MoviesSD, "Movie/480p"); + AddCategoryMapping(89, TorznabCatType.MoviesSD, "Movie/BD-R"); + AddCategoryMapping(90, TorznabCatType.MoviesSD, "Movie/BD-Rip"); + AddCategoryMapping(96, TorznabCatType.MoviesSD, "Movie/Cam"); + AddCategoryMapping(6, TorznabCatType.MoviesDVD, "Movie/DVD-R"); + AddCategoryMapping(48, TorznabCatType.MoviesBluRay, "Movie/HD/Bluray"); + AddCategoryMapping(54, TorznabCatType.Movies, "Movie/Kids"); + AddCategoryMapping(62, TorznabCatType.MoviesSD, "Movie/MP4"); + AddCategoryMapping(38, TorznabCatType.MoviesForeign, "Movie/Non-English"); + AddCategoryMapping(68, TorznabCatType.Movies, "Movie/Packs"); + AddCategoryMapping(20, TorznabCatType.MoviesHD, "Movie/Web-DL"); + AddCategoryMapping(7, TorznabCatType.MoviesSD, "Movie/Xvid"); + AddCategoryMapping(100, TorznabCatType.Movies, "Movie/x265"); + + AddCategoryMapping(73, TorznabCatType.TV, "TV"); + AddCategoryMapping(26, TorznabCatType.TVDocumentary, "Documentaries"); + AddCategoryMapping(55, TorznabCatType.TVSport, "Sports"); + AddCategoryMapping(78, TorznabCatType.TVSD, "TV/480p"); + AddCategoryMapping(23, TorznabCatType.TVHD, "TV/BD"); + AddCategoryMapping(24, TorznabCatType.TVSD, "TV/DVD-R"); + AddCategoryMapping(25, TorznabCatType.TVSD, "TV/DVD-Rip"); + AddCategoryMapping(66, TorznabCatType.TVSD, "TV/Mobile"); + AddCategoryMapping(82, TorznabCatType.TVFOREIGN, "TV/Non-English"); + AddCategoryMapping(65, TorznabCatType.TV, "TV/Packs"); + AddCategoryMapping(83, TorznabCatType.TVFOREIGN, "TV/Packs/Non-English"); + AddCategoryMapping(79, TorznabCatType.TVSD, "TV/SD/x264"); + AddCategoryMapping(22, TorznabCatType.TVWEBDL, "TV/Web-DL"); + AddCategoryMapping(5, TorznabCatType.TVHD, "TV/x264"); + AddCategoryMapping(99, TorznabCatType.TVHD, "TV/x265"); + AddCategoryMapping(4, TorznabCatType.TVSD, "TV/Xvid"); + + AddCategoryMapping(74, TorznabCatType.Console, "Games"); + AddCategoryMapping(2, TorznabCatType.ConsoleOther, "Games/Mixed"); + AddCategoryMapping(47, TorznabCatType.ConsoleNDS, "Games/Nintendo DS"); + AddCategoryMapping(43, TorznabCatType.PCISO, "Games/PC-ISO"); + AddCategoryMapping(45, TorznabCatType.PCGames, "Games/PC-Rip"); + AddCategoryMapping(39, TorznabCatType.ConsolePS3, "Games/PS2"); + AddCategoryMapping(71, TorznabCatType.ConsolePS3, "Games/PS3"); + AddCategoryMapping(40, TorznabCatType.ConsolePSP, "Games/PSP"); + AddCategoryMapping(50, TorznabCatType.ConsoleWii, "Games/Wii"); + AddCategoryMapping(44, TorznabCatType.ConsoleXbox360, "Games/Xbox-360"); + + AddCategoryMapping(75, TorznabCatType.Audio, "Music"); + AddCategoryMapping(3, TorznabCatType.AudioMP3, "Music/Audio"); + AddCategoryMapping(80, TorznabCatType.AudioLossless, "Music/Flac"); + AddCategoryMapping(93, TorznabCatType.Audio, "Music/Packs"); + AddCategoryMapping(37, TorznabCatType.AudioVideo, "Music/Video"); + AddCategoryMapping(21, TorznabCatType.AudioVideo, "Podcast"); + + AddCategoryMapping(76, TorznabCatType.Other, "Miscellaneous"); + AddCategoryMapping(60, TorznabCatType.TVAnime, "Anime"); + AddCategoryMapping(1, TorznabCatType.PC0day, "Appz"); + AddCategoryMapping(86, TorznabCatType.PC0day, "Appz/Non-English"); + AddCategoryMapping(64, TorznabCatType.AudioAudiobook, "AudioBook"); + AddCategoryMapping(35, TorznabCatType.Books, "Books"); + AddCategoryMapping(94, TorznabCatType.BooksComics, "Comics"); + AddCategoryMapping(95, TorznabCatType.BooksOther, "Educational"); + AddCategoryMapping(98, TorznabCatType.Other, "Fonts"); + AddCategoryMapping(69, TorznabCatType.PCMac, "Mac"); + AddCategoryMapping(92, TorznabCatType.BooksMagazines, "Magazines / Newspapers"); + AddCategoryMapping(58, TorznabCatType.PCPhoneOther, "Mobile"); + AddCategoryMapping(36, TorznabCatType.Other, "Pics/Wallpapers"); + + AddCategoryMapping(88, TorznabCatType.XXX, "XXX"); + AddCategoryMapping(85, TorznabCatType.XXXOther, "XXX/Magazines"); + AddCategoryMapping(8, TorznabCatType.XXX, "XXX/Movie"); + AddCategoryMapping(81, TorznabCatType.XXX, "XXX/Movie/0Day"); + AddCategoryMapping(91, TorznabCatType.XXXPacks, "XXX/Packs"); AddCategoryMapping(84, TorznabCatType.XXXImageset, "XXX/Pics/Wallpapers"); } - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - CQ cq = loginPage.Content; - var captcha = cq.Find(".g-recaptcha"); - if(captcha.Any()) - { - var result = this.configData; - result.CookieHeader.Value = loginPage.Cookies; - result.Captcha.SiteKey = captcha.Attr("data-sitekey"); - result.Captcha.Version = "2"; - return result; - } + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + CQ cq = loginPage.Content; + var captcha = cq.Find(".g-recaptcha"); + if(captcha.Any()) + { + var result = this.configData; + result.CookieHeader.Value = loginPage.Cookies; + result.Captcha.SiteKey = captcha.Attr("data-sitekey"); + result.Captcha.Version = "2"; + return result; + } else { var result = new ConfigurationDataBasicLogin(); @@ -144,7 +144,7 @@ namespace Jackett.Indexers result.Password.Value = configData.Password.Value; result.CookieHeader.Value = loginPage.Cookies; return result; - } + } } @@ -280,8 +280,8 @@ namespace Jackett.Indexers var grabs = row.Cq().Find("td:nth-last-child(3)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if(row.Cq().Find("span.t_tag_free_leech").Any()) - release.DownloadVolumeFactor = 0; + if(row.Cq().Find("span.t_tag_free_leech").Any()) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/ImmortalSeed.cs b/src/Jackett/Indexers/ImmortalSeed.cs index cadd69d5..02c5825c 100644 --- a/src/Jackett/Indexers/ImmortalSeed.cs +++ b/src/Jackett/Indexers/ImmortalSeed.cs @@ -85,7 +85,7 @@ namespace Jackett.Indexers await ConfigureIfOK(response.Cookies, response.Content.Contains("/logout.php"), () => { - var errorMessage = response.Content; + var errorMessage = response.Content; throw new ExceptionWithConfigData(errorMessage, configData); }); @@ -105,10 +105,10 @@ namespace Jackett.Indexers var results = await RequestStringWithCookiesAndRetry(searchUrl); // Occasionally the cookies become invalid, login again if that happens - if (results.Content.Contains("You do not have permission to access this page.")) - { - await ApplyConfiguration(null); - results = await RequestStringWithCookiesAndRetry(searchUrl); + if (results.Content.Contains("You do not have permission to access this page.")) + { + await ApplyConfiguration(null); + results = await RequestStringWithCookiesAndRetry(searchUrl); } try @@ -121,12 +121,12 @@ namespace Jackett.Indexers var release = new ReleaseInfo(); var qRow = row.Cq(); - var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long - var qTitle = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip - if (!qTitle.Any()) // fallback to Details link if there's no tooltip - { - qTitle = qDetails; - } + var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long + var qTitle = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip + if (!qTitle.Any()) // fallback to Details link if there's no tooltip + { + qTitle = qDetails; + } release.Title = qTitle.Text(); var qDesciption = qRow.Find(".tooltip-content > div"); @@ -160,10 +160,10 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(6)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[title^=\"Free Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[title^=\"Silver Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; + if (qRow.Find("img[title^=\"Free Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[title^=\"Silver Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs index 41895de7..1e62c00a 100644 --- a/src/Jackett/Indexers/MoreThanTV.cs +++ b/src/Jackett/Indexers/MoreThanTV.cs @@ -15,8 +15,8 @@ using AngleSharp.Dom; using AngleSharp.Parser.Html; using CsQuery; using Jackett.Models.IndexerConfig; -using Jackett.Utils; - +using Jackett.Utils; + namespace Jackett.Indexers { public class MoreThanTV : BaseIndexer, IIndexer @@ -109,11 +109,11 @@ namespace Jackett.Indexers { var searchUrl = GetTorrentSearchUrl(query.Categories, searchQuery); var response = await RequestStringWithCookiesAndRetry(searchUrl); - if (response.IsRedirect) - { - // re login - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(searchUrl); + if (response.IsRedirect) + { + // re login + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(searchUrl); } try @@ -165,8 +165,8 @@ namespace Jackett.Indexers qualityData[1].Trim(), qualityEdition, // Audio quality should be after this one. Unobtainable at the moment. $"{qualityData[0].Trim()}-MTV" - }); - + }); + releases.Add(GetReleaseInfo(groupItem, downloadAnchor, title, TorznabCatType.TV.ID)); } else diff --git a/src/Jackett/Indexers/MyAnonamouse.cs b/src/Jackett/Indexers/MyAnonamouse.cs index 53a3dd44..46387efa 100644 --- a/src/Jackett/Indexers/MyAnonamouse.cs +++ b/src/Jackett/Indexers/MyAnonamouse.cs @@ -196,8 +196,8 @@ namespace Jackett.Indexers foreach (IDomObject row in rows) { CQ torrentData = row.OuterHTML; - CQ cells = row.Cq().Find("td"); - + CQ cells = row.Cq().Find("td"); + string tid = torrentData.Attr("id").Substring(4); var qTitle = torrentData.Find("a[class='title']").First(); string title = qTitle.Text().Trim(); @@ -234,14 +234,14 @@ namespace Jackett.Indexers release.MinimumRatio = 1; release.MinimumSeedTime = 172800; release.Category = MapTrackerCatToNewznab(category.ToString()); - release.Comments = details; - - if (freeleech) - release.DownloadVolumeFactor = 0; + release.Comments = details; + + if (freeleech) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; releases.Add(release); } diff --git a/src/Jackett/Indexers/NCore.cs b/src/Jackett/Indexers/NCore.cs index af39a5b5..705f9108 100644 --- a/src/Jackett/Indexers/NCore.cs +++ b/src/Jackett/Indexers/NCore.cs @@ -1,122 +1,122 @@ -using CsQuery; -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.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig.Bespoke; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public class NCore : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string SearchUrl { get { return SiteLink + "torrents.php"; } } - private string[] LanguageCats = new string[] { "xvidser", "dvdser", "hdser", "xvid", "dvd", "dvd9", "hd", "mp3", "lossless", "ebook" }; - - new ConfigurationDataNCore configData - { - get { return (ConfigurationDataNCore)base.configData; } - set { base.configData = value; } - } - - public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "nCore", - description: "A Hungarian private torrent site.", - link: "https://ncore.cc/", - caps: new TorznabCapabilities(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataNCore()) - { - Encoding = Encoding.UTF8; - Language = "hu-hu"; - Type = "private"; - - AddCategoryMapping("xvid_hun", TorznabCatType.MoviesSD, "Film SD/HU"); - AddCategoryMapping("xvid", TorznabCatType.MoviesSD , "Film SD/EN"); - AddCategoryMapping("dvd_hun", TorznabCatType.MoviesDVD, "Film DVDR/HU"); - AddCategoryMapping("dvd", TorznabCatType.MoviesDVD, "Film DVDR/EN"); - AddCategoryMapping("dvd9_hun", TorznabCatType.MoviesDVD, "Film DVD9/HU"); - AddCategoryMapping("dvd9", TorznabCatType.MoviesDVD, "Film DVD9/EN"); - AddCategoryMapping("hd_hun", TorznabCatType.MoviesHD, "Film HD/HU"); - AddCategoryMapping("hd", TorznabCatType.MoviesHD, "Film HD/EN"); - - AddCategoryMapping("xvidser_hun", TorznabCatType.TVSD , "Sorozat SD/HU"); - AddCategoryMapping("xvidser", TorznabCatType.TVSD , "Sorozat SD/EN"); - AddCategoryMapping("dvdser_hun", TorznabCatType.TVSD , "Sorozat DVDR/HU"); - AddCategoryMapping("dvdser", TorznabCatType.TVSD, "Sorozat DVDR/EN"); - AddCategoryMapping("hdser_hun", TorznabCatType.TVHD, "Sorozat HD/HU"); - AddCategoryMapping("hdser", TorznabCatType.TVHD , "Sorozat HD/EN"); - - AddCategoryMapping("mp3_hun", TorznabCatType.AudioMP3 , "Zene MP3/HU"); - AddCategoryMapping("mp3", TorznabCatType.AudioMP3, "Zene MP3/EN"); - AddCategoryMapping("lossless_hun", TorznabCatType.AudioLossless, "Zene Lossless/HU"); - AddCategoryMapping("lossless", TorznabCatType.AudioLossless, "Zene Lossless/EN"); - AddCategoryMapping("clip", TorznabCatType.AudioVideo , "Zene Klip"); - - AddCategoryMapping("xxx_xvid", TorznabCatType.XXXXviD , "XXX SD"); - AddCategoryMapping("xxx_dvd", TorznabCatType.XXXDVD, "XXX DVDR"); - AddCategoryMapping("xxx_imageset", TorznabCatType.XXXImageset , "XXX Imageset"); - AddCategoryMapping("xxx_hd", TorznabCatType.XXX , "XXX HD"); - - AddCategoryMapping("game_iso", TorznabCatType.PCGames , "Játék PC/ISO"); - AddCategoryMapping("game_rip", TorznabCatType.PCGames , "Játék PC/RIP"); - AddCategoryMapping("console", TorznabCatType.Console , "Játék Konzol"); - - AddCategoryMapping("iso", TorznabCatType.PCISO , "Program Prog/ISO"); - AddCategoryMapping("misc", TorznabCatType.PC0day , "Program Prog/RIP"); - AddCategoryMapping("mobil", TorznabCatType.PCPhoneOther , "Program Prog/Mobil"); - - AddCategoryMapping("ebook_hun", TorznabCatType.Books , "Könyv eBook/HU"); - AddCategoryMapping("ebook", TorznabCatType.Books , "Könyv eBook/EN"); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - if (configData.Hungarian.Value == false && configData.English.Value == false) - throw new ExceptionWithConfigData("Please select atleast one language.", configData); - - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - var pairs = new Dictionary<string, string> { - { "nev", configData.Username.Value }, - { "pass", configData.Password.Value }, - { "ne_leptessen_ki", "1"}, - { "set_lang", "en" }, - { "submitted", "1" }, - { "submit", "Access!" } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["#hibauzenet table tbody tr"]; - var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1); - var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login."; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); +using CsQuery; +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.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig.Bespoke; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class NCore : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string SearchUrl { get { return SiteLink + "torrents.php"; } } + private string[] LanguageCats = new string[] { "xvidser", "dvdser", "hdser", "xvid", "dvd", "dvd9", "hd", "mp3", "lossless", "ebook" }; + + new ConfigurationDataNCore configData + { + get { return (ConfigurationDataNCore)base.configData; } + set { base.configData = value; } + } + + public NCore(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "nCore", + description: "A Hungarian private torrent site.", + link: "https://ncore.cc/", + caps: new TorznabCapabilities(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataNCore()) + { + Encoding = Encoding.UTF8; + Language = "hu-hu"; + Type = "private"; + + AddCategoryMapping("xvid_hun", TorznabCatType.MoviesSD, "Film SD/HU"); + AddCategoryMapping("xvid", TorznabCatType.MoviesSD , "Film SD/EN"); + AddCategoryMapping("dvd_hun", TorznabCatType.MoviesDVD, "Film DVDR/HU"); + AddCategoryMapping("dvd", TorznabCatType.MoviesDVD, "Film DVDR/EN"); + AddCategoryMapping("dvd9_hun", TorznabCatType.MoviesDVD, "Film DVD9/HU"); + AddCategoryMapping("dvd9", TorznabCatType.MoviesDVD, "Film DVD9/EN"); + AddCategoryMapping("hd_hun", TorznabCatType.MoviesHD, "Film HD/HU"); + AddCategoryMapping("hd", TorznabCatType.MoviesHD, "Film HD/EN"); + + AddCategoryMapping("xvidser_hun", TorznabCatType.TVSD , "Sorozat SD/HU"); + AddCategoryMapping("xvidser", TorznabCatType.TVSD , "Sorozat SD/EN"); + AddCategoryMapping("dvdser_hun", TorznabCatType.TVSD , "Sorozat DVDR/HU"); + AddCategoryMapping("dvdser", TorznabCatType.TVSD, "Sorozat DVDR/EN"); + AddCategoryMapping("hdser_hun", TorznabCatType.TVHD, "Sorozat HD/HU"); + AddCategoryMapping("hdser", TorznabCatType.TVHD , "Sorozat HD/EN"); + + AddCategoryMapping("mp3_hun", TorznabCatType.AudioMP3 , "Zene MP3/HU"); + AddCategoryMapping("mp3", TorznabCatType.AudioMP3, "Zene MP3/EN"); + AddCategoryMapping("lossless_hun", TorznabCatType.AudioLossless, "Zene Lossless/HU"); + AddCategoryMapping("lossless", TorznabCatType.AudioLossless, "Zene Lossless/EN"); + AddCategoryMapping("clip", TorznabCatType.AudioVideo , "Zene Klip"); + + AddCategoryMapping("xxx_xvid", TorznabCatType.XXXXviD , "XXX SD"); + AddCategoryMapping("xxx_dvd", TorznabCatType.XXXDVD, "XXX DVDR"); + AddCategoryMapping("xxx_imageset", TorznabCatType.XXXImageset , "XXX Imageset"); + AddCategoryMapping("xxx_hd", TorznabCatType.XXX , "XXX HD"); + + AddCategoryMapping("game_iso", TorznabCatType.PCGames , "Játék PC/ISO"); + AddCategoryMapping("game_rip", TorznabCatType.PCGames , "Játék PC/RIP"); + AddCategoryMapping("console", TorznabCatType.Console , "Játék Konzol"); + + AddCategoryMapping("iso", TorznabCatType.PCISO , "Program Prog/ISO"); + AddCategoryMapping("misc", TorznabCatType.PC0day , "Program Prog/RIP"); + AddCategoryMapping("mobil", TorznabCatType.PCPhoneOther , "Program Prog/Mobil"); + + AddCategoryMapping("ebook_hun", TorznabCatType.Books , "Könyv eBook/HU"); + AddCategoryMapping("ebook", TorznabCatType.Books , "Könyv eBook/EN"); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + if (configData.Hungarian.Value == false && configData.English.Value == false) + throw new ExceptionWithConfigData("Please select atleast one language.", configData); + + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + var pairs = new Dictionary<string, string> { + { "nev", configData.Username.Value }, + { "pass", configData.Password.Value }, + { "ne_leptessen_ki", "1"}, + { "set_lang", "en" }, + { "submitted", "1" }, + { "submit", "Access!" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, loginPage.Cookies, true, referer: SiteLink); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("profile.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["#hibauzenet table tbody tr"]; + var msgContainer = messageEl.Get(0).ChildElements.ElementAt(1); + var errorMessage = msgContainer != null ? msgContainer.InnerText : "Error while trying to login."; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); var searchString = query.GetQueryString(); - var pairs = new List<KeyValuePair<string, string>>(); + var pairs = new List<KeyValuePair<string, string>>(); pairs.Add(new KeyValuePair<string, string>("nyit_sorozat_resz", "true")); pairs.Add(new KeyValuePair<string, string>("miben", "name")); @@ -125,83 +125,83 @@ namespace Jackett.Indexers pairs.Add(new KeyValuePair<string, string>("submit.y", "1")); pairs.Add(new KeyValuePair<string, string>("submit", "Ok")); pairs.Add(new KeyValuePair<string, string>("mire", searchString)); - - var cats = MapTorznabCapsToTrackers(query); - - if (cats.Count == 0) - cats = GetAllTrackerCategories(); - - foreach (var lcat in LanguageCats) - { - if (!configData.Hungarian.Value) - cats.Remove(lcat + "_hun"); - if (!configData.English.Value) - cats.Remove(lcat); - } - - foreach (var cat in cats) - { - pairs.Add(new KeyValuePair<string, string>("kivalasztott_tipus[]", cat)); - } - - var results = await PostDataWithCookiesAndRetry(SearchUrl, pairs); - - try - { - CQ dom = results.Content; - - ReleaseInfo release; - var rows = dom[".box_torrent_all"].Find(".box_torrent"); - - foreach (var row in rows) - { - CQ qRow = row.Cq(); - - release = new ReleaseInfo(); - var torrentTxt = qRow.Find(".torrent_txt, .torrent_txt2").Find("a").Get(0); - //if (torrentTxt == null) continue; - release.Title = torrentTxt.GetAttribute("title"); - release.Description = qRow.Find("div.siterank").Text(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 1; - - string downloadLink = SiteLink + torrentTxt.GetAttribute("href"); - string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4); - - release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId); - release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId); - release.Guid = new Uri(release.Comments.ToString() + "#comments"); ; - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders; - var imdblink = qRow.Find("a[href*=\".imdb.com/title\"]").Attr("href"); - release.Imdb = ParseUtil.GetLongFromString(imdblink); - var banner = qRow.Find("img.infobar_ico").Attr("onmouseover"); - if (banner != null) - { - Regex BannerRegEx = new Regex(@"mutat\('(.*?)', '", RegexOptions.Compiled); - var BannerMatch = BannerRegEx.Match(banner); - var bannerurl = BannerMatch.Groups[1].Value; - release.BannerUrl = new Uri(bannerurl); - } - release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("<br />", " "), CultureInfo.InvariantCulture); - string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' '); - release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); - string catlink = qRow.Find("a:has(img[class='categ_link'])").First().Attr("href"); - string cat = ParseUtil.GetArgumentFromQueryString(catlink, "tipus"); - release.Category = MapTrackerCatToNewznab(cat); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - - } -} + + var cats = MapTorznabCapsToTrackers(query); + + if (cats.Count == 0) + cats = GetAllTrackerCategories(); + + foreach (var lcat in LanguageCats) + { + if (!configData.Hungarian.Value) + cats.Remove(lcat + "_hun"); + if (!configData.English.Value) + cats.Remove(lcat); + } + + foreach (var cat in cats) + { + pairs.Add(new KeyValuePair<string, string>("kivalasztott_tipus[]", cat)); + } + + var results = await PostDataWithCookiesAndRetry(SearchUrl, pairs); + + try + { + CQ dom = results.Content; + + ReleaseInfo release; + var rows = dom[".box_torrent_all"].Find(".box_torrent"); + + foreach (var row in rows) + { + CQ qRow = row.Cq(); + + release = new ReleaseInfo(); + var torrentTxt = qRow.Find(".torrent_txt, .torrent_txt2").Find("a").Get(0); + //if (torrentTxt == null) continue; + release.Title = torrentTxt.GetAttribute("title"); + release.Description = qRow.Find("div.siterank").Text(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + + string downloadLink = SiteLink + torrentTxt.GetAttribute("href"); + string downloadId = downloadLink.Substring(downloadLink.IndexOf("&id=") + 4); + + release.Link = new Uri(SiteLink.ToString() + "torrents.php?action=download&id=" + downloadId); + release.Comments = new Uri(SiteLink.ToString() + "torrents.php?action=details&id=" + downloadId); + release.Guid = new Uri(release.Comments.ToString() + "#comments"); ; + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".box_s2").Find("a").First().Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".box_l2").Find("a").First().Text()) + release.Seeders; + var imdblink = qRow.Find("a[href*=\".imdb.com/title\"]").Attr("href"); + release.Imdb = ParseUtil.GetLongFromString(imdblink); + var banner = qRow.Find("img.infobar_ico").Attr("onmouseover"); + if (banner != null) + { + Regex BannerRegEx = new Regex(@"mutat\('(.*?)', '", RegexOptions.Compiled); + var BannerMatch = BannerRegEx.Match(banner); + var bannerurl = BannerMatch.Groups[1].Value; + release.BannerUrl = new Uri(bannerurl); + } + release.PublishDate = DateTime.Parse(qRow.Find(".box_feltoltve2").Get(0).InnerHTML.Replace("<br />", " "), CultureInfo.InvariantCulture); + string[] sizeSplit = qRow.Find(".box_meret2").Get(0).InnerText.Split(' '); + release.Size = ReleaseInfo.GetBytes(sizeSplit[1].ToLower(), ParseUtil.CoerceFloat(sizeSplit[0])); + string catlink = qRow.Find("a:has(img[class='categ_link'])").First().Attr("href"); + string cat = ParseUtil.GetArgumentFromQueryString(catlink, "tipus"); + release.Category = MapTrackerCatToNewznab(cat); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + + } +} diff --git a/src/Jackett/Indexers/NewRealWorld.cs b/src/Jackett/Indexers/NewRealWorld.cs index 77283b29..b8d03ac3 100644 --- a/src/Jackett/Indexers/NewRealWorld.cs +++ b/src/Jackett/Indexers/NewRealWorld.cs @@ -10,9 +10,9 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; - +using System.Collections.Specialized; +using System.Text; + namespace Jackett.Indexers { public class NewRealWorld : BaseIndexer, IIndexer @@ -41,57 +41,57 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - AddCategoryMapping(39, TorznabCatType.TVAnime); // Anime: HD|1080p - AddCategoryMapping(38, TorznabCatType.TVAnime); // Anime: HD|720p - AddCategoryMapping(1, TorznabCatType.TVAnime); // Anime: SD - AddCategoryMapping(7, TorznabCatType.PCPhoneOther); // Appz: Handy-PDA - AddCategoryMapping(36, TorznabCatType.PCMac); // Appz: Mac - AddCategoryMapping(18, TorznabCatType.PC); // Appz: Sonstiges - AddCategoryMapping(17, TorznabCatType.PC); // Appz: Win - AddCategoryMapping(15, TorznabCatType.Audio); // Audio: DVD-R - AddCategoryMapping(49, TorznabCatType.AudioLossless); // Audio: Flac - AddCategoryMapping(30, TorznabCatType.AudioAudiobook); // Audio: Hörspiele - AddCategoryMapping(14, TorznabCatType.AudioMP3); // Audio: MP3 - AddCategoryMapping(22, TorznabCatType.AudioVideo); // Audio: Videoclip - AddCategoryMapping(19, TorznabCatType.Other); // Diverses: Sonstiges - AddCategoryMapping(43, TorznabCatType.TVDocumentary); // Dokus: HD - AddCategoryMapping(2, TorznabCatType.TVDocumentary); // Dokus: SD - AddCategoryMapping(3, TorznabCatType.Books); // Ebooks: Bücher - AddCategoryMapping(52, TorznabCatType.BooksComics); // Ebooks: Comics - AddCategoryMapping(53, TorznabCatType.BooksMagazines); // Ebooks: Magazine - AddCategoryMapping(55, TorznabCatType.BooksOther); // Ebooks: XXX - AddCategoryMapping(54, TorznabCatType.BooksOther); // Ebooks: Zeitungen - AddCategoryMapping(47, TorznabCatType.PCPhoneOther); // Games: Andere - AddCategoryMapping(32, TorznabCatType.PCMac); // Games: Mac - AddCategoryMapping(41, TorznabCatType.ConsoleNDS); // Games: NDS/3DS - AddCategoryMapping(4, TorznabCatType.PCGames); // Games: PC - AddCategoryMapping(5, TorznabCatType.ConsolePS3); // Games: PS2 - AddCategoryMapping(9, TorznabCatType.ConsolePS3); // Games: PS3 - AddCategoryMapping(6, TorznabCatType.ConsolePSP); // Games: PSP - AddCategoryMapping(28, TorznabCatType.ConsoleWii); // Games: Wii - AddCategoryMapping(31, TorznabCatType.ConsoleXbox); // Games: XboX - AddCategoryMapping(51, TorznabCatType.Movies3D); // Movies: 3D - AddCategoryMapping(37, TorznabCatType.MoviesBluRay); // Movies: BluRay - AddCategoryMapping(25, TorznabCatType.MoviesHD); // Movies: HD|1080p - AddCategoryMapping(29, TorznabCatType.MoviesHD); // Movies: HD|720p - AddCategoryMapping(11, TorznabCatType.MoviesDVD); // Movies: SD|DVD-R - AddCategoryMapping(8, TorznabCatType.MoviesSD); // Movies: SD|x264 - AddCategoryMapping(13, TorznabCatType.MoviesSD); // Movies: SD|XviD - AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Movies: US Movies - AddCategoryMapping(33, TorznabCatType.TV); // Serien: DVD-R - AddCategoryMapping(34, TorznabCatType.TVHD); // Serien: HD - AddCategoryMapping(56, TorznabCatType.TVHD); // Serien: Packs|HD - AddCategoryMapping(44, TorznabCatType.TVSD); // Serien: Packs|SD - AddCategoryMapping(16, TorznabCatType.TVSD); // Serien: SD - AddCategoryMapping(10, TorznabCatType.TVOTHER); // Serien: TV/Shows - AddCategoryMapping(21, TorznabCatType.TVFOREIGN); // Serien: US TV - AddCategoryMapping(24, TorznabCatType.TVSport); // Sport: Diverses - AddCategoryMapping(23, TorznabCatType.TVSport); // Sport: Wrestling - AddCategoryMapping(57, TorznabCatType.Movies); // Tracker - Crew: pmHD - AddCategoryMapping(58, TorznabCatType.MoviesHD); // Ultra-HD: 4K - AddCategoryMapping(46, TorznabCatType.XXXOther); // XXX: Diverses - AddCategoryMapping(50, TorznabCatType.XXX); // XXX: HD - AddCategoryMapping(45, TorznabCatType.XXXPacks); // XXX: Packs + AddCategoryMapping(39, TorznabCatType.TVAnime); // Anime: HD|1080p + AddCategoryMapping(38, TorznabCatType.TVAnime); // Anime: HD|720p + AddCategoryMapping(1, TorznabCatType.TVAnime); // Anime: SD + AddCategoryMapping(7, TorznabCatType.PCPhoneOther); // Appz: Handy-PDA + AddCategoryMapping(36, TorznabCatType.PCMac); // Appz: Mac + AddCategoryMapping(18, TorznabCatType.PC); // Appz: Sonstiges + AddCategoryMapping(17, TorznabCatType.PC); // Appz: Win + AddCategoryMapping(15, TorznabCatType.Audio); // Audio: DVD-R + AddCategoryMapping(49, TorznabCatType.AudioLossless); // Audio: Flac + AddCategoryMapping(30, TorznabCatType.AudioAudiobook); // Audio: Hörspiele + AddCategoryMapping(14, TorznabCatType.AudioMP3); // Audio: MP3 + AddCategoryMapping(22, TorznabCatType.AudioVideo); // Audio: Videoclip + AddCategoryMapping(19, TorznabCatType.Other); // Diverses: Sonstiges + AddCategoryMapping(43, TorznabCatType.TVDocumentary); // Dokus: HD + AddCategoryMapping(2, TorznabCatType.TVDocumentary); // Dokus: SD + AddCategoryMapping(3, TorznabCatType.Books); // Ebooks: Bücher + AddCategoryMapping(52, TorznabCatType.BooksComics); // Ebooks: Comics + AddCategoryMapping(53, TorznabCatType.BooksMagazines); // Ebooks: Magazine + AddCategoryMapping(55, TorznabCatType.BooksOther); // Ebooks: XXX + AddCategoryMapping(54, TorznabCatType.BooksOther); // Ebooks: Zeitungen + AddCategoryMapping(47, TorznabCatType.PCPhoneOther); // Games: Andere + AddCategoryMapping(32, TorznabCatType.PCMac); // Games: Mac + AddCategoryMapping(41, TorznabCatType.ConsoleNDS); // Games: NDS/3DS + AddCategoryMapping(4, TorznabCatType.PCGames); // Games: PC + AddCategoryMapping(5, TorznabCatType.ConsolePS3); // Games: PS2 + AddCategoryMapping(9, TorznabCatType.ConsolePS3); // Games: PS3 + AddCategoryMapping(6, TorznabCatType.ConsolePSP); // Games: PSP + AddCategoryMapping(28, TorznabCatType.ConsoleWii); // Games: Wii + AddCategoryMapping(31, TorznabCatType.ConsoleXbox); // Games: XboX + AddCategoryMapping(51, TorznabCatType.Movies3D); // Movies: 3D + AddCategoryMapping(37, TorznabCatType.MoviesBluRay); // Movies: BluRay + AddCategoryMapping(25, TorznabCatType.MoviesHD); // Movies: HD|1080p + AddCategoryMapping(29, TorznabCatType.MoviesHD); // Movies: HD|720p + AddCategoryMapping(11, TorznabCatType.MoviesDVD); // Movies: SD|DVD-R + AddCategoryMapping(8, TorznabCatType.MoviesSD); // Movies: SD|x264 + AddCategoryMapping(13, TorznabCatType.MoviesSD); // Movies: SD|XviD + AddCategoryMapping(40, TorznabCatType.MoviesForeign); // Movies: US Movies + AddCategoryMapping(33, TorznabCatType.TV); // Serien: DVD-R + AddCategoryMapping(34, TorznabCatType.TVHD); // Serien: HD + AddCategoryMapping(56, TorznabCatType.TVHD); // Serien: Packs|HD + AddCategoryMapping(44, TorznabCatType.TVSD); // Serien: Packs|SD + AddCategoryMapping(16, TorznabCatType.TVSD); // Serien: SD + AddCategoryMapping(10, TorznabCatType.TVOTHER); // Serien: TV/Shows + AddCategoryMapping(21, TorznabCatType.TVFOREIGN); // Serien: US TV + AddCategoryMapping(24, TorznabCatType.TVSport); // Sport: Diverses + AddCategoryMapping(23, TorznabCatType.TVSport); // Sport: Wrestling + AddCategoryMapping(57, TorznabCatType.Movies); // Tracker - Crew: pmHD + AddCategoryMapping(58, TorznabCatType.MoviesHD); // Ultra-HD: 4K + AddCategoryMapping(46, TorznabCatType.XXXOther); // XXX: Diverses + AddCategoryMapping(50, TorznabCatType.XXX); // XXX: HD + AddCategoryMapping(45, TorznabCatType.XXXPacks); // XXX: Packs AddCategoryMapping(27, TorznabCatType.XXX); // XXX: SD } @@ -118,36 +118,36 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("showsearch", "1"); - queryCollection.Add("incldead", "1"); - queryCollection.Add("orderby", "added"); - queryCollection.Add("sort", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - var cats = MapTorznabCapsToTrackers(query); - string cat = "0"; - if (cats.Count == 1) - { - cat = cats[0]; - } - queryCollection.Add("cat", cat); - + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("showsearch", "1"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("orderby", "added"); + queryCollection.Add("sort", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + var cats = MapTorznabCapsToTrackers(query); + string cat = "0"; + if (cats.Count == 1) + { + cat = cats[0]; + } + queryCollection.Add("cat", cat); + searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookies(searchUrl); @@ -160,52 +160,52 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 0.75; + release.MinimumRatio = 0.75; release.MinimumSeedTime = 0; - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - release.Title = qDetailsLink.Text(); - - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - var qSeeders = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(3)"); - var qLeechers = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(4)"); - var qDateStr = qRow.Find("td > table.testtable > tbody > tr > td:eq(6)"); - var qSize = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(1)"); - var qDownloadLink = qRow.Find("a[href*=download]").First(); - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - var dlLink = qDownloadLink.Attr("href"); - if(dlLink.Contains("javascript")) // depending on the user agent the DL link is a javascript call - { - var dlLinkParts = dlLink.Split(new char[] { '\'', ',' }); - dlLink = SiteLink + "download/" + dlLinkParts[3] + "/" + dlLinkParts[5]; - } - release.Link = new Uri(dlLink); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(".", "").Replace(",", ".")); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + release.Title = qDetailsLink.Text(); + + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qSeeders = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(3)"); + var qLeechers = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(4)"); + var qDateStr = qRow.Find("td > table.testtable > tbody > tr > td:eq(6)"); + var qSize = qRow.Find("td > table.testtable > tbody > tr > td > strong:eq(1)"); + var qDownloadLink = qRow.Find("a[href*=download]").First(); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + var dlLink = qDownloadLink.Attr("href"); + if(dlLink.Contains("javascript")) // depending on the user agent the DL link is a javascript call + { + var dlLinkParts = dlLink.Split(new char[] { '\'', ',' }); + dlLink = SiteLink + "download/" + dlLinkParts[3] + "/" + dlLinkParts[5]; + } + release.Link = new Uri(dlLink); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr.Replace(".", "").Replace(",", ".")); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text().Replace('\xA0', ' '); var dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc; var files = qRow.Find("td:contains(Datei) > strong ~ strong").Text(); release.Files = ParseUtil.CoerceInt(files); - if (qRow.Find("img[title=\"OnlyUpload\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("img[title=\"OnlyUpload\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/Norbits.cs b/src/Jackett/Indexers/Norbits.cs index bc9fbcf2..66292050 100644 --- a/src/Jackett/Indexers/Norbits.cs +++ b/src/Jackett/Indexers/Norbits.cs @@ -1,875 +1,875 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using CsQuery; -using Jackett.Models; -using Jackett.Models.IndexerConfig.Bespoke; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NLog; -using System.Text; - -namespace Jackett.Indexers -{ - /// <summary>s - /// Provider for Norbits Private Tracker - /// </summary> - public class Norbits : BaseIndexer, IIndexer - { - private string LoginUrl => SiteLink + "login.php"; - private string LoginCheckUrl => SiteLink + "takelogin.php"; - private string SearchUrl => SiteLink + "browse.php"; - private string TorrentCommentUrl => SiteLink + "details.php?id={id}&comonly=1#page1"; - private string TorrentDescriptionUrl => SiteLink + "details.php?id={id}"; - private string TorrentDownloadUrl => SiteLink + "download.php?id={id}&passkey={passkey}"; - private bool Latency => ConfigData.Latency.Value; - 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 + "\\"; - - private readonly Dictionary<string, string> _emulatedBrowserHeaders = new Dictionary<string, string>(); - private CQ _fDom; - private ConfigurationDataNorbits ConfigData => (ConfigurationDataNorbits)configData; - - public Norbits(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) - : base( - name: "Norbits", - description: "Norbits", - link: "https://norbits.net/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - downloadBase: "https://norbits.net/download.php?id=", - configData: new ConfigurationDataNorbits()) - { - Encoding = Encoding.GetEncoding("iso-8859-1"); - Language = "nb-no"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", TorznabCatType.MoviesHD, "Filmer - HD-1080p/i"); - AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", TorznabCatType.MoviesHD, "Filmer - HD-720p"); - AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", TorznabCatType.MoviesSD, "Filmer - SD"); - AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", TorznabCatType.TVHD, "TV - HD-1080p/i"); - AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", TorznabCatType.TVHD, "TV - HD-720p"); - AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", TorznabCatType.TVSD, "TV - SD"); - AddCategoryMapping("main_cat[]=3", TorznabCatType.PC, "Programmer"); - AddCategoryMapping("main_cat[]=4", TorznabCatType.Console, "Spill"); - AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", TorznabCatType.AudioMP3, "Musikk - 192"); - AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", TorznabCatType.AudioMP3, "Musikk - 256"); - AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", TorznabCatType.AudioMP3, "Musikk - 320"); - AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", TorznabCatType.AudioMP3, "Musikk - VBR"); - AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", TorznabCatType.AudioLossless, "Musikk - Lossless"); - AddCategoryMapping("main_cat[]=6", TorznabCatType.Books, "Tidsskrift"); - AddCategoryMapping("main_cat[]=7", TorznabCatType.AudioAudiobook, "Lydbøker"); - AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", TorznabCatType.AudioVideo, "Musikkvideoer - HD-1080p/i"); - AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", TorznabCatType.AudioVideo, "Musikkvideoer - HD-720p"); - AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", TorznabCatType.AudioVideo, "Musikkvideoer - SD"); - AddCategoryMapping("main_cat[]=40", TorznabCatType.AudioOther, "Podcasts"); - } - - /// <summary> - /// Configure our FADN Provider - /// </summary> - /// <param name="configJson">Our params in Json</param> - /// <returns>Configuration state</returns> - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - // Retrieve config values set by Jackett's user - 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"); - - // If we want to simulate a browser - if (ConfigData.Browser.Value) - { - - // Clean headers - _emulatedBrowserHeaders.Clear(); - - // Inject headers - _emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value); - _emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value); - _emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDnt.Value).ToString()); - _emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString()); - _emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value); - _emulatedBrowserHeaders.Add("Referer", LoginUrl); - } - - await DoLogin(); - - return IndexerConfigurationStatus.RequiresTesting; - } - - /// <summary> - /// Perform login to racker - /// </summary> - /// <returns></returns> - private async Task DoLogin() - { - // Build WebRequest for index - var myIndexRequest = new WebRequest() - { - Type = RequestType.GET, - Url = SiteLink, - Headers = _emulatedBrowserHeaders, - Encoding = Encoding - }; - - // Get index page for cookies - Output("\nGetting index page (for cookies).. with " + SiteLink); - var indexPage = await webclient.GetString(myIndexRequest); - - // Building login form data - var pairs = new Dictionary<string, string> { - { "username", ConfigData.Username.Value }, - { "password", ConfigData.Password.Value } - }; - - // Build WebRequest for login - var myRequestLogin = new WebRequest() - { - Type = RequestType.GET, - Url = LoginUrl, - Headers = _emulatedBrowserHeaders, - Cookies = indexPage.Cookies, - Referer = SiteLink, - Encoding = Encoding - }; - - // Get login page -- (not used, but simulation needed by tracker security's checks) - LatencyNow(); - Output("\nGetting login page (user simulation).. with " + LoginUrl); - await webclient.GetString(myRequestLogin); - - // Build WebRequest for submitting authentification - var request = new WebRequest() - { - PostData = pairs, - Referer = LoginUrl, - Type = RequestType.POST, - Url = LoginCheckUrl, - Headers = _emulatedBrowserHeaders, - Cookies = indexPage.Cookies, - Encoding = Encoding - }; - - // Perform loggin - LatencyNow(); - Output("\nPerform loggin.. with " + LoginCheckUrl); - var response = await webclient.GetString(request); - - // Test if we are logged in - await ConfigureIfOK(response.Cookies, response.Content != null && response.Cookies.Contains("uid="), () => - { - // Default error message - var message = "Error during attempt !"; - // Parse redirect header - var redirectTo = response.RedirectingTo; - - // Oops, unable to login - Output("-> Login failed: " + message, "error"); - throw new ExceptionWithConfigData("Login failed: " + message, configData); - }); - - Output("\nCookies saved for future uses..."); - ConfigData.CookieHeader.Value = indexPage.Cookies + " " + response.Cookies + " ts_username=" + ConfigData.Username.Value; - - Output("\n-> Login Success\n"); - } - - /// <summary> - /// Check logged-in state for provider - /// </summary> - /// <returns></returns> - private async Task CheckLogin() - { - // Checking ... - Output("\n-> Checking logged-in state...."); - var loggedInCheck = await RequestStringWithCookies(SearchUrl); - if (!loggedInCheck.Content.Contains("logout.php")) - { - // Cookie expired, renew session on provider - Output("-> Not logged, login now...\n"); - - await DoLogin(); - } - else - { - // Already logged, session active - Output("-> Already logged, continue...\n"); - } - } - - /// <summary> - /// Execute our search query - /// </summary> - /// <param name="query">Query</param> - /// <returns>Releases</returns> - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var torrentRowList = new List<CQ>(); - var exactSearchTerm = query.GetQueryString(); - var searchUrl = SearchUrl; - - // Check login before performing a query - await CheckLogin(); - - // Check cache first so we don't query the server (if search term used or not in dev mode) - if (!DevMode && !string.IsNullOrEmpty(exactSearchTerm)) - { - lock (cache) - { - // Remove old cache items - CleanCache(); - - // Search in cache - var cachedResult = cache.FirstOrDefault(i => i.Query == exactSearchTerm); - if (cachedResult != null) - return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); - } - } - - var SearchTerms = new List<string> { exactSearchTerm }; - - // duplicate search without diacritics - var baseSearchTerm = StringUtil.RemoveDiacritics(exactSearchTerm); - if (baseSearchTerm != exactSearchTerm) - SearchTerms.Add(baseSearchTerm); - - foreach (var searchTerm in SearchTerms) - { - // Build our query - var request = BuildQuery(searchTerm, query, searchUrl); - - // Getting results & Store content - var response = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value); - _fDom = response.Content; - - try - { - var firstPageRows = FindTorrentRows(); - - // Add them to torrents list - torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq())); - - // If pagination available - int nbResults; - int pageLinkCount; - nbResults = 1; - pageLinkCount = 1; - - // Check if we have a minimum of one result - if (firstPageRows.Length > 1) - { - // Retrieve total count on our alone page - nbResults = firstPageRows.Count(); - } - else - { - // Check if no result - if(torrentRowList.Count == 0) - { - // No results found - Output("\nNo result found for your query, please try another search term ...\n", "info"); - - // No result found for this query - break; - } - } - - Output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); - Output("\nThere are " + firstPageRows.Length + " results on the first page !"); - - // Loop on results - - foreach (var tRow in torrentRowList) - { - Output("Torrent #" + (releases.Count + 1)); - - // ID - var id = tRow.Find("td:eq(1) > a:eq(0)").Attr("href").Split('=').Last(); - Output("ID: " + id); - - // Release Name - var name = tRow.Find("td:eq(1) > a:eq(0)").Attr("title"); - - // Category - var categoryId = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last(); - var categoryName = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("title"); - - var MainCat = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last(); - var SubCat1 = "none"; - var SubCat2 = "none"; - - var testcat = MainCat; - - if (tRow.Find("td:eq(0) > div > a:eq(1)").Length == 1) - { - SubCat1 = tRow.Find("td:eq(0) > div > a:eq(1)").Attr("href").Split('?').Last(); - } - if (tRow.Find("td:eq(0) > div > a[href^=\"/browse.php?sub2_cat[]=\"]").Length == 1) - { - SubCat2 = tRow.Find("td:eq(0) > div > a[href^=\"/browse.php?sub2_cat[]=\"]").Attr("href").Split('?').Last(); - testcat = MainCat + '&' + SubCat2; - } - - Output("Category: " + testcat + " - " + categoryName); - - // Seeders - var seeders = ParseUtil.CoerceInt(tRow.Find("td:eq(9)").Text()); - Output("Seeders: " + seeders); - - // Leechers - var leechers = ParseUtil.CoerceInt(tRow.Find("td:eq(10)").Text()); - Output("Leechers: " + leechers); - - // Completed - Regex regexObj = new Regex(@"[^\d]"); - var completed2 = tRow.Find("td:eq(7)").Text(); - var completed = ParseUtil.CoerceLong(regexObj.Replace(completed2, "")); - Output("Completed: " + completed); - - // Files - var files = 1; - if (tRow.Find("td:eq(2) > a").Length == 1) - { - files = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(2) > a").Text(), @"\d+").Value); - } - Output("Files: " + files); - - // Health - var percent = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(8)").Text(), @"\d+").Value.Trim()); - Output("Health: " + percent + "%"); - - // Size - var humanSize = tRow.Find("td:eq(6)").Text().ToLowerInvariant(); - var size = ReleaseInfo.GetBytes(humanSize); - Output("Size: " + humanSize + " (" + size + " bytes)"); - - // --> Date - var dateTimeOrig = tRow.Find("td:eq(4)").Text(); - var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); - var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); - Output("Released on: " + date); - - // Torrent Details URL - var detailsLink = new Uri(TorrentDescriptionUrl.Replace("{id}", id.ToString())); - Output("Details: " + detailsLink.AbsoluteUri); - - // Torrent Comments URL - var commentsLink = new Uri(TorrentCommentUrl.Replace("{id}", id.ToString())); - Output("Comments Link: " + commentsLink.AbsoluteUri); - - // Torrent Download URL - var passkey = tRow.Find("td:eq(1) > a:eq(1)").Attr("href"); - var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)"); - Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); - Output("Download Link: " + downloadLink.AbsoluteUri); - - // Building release infos - var release = new ReleaseInfo - { - Category = MapTrackerCatToNewznab(testcat.ToString()), - Title = name, - Seeders = seeders, - Peers = seeders + leechers, - MinimumRatio = 1, - MinimumSeedTime = 172800, - PublishDate = date, - Size = size, - Files = files, - Grabs = completed, - Guid = detailsLink, - Comments = commentsLink, - Link = downloadLink - }; - - var genres = tRow.Find("span.genres").Text(); - if (!string.IsNullOrEmpty(genres)) - release.Description = genres; - - // IMDB - var imdbLink = tRow.Find("a[href*=\"http://imdb.com/title/\"]").First().Attr("href"); - release.Imdb = ParseUtil.GetLongFromString(imdbLink); - - if (tRow.Find("img[title=\"100% freeleech\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (tRow.Find("img[title=\"Halfleech\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; - else if (tRow.Find("img[title=\"90% Freeleech\"]").Length >= 1) - release.DownloadVolumeFactor = 0.1; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using CsQuery; +using Jackett.Models; +using Jackett.Models.IndexerConfig.Bespoke; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using System.Text; + +namespace Jackett.Indexers +{ + /// <summary>s + /// Provider for Norbits Private Tracker + /// </summary> + public class Norbits : BaseIndexer, IIndexer + { + private string LoginUrl => SiteLink + "login.php"; + private string LoginCheckUrl => SiteLink + "takelogin.php"; + private string SearchUrl => SiteLink + "browse.php"; + private string TorrentCommentUrl => SiteLink + "details.php?id={id}&comonly=1#page1"; + private string TorrentDescriptionUrl => SiteLink + "details.php?id={id}"; + private string TorrentDownloadUrl => SiteLink + "download.php?id={id}&passkey={passkey}"; + private bool Latency => ConfigData.Latency.Value; + 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 + "\\"; + + private readonly Dictionary<string, string> _emulatedBrowserHeaders = new Dictionary<string, string>(); + private CQ _fDom; + private ConfigurationDataNorbits ConfigData => (ConfigurationDataNorbits)configData; + + public Norbits(IIndexerManagerService i, IWebClient w, Logger l, IProtectionService ps) + : base( + name: "Norbits", + description: "Norbits", + link: "https://norbits.net/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + downloadBase: "https://norbits.net/download.php?id=", + configData: new ConfigurationDataNorbits()) + { + Encoding = Encoding.GetEncoding("iso-8859-1"); + Language = "nb-no"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", TorznabCatType.MoviesHD, "Filmer - HD-1080p/i"); + AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", TorznabCatType.MoviesHD, "Filmer - HD-720p"); + AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", TorznabCatType.MoviesSD, "Filmer - SD"); + AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", TorznabCatType.TVHD, "TV - HD-1080p/i"); + AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", TorznabCatType.TVHD, "TV - HD-720p"); + AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", TorznabCatType.TVSD, "TV - SD"); + AddCategoryMapping("main_cat[]=3", TorznabCatType.PC, "Programmer"); + AddCategoryMapping("main_cat[]=4", TorznabCatType.Console, "Spill"); + AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", TorznabCatType.AudioMP3, "Musikk - 192"); + AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", TorznabCatType.AudioMP3, "Musikk - 256"); + AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", TorznabCatType.AudioMP3, "Musikk - 320"); + AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", TorznabCatType.AudioMP3, "Musikk - VBR"); + AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", TorznabCatType.AudioLossless, "Musikk - Lossless"); + AddCategoryMapping("main_cat[]=6", TorznabCatType.Books, "Tidsskrift"); + AddCategoryMapping("main_cat[]=7", TorznabCatType.AudioAudiobook, "Lydbøker"); + AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", TorznabCatType.AudioVideo, "Musikkvideoer - HD-1080p/i"); + AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", TorznabCatType.AudioVideo, "Musikkvideoer - HD-720p"); + AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", TorznabCatType.AudioVideo, "Musikkvideoer - SD"); + AddCategoryMapping("main_cat[]=40", TorznabCatType.AudioOther, "Podcasts"); + } + + /// <summary> + /// Configure our FADN Provider + /// </summary> + /// <param name="configJson">Our params in Json</param> + /// <returns>Configuration state</returns> + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + // Retrieve config values set by Jackett's user + 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"); + + // If we want to simulate a browser + if (ConfigData.Browser.Value) + { + + // Clean headers + _emulatedBrowserHeaders.Clear(); + + // Inject headers + _emulatedBrowserHeaders.Add("Accept", ConfigData.HeaderAccept.Value); + _emulatedBrowserHeaders.Add("Accept-Language", ConfigData.HeaderAcceptLang.Value); + _emulatedBrowserHeaders.Add("DNT", Convert.ToInt32(ConfigData.HeaderDnt.Value).ToString()); + _emulatedBrowserHeaders.Add("Upgrade-Insecure-Requests", Convert.ToInt32(ConfigData.HeaderUpgradeInsecure.Value).ToString()); + _emulatedBrowserHeaders.Add("User-Agent", ConfigData.HeaderUserAgent.Value); + _emulatedBrowserHeaders.Add("Referer", LoginUrl); + } + + await DoLogin(); + + return IndexerConfigurationStatus.RequiresTesting; + } + + /// <summary> + /// Perform login to racker + /// </summary> + /// <returns></returns> + private async Task DoLogin() + { + // Build WebRequest for index + var myIndexRequest = new WebRequest() + { + Type = RequestType.GET, + Url = SiteLink, + Headers = _emulatedBrowserHeaders, + Encoding = Encoding + }; + + // Get index page for cookies + Output("\nGetting index page (for cookies).. with " + SiteLink); + var indexPage = await webclient.GetString(myIndexRequest); + + // Building login form data + var pairs = new Dictionary<string, string> { + { "username", ConfigData.Username.Value }, + { "password", ConfigData.Password.Value } + }; + + // Build WebRequest for login + var myRequestLogin = new WebRequest() + { + Type = RequestType.GET, + Url = LoginUrl, + Headers = _emulatedBrowserHeaders, + Cookies = indexPage.Cookies, + Referer = SiteLink, + Encoding = Encoding + }; + + // Get login page -- (not used, but simulation needed by tracker security's checks) + LatencyNow(); + Output("\nGetting login page (user simulation).. with " + LoginUrl); + await webclient.GetString(myRequestLogin); + + // Build WebRequest for submitting authentification + var request = new WebRequest() + { + PostData = pairs, + Referer = LoginUrl, + Type = RequestType.POST, + Url = LoginCheckUrl, + Headers = _emulatedBrowserHeaders, + Cookies = indexPage.Cookies, + Encoding = Encoding + }; + + // Perform loggin + LatencyNow(); + Output("\nPerform loggin.. with " + LoginCheckUrl); + var response = await webclient.GetString(request); + + // Test if we are logged in + await ConfigureIfOK(response.Cookies, response.Content != null && response.Cookies.Contains("uid="), () => + { + // Default error message + var message = "Error during attempt !"; + // Parse redirect header + var redirectTo = response.RedirectingTo; + + // Oops, unable to login + Output("-> Login failed: " + message, "error"); + throw new ExceptionWithConfigData("Login failed: " + message, configData); + }); + + Output("\nCookies saved for future uses..."); + ConfigData.CookieHeader.Value = indexPage.Cookies + " " + response.Cookies + " ts_username=" + ConfigData.Username.Value; + + Output("\n-> Login Success\n"); + } + + /// <summary> + /// Check logged-in state for provider + /// </summary> + /// <returns></returns> + private async Task CheckLogin() + { + // Checking ... + Output("\n-> Checking logged-in state...."); + var loggedInCheck = await RequestStringWithCookies(SearchUrl); + if (!loggedInCheck.Content.Contains("logout.php")) + { + // Cookie expired, renew session on provider + Output("-> Not logged, login now...\n"); + + await DoLogin(); + } + else + { + // Already logged, session active + Output("-> Already logged, continue...\n"); + } + } + + /// <summary> + /// Execute our search query + /// </summary> + /// <param name="query">Query</param> + /// <returns>Releases</returns> + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var torrentRowList = new List<CQ>(); + var exactSearchTerm = query.GetQueryString(); + var searchUrl = SearchUrl; + + // Check login before performing a query + await CheckLogin(); + + // Check cache first so we don't query the server (if search term used or not in dev mode) + if (!DevMode && !string.IsNullOrEmpty(exactSearchTerm)) + { + lock (cache) + { + // Remove old cache items + CleanCache(); + + // Search in cache + var cachedResult = cache.FirstOrDefault(i => i.Query == exactSearchTerm); + if (cachedResult != null) + return cachedResult.Results.Select(s => (ReleaseInfo)s.Clone()).ToArray(); + } + } + + var SearchTerms = new List<string> { exactSearchTerm }; + + // duplicate search without diacritics + var baseSearchTerm = StringUtil.RemoveDiacritics(exactSearchTerm); + if (baseSearchTerm != exactSearchTerm) + SearchTerms.Add(baseSearchTerm); + + foreach (var searchTerm in SearchTerms) + { + // Build our query + var request = BuildQuery(searchTerm, query, searchUrl); + + // Getting results & Store content + var response = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value); + _fDom = response.Content; + + try + { + var firstPageRows = FindTorrentRows(); + + // Add them to torrents list + torrentRowList.AddRange(firstPageRows.Select(fRow => fRow.Cq())); + + // If pagination available + int nbResults; + int pageLinkCount; + nbResults = 1; + pageLinkCount = 1; + + // Check if we have a minimum of one result + if (firstPageRows.Length > 1) + { + // Retrieve total count on our alone page + nbResults = firstPageRows.Count(); + } + else + { + // Check if no result + if(torrentRowList.Count == 0) + { + // No results found + Output("\nNo result found for your query, please try another search term ...\n", "info"); + + // No result found for this query + break; + } + } + + Output("\nFound " + nbResults + " result(s) (+/- " + firstPageRows.Length + ") in " + pageLinkCount + " page(s) for this query !"); + Output("\nThere are " + firstPageRows.Length + " results on the first page !"); + + // Loop on results + + foreach (var tRow in torrentRowList) + { + Output("Torrent #" + (releases.Count + 1)); + + // ID + var id = tRow.Find("td:eq(1) > a:eq(0)").Attr("href").Split('=').Last(); + Output("ID: " + id); + + // Release Name + var name = tRow.Find("td:eq(1) > a:eq(0)").Attr("title"); + + // Category + var categoryId = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last(); + var categoryName = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("title"); + + var MainCat = tRow.Find("td:eq(0) > div > a:eq(0)").Attr("href").Split('?').Last(); + var SubCat1 = "none"; + var SubCat2 = "none"; + + var testcat = MainCat; + + if (tRow.Find("td:eq(0) > div > a:eq(1)").Length == 1) + { + SubCat1 = tRow.Find("td:eq(0) > div > a:eq(1)").Attr("href").Split('?').Last(); + } + if (tRow.Find("td:eq(0) > div > a[href^=\"/browse.php?sub2_cat[]=\"]").Length == 1) + { + SubCat2 = tRow.Find("td:eq(0) > div > a[href^=\"/browse.php?sub2_cat[]=\"]").Attr("href").Split('?').Last(); + testcat = MainCat + '&' + SubCat2; + } + + Output("Category: " + testcat + " - " + categoryName); + + // Seeders + var seeders = ParseUtil.CoerceInt(tRow.Find("td:eq(9)").Text()); + Output("Seeders: " + seeders); + + // Leechers + var leechers = ParseUtil.CoerceInt(tRow.Find("td:eq(10)").Text()); + Output("Leechers: " + leechers); + + // Completed + Regex regexObj = new Regex(@"[^\d]"); + var completed2 = tRow.Find("td:eq(7)").Text(); + var completed = ParseUtil.CoerceLong(regexObj.Replace(completed2, "")); + Output("Completed: " + completed); + + // Files + var files = 1; + if (tRow.Find("td:eq(2) > a").Length == 1) + { + files = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(2) > a").Text(), @"\d+").Value); + } + Output("Files: " + files); + + // Health + var percent = ParseUtil.CoerceInt(Regex.Match(tRow.Find("td:eq(8)").Text(), @"\d+").Value.Trim()); + Output("Health: " + percent + "%"); + + // Size + var humanSize = tRow.Find("td:eq(6)").Text().ToLowerInvariant(); + var size = ReleaseInfo.GetBytes(humanSize); + Output("Size: " + humanSize + " (" + size + " bytes)"); + + // --> Date + var dateTimeOrig = tRow.Find("td:eq(4)").Text(); + var dateTime = Regex.Replace(dateTimeOrig, @"<[^>]+>| ", "").Trim(); + var date = DateTime.ParseExact(dateTime, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); + Output("Released on: " + date); + + // Torrent Details URL + var detailsLink = new Uri(TorrentDescriptionUrl.Replace("{id}", id.ToString())); + Output("Details: " + detailsLink.AbsoluteUri); + + // Torrent Comments URL + var commentsLink = new Uri(TorrentCommentUrl.Replace("{id}", id.ToString())); + Output("Comments Link: " + commentsLink.AbsoluteUri); + + // Torrent Download URL + var passkey = tRow.Find("td:eq(1) > a:eq(1)").Attr("href"); + var key = Regex.Match(passkey, "(?<=passkey\\=)([a-zA-z0-9]*)"); + Uri downloadLink = new Uri(TorrentDownloadUrl.Replace("{id}", id.ToString()).Replace("{passkey}", key.ToString())); + Output("Download Link: " + downloadLink.AbsoluteUri); + + // Building release infos + var release = new ReleaseInfo + { + Category = MapTrackerCatToNewznab(testcat.ToString()), + Title = name, + Seeders = seeders, + Peers = seeders + leechers, + MinimumRatio = 1, + MinimumSeedTime = 172800, + PublishDate = date, + Size = size, + Files = files, + Grabs = completed, + Guid = detailsLink, + Comments = commentsLink, + Link = downloadLink + }; + + var genres = tRow.Find("span.genres").Text(); + if (!string.IsNullOrEmpty(genres)) + release.Description = genres; + + // IMDB + var imdbLink = tRow.Find("a[href*=\"http://imdb.com/title/\"]").First().Attr("href"); + release.Imdb = ParseUtil.GetLongFromString(imdbLink); + + if (tRow.Find("img[title=\"100% freeleech\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (tRow.Find("img[title=\"Halfleech\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; + else if (tRow.Find("img[title=\"90% Freeleech\"]").Length >= 1) + release.DownloadVolumeFactor = 0.1; else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - - } - catch (Exception ex) - { - OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); - } - } - // Return found releases - return releases; - } - - /// <summary> - /// Build query to process - /// </summary> - /// <param name="term">Term to search</param> - /// <param name="query">Torznab Query for categories mapping</param> - /// <param name="url">Search url for provider</param> - /// <param name="page">Page number to request</param> - /// <returns>URL to query for parsing and processing results</returns> - private string BuildQuery(string term, TorznabQuery query, string url, int page = 0) - { - var parameters = new NameValueCollection(); - var categoriesList = MapTorznabCapsToTrackers(query); - string searchterm = term; - - // Building our tracker query - parameters.Add("incldead", "1"); - parameters.Add("fullsearch", "0"); - parameters.Add("scenerelease", "0"); - - // If search term provided + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + + } + catch (Exception ex) + { + OnParseError("Error, unable to parse result \n" + ex.StackTrace, ex); + } + } + // Return found releases + return releases; + } + + /// <summary> + /// Build query to process + /// </summary> + /// <param name="term">Term to search</param> + /// <param name="query">Torznab Query for categories mapping</param> + /// <param name="url">Search url for provider</param> + /// <param name="page">Page number to request</param> + /// <returns>URL to query for parsing and processing results</returns> + private string BuildQuery(string term, TorznabQuery query, string url, int page = 0) + { + var parameters = new NameValueCollection(); + var categoriesList = MapTorznabCapsToTrackers(query); + string searchterm = term; + + // Building our tracker query + parameters.Add("incldead", "1"); + parameters.Add("fullsearch", "0"); + parameters.Add("scenerelease", "0"); + + // If search term provided if (!string.IsNullOrWhiteSpace(query.ImdbID)) { searchterm = "imdbsearch=" + query.ImdbID; } - else if (!string.IsNullOrWhiteSpace(term)) - { - searchterm = "search=" + System.Web.HttpUtility.UrlEncode(term, Encoding.GetEncoding(28591)); - } - else - { - // Showing all torrents (just for output function) - searchterm = "search="; - term = "all"; - } - - var CatQryStr = ""; - foreach (var cat in categoriesList) - CatQryStr += "&" + cat; - - // Building our query - url += "?" + searchterm + "&" + parameters.GetQueryString() + "&" + CatQryStr; - - Output("\nBuilded query for \"" + term + "\"... " + url); - - // Return our search url - return url; - } - - /// <summary> - /// Switch Method for Querying - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> 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; - } - - /// <summary> - /// Get Torrents Page from Cache by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> 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 - var 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<WebClientStringResult>(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; - } - - /// <summary> - /// Get Torrents Page from Tracker by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> QueryTracker(string request) - { - // Cache mode not enabled or cached file didn't exist for our query - Output("\nQuerying tracker for results...."); - - // Request our first page - LatencyNow(); - var results = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value, SearchUrl, _emulatedBrowserHeaders); - - // Return results from tracker - return results; - } - - /// <summary> - /// Clean Hard Drive Cache Storage - /// </summary> - /// <param name="force">Force Provider Folder deletion</param> - 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."); - } - } - } - - /// <summary> - /// Generate a random fake latency to avoid detection on tracker side - /// </summary> - private void LatencyNow() - { - // Need latency ? - if (Latency) - { - var random = new Random(DateTime.Now.Millisecond); - var waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value), - Convert.ToInt32(ConfigData.LatencyEnd.Value)); - Output("\nLatency Faker => Sleeping for " + waiting + " ms..."); - - // Sleep now... - System.Threading.Thread.Sleep(waiting); - } - // Generate a random value in our range - } - - /// <summary> - /// Find torrent rows in search pages - /// </summary> - /// <returns>JQuery Object</returns> - private CQ FindTorrentRows() - { - // Return all occurencis of torrents found - //return _fDom["#content > table > tr"]; - return _fDom["# torrentTable > tbody > tr:not(:first)"]; - } - - /// <summary> - /// Download torrent file from tracker - /// </summary> - /// <param name="link">URL string</param> - /// <returns></returns> - public override async Task<byte[]> Download(Uri link) - { - - // Retrieving ID from link provided - var id = ParseUtil.CoerceInt(Regex.Match(link.AbsoluteUri, @"\d+").Value); - Output("Torrent Requested ID: " + id); - - // Building login form data - var pairs = new Dictionary<string, string> { - { "torrentid", id.ToString() }, - { "_", string.Empty } // ~~ Strange, blank param... - }; - - // Add emulated XHR request - _emulatedBrowserHeaders.Add("X-Prototype-Version", "1.6.0.3"); - _emulatedBrowserHeaders.Add("X-Requested-With", "XMLHttpRequest"); - - // Get torrent file now - Output("Getting torrent file now...."); - var response = await base.Download(link); - - // Remove our XHR request header - _emulatedBrowserHeaders.Remove("X-Prototype-Version"); - _emulatedBrowserHeaders.Remove("X-Requested-With"); - - // Return content - return response; - } - - /// <summary> - /// Output message for logging or developpment (console) - /// </summary> - /// <param name="message">Message to output</param> - /// <param name="level">Level for Logger</param> - 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; - } - } - } - - /// <summary> - /// Validate Config entered by user on Jackett - /// </summary> - private void ValidateConfig() - { - Output("\nValidating Settings ... \n"); - - // Check Username Setting - if (string.IsNullOrEmpty(ConfigData.Username.Value)) - { - throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData); - } - else - { - Output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value); - } - - // Check Password Setting - if (string.IsNullOrEmpty(ConfigData.Password.Value)) - { - throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData); - } - else - { - Output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value); - } - - // Check Max Page Setting - if (!string.IsNullOrEmpty(ConfigData.Pages.Value)) - { - try - { - Output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData); - } - - // Check Latency Setting - if (ConfigData.Latency.Value) - { - Output("\nValidated Setting -- Latency Simulation enabled"); - - // Check Latency Start Setting - if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value)) - { - try - { - Output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData); - } - - // Check Latency End Setting - if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value)) - { - try - { - Output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value)); - } - catch (Exception) - { - throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData); - } - } - else - { - throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData); - } - } - - // Check Browser Setting - if (ConfigData.Browser.Value) - { - Output("\nValidated Setting -- Browser Simulation enabled"); - - // Check ACCEPT header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData); - } - else - { - Output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value); - } - - // Check ACCEPT-LANG header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData); - } - else - { - Output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value); - } - - // Check USER-AGENT header Setting - if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value)) - { - throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData); - } - else - { - Output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value); - } - } - else - { - // Browser simulation must be enabled (otherwhise, this provider will not work due to tracker's security) - throw new ExceptionWithConfigData("Browser Simulation must be enabled for this provider to work, please enable it !", ConfigData); - } - - // 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); - } - } - } -} + else if (!string.IsNullOrWhiteSpace(term)) + { + searchterm = "search=" + System.Web.HttpUtility.UrlEncode(term, Encoding.GetEncoding(28591)); + } + else + { + // Showing all torrents (just for output function) + searchterm = "search="; + term = "all"; + } + + var CatQryStr = ""; + foreach (var cat in categoriesList) + CatQryStr += "&" + cat; + + // Building our query + url += "?" + searchterm + "&" + parameters.GetQueryString() + "&" + CatQryStr; + + Output("\nBuilded query for \"" + term + "\"... " + url); + + // Return our search url + return url; + } + + /// <summary> + /// Switch Method for Querying + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> 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; + } + + /// <summary> + /// Get Torrents Page from Cache by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> 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 + var 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<WebClientStringResult>(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; + } + + /// <summary> + /// Get Torrents Page from Tracker by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> QueryTracker(string request) + { + // Cache mode not enabled or cached file didn't exist for our query + Output("\nQuerying tracker for results...."); + + // Request our first page + LatencyNow(); + var results = await RequestStringWithCookiesAndRetry(request, ConfigData.CookieHeader.Value, SearchUrl, _emulatedBrowserHeaders); + + // Return results from tracker + return results; + } + + /// <summary> + /// Clean Hard Drive Cache Storage + /// </summary> + /// <param name="force">Force Provider Folder deletion</param> + 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."); + } + } + } + + /// <summary> + /// Generate a random fake latency to avoid detection on tracker side + /// </summary> + private void LatencyNow() + { + // Need latency ? + if (Latency) + { + var random = new Random(DateTime.Now.Millisecond); + var waiting = random.Next(Convert.ToInt32(ConfigData.LatencyStart.Value), + Convert.ToInt32(ConfigData.LatencyEnd.Value)); + Output("\nLatency Faker => Sleeping for " + waiting + " ms..."); + + // Sleep now... + System.Threading.Thread.Sleep(waiting); + } + // Generate a random value in our range + } + + /// <summary> + /// Find torrent rows in search pages + /// </summary> + /// <returns>JQuery Object</returns> + private CQ FindTorrentRows() + { + // Return all occurencis of torrents found + //return _fDom["#content > table > tr"]; + return _fDom["# torrentTable > tbody > tr:not(:first)"]; + } + + /// <summary> + /// Download torrent file from tracker + /// </summary> + /// <param name="link">URL string</param> + /// <returns></returns> + public override async Task<byte[]> Download(Uri link) + { + + // Retrieving ID from link provided + var id = ParseUtil.CoerceInt(Regex.Match(link.AbsoluteUri, @"\d+").Value); + Output("Torrent Requested ID: " + id); + + // Building login form data + var pairs = new Dictionary<string, string> { + { "torrentid", id.ToString() }, + { "_", string.Empty } // ~~ Strange, blank param... + }; + + // Add emulated XHR request + _emulatedBrowserHeaders.Add("X-Prototype-Version", "1.6.0.3"); + _emulatedBrowserHeaders.Add("X-Requested-With", "XMLHttpRequest"); + + // Get torrent file now + Output("Getting torrent file now...."); + var response = await base.Download(link); + + // Remove our XHR request header + _emulatedBrowserHeaders.Remove("X-Prototype-Version"); + _emulatedBrowserHeaders.Remove("X-Requested-With"); + + // Return content + return response; + } + + /// <summary> + /// Output message for logging or developpment (console) + /// </summary> + /// <param name="message">Message to output</param> + /// <param name="level">Level for Logger</param> + 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; + } + } + } + + /// <summary> + /// Validate Config entered by user on Jackett + /// </summary> + private void ValidateConfig() + { + Output("\nValidating Settings ... \n"); + + // Check Username Setting + if (string.IsNullOrEmpty(ConfigData.Username.Value)) + { + throw new ExceptionWithConfigData("You must provide a username for this tracker to login !", ConfigData); + } + else + { + Output("Validated Setting -- Username (auth) => " + ConfigData.Username.Value); + } + + // Check Password Setting + if (string.IsNullOrEmpty(ConfigData.Password.Value)) + { + throw new ExceptionWithConfigData("You must provide a password with your username for this tracker to login !", ConfigData); + } + else + { + Output("Validated Setting -- Password (auth) => " + ConfigData.Password.Value); + } + + // Check Max Page Setting + if (!string.IsNullOrEmpty(ConfigData.Pages.Value)) + { + try + { + Output("Validated Setting -- Max Pages => " + Convert.ToInt32(ConfigData.Pages.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric maximum number of pages to crawl !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Please enter a maximum number of pages to crawl !", ConfigData); + } + + // Check Latency Setting + if (ConfigData.Latency.Value) + { + Output("\nValidated Setting -- Latency Simulation enabled"); + + // Check Latency Start Setting + if (!string.IsNullOrEmpty(ConfigData.LatencyStart.Value)) + { + try + { + Output("Validated Setting -- Latency Start => " + Convert.ToInt32(ConfigData.LatencyStart.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric latency start in ms !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a start latency !", ConfigData); + } + + // Check Latency End Setting + if (!string.IsNullOrEmpty(ConfigData.LatencyEnd.Value)) + { + try + { + Output("Validated Setting -- Latency End => " + Convert.ToInt32(ConfigData.LatencyEnd.Value)); + } + catch (Exception) + { + throw new ExceptionWithConfigData("Please enter a numeric latency end in ms !", ConfigData); + } + } + else + { + throw new ExceptionWithConfigData("Latency Simulation enabled, Please enter a end latency !", ConfigData); + } + } + + // Check Browser Setting + if (ConfigData.Browser.Value) + { + Output("\nValidated Setting -- Browser Simulation enabled"); + + // Check ACCEPT header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderAccept.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT header !", ConfigData); + } + else + { + Output("Validated Setting -- ACCEPT (header) => " + ConfigData.HeaderAccept.Value); + } + + // Check ACCEPT-LANG header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderAcceptLang.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an ACCEPT-LANG header !", ConfigData); + } + else + { + Output("Validated Setting -- ACCEPT-LANG (header) => " + ConfigData.HeaderAcceptLang.Value); + } + + // Check USER-AGENT header Setting + if (string.IsNullOrEmpty(ConfigData.HeaderUserAgent.Value)) + { + throw new ExceptionWithConfigData("Browser Simulation enabled, Please enter an USER-AGENT header !", ConfigData); + } + else + { + Output("Validated Setting -- USER-AGENT (header) => " + ConfigData.HeaderUserAgent.Value); + } + } + else + { + // Browser simulation must be enabled (otherwhise, this provider will not work due to tracker's security) + throw new ExceptionWithConfigData("Browser Simulation must be enabled for this provider to work, please enable it !", ConfigData); + } + + // 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); + } + } + } +} diff --git a/src/Jackett/Indexers/PassThePopcorn.cs b/src/Jackett/Indexers/PassThePopcorn.cs index b654ac21..6840ac94 100644 --- a/src/Jackett/Indexers/PassThePopcorn.cs +++ b/src/Jackett/Indexers/PassThePopcorn.cs @@ -46,10 +46,10 @@ namespace Jackett.Indexers Language = "en-us"; Type = "private"; - TorznabCaps.SupportsImdbSearch = true; - - webclient.requestDelay = 2; // 0.5 requests per second - + TorznabCaps.SupportsImdbSearch = true; + + webclient.requestDelay = 2; // 0.5 requests per second + AddCategoryMapping(1, TorznabCatType.Movies, "Feature Film"); AddCategoryMapping(1, TorznabCatType.MoviesForeign); AddCategoryMapping(1, TorznabCatType.MoviesOther); @@ -113,8 +113,8 @@ namespace Jackett.Indexers movieListSearchUrl = string.Format("{0}?json=noredirect&searchstr={1}", SearchUrl, HttpUtility.UrlEncode(query.GetQueryString())); } else - { - movieListSearchUrl = string.Format("{0}?json=noredirect", SearchUrl); + { + movieListSearchUrl = string.Format("{0}?json=noredirect", SearchUrl); } var results = await RequestStringWithCookiesAndRetry(movieListSearchUrl); @@ -181,50 +181,50 @@ namespace Jackett.Indexers string Container = (string)torrent["Container"]; string Codec = (string)torrent["Codec"]; string Resolution = (string)torrent["Resolution"]; - string Source = (string)torrent["Source"]; - - if (Year != null) - { - release.Description += string.Format("<br>\nYear: {0}", Year); - } - if (Quality != null) - { - release.Description += string.Format("<br>\nQuality: {0}", Quality); - } - if (Resolution != null) - { - titletags.Add(Resolution); - release.Description += string.Format("<br>\nResolution: {0}", Resolution); + string Source = (string)torrent["Source"]; + + if (Year != null) + { + release.Description += string.Format("<br>\nYear: {0}", Year); } - if (Source != null) - { - titletags.Add(Source); - release.Description += string.Format("<br>\nSource: {0}", Source); + if (Quality != null) + { + release.Description += string.Format("<br>\nQuality: {0}", Quality); } - if (Codec != null) - { - titletags.Add(Codec); - release.Description += string.Format("<br>\nCodec: {0}", Codec); + if (Resolution != null) + { + titletags.Add(Resolution); + release.Description += string.Format("<br>\nResolution: {0}", Resolution); } - if (Container != null) - { - titletags.Add(Container); - release.Description += string.Format("<br>\nContainer: {0}", Container); + if (Source != null) + { + titletags.Add(Source); + release.Description += string.Format("<br>\nSource: {0}", Source); } - if (scene) - { - titletags.Add("Scene"); - release.Description += "<br>\nScene"; + if (Codec != null) + { + titletags.Add(Codec); + release.Description += string.Format("<br>\nCodec: {0}", Codec); + } + if (Container != null) + { + titletags.Add(Container); + release.Description += string.Format("<br>\nContainer: {0}", Container); } - if (check) - { - titletags.Add("Checked"); - release.Description += "<br>\nChecked"; + if (scene) + { + titletags.Add("Scene"); + release.Description += "<br>\nScene"; } - if (golden) - { - titletags.Add("Golden Popcorn"); - release.Description += "<br>\nGolden Popcorn"; + if (check) + { + titletags.Add("Checked"); + release.Description += "<br>\nChecked"; + } + if (golden) + { + titletags.Add("Golden Popcorn"); + release.Description += "<br>\nGolden Popcorn"; } if (titletags.Count() > 0) diff --git a/src/Jackett/Indexers/PiXELHD.cs b/src/Jackett/Indexers/PiXELHD.cs index 614033a7..f8e88d2c 100644 --- a/src/Jackett/Indexers/PiXELHD.cs +++ b/src/Jackett/Indexers/PiXELHD.cs @@ -1,37 +1,37 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -using AngleSharp.Parser.Html; -using Newtonsoft.Json.Linq; -using NLog; - -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using System.Collections.Specialized; - -namespace Jackett.Indexers -{ - class PiXELHD : BaseIndexer, IIndexer - { +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using AngleSharp.Parser.Html; +using Newtonsoft.Json.Linq; +using NLog; + +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + class PiXELHD : BaseIndexer, IIndexer + { string LoginUrl { get { return SiteLink + "login.php"; } } - string BrowseUrl { get { return SiteLink + "torrents.php"; } } - + string BrowseUrl { get { return SiteLink + "torrents.php"; } } + new ConfigurationDataCaptchaLogin configData { get { return (ConfigurationDataCaptchaLogin)base.configData; } set { base.configData = value; } - } - - string input_captcha = null; - string input_username = null; - string input_password = null; - + } + + string input_captcha = null; + string input_username = null; + string input_password = null; + public PiXELHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) : base(name: "PiXELHD", description: null, @@ -43,51 +43,51 @@ namespace Jackett.Indexers client: webClient, configData: new ConfigurationDataCaptchaLogin() ) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(1, TorznabCatType.MoviesHD); - - } - - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - var LoginParser = new HtmlParser(); - var LoginDocument = LoginParser.Parse(loginPage.Content); - - configData.CaptchaCookie.Value = loginPage.Cookies; - - var catchaImg = LoginDocument.QuerySelector("img[alt=\"FuckOff Image\"]"); - if (catchaImg != null) - { - var catchaInput = LoginDocument.QuerySelector("input[maxlength=\"6\"]"); - input_captcha = catchaInput.GetAttribute("name"); - - var captchaImage = await RequestBytesWithCookies(SiteLink + catchaImg.GetAttribute("src"), loginPage.Cookies, RequestType.GET, LoginUrl); - configData.CaptchaImage.Value = captchaImage.Content; - } - else - { - input_captcha = null; - configData.CaptchaImage.Value = null; - } - - var usernameInput = LoginDocument.QuerySelector("input[maxlength=\"20\"]"); - input_username = usernameInput.GetAttribute("name"); - - var passwordInput = LoginDocument.QuerySelector("input[maxlength=\"40\"]"); - input_password = passwordInput.GetAttribute("name"); + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(1, TorznabCatType.MoviesHD); + + } + + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + var LoginParser = new HtmlParser(); + var LoginDocument = LoginParser.Parse(loginPage.Content); + + configData.CaptchaCookie.Value = loginPage.Cookies; + + var catchaImg = LoginDocument.QuerySelector("img[alt=\"FuckOff Image\"]"); + if (catchaImg != null) + { + var catchaInput = LoginDocument.QuerySelector("input[maxlength=\"6\"]"); + input_captcha = catchaInput.GetAttribute("name"); + + var captchaImage = await RequestBytesWithCookies(SiteLink + catchaImg.GetAttribute("src"), loginPage.Cookies, RequestType.GET, LoginUrl); + configData.CaptchaImage.Value = captchaImage.Content; + } + else + { + input_captcha = null; + configData.CaptchaImage.Value = null; + } + + var usernameInput = LoginDocument.QuerySelector("input[maxlength=\"20\"]"); + input_username = usernameInput.GetAttribute("name"); + + var passwordInput = LoginDocument.QuerySelector("input[maxlength=\"40\"]"); + input_password = passwordInput.GetAttribute("name"); - return configData; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { + return configData; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { configData.LoadValuesFromJson(configJson); var pairs = new Dictionary<string, string> @@ -95,32 +95,32 @@ namespace Jackett.Indexers { input_username, configData.Username.Value }, { input_password, configData.Password.Value }, { "keeplogged", "1" } - }; - - if (input_captcha != null) - pairs.Add(input_captcha, configData.CaptchaText.Value); - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CaptchaCookie.Value, true); - - await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => - { - var LoginParser = new HtmlParser(); - var LoginDocument = LoginParser.Parse(result.Content); - var errorMessage = LoginDocument.QuerySelector("span.warning:has(br)").TextContent; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var queryCollection = new NameValueCollection(); - queryCollection.Add("order_by", "time"); - queryCollection.Add("order_way", "desc"); - + }; + + if (input_captcha != null) + pairs.Add(input_captcha, configData.CaptchaText.Value); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CaptchaCookie.Value, true); + + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + var LoginParser = new HtmlParser(); + var LoginDocument = LoginParser.Parse(result.Content); + var errorMessage = LoginDocument.QuerySelector("span.warning:has(br)").TextContent; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var queryCollection = new NameValueCollection(); + queryCollection.Add("order_by", "time"); + queryCollection.Add("order_way", "desc"); + if (!string.IsNullOrWhiteSpace(query.ImdbID)) { queryCollection.Add("imdbid", query.ImdbID); @@ -128,82 +128,82 @@ namespace Jackett.Indexers else if (!string.IsNullOrWhiteSpace(searchString)) { queryCollection.Add("groupname", searchString); - } - - queryCollection.Add("groupname", searchString); - - var searchUrl = BrowseUrl + "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookies(searchUrl); - if (results.IsRedirect) - { - // re login - await GetConfigurationForSetup(); - await ApplyConfiguration(null); - results = await RequestStringWithCookies(searchUrl); - } - - Regex IMDBRegEx = new Regex(@"tt(\d+)", RegexOptions.Compiled); - var hParser = new HtmlParser(); - var ResultDocument = hParser.Parse(results.Content); + } + + queryCollection.Add("groupname", searchString); + + var searchUrl = BrowseUrl + "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookies(searchUrl); + if (results.IsRedirect) + { + // re login + await GetConfigurationForSetup(); + await ApplyConfiguration(null); + results = await RequestStringWithCookies(searchUrl); + } + + Regex IMDBRegEx = new Regex(@"tt(\d+)", RegexOptions.Compiled); + var hParser = new HtmlParser(); + var ResultDocument = hParser.Parse(results.Content); try { var Groups = ResultDocument.QuerySelectorAll("div.browsePoster"); - - foreach (var Group in Groups) - { - var groupPoster = Group.QuerySelector("img.classBrowsePoster"); - var bannerURL = new Uri(SiteLink + groupPoster.GetAttribute("src")); - - long? IMDBId = null; - var imdbLink = Group.QuerySelector("a[href^=\"http://anonym.to/?http://www.imdb.com/title/tt\"]"); - if (imdbLink != null) - { - var IMDBMatch = IMDBRegEx.Match(imdbLink.GetAttribute("href")); - IMDBId = ParseUtil.CoerceLong(IMDBMatch.Groups[1].Value); - } - - var GroupTitle = Group.QuerySelector("strong:has(a[title=\"View Torrent\"])").TextContent.Replace(" ]", "]"); - - var Rows = Group.QuerySelectorAll("tr.group_torrent:has(a[href^=\"torrents.php?id=\"])"); - foreach (var Row in Rows) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 60 * 60; - - var title = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); - var link = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); - var added = Row.QuerySelector("td:nth-child(3)"); - var Size = Row.QuerySelector("td:nth-child(4)"); - var Grabs = Row.QuerySelector("td:nth-child(6)"); - var Seeders = Row.QuerySelector("td:nth-child(7)"); - var Leechers = Row.QuerySelector("td:nth-child(8)"); - - release.Title = GroupTitle + " " + title.TextContent; - release.Category = new List<int> { TorznabCatType.MoviesHD.ID }; - release.Link = new Uri(SiteLink + link.GetAttribute("href")); - release.Comments = new Uri(SiteLink + title.GetAttribute("href")); - release.Guid = release.Link; - release.Size = ReleaseInfo.GetBytes(Size.TextContent); - release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); - release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; - release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); - release.PublishDate = DateTimeUtil.FromTimeAgo(added.TextContent); - release.BannerUrl = bannerURL; - release.Imdb = IMDBId; - - releases.Add(release); + + foreach (var Group in Groups) + { + var groupPoster = Group.QuerySelector("img.classBrowsePoster"); + var bannerURL = new Uri(SiteLink + groupPoster.GetAttribute("src")); + + long? IMDBId = null; + var imdbLink = Group.QuerySelector("a[href^=\"http://anonym.to/?http://www.imdb.com/title/tt\"]"); + if (imdbLink != null) + { + var IMDBMatch = IMDBRegEx.Match(imdbLink.GetAttribute("href")); + IMDBId = ParseUtil.CoerceLong(IMDBMatch.Groups[1].Value); } - } + + var GroupTitle = Group.QuerySelector("strong:has(a[title=\"View Torrent\"])").TextContent.Replace(" ]", "]"); + + var Rows = Group.QuerySelectorAll("tr.group_torrent:has(a[href^=\"torrents.php?id=\"])"); + foreach (var Row in Rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + + var title = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); + var link = Row.QuerySelector("a[href^=\"torrents.php?action=download\"]"); + var added = Row.QuerySelector("td:nth-child(3)"); + var Size = Row.QuerySelector("td:nth-child(4)"); + var Grabs = Row.QuerySelector("td:nth-child(6)"); + var Seeders = Row.QuerySelector("td:nth-child(7)"); + var Leechers = Row.QuerySelector("td:nth-child(8)"); + + release.Title = GroupTitle + " " + title.TextContent; + release.Category = new List<int> { TorznabCatType.MoviesHD.ID }; + release.Link = new Uri(SiteLink + link.GetAttribute("href")); + release.Comments = new Uri(SiteLink + title.GetAttribute("href")); + release.Guid = release.Link; + release.Size = ReleaseInfo.GetBytes(Size.TextContent); + release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); + release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; + release.Grabs = ParseUtil.CoerceLong(Grabs.TextContent); + release.PublishDate = DateTimeUtil.FromTimeAgo(added.TextContent); + release.BannerUrl = bannerURL; + release.Imdb = IMDBId; + + releases.Add(release); + } + } } catch (Exception ex) - { - OnParseError(results.Content, ex); + { + OnParseError(results.Content, ex); } - return releases; - } - - } -} + return releases; + } + + } +} diff --git a/src/Jackett/Indexers/PirateTheNet.cs b/src/Jackett/Indexers/PirateTheNet.cs index 121b99e2..b3866c0d 100644 --- a/src/Jackett/Indexers/PirateTheNet.cs +++ b/src/Jackett/Indexers/PirateTheNet.cs @@ -1,226 +1,226 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Globalization; - -namespace Jackett.Indexers -{ - public class PirateTheNet : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "torrentsutils.php"; } } - private string LoginUrl { get { return SiteLink + "takelogin.php"; } } - private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } - TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time"); - private readonly List<String> categories = new List<string>() { "1080P", "720P", "BDRip", "BluRay", "BRRip", "DVDR", "DVDRip", "FLAC", "MP3", "MP4", "Packs", "R5", "Remux", "TVRip", "WebRip" }; - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public PirateTheNet(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "PirateTheNet", - description: "A movie tracker", - link: "http://piratethenet.org/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; - this.configData.DisplayText.Name = "Notice"; - - AddCategoryMapping("1080P", TorznabCatType.MoviesHD); - AddCategoryMapping("720P", TorznabCatType.MoviesHD); - AddCategoryMapping("BDRip", TorznabCatType.MoviesSD); - AddCategoryMapping("BluRay", TorznabCatType.MoviesBluRay); - AddCategoryMapping("BRRip", TorznabCatType.MoviesSD); - AddCategoryMapping("DVDR", TorznabCatType.MoviesDVD); - AddCategoryMapping("DVDRip", TorznabCatType.MoviesSD); - AddCategoryMapping("FLAC", TorznabCatType.AudioLossless); - AddCategoryMapping("MP3", TorznabCatType.AudioMP3); - AddCategoryMapping("MP4", TorznabCatType.AudioOther); - AddCategoryMapping("Packs", TorznabCatType.Movies); - AddCategoryMapping("R5", TorznabCatType.MoviesDVD); - AddCategoryMapping("Remux", TorznabCatType.Movies); - AddCategoryMapping("TVRip", TorznabCatType.MoviesOther); - AddCategoryMapping("WebRip", TorznabCatType.MoviesWEBDL); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var result1 = await RequestStringWithCookies(CaptchaUrl); - var json1 = JObject.Parse(result1.Content); - var captchaSelection = json1["images"][0]["hash"]; - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "captchaSelection", (string)captchaSelection } - }; - - var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); - - await ConfigureIfOK(result2.Cookies, result2.Content.Contains("logout.php"), () => - { - var errorMessage = "Login Failed"; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("action", "torrentstable"); - queryCollection.Add("viewtype", "0"); - queryCollection.Add("visiblecategories", "Action,Adventure,Animation,Biography,Comedy,Crime,Documentary,Drama,Eastern,Family,Fantasy,History,Holiday,Horror,Kids,Musical,Mystery,Romance,Sci-Fi,Short,Sports,Thriller,War,Western"); - queryCollection.Add("page", "1"); - queryCollection.Add("visibility", "showall"); - queryCollection.Add("compression", "showall"); - queryCollection.Add("sort", "added"); - queryCollection.Add("order", "DESC"); - queryCollection.Add("titleonly", "true"); - queryCollection.Add("packs", "showall"); - queryCollection.Add("bookmarks", "showall"); - queryCollection.Add("subscriptions", "showall"); - queryCollection.Add("skw", "showall"); - queryCollection.Add("advancedsearchparameters", ""); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - // search keywords use OR by default and it seems like there's no way to change it, expect unwanted results - queryCollection.Add("searchstring", searchString); - } - - var cats = MapTorznabCapsToTrackers(query); - var hiddenqualities = ""; - if (cats.Count > 0) - { - hiddenqualities = String.Join(",", categories.Where(cat => !cats.Contains(cat))); - } - queryCollection.Add("hiddenqualities", hiddenqualities); - - searchUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - try - { - CQ dom = results.Content; - /* - // parse logic for viewtype=1, unfortunately it's missing the release time so we can't use it - var movieBlocks = dom["table.main"]; - foreach (var movieBlock in movieBlocks) - { - var qMovieBlock = movieBlock.Cq(); - - var movieLink = qMovieBlock.Find("tr > td[class=colhead] > a").First(); - var movieName = movieLink.Text(); - - var qDetailsBlock = qMovieBlock.Find("tr > td.torrentstd > table > tbody > tr"); - var qDetailsHeader = qDetailsBlock.ElementAt(0); - var qDetailsTags = qDetailsBlock.ElementAt(1); - var qTorrents = qDetailsBlock.Find("td.moviestorrentstd > table > tbody > tr:eq(0)"); - - foreach (var torrent in qTorrents) - { - var qTorrent = torrent.Cq(); - var qCatIcon = qTorrent.Find("td:eq(0) > img"); - var qDetailsLink = qTorrent.Find("td:eq(1) > a:eq(0)"); - var qSeeders = qTorrent.Find("td:eq(1) > b > a[alt=\"Number of Seeders\"]"); - var qLeechers = qTorrent.Find("td:eq(1) > span[alt=\"Number of Leechers\"]"); - var qDownloadLink = qTorrent.Find("td:eq(1) > a:has(img[alt=\"Download Torrent\"])"); - } - } - */ - - var rows = dom["table.main > tbody > tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 72 * 60 * 60; - - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("td:eq(1) > a:eq(0)"); // link to the movie, not the actual torrent - release.Title = qDetailsLink.Attr("alt"); - - var qCatIcon = qRow.Find("td:eq(0) > img"); - var qSeeders = qRow.Find("td:eq(8)"); - var qLeechers = qRow.Find("td:eq(9)"); - var qDownloadLink = qRow.Find("td > a:has(img[alt=\"Download Torrent\"])"); - var qPudDate = qRow.Find("td:eq(5) > nobr"); - var qSize = qRow.Find("td:eq(6)"); - - var catStr = qCatIcon.Attr("alt"); - release.Category = MapTrackerCatToNewznab(catStr); - release.Link = new Uri(SiteLink + qDownloadLink.Attr("href").Substring(1)); - release.Title = qDetailsLink.Attr("alt"); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var dateStr = qPudDate.Text().Trim(); - DateTime pubDateUtc; - var Timeparts = dateStr.Split(new char[] { ' ' }, 2)[1]; - if (dateStr.StartsWith("Today ")) - pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay; - else if (dateStr.StartsWith("Yesterday ")) - pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + - DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay - TimeSpan.FromDays(1); - else - pubDateUtc = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy hh:mm tt", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - release.PublishDate = pubDateUtc.ToLocalTime(); - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); - release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; - - var files = qRow.Find("td:nth-child(4)").Text(); - release.Files = ParseUtil.CoerceInt(files); - - var grabs = qRow.Find("td:nth-child(8)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - release.DownloadVolumeFactor = 0; // ratioless - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Globalization; + +namespace Jackett.Indexers +{ + public class PirateTheNet : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "torrentsutils.php"; } } + private string LoginUrl { get { return SiteLink + "takelogin.php"; } } + private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } + TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time"); + private readonly List<String> categories = new List<string>() { "1080P", "720P", "BDRip", "BluRay", "BRRip", "DVDR", "DVDRip", "FLAC", "MP3", "MP4", "Packs", "R5", "Remux", "TVRip", "WebRip" }; + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public PirateTheNet(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "PirateTheNet", + description: "A movie tracker", + link: "http://piratethenet.org/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; + this.configData.DisplayText.Name = "Notice"; + + AddCategoryMapping("1080P", TorznabCatType.MoviesHD); + AddCategoryMapping("720P", TorznabCatType.MoviesHD); + AddCategoryMapping("BDRip", TorznabCatType.MoviesSD); + AddCategoryMapping("BluRay", TorznabCatType.MoviesBluRay); + AddCategoryMapping("BRRip", TorznabCatType.MoviesSD); + AddCategoryMapping("DVDR", TorznabCatType.MoviesDVD); + AddCategoryMapping("DVDRip", TorznabCatType.MoviesSD); + AddCategoryMapping("FLAC", TorznabCatType.AudioLossless); + AddCategoryMapping("MP3", TorznabCatType.AudioMP3); + AddCategoryMapping("MP4", TorznabCatType.AudioOther); + AddCategoryMapping("Packs", TorznabCatType.Movies); + AddCategoryMapping("R5", TorznabCatType.MoviesDVD); + AddCategoryMapping("Remux", TorznabCatType.Movies); + AddCategoryMapping("TVRip", TorznabCatType.MoviesOther); + AddCategoryMapping("WebRip", TorznabCatType.MoviesWEBDL); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var result1 = await RequestStringWithCookies(CaptchaUrl); + var json1 = JObject.Parse(result1.Content); + var captchaSelection = json1["images"][0]["hash"]; + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "captchaSelection", (string)captchaSelection } + }; + + var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); + + await ConfigureIfOK(result2.Cookies, result2.Content.Contains("logout.php"), () => + { + var errorMessage = "Login Failed"; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("action", "torrentstable"); + queryCollection.Add("viewtype", "0"); + queryCollection.Add("visiblecategories", "Action,Adventure,Animation,Biography,Comedy,Crime,Documentary,Drama,Eastern,Family,Fantasy,History,Holiday,Horror,Kids,Musical,Mystery,Romance,Sci-Fi,Short,Sports,Thriller,War,Western"); + queryCollection.Add("page", "1"); + queryCollection.Add("visibility", "showall"); + queryCollection.Add("compression", "showall"); + queryCollection.Add("sort", "added"); + queryCollection.Add("order", "DESC"); + queryCollection.Add("titleonly", "true"); + queryCollection.Add("packs", "showall"); + queryCollection.Add("bookmarks", "showall"); + queryCollection.Add("subscriptions", "showall"); + queryCollection.Add("skw", "showall"); + queryCollection.Add("advancedsearchparameters", ""); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + // search keywords use OR by default and it seems like there's no way to change it, expect unwanted results + queryCollection.Add("searchstring", searchString); + } + + var cats = MapTorznabCapsToTrackers(query); + var hiddenqualities = ""; + if (cats.Count > 0) + { + hiddenqualities = String.Join(",", categories.Where(cat => !cats.Contains(cat))); + } + queryCollection.Add("hiddenqualities", hiddenqualities); + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + /* + // parse logic for viewtype=1, unfortunately it's missing the release time so we can't use it + var movieBlocks = dom["table.main"]; + foreach (var movieBlock in movieBlocks) + { + var qMovieBlock = movieBlock.Cq(); + + var movieLink = qMovieBlock.Find("tr > td[class=colhead] > a").First(); + var movieName = movieLink.Text(); + + var qDetailsBlock = qMovieBlock.Find("tr > td.torrentstd > table > tbody > tr"); + var qDetailsHeader = qDetailsBlock.ElementAt(0); + var qDetailsTags = qDetailsBlock.ElementAt(1); + var qTorrents = qDetailsBlock.Find("td.moviestorrentstd > table > tbody > tr:eq(0)"); + + foreach (var torrent in qTorrents) + { + var qTorrent = torrent.Cq(); + var qCatIcon = qTorrent.Find("td:eq(0) > img"); + var qDetailsLink = qTorrent.Find("td:eq(1) > a:eq(0)"); + var qSeeders = qTorrent.Find("td:eq(1) > b > a[alt=\"Number of Seeders\"]"); + var qLeechers = qTorrent.Find("td:eq(1) > span[alt=\"Number of Leechers\"]"); + var qDownloadLink = qTorrent.Find("td:eq(1) > a:has(img[alt=\"Download Torrent\"])"); + } + } + */ + + var rows = dom["table.main > tbody > tr"]; + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 72 * 60 * 60; + + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("td:eq(1) > a:eq(0)"); // link to the movie, not the actual torrent + release.Title = qDetailsLink.Attr("alt"); + + var qCatIcon = qRow.Find("td:eq(0) > img"); + var qSeeders = qRow.Find("td:eq(8)"); + var qLeechers = qRow.Find("td:eq(9)"); + var qDownloadLink = qRow.Find("td > a:has(img[alt=\"Download Torrent\"])"); + var qPudDate = qRow.Find("td:eq(5) > nobr"); + var qSize = qRow.Find("td:eq(6)"); + + var catStr = qCatIcon.Attr("alt"); + release.Category = MapTrackerCatToNewznab(catStr); + release.Link = new Uri(SiteLink + qDownloadLink.Attr("href").Substring(1)); + release.Title = qDetailsLink.Attr("alt"); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var dateStr = qPudDate.Text().Trim(); + DateTime pubDateUtc; + var Timeparts = dateStr.Split(new char[] { ' ' }, 2)[1]; + if (dateStr.StartsWith("Today ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay; + else if (dateStr.StartsWith("Yesterday ")) + pubDateUtc = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + + DateTime.ParseExact(dateStr.Split(new char[] { ' ' }, 2)[1], "hh:mm tt", System.Globalization.CultureInfo.InvariantCulture).TimeOfDay - TimeSpan.FromDays(1); + else + pubDateUtc = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy hh:mm tt", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + release.PublishDate = pubDateUtc.ToLocalTime(); + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + + var files = qRow.Find("td:nth-child(4)").Text(); + release.Files = ParseUtil.CoerceInt(files); + + var grabs = qRow.Find("td:nth-child(8)").Text(); + release.Grabs = ParseUtil.CoerceInt(grabs); + + release.DownloadVolumeFactor = 0; // ratioless + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Pretome.cs b/src/Jackett/Indexers/Pretome.cs index d1bdac6d..a0986572 100644 --- a/src/Jackett/Indexers/Pretome.cs +++ b/src/Jackett/Indexers/Pretome.cs @@ -255,12 +255,12 @@ namespace Jackett.Indexers queryCollection.Add("tags", tags); if(!string.IsNullOrWhiteSpace(tags)) { // if tags are specified match any - queryCollection.Add("tf", "any"); + queryCollection.Add("tf", "any"); } - else + else { // if no tags are specified match all, with any we get random results - queryCollection.Add("tf", "all"); + queryCollection.Add("tf", "all"); } } @@ -271,10 +271,10 @@ namespace Jackett.Indexers var response = await RequestStringWithCookiesAndRetry(queryUrl); - if (response.IsRedirect) - { - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(queryUrl); + if (response.IsRedirect) + { + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(queryUrl); } try @@ -320,7 +320,7 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(9)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - release.DownloadVolumeFactor = 0; // ratioless + release.DownloadVolumeFactor = 0; // ratioless release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/PrivateHD.cs b/src/Jackett/Indexers/PrivateHD.cs index affb316e..89d182b8 100644 --- a/src/Jackett/Indexers/PrivateHD.cs +++ b/src/Jackett/Indexers/PrivateHD.cs @@ -1,34 +1,34 @@ -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 CsQuery; -using System.Web; -using Jackett.Services; -using Jackett.Utils.Clients; -using Jackett.Models.IndexerConfig; -using System.Globalization; - -namespace Jackett.Indexers -{ - public class PrivateHD : AvistazTracker, IIndexer - { - public PrivateHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) - : base(name: "PrivateHD", - desc: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", - link: "https://privatehd.to/", - indexerManager: indexerManager, - logger: logger, - protectionService: protectionService, - webClient: webClient - ) - { - Type = "private"; - } - } -} +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 CsQuery; +using System.Web; +using Jackett.Services; +using Jackett.Utils.Clients; +using Jackett.Models.IndexerConfig; +using System.Globalization; + +namespace Jackett.Indexers +{ + public class PrivateHD : AvistazTracker, IIndexer + { + public PrivateHD(IIndexerManagerService indexerManager, IWebClient webClient, Logger logger, IProtectionService protectionService) + : base(name: "PrivateHD", + desc: "BitTorrent site for High Quality, High Definition (HD) movies and TV Shows", + link: "https://privatehd.to/", + indexerManager: indexerManager, + logger: logger, + protectionService: protectionService, + webClient: webClient + ) + { + Type = "private"; + } + } +} diff --git a/src/Jackett/Indexers/Psytorrents.cs b/src/Jackett/Indexers/Psytorrents.cs index e2351513..f15a11ec 100644 --- a/src/Jackett/Indexers/Psytorrents.cs +++ b/src/Jackett/Indexers/Psytorrents.cs @@ -2,8 +2,8 @@ using NLog; using Jackett.Services; using Jackett.Utils.Clients; -using Jackett.Indexers.Abstract; - +using Jackett.Indexers.Abstract; + namespace Jackett.Indexers { public class Psytorrents : GazelleTracker, IIndexer @@ -22,8 +22,8 @@ namespace Jackett.Indexers Type = "private"; AddCategoryMapping(1, TorznabCatType.Audio, "Music"); - AddCategoryMapping(2, TorznabCatType.Movies, "Movies"); - AddCategoryMapping(3, TorznabCatType.PC0day, "App"); + AddCategoryMapping(2, TorznabCatType.Movies, "Movies"); + AddCategoryMapping(3, TorznabCatType.PC0day, "App"); } } } \ No newline at end of file diff --git a/src/Jackett/Indexers/Rarbg.cs b/src/Jackett/Indexers/Rarbg.cs index b7d7d9e6..6dcb7f16 100644 --- a/src/Jackett/Indexers/Rarbg.cs +++ b/src/Jackett/Indexers/Rarbg.cs @@ -1,238 +1,238 @@ -using Jackett.Models; -using Jackett.Models.IndexerConfig; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using System.Text; -using System.Web; - -namespace Jackett.Indexers -{ - public class Rarbg : BaseIndexer, IIndexer - { - readonly static string defaultSiteLink = "https://torrentapi.org/"; - - private Uri BaseUri - { - get { return new Uri(configData.Url.Value); } - set { configData.Url.Value = value.ToString(); } - } - - private string ApiEndpoint { get { return BaseUri + "pubapi_v2.php"; } } - - new ConfigurationDataUrl configData - { - get { return (ConfigurationDataUrl)base.configData; } - set { base.configData = value; } - } - - private DateTime lastTokenFetch; - private string token; - - readonly TimeSpan TOKEN_DURATION = TimeSpan.FromMinutes(10); - - private bool HasValidToken { get { return !string.IsNullOrEmpty(token) && lastTokenFetch > DateTime.Now - TOKEN_DURATION; } } - - public Rarbg(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "RARBG", - description: null, - link: "https://rarbg.to/", - caps: new TorznabCapabilities(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataUrl(defaultSiteLink)) - { - Encoding = Encoding.GetEncoding("windows-1252"); +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using System.Text; +using System.Web; + +namespace Jackett.Indexers +{ + public class Rarbg : BaseIndexer, IIndexer + { + readonly static string defaultSiteLink = "https://torrentapi.org/"; + + private Uri BaseUri + { + get { return new Uri(configData.Url.Value); } + set { configData.Url.Value = value.ToString(); } + } + + private string ApiEndpoint { get { return BaseUri + "pubapi_v2.php"; } } + + new ConfigurationDataUrl configData + { + get { return (ConfigurationDataUrl)base.configData; } + set { base.configData = value; } + } + + private DateTime lastTokenFetch; + private string token; + + readonly TimeSpan TOKEN_DURATION = TimeSpan.FromMinutes(10); + + private bool HasValidToken { get { return !string.IsNullOrEmpty(token) && lastTokenFetch > DateTime.Now - TOKEN_DURATION; } } + + public Rarbg(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "RARBG", + description: null, + link: "https://rarbg.to/", + caps: new TorznabCapabilities(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataUrl(defaultSiteLink)) + { + Encoding = Encoding.GetEncoding("windows-1252"); Language = "en-us"; - Type = "public"; - - TorznabCaps.SupportsImdbSearch = true; - - webclient.requestDelay = 2; // 0.5 requests per second - - AddCategoryMapping(4, TorznabCatType.XXX, "XXX (18+)"); - AddCategoryMapping(14, TorznabCatType.MoviesSD, "Movies/XVID"); - AddCategoryMapping(48, TorznabCatType.MoviesHD, "Movies/XVID/720"); - AddCategoryMapping(17, TorznabCatType.MoviesSD, "Movies/x264"); - AddCategoryMapping(44, TorznabCatType.MoviesHD, "Movies/x264/1080"); - AddCategoryMapping(45, TorznabCatType.MoviesHD, "Movies/x264/720"); - AddCategoryMapping(47, TorznabCatType.Movies3D, "Movies/x264/3D"); - AddCategoryMapping(42, TorznabCatType.MoviesBluRay, "Movies/Full BD"); - AddCategoryMapping(46, TorznabCatType.MoviesBluRay, "Movies/BD Remux"); - AddCategoryMapping(18, TorznabCatType.TVSD, "TV Episodes"); - AddCategoryMapping(41, TorznabCatType.TVHD, "TV HD Episodes"); - AddCategoryMapping(23, TorznabCatType.AudioMP3, "Music/MP3"); - AddCategoryMapping(25, TorznabCatType.AudioLossless, "Music/FLAC"); - AddCategoryMapping(27, TorznabCatType.PCGames, "Games/PC ISO"); - AddCategoryMapping(28, TorznabCatType.PCGames, "Games/PC RIP"); - AddCategoryMapping(40, TorznabCatType.ConsolePS3, "Games/PS3"); - AddCategoryMapping(32, TorznabCatType.ConsoleXbox360, "Games/XBOX-360"); - AddCategoryMapping(33, TorznabCatType.PCISO, "Software/PC ISO"); - AddCategoryMapping(35, TorznabCatType.BooksEbook, "e-Books"); - } - - - async Task CheckToken() - { - if (!HasValidToken) - { - var queryCollection = new NameValueCollection(); - queryCollection.Add("get_token", "get_token"); - - var tokenUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); - - var result = await RequestStringWithCookiesAndRetry(tokenUrl); - var json = JObject.Parse(result.Content); - token = json.Value<string>("token"); - lastTokenFetch = DateTime.Now; - } - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var releases = await PerformQuery(new TorznabQuery()); - - await ConfigureIfOK(string.Empty, releases.Count() > 0, () => - { - throw new Exception("Could not find releases from this URL"); - }); - - return IndexerConfigurationStatus.Completed; - } - - public Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - return PerformQuery(query, 0); - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, int attempts = 0) - { - await CheckToken(); - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - var queryCollection = new NameValueCollection(); - queryCollection.Add("token", token); - queryCollection.Add("format", "json_extended"); - queryCollection.Add("app_id", "jackett_v" + Engine.ConfigService.GetVersion()); - queryCollection.Add("limit", "100"); - queryCollection.Add("ranked", "0"); - - if (query.ImdbID != null) - { - queryCollection.Add("mode", "search"); - queryCollection.Add("search_imdb", query.ImdbID); - } - else if (query.RageID != null) - { - queryCollection.Add("mode", "search"); - queryCollection.Add("search_tvrage", query.RageID.ToString()); - } - /*else if (query.TvdbID != null) - { - queryCollection.Add("mode", "search"); - queryCollection.Add("search_tvdb", query.TvdbID); - }*/ - else if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("mode", "search"); - queryCollection.Add("search_string", searchString); - } - else - { - queryCollection.Add("mode", "list"); - } - - var cats = string.Join(";", MapTorznabCapsToTrackers(query)); - if (!string.IsNullOrEmpty(cats)) - { - queryCollection.Add("category", cats); - } - - var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); - var response = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty); - - try - { - var jsonContent = JObject.Parse(response.Content); - - int errorCode = jsonContent.Value<int>("error_code"); - if (errorCode == 20) // no results found - { - return releases.ToArray(); - } - - if (errorCode > 0) // too many requests per second - { - // we use the IwebClient rate limiter now, this shouldn't happen - throw new Exception(jsonContent.Value<string>("error")); - - /*if (attempts < 3) - { - await Task.Delay(TimeSpan.FromSeconds(2)); - return await PerformQuery(query, ++attempts); - } - else - { - throw new Exception(jsonContent.Value<string>("error")); - }*/ - } - - foreach (var item in jsonContent.Value<JArray>("torrent_results")) - { - var release = new ReleaseInfo(); - release.Title = item.Value<string>("title"); - release.Category = MapTrackerCatDescToNewznab(item.Value<string>("category")); - - release.MagnetUri = new Uri(item.Value<string>("download")); - release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; - - release.Comments = new Uri(item.Value<string>("info_page")); - release.Guid = release.Comments; - - var episode_info = item.Value<JToken>("episode_info"); - - if (episode_info.HasValues) - { - var imdb = episode_info.Value<string>("imdb"); - release.Imdb = ParseUtil.GetImdbID(imdb); - release.TVDBId = episode_info.Value<long?>("tvdb"); - release.RageID = episode_info.Value<long?>("tvrage"); - release.TMDb = episode_info.Value<long?>("themoviedb"); - } - - // ex: 2015-08-16 21:25:08 +0000 - var dateStr = item.Value<string>("pubdate").Replace(" +0000", ""); - var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); - - release.Seeders = item.Value<int>("seeders"); - release.Peers = item.Value<int>("leechers") + release.Seeders; - release.Size = item.Value<long>("size"); - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(response.Content, ex); - } - - return releases; - } - - } + Type = "public"; + + TorznabCaps.SupportsImdbSearch = true; + + webclient.requestDelay = 2; // 0.5 requests per second + + AddCategoryMapping(4, TorznabCatType.XXX, "XXX (18+)"); + AddCategoryMapping(14, TorznabCatType.MoviesSD, "Movies/XVID"); + AddCategoryMapping(48, TorznabCatType.MoviesHD, "Movies/XVID/720"); + AddCategoryMapping(17, TorznabCatType.MoviesSD, "Movies/x264"); + AddCategoryMapping(44, TorznabCatType.MoviesHD, "Movies/x264/1080"); + AddCategoryMapping(45, TorznabCatType.MoviesHD, "Movies/x264/720"); + AddCategoryMapping(47, TorznabCatType.Movies3D, "Movies/x264/3D"); + AddCategoryMapping(42, TorznabCatType.MoviesBluRay, "Movies/Full BD"); + AddCategoryMapping(46, TorznabCatType.MoviesBluRay, "Movies/BD Remux"); + AddCategoryMapping(18, TorznabCatType.TVSD, "TV Episodes"); + AddCategoryMapping(41, TorznabCatType.TVHD, "TV HD Episodes"); + AddCategoryMapping(23, TorznabCatType.AudioMP3, "Music/MP3"); + AddCategoryMapping(25, TorznabCatType.AudioLossless, "Music/FLAC"); + AddCategoryMapping(27, TorznabCatType.PCGames, "Games/PC ISO"); + AddCategoryMapping(28, TorznabCatType.PCGames, "Games/PC RIP"); + AddCategoryMapping(40, TorznabCatType.ConsolePS3, "Games/PS3"); + AddCategoryMapping(32, TorznabCatType.ConsoleXbox360, "Games/XBOX-360"); + AddCategoryMapping(33, TorznabCatType.PCISO, "Software/PC ISO"); + AddCategoryMapping(35, TorznabCatType.BooksEbook, "e-Books"); + } + + + async Task CheckToken() + { + if (!HasValidToken) + { + var queryCollection = new NameValueCollection(); + queryCollection.Add("get_token", "get_token"); + + var tokenUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); + + var result = await RequestStringWithCookiesAndRetry(tokenUrl); + var json = JObject.Parse(result.Content); + token = json.Value<string>("token"); + lastTokenFetch = DateTime.Now; + } + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var releases = await PerformQuery(new TorznabQuery()); + + await ConfigureIfOK(string.Empty, releases.Count() > 0, () => + { + throw new Exception("Could not find releases from this URL"); + }); + + return IndexerConfigurationStatus.Completed; + } + + public Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + return PerformQuery(query, 0); + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query, int attempts = 0) + { + await CheckToken(); + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + + var queryCollection = new NameValueCollection(); + queryCollection.Add("token", token); + queryCollection.Add("format", "json_extended"); + queryCollection.Add("app_id", "jackett_v" + Engine.ConfigService.GetVersion()); + queryCollection.Add("limit", "100"); + queryCollection.Add("ranked", "0"); + + if (query.ImdbID != null) + { + queryCollection.Add("mode", "search"); + queryCollection.Add("search_imdb", query.ImdbID); + } + else if (query.RageID != null) + { + queryCollection.Add("mode", "search"); + queryCollection.Add("search_tvrage", query.RageID.ToString()); + } + /*else if (query.TvdbID != null) + { + queryCollection.Add("mode", "search"); + queryCollection.Add("search_tvdb", query.TvdbID); + }*/ + else if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("mode", "search"); + queryCollection.Add("search_string", searchString); + } + else + { + queryCollection.Add("mode", "list"); + } + + var cats = string.Join(";", MapTorznabCapsToTrackers(query)); + if (!string.IsNullOrEmpty(cats)) + { + queryCollection.Add("category", cats); + } + + var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); + var response = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty); + + try + { + var jsonContent = JObject.Parse(response.Content); + + int errorCode = jsonContent.Value<int>("error_code"); + if (errorCode == 20) // no results found + { + return releases.ToArray(); + } + + if (errorCode > 0) // too many requests per second + { + // we use the IwebClient rate limiter now, this shouldn't happen + throw new Exception(jsonContent.Value<string>("error")); + + /*if (attempts < 3) + { + await Task.Delay(TimeSpan.FromSeconds(2)); + return await PerformQuery(query, ++attempts); + } + else + { + throw new Exception(jsonContent.Value<string>("error")); + }*/ + } + + foreach (var item in jsonContent.Value<JArray>("torrent_results")) + { + var release = new ReleaseInfo(); + release.Title = item.Value<string>("title"); + release.Category = MapTrackerCatDescToNewznab(item.Value<string>("category")); + + release.MagnetUri = new Uri(item.Value<string>("download")); + release.InfoHash = release.MagnetUri.ToString().Split(':')[3].Split('&')[0]; + + release.Comments = new Uri(item.Value<string>("info_page")); + release.Guid = release.Comments; + + var episode_info = item.Value<JToken>("episode_info"); + + if (episode_info.HasValues) + { + var imdb = episode_info.Value<string>("imdb"); + release.Imdb = ParseUtil.GetImdbID(imdb); + release.TVDBId = episode_info.Value<long?>("tvdb"); + release.RageID = episode_info.Value<long?>("tvrage"); + release.TMDb = episode_info.Value<long?>("themoviedb"); + } + + // ex: 2015-08-16 21:25:08 +0000 + var dateStr = item.Value<string>("pubdate").Replace(" +0000", ""); + var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); + + release.Seeders = item.Value<int>("seeders"); + release.Peers = item.Value<int>("leechers") + release.Seeders; + release.Size = item.Value<long>("size"); + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + return releases; + } + + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/Redacted.cs b/src/Jackett/Indexers/Redacted.cs index 82d0f130..1fc5b3fe 100644 --- a/src/Jackett/Indexers/Redacted.cs +++ b/src/Jackett/Indexers/Redacted.cs @@ -2,8 +2,8 @@ using NLog; using Jackett.Services; using Jackett.Utils.Clients; -using Jackett.Indexers.Abstract; - +using Jackett.Indexers.Abstract; + namespace Jackett.Indexers { public class PassTheHeadphones : GazelleTracker, IIndexer @@ -22,12 +22,12 @@ namespace Jackett.Indexers Type = "private"; AddCategoryMapping(1, TorznabCatType.Audio, "Music"); - AddCategoryMapping(2, TorznabCatType.PC, "Applications"); - AddCategoryMapping(3, TorznabCatType.Books, "E-Books"); - AddCategoryMapping(4, TorznabCatType.AudioAudiobook, "Audiobooks"); - AddCategoryMapping(5, TorznabCatType.Movies, "E-Learning Videos"); - AddCategoryMapping(6, TorznabCatType.TV, "Comedy"); - AddCategoryMapping(7, TorznabCatType.Books, "Comics"); + AddCategoryMapping(2, TorznabCatType.PC, "Applications"); + AddCategoryMapping(3, TorznabCatType.Books, "E-Books"); + AddCategoryMapping(4, TorznabCatType.AudioAudiobook, "Audiobooks"); + AddCategoryMapping(5, TorznabCatType.Movies, "E-Learning Videos"); + AddCategoryMapping(6, TorznabCatType.TV, "Comedy"); + AddCategoryMapping(7, TorznabCatType.Books, "Comics"); } } } \ No newline at end of file diff --git a/src/Jackett/Indexers/SceneAccess.cs b/src/Jackett/Indexers/SceneAccess.cs index fa62fea5..9dcd6ef8 100644 --- a/src/Jackett/Indexers/SceneAccess.cs +++ b/src/Jackett/Indexers/SceneAccess.cs @@ -1,175 +1,175 @@ -using CsQuery; -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.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Web; - -namespace Jackett.Indexers -{ - class SceneAccess : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login"; } } - private string SearchUrl { get { return SiteLink + "all?search={0}&method=2"; } } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps) - : base(name: "SceneAccess", - description: "Your gateway to the scene", - link: "https://sceneaccess.eu/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: c, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - AddCategoryMapping(8, TorznabCatType.MoviesSD); - AddCategoryMapping(22, TorznabCatType.MoviesHD); - AddCategoryMapping(7, TorznabCatType.MoviesSD); - AddCategoryMapping(4, TorznabCatType.Movies); - - AddCategoryMapping(27, TorznabCatType.TVHD); - AddCategoryMapping(17, TorznabCatType.TVSD); - AddCategoryMapping(11, TorznabCatType.MoviesSD); - AddCategoryMapping(26, TorznabCatType.TV); - - AddCategoryMapping(3, TorznabCatType.PCGames); - AddCategoryMapping(5, TorznabCatType.ConsolePS3); - AddCategoryMapping(20, TorznabCatType.ConsolePSP); - AddCategoryMapping(28, TorznabCatType.TV); - AddCategoryMapping(23, TorznabCatType.Console); - AddCategoryMapping(29, TorznabCatType.Console); - - AddCategoryMapping(40, TorznabCatType.AudioLossless); - AddCategoryMapping(13, TorznabCatType.AudioMP3); - AddCategoryMapping(15, TorznabCatType.AudioVideo); - - AddCategoryMapping(1, TorznabCatType.PCISO); - AddCategoryMapping(2, TorznabCatType.PCISO); - AddCategoryMapping(14, TorznabCatType.PCISO); - AddCategoryMapping(21, TorznabCatType.Other); - - AddCategoryMapping(41, TorznabCatType.MoviesHD); - AddCategoryMapping(42, TorznabCatType.MoviesSD); - AddCategoryMapping(43, TorznabCatType.MoviesSD); - AddCategoryMapping(44, TorznabCatType.TVHD); - AddCategoryMapping(45, TorznabCatType.TVSD); - - AddCategoryMapping(12, TorznabCatType.XXXXviD); - AddCategoryMapping(35, TorznabCatType.XXXx264); - AddCategoryMapping(36, TorznabCatType.XXX); - - AddCategoryMapping(30, TorznabCatType.MoviesForeign); - AddCategoryMapping(31, TorznabCatType.MoviesForeign); - AddCategoryMapping(32, TorznabCatType.MoviesForeign); - AddCategoryMapping(33, TorznabCatType.TVFOREIGN); - AddCategoryMapping(34, TorznabCatType.TVFOREIGN); - - AddCategoryMapping(4, TorznabCatType.Movies); - AddCategoryMapping(37, TorznabCatType.XXX); - AddCategoryMapping(38, TorznabCatType.Audio); - - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "submit", "come on in" } - }; - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("nav_profile"), () => - { - CQ dom = result.Content; - var messageEl = dom["#login_box_desc"]; - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var results = await RequestStringWithCookiesAndRetry(string.Format(SearchUrl, HttpUtility.UrlEncode(query.GetQueryString()))); - - try - { - CQ dom = results.Content; - var rows = dom["#torrents-table > tbody > tr.tt_row"]; - foreach (var row in rows) - { - CQ qRow = row.Cq(); - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 129600; - release.Title = qRow.Find(".ttr_name > a").Text(); - release.Description = release.Title; - release.Guid = new Uri(SiteLink + qRow.Find(".ttr_name > a").Attr("href")); - release.Comments = release.Guid; - release.Link = new Uri(SiteLink + qRow.Find(".td_dl > a").Attr("href")); - - var sizeStr = qRow.Find(".ttr_size").Contents()[0].NodeValue; - release.Size = ReleaseInfo.GetBytes(sizeStr); - - var timeStr = qRow.Find(".ttr_added").Text(); - DateTime time; - if (DateTime.TryParseExact(timeStr, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out time)) - { - release.PublishDate = time; - } - - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".ttr_seeders").Text()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".ttr_leechers").Text()) + release.Seeders; - - var cat = qRow.Find(".ttr_type a").Attr("href").Replace("?cat=",string.Empty); - - release.Category = MapTrackerCatToNewznab(cat); - +using CsQuery; +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.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Web; + +namespace Jackett.Indexers +{ + class SceneAccess : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login"; } } + private string SearchUrl { get { return SiteLink + "all?search={0}&method=2"; } } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public SceneAccess(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps) + : base(name: "SceneAccess", + description: "Your gateway to the scene", + link: "https://sceneaccess.eu/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: c, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + AddCategoryMapping(8, TorznabCatType.MoviesSD); + AddCategoryMapping(22, TorznabCatType.MoviesHD); + AddCategoryMapping(7, TorznabCatType.MoviesSD); + AddCategoryMapping(4, TorznabCatType.Movies); + + AddCategoryMapping(27, TorznabCatType.TVHD); + AddCategoryMapping(17, TorznabCatType.TVSD); + AddCategoryMapping(11, TorznabCatType.MoviesSD); + AddCategoryMapping(26, TorznabCatType.TV); + + AddCategoryMapping(3, TorznabCatType.PCGames); + AddCategoryMapping(5, TorznabCatType.ConsolePS3); + AddCategoryMapping(20, TorznabCatType.ConsolePSP); + AddCategoryMapping(28, TorznabCatType.TV); + AddCategoryMapping(23, TorznabCatType.Console); + AddCategoryMapping(29, TorznabCatType.Console); + + AddCategoryMapping(40, TorznabCatType.AudioLossless); + AddCategoryMapping(13, TorznabCatType.AudioMP3); + AddCategoryMapping(15, TorznabCatType.AudioVideo); + + AddCategoryMapping(1, TorznabCatType.PCISO); + AddCategoryMapping(2, TorznabCatType.PCISO); + AddCategoryMapping(14, TorznabCatType.PCISO); + AddCategoryMapping(21, TorznabCatType.Other); + + AddCategoryMapping(41, TorznabCatType.MoviesHD); + AddCategoryMapping(42, TorznabCatType.MoviesSD); + AddCategoryMapping(43, TorznabCatType.MoviesSD); + AddCategoryMapping(44, TorznabCatType.TVHD); + AddCategoryMapping(45, TorznabCatType.TVSD); + + AddCategoryMapping(12, TorznabCatType.XXXXviD); + AddCategoryMapping(35, TorznabCatType.XXXx264); + AddCategoryMapping(36, TorznabCatType.XXX); + + AddCategoryMapping(30, TorznabCatType.MoviesForeign); + AddCategoryMapping(31, TorznabCatType.MoviesForeign); + AddCategoryMapping(32, TorznabCatType.MoviesForeign); + AddCategoryMapping(33, TorznabCatType.TVFOREIGN); + AddCategoryMapping(34, TorznabCatType.TVFOREIGN); + + AddCategoryMapping(4, TorznabCatType.Movies); + AddCategoryMapping(37, TorznabCatType.XXX); + AddCategoryMapping(38, TorznabCatType.Audio); + + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "submit", "come on in" } + }; + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SiteLink, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("nav_profile"), () => + { + CQ dom = result.Content; + var messageEl = dom["#login_box_desc"]; + var errorMessage = messageEl.Text().Trim(); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var results = await RequestStringWithCookiesAndRetry(string.Format(SearchUrl, HttpUtility.UrlEncode(query.GetQueryString()))); + + try + { + CQ dom = results.Content; + var rows = dom["#torrents-table > tbody > tr.tt_row"]; + foreach (var row in rows) + { + CQ qRow = row.Cq(); + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 129600; + release.Title = qRow.Find(".ttr_name > a").Text(); + release.Description = release.Title; + release.Guid = new Uri(SiteLink + qRow.Find(".ttr_name > a").Attr("href")); + release.Comments = release.Guid; + release.Link = new Uri(SiteLink + qRow.Find(".td_dl > a").Attr("href")); + + var sizeStr = qRow.Find(".ttr_size").Contents()[0].NodeValue; + release.Size = ReleaseInfo.GetBytes(sizeStr); + + var timeStr = qRow.Find(".ttr_added").Text(); + DateTime time; + if (DateTime.TryParseExact(timeStr, "yyyy-MM-ddHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out time)) + { + release.PublishDate = time; + } + + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".ttr_seeders").Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".ttr_leechers").Text()) + release.Seeders; + + var cat = qRow.Find(".ttr_type a").Attr("href").Replace("?cat=",string.Empty); + + release.Category = MapTrackerCatToNewznab(cat); + var files = qRow.Find("td.ttr_size > a").Text().Split(' ')[0]; release.Files = ParseUtil.CoerceInt(files); var grabs = qRow.Find("td.ttr_snatched").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/SceneFZ.cs b/src/Jackett/Indexers/SceneFZ.cs index 7fe1346d..6a2fc5fc 100644 --- a/src/Jackett/Indexers/SceneFZ.cs +++ b/src/Jackett/Indexers/SceneFZ.cs @@ -44,51 +44,51 @@ namespace Jackett.Indexers this.configData.Instructions.Value = "The published date is only available if you set \"Torrent Listing\" to Complex is your profile."; - AddCategoryMapping("mc32", TorznabCatType.Movies); // Movies - AddCategoryMapping("scat22", TorznabCatType.MoviesBluRay); // BluRay - AddCategoryMapping("scat40", TorznabCatType.MoviesSD); // Xvid - AddCategoryMapping("scat41", TorznabCatType.MoviesDVD); // Dvd - AddCategoryMapping("scat47", TorznabCatType.MoviesHD); // HD - AddCategoryMapping("scat52", TorznabCatType.MoviesDVD); // DVD-RO - AddCategoryMapping("scat53", TorznabCatType.MoviesHD); // HD-RO - AddCategoryMapping("scat54", TorznabCatType.MoviesBluRay); // BluRay-RO - AddCategoryMapping("scat55", TorznabCatType.MoviesSD); // XVID-RO - AddCategoryMapping("scat60", TorznabCatType.MoviesOther); // Sport - AddCategoryMapping("mc33", TorznabCatType.TV); // TV - AddCategoryMapping("scat66", TorznabCatType.TVSD); // SD - AddCategoryMapping("scat67", TorznabCatType.TVSD); // SD-RO - AddCategoryMapping("scat68", TorznabCatType.TVHD); // HD - AddCategoryMapping("scat69", TorznabCatType.TVHD); // HDTV-RO - AddCategoryMapping("mc30", TorznabCatType.Console); // Games - AddCategoryMapping("scat58", TorznabCatType.ConsolePS3); // PS2 - AddCategoryMapping("scat16", TorznabCatType.PCGames); // Pc-Iso - AddCategoryMapping("scat17", TorznabCatType.Console); // Misc - AddCategoryMapping("scat18", TorznabCatType.PCGames); // Pc-Rip - AddCategoryMapping("scat19", TorznabCatType.Console); // Consoles - AddCategoryMapping("scat57", TorznabCatType.ConsoleXbox360); // Xbox 360 - AddCategoryMapping("scat46", TorznabCatType.Console); // Oldies - AddCategoryMapping("scat59", TorznabCatType.ConsolePS3); // PS3 - AddCategoryMapping("mc31", TorznabCatType.PC); // Soft - AddCategoryMapping("scat20", TorznabCatType.PC); // Pc-Iso - AddCategoryMapping("scat21", TorznabCatType.PC); // Misc - AddCategoryMapping("scat48", TorznabCatType.PCMac); // Mac OS - AddCategoryMapping("mc27", TorznabCatType.Audio); // Music - AddCategoryMapping("scat8", TorznabCatType.AudioMP3); // MP3 - AddCategoryMapping("scat45", TorznabCatType.AudioVideo); // Videoclips - AddCategoryMapping("scat61", TorznabCatType.AudioLossless); // FLAC - AddCategoryMapping("mc35", TorznabCatType.PCPhoneOther); // Mobile - AddCategoryMapping("scat44", TorznabCatType.PCPhoneOther); // Misc - AddCategoryMapping("scat64", TorznabCatType.PCPhoneIOS); // iOS - AddCategoryMapping("scat65", TorznabCatType.PCPhoneAndroid); // Android - AddCategoryMapping("mc28", TorznabCatType.TVAnime); // Anime - AddCategoryMapping("scat13", TorznabCatType.TVAnime); // Tv-Eps - AddCategoryMapping("scat12", TorznabCatType.TVAnime); // Cartoons - AddCategoryMapping("mc29", TorznabCatType.TVDocumentary); // Docs - AddCategoryMapping("scat14", TorznabCatType.Books); // Books - AddCategoryMapping("scat15", TorznabCatType.Other); // Misc - AddCategoryMapping("mc36", TorznabCatType.PC0day); // 0Day - AddCategoryMapping("mc34", TorznabCatType.XXX); // XXX 18 - AddCategoryMapping("scat33", TorznabCatType.Other); // Images + AddCategoryMapping("mc32", TorznabCatType.Movies); // Movies + AddCategoryMapping("scat22", TorznabCatType.MoviesBluRay); // BluRay + AddCategoryMapping("scat40", TorznabCatType.MoviesSD); // Xvid + AddCategoryMapping("scat41", TorznabCatType.MoviesDVD); // Dvd + AddCategoryMapping("scat47", TorznabCatType.MoviesHD); // HD + AddCategoryMapping("scat52", TorznabCatType.MoviesDVD); // DVD-RO + AddCategoryMapping("scat53", TorznabCatType.MoviesHD); // HD-RO + AddCategoryMapping("scat54", TorznabCatType.MoviesBluRay); // BluRay-RO + AddCategoryMapping("scat55", TorznabCatType.MoviesSD); // XVID-RO + AddCategoryMapping("scat60", TorznabCatType.MoviesOther); // Sport + AddCategoryMapping("mc33", TorznabCatType.TV); // TV + AddCategoryMapping("scat66", TorznabCatType.TVSD); // SD + AddCategoryMapping("scat67", TorznabCatType.TVSD); // SD-RO + AddCategoryMapping("scat68", TorznabCatType.TVHD); // HD + AddCategoryMapping("scat69", TorznabCatType.TVHD); // HDTV-RO + AddCategoryMapping("mc30", TorznabCatType.Console); // Games + AddCategoryMapping("scat58", TorznabCatType.ConsolePS3); // PS2 + AddCategoryMapping("scat16", TorznabCatType.PCGames); // Pc-Iso + AddCategoryMapping("scat17", TorznabCatType.Console); // Misc + AddCategoryMapping("scat18", TorznabCatType.PCGames); // Pc-Rip + AddCategoryMapping("scat19", TorznabCatType.Console); // Consoles + AddCategoryMapping("scat57", TorznabCatType.ConsoleXbox360); // Xbox 360 + AddCategoryMapping("scat46", TorznabCatType.Console); // Oldies + AddCategoryMapping("scat59", TorznabCatType.ConsolePS3); // PS3 + AddCategoryMapping("mc31", TorznabCatType.PC); // Soft + AddCategoryMapping("scat20", TorznabCatType.PC); // Pc-Iso + AddCategoryMapping("scat21", TorznabCatType.PC); // Misc + AddCategoryMapping("scat48", TorznabCatType.PCMac); // Mac OS + AddCategoryMapping("mc27", TorznabCatType.Audio); // Music + AddCategoryMapping("scat8", TorznabCatType.AudioMP3); // MP3 + AddCategoryMapping("scat45", TorznabCatType.AudioVideo); // Videoclips + AddCategoryMapping("scat61", TorznabCatType.AudioLossless); // FLAC + AddCategoryMapping("mc35", TorznabCatType.PCPhoneOther); // Mobile + AddCategoryMapping("scat44", TorznabCatType.PCPhoneOther); // Misc + AddCategoryMapping("scat64", TorznabCatType.PCPhoneIOS); // iOS + AddCategoryMapping("scat65", TorznabCatType.PCPhoneAndroid); // Android + AddCategoryMapping("mc28", TorznabCatType.TVAnime); // Anime + AddCategoryMapping("scat13", TorznabCatType.TVAnime); // Tv-Eps + AddCategoryMapping("scat12", TorznabCatType.TVAnime); // Cartoons + AddCategoryMapping("mc29", TorznabCatType.TVDocumentary); // Docs + AddCategoryMapping("scat14", TorznabCatType.Books); // Books + AddCategoryMapping("scat15", TorznabCatType.Other); // Misc + AddCategoryMapping("mc36", TorznabCatType.PC0day); // 0Day + AddCategoryMapping("mc34", TorznabCatType.XXX); // XXX 18 + AddCategoryMapping("scat33", TorznabCatType.Other); // Images AddCategoryMapping("scat34", TorznabCatType.Other); // Video } @@ -140,9 +140,9 @@ namespace Jackett.Indexers var qRow = row.Cq(); var qTitleLink = qRow.Find("a[href^=\"details\"]").First(); if (qTitleLink.HasAttr("title")) - release.Title = qTitleLink.Attr("title"); - else - release.Title = qTitleLink.Text(); + release.Title = qTitleLink.Attr("title"); + else + release.Title = qTitleLink.Text(); release.Description = qRow.Find("small > i").Text(); release.Guid = new Uri(SiteLink + qTitleLink.Attr("href")); release.Comments = release.Guid; @@ -160,8 +160,8 @@ namespace Jackett.Indexers release.Seeders = ParseUtil.CoerceInt(qRow.Find("td > a[href*=\"&toseeders=1\"]:first-child, td:has(a[href*=\"&toseeders=1\"]) > b:nth-child(1)").Text()); release.Peers = ParseUtil.CoerceInt(qRow.Find("td > a[href*=\"&todlers=1\"]:last-child, a[href*=\"&toseeders=1\"] + b").Text().Replace("L.", "")) + release.Seeders; - release.Grabs = ParseUtil.CoerceLong(qRow.Find("td[style]:has(a[href*=\"tosnatchers=1\"])").Text().Replace(" Completed", "")); - + release.Grabs = ParseUtil.CoerceLong(qRow.Find("td[style]:has(a[href*=\"tosnatchers=1\"])").Text().Replace(" Completed", "")); + release.DownloadVolumeFactor = 0; release.UploadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/SceneTime.cs b/src/Jackett/Indexers/SceneTime.cs index f2af2110..1bbe36da 100644 --- a/src/Jackett/Indexers/SceneTime.cs +++ b/src/Jackett/Indexers/SceneTime.cs @@ -37,7 +37,7 @@ namespace Jackett.Indexers client: w, logger: l, p: ps, - configData: new ConfigurationDataRecaptchaLogin("For best results, change the 'Torrents per page' setting to the maximum in your profile on the SceneTime webpage.")) + configData: new ConfigurationDataRecaptchaLogin("For best results, change the 'Torrents per page' setting to the maximum in your profile on the SceneTime webpage.")) { Encoding = Encoding.GetEncoding("iso-8859-1"); Language = "en-us"; @@ -96,7 +96,7 @@ namespace Jackett.Indexers result.CookieHeader.Value = loginPage.Cookies; result.Captcha.SiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); return result; - } + } else { var stdResult = new ConfigurationDataBasicLogin(); @@ -105,7 +105,7 @@ namespace Jackett.Indexers stdResult.Password.Value = configData.Password.Value; stdResult.CookieHeader.Value = loginPage.Cookies; return stdResult; - } + } } public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) @@ -205,7 +205,7 @@ namespace Jackett.Indexers var qDescCol = descCol.Cq(); var qLink = qDescCol.Find("a"); release.Title = qLink.Text(); - if (!query.MatchQueryStringAND(release.Title)) + if (!query.MatchQueryStringAND(release.Title)) continue; release.Description = release.Title; @@ -222,11 +222,11 @@ namespace Jackett.Indexers release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(seedersIndex).Cq().Text().Trim()); release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(leechersIndex).Cq().Text().Trim()) + release.Seeders; - if (row.Cq().Find("font > b:contains(Freeleech)").Length >= 1) - release.DownloadVolumeFactor = 0; + if (row.Cq().Find("font > b:contains(Freeleech)").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/Shazbat.cs b/src/Jackett/Indexers/Shazbat.cs index d8ebf58e..1301a596 100644 --- a/src/Jackett/Indexers/Shazbat.cs +++ b/src/Jackett/Indexers/Shazbat.cs @@ -1,265 +1,265 @@ -using CsQuery; -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.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; -using System.Globalization; -using System.Text.RegularExpressions; -using System.Xml.Linq; -using System.Xml.XPath; - -namespace Jackett.Indexers -{ - public class Shazbat : BaseIndexer, IIndexer - { - private string LoginUrl { get { return SiteLink + "login"; } } - private string SearchUrl { get { return SiteLink + "search"; } } - private string TorrentsUrl { get { return SiteLink + "torrents"; } } - private string ShowUrl { get { return SiteLink + "show?id="; } } - private string RSSProfile { get { return SiteLink + "rss_feeds"; } } - - new ConfigurationDataBasicLoginWithRSS configData - { - get { return (ConfigurationDataBasicLoginWithRSS)base.configData; } - set { base.configData = value; } - } - - public Shazbat(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps) - : base(name: "Shazbat", - description: "Modern indexer", - link: "https://www.shazbat.tv/", - caps: new TorznabCapabilities(TorznabCatType.TV, - TorznabCatType.TVHD, - TorznabCatType.TVSD), - manager: i, - client: c, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSS()) - { - Encoding = Encoding.UTF8; - Language = "en-us"; - Type = "private"; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "referer", "login"}, - { "query", ""}, - { "tv_login", configData.Username.Value }, - { "tv_password", configData.Password.Value }, - { "email", "" } - }; - - // Get cookie - var firstRequest = await RequestStringWithCookiesAndRetry(LoginUrl); - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("glyphicon-log-out"), () => - { - throw new ExceptionWithConfigData("The username and password entered do not match.", configData); - }); - - var rssProfile = await RequestStringWithCookiesAndRetry(RSSProfile); - CQ rssDom = rssProfile.Content; - configData.RSSKey.Value = rssDom.Find(".col-sm-9:eq(0)").Text().Trim(); - if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) - { - throw new ExceptionWithConfigData("Failed to find RSS key.", configData); - } - - SaveConfig(); - return IndexerConfigurationStatus.RequiresTesting; - } - - protected async Task<WebClientStringResult> ReloginIfNecessary(WebClientStringResult response) - { - if (!response.Content.Contains("onclick=\"document.location='logout'\"")) - { - await ApplyConfiguration(null); - response.Request.Cookies = CookieHeader; - return await webclient.GetString(response.Request); - } - return response; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - - var queryString = query.GetQueryString(); - var url = TorrentsUrl; - - WebClientStringResult results = null; - - var searchUrls = new List<string>(); - if (!string.IsNullOrWhiteSpace(query.SanitizedSearchTerm)) - { - var pairs = new Dictionary<string, string>(); - pairs.Add("search", query.SanitizedSearchTerm); - - results = await PostDataWithCookiesAndRetry(SearchUrl, pairs, null, TorrentsUrl); - results = await ReloginIfNecessary(results); - CQ dom = results.Content; - var shows = dom.Find("div.show[data-id]"); - foreach (var show in shows) - { - var showUrl = ShowUrl + show.GetAttribute("data-id"); - searchUrls.Add(showUrl); - } - } - else - { - searchUrls.Add(TorrentsUrl); - } - - try - { - foreach (var searchUrl in searchUrls) - { - results = await RequestStringWithCookies(searchUrl); - results = await ReloginIfNecessary(results); - - CQ dom = results.Content; - var rows = dom["#torrent-table tr"]; - - if (!string.IsNullOrWhiteSpace(queryString)) - { - rows = dom["table tr"]; - } - - var globalFreeleech = dom.Find("span:contains(\"Freeleech until:\"):has(span.datetime)").Any(); - - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - var titleRow = qRow.Find("td:eq(2)").First(); - titleRow.Children().Remove(); - release.Title = titleRow.Text().Trim(); - if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) - continue; - - var qBanner = qRow.Find("div[style^=\"cursor: pointer; background-image:url\"]"); - var qBannerStyle = qBanner.Attr("style"); - if (!string.IsNullOrEmpty(qBannerStyle)) - { - var bannerImg = Regex.Match(qBannerStyle, @"url\('(.*?)'\);").Groups[1].Value; - release.BannerUrl = new Uri(SiteLink + bannerImg); - } - - var qLink = row.Cq().Find("td:eq(4) a:eq(0)"); - release.Link = new Uri(SiteLink + qLink.Attr("href")); - release.Guid = release.Link; - var qLinkComm = row.Cq().Find("td:eq(4) a:eq(1)"); - release.Comments = new Uri(SiteLink + qLinkComm.Attr("href")); - - var dateString = qRow.Find(".datetime").Attr("data-timestamp"); - if (dateString != null) - release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)).ToLocalTime(); - var infoString = row.Cq().Find("td:eq(3)").Text(); - - release.Size = ParseUtil.CoerceLong(Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(", "").Replace(")", "")); - - var infosplit = infoString.Replace("/", string.Empty).Split(":".ToCharArray()); - release.Seeders = ParseUtil.CoerceInt(infosplit[1]); - release.Peers = release.Seeders + ParseUtil.CoerceInt(infosplit[2]); - - if (globalFreeleech) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - // var tags = row.Cq().Find(".label-tag").Text(); These don't see to parse - bad tags? - - releases.Add(release); - } - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - /* else - { - var rssUrl = SiteLink + "rss/recent?passkey=" + configData.RSSKey.Value; - - results = await RequestStringWithCookiesAndRetry(rssUrl); - try - { - var doc = XDocument.Parse(results.Content); - foreach (var result in doc.Descendants("item")) - { - var xTitle = result.Element("title").Value; - var xLink = result.Element("link").Value; - var xGUID = result.Element("guid").Value; - var xDesc = result.Element("description").Value; - var xDate = result.Element("pubDate").Value; - var release = new ReleaseInfo(); - release.Guid =release.Link = new Uri(xLink); - release.MinimumRatio = 1; - release.Seeders = 1; // We are not supplied with peer info so just mark it as one. - foreach (var element in xDesc.Split(";".ToCharArray())) - { - var split = element.IndexOf(':'); - if (split > -1) - { - var key = element.Substring(0, split).Trim(); - var value = element.Substring(split+1).Trim(); - - switch (key) - { - case "Filename": - release.Title = release.Description = value; - break; - } - } - } - - //"Thu, 24 Sep 2015 18:07:07 +0000" - release.PublishDate = DateTime.ParseExact(xDate, "ddd, dd MMM yyyy HH:mm:ss +0000", CultureInfo.InvariantCulture); - - if (!string.IsNullOrWhiteSpace(release.Title)) - { - releases.Add(release); - } - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - }*/ - - - foreach (var release in releases) - { - if (release.Title.Contains("1080p") || release.Title.Contains("720p")) - { - release.Category = new List<int> { TorznabCatType.TVHD.ID }; - } - else - { - release.Category = new List<int> { TorznabCatType.TVSD.ID }; - } - } - - return releases; - } - } -} +using CsQuery; +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.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Jackett.Indexers +{ + public class Shazbat : BaseIndexer, IIndexer + { + private string LoginUrl { get { return SiteLink + "login"; } } + private string SearchUrl { get { return SiteLink + "search"; } } + private string TorrentsUrl { get { return SiteLink + "torrents"; } } + private string ShowUrl { get { return SiteLink + "show?id="; } } + private string RSSProfile { get { return SiteLink + "rss_feeds"; } } + + new ConfigurationDataBasicLoginWithRSS configData + { + get { return (ConfigurationDataBasicLoginWithRSS)base.configData; } + set { base.configData = value; } + } + + public Shazbat(IIndexerManagerService i, IWebClient c, Logger l, IProtectionService ps) + : base(name: "Shazbat", + description: "Modern indexer", + link: "https://www.shazbat.tv/", + caps: new TorznabCapabilities(TorznabCatType.TV, + TorznabCatType.TVHD, + TorznabCatType.TVSD), + manager: i, + client: c, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSS()) + { + Encoding = Encoding.UTF8; + Language = "en-us"; + Type = "private"; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "referer", "login"}, + { "query", ""}, + { "tv_login", configData.Username.Value }, + { "tv_password", configData.Password.Value }, + { "email", "" } + }; + + // Get cookie + var firstRequest = await RequestStringWithCookiesAndRetry(LoginUrl); + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("glyphicon-log-out"), () => + { + throw new ExceptionWithConfigData("The username and password entered do not match.", configData); + }); + + var rssProfile = await RequestStringWithCookiesAndRetry(RSSProfile); + CQ rssDom = rssProfile.Content; + configData.RSSKey.Value = rssDom.Find(".col-sm-9:eq(0)").Text().Trim(); + if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) + { + throw new ExceptionWithConfigData("Failed to find RSS key.", configData); + } + + SaveConfig(); + return IndexerConfigurationStatus.RequiresTesting; + } + + protected async Task<WebClientStringResult> ReloginIfNecessary(WebClientStringResult response) + { + if (!response.Content.Contains("onclick=\"document.location='logout'\"")) + { + await ApplyConfiguration(null); + response.Request.Cookies = CookieHeader; + return await webclient.GetString(response.Request); + } + return response; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + + var queryString = query.GetQueryString(); + var url = TorrentsUrl; + + WebClientStringResult results = null; + + var searchUrls = new List<string>(); + if (!string.IsNullOrWhiteSpace(query.SanitizedSearchTerm)) + { + var pairs = new Dictionary<string, string>(); + pairs.Add("search", query.SanitizedSearchTerm); + + results = await PostDataWithCookiesAndRetry(SearchUrl, pairs, null, TorrentsUrl); + results = await ReloginIfNecessary(results); + CQ dom = results.Content; + var shows = dom.Find("div.show[data-id]"); + foreach (var show in shows) + { + var showUrl = ShowUrl + show.GetAttribute("data-id"); + searchUrls.Add(showUrl); + } + } + else + { + searchUrls.Add(TorrentsUrl); + } + + try + { + foreach (var searchUrl in searchUrls) + { + results = await RequestStringWithCookies(searchUrl); + results = await ReloginIfNecessary(results); + + CQ dom = results.Content; + var rows = dom["#torrent-table tr"]; + + if (!string.IsNullOrWhiteSpace(queryString)) + { + rows = dom["table tr"]; + } + + var globalFreeleech = dom.Find("span:contains(\"Freeleech until:\"):has(span.datetime)").Any(); + + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + var titleRow = qRow.Find("td:eq(2)").First(); + titleRow.Children().Remove(); + release.Title = titleRow.Text().Trim(); + if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) + continue; + + var qBanner = qRow.Find("div[style^=\"cursor: pointer; background-image:url\"]"); + var qBannerStyle = qBanner.Attr("style"); + if (!string.IsNullOrEmpty(qBannerStyle)) + { + var bannerImg = Regex.Match(qBannerStyle, @"url\('(.*?)'\);").Groups[1].Value; + release.BannerUrl = new Uri(SiteLink + bannerImg); + } + + var qLink = row.Cq().Find("td:eq(4) a:eq(0)"); + release.Link = new Uri(SiteLink + qLink.Attr("href")); + release.Guid = release.Link; + var qLinkComm = row.Cq().Find("td:eq(4) a:eq(1)"); + release.Comments = new Uri(SiteLink + qLinkComm.Attr("href")); + + var dateString = qRow.Find(".datetime").Attr("data-timestamp"); + if (dateString != null) + release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(ParseUtil.CoerceDouble(dateString)).ToLocalTime(); + var infoString = row.Cq().Find("td:eq(3)").Text(); + + release.Size = ParseUtil.CoerceLong(Regex.Match(infoString, "\\((\\d+)\\)").Value.Replace("(", "").Replace(")", "")); + + var infosplit = infoString.Replace("/", string.Empty).Split(":".ToCharArray()); + release.Seeders = ParseUtil.CoerceInt(infosplit[1]); + release.Peers = release.Seeders + ParseUtil.CoerceInt(infosplit[2]); + + if (globalFreeleech) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + // var tags = row.Cq().Find(".label-tag").Text(); These don't see to parse - bad tags? + + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + /* else + { + var rssUrl = SiteLink + "rss/recent?passkey=" + configData.RSSKey.Value; + + results = await RequestStringWithCookiesAndRetry(rssUrl); + try + { + var doc = XDocument.Parse(results.Content); + foreach (var result in doc.Descendants("item")) + { + var xTitle = result.Element("title").Value; + var xLink = result.Element("link").Value; + var xGUID = result.Element("guid").Value; + var xDesc = result.Element("description").Value; + var xDate = result.Element("pubDate").Value; + var release = new ReleaseInfo(); + release.Guid =release.Link = new Uri(xLink); + release.MinimumRatio = 1; + release.Seeders = 1; // We are not supplied with peer info so just mark it as one. + foreach (var element in xDesc.Split(";".ToCharArray())) + { + var split = element.IndexOf(':'); + if (split > -1) + { + var key = element.Substring(0, split).Trim(); + var value = element.Substring(split+1).Trim(); + + switch (key) + { + case "Filename": + release.Title = release.Description = value; + break; + } + } + } + + //"Thu, 24 Sep 2015 18:07:07 +0000" + release.PublishDate = DateTime.ParseExact(xDate, "ddd, dd MMM yyyy HH:mm:ss +0000", CultureInfo.InvariantCulture); + + if (!string.IsNullOrWhiteSpace(release.Title)) + { + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + }*/ + + + foreach (var release in releases) + { + if (release.Title.Contains("1080p") || release.Title.Contains("720p")) + { + release.Category = new List<int> { TorznabCatType.TVHD.ID }; + } + else + { + release.Category = new List<int> { TorznabCatType.TVSD.ID }; + } + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs index c865f378..ff305b0a 100644 --- a/src/Jackett/Indexers/ShowRSS.cs +++ b/src/Jackett/Indexers/ShowRSS.cs @@ -1,115 +1,115 @@ -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.Xml; -using System.Text; -using Jackett.Models.IndexerConfig; - -namespace Jackett.Indexers -{ - public class ShowRSS : BaseIndexer, IIndexer - { - private string SearchAllUrl { get { return SiteLink + "feeds/all.rss"; } } - - new ConfigurationData configData - { - get { return (ConfigurationData)base.configData; } - set { base.configData = value; } - } - - public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "ShowRSS", - description: "showRSS is a service that allows you to keep track of your favorite TV shows", - link: "http://showrss.info/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationData()) - { - Encoding = Encoding.UTF8; - Language = "en-us"; - Type = "public"; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - var releases = await PerformQuery(new TorznabQuery()); - - await ConfigureIfOK(string.Empty, releases.Count() > 0, () => - { - throw new Exception("Could not find releases from this URL"); - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public override Task<byte[]> Download(Uri link) - { - throw new NotImplementedException(); - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var episodeSearchUrl = string.Format(SearchAllUrl); - var result = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty); - var xmlDoc = new XmlDocument(); - - try - { - xmlDoc.LoadXml(result.Content); - ReleaseInfo release; - string serie_title; - - foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) - { - release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - - serie_title = node.SelectSingleNode(".//*[local-name()='rawtitle']").InnerText; - release.Title = serie_title; - - if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) - continue; - - release.Comments = new Uri(node.SelectSingleNode("link").InnerText); - int category = 0; - int.TryParse(node.SelectSingleNode("title").InnerText, out category); - release.Category = new List<int> { category }; - var test = node.SelectSingleNode("enclosure"); - release.Guid = new Uri(test.Attributes["url"].Value); - release.PublishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture); - - release.Description = node.SelectSingleNode("description").InnerText; - release.InfoHash = node.SelectSingleNode("description").InnerText; - release.Size = 0; - release.Seeders = 1; - release.Peers = 1; - release.DownloadVolumeFactor = 0; - release.UploadVolumeFactor = 1; - release.MagnetUri = new Uri(node.SelectSingleNode("link").InnerText); - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(result.Content, ex); - } - - return releases; - } - } +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.Xml; +using System.Text; +using Jackett.Models.IndexerConfig; + +namespace Jackett.Indexers +{ + public class ShowRSS : BaseIndexer, IIndexer + { + private string SearchAllUrl { get { return SiteLink + "feeds/all.rss"; } } + + new ConfigurationData configData + { + get { return (ConfigurationData)base.configData; } + set { base.configData = value; } + } + + public ShowRSS(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "ShowRSS", + description: "showRSS is a service that allows you to keep track of your favorite TV shows", + link: "http://showrss.info/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationData()) + { + Encoding = Encoding.UTF8; + Language = "en-us"; + Type = "public"; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var releases = await PerformQuery(new TorznabQuery()); + + await ConfigureIfOK(string.Empty, releases.Count() > 0, () => + { + throw new Exception("Could not find releases from this URL"); + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public override Task<byte[]> Download(Uri link) + { + throw new NotImplementedException(); + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var episodeSearchUrl = string.Format(SearchAllUrl); + var result = await RequestStringWithCookiesAndRetry(episodeSearchUrl, string.Empty); + var xmlDoc = new XmlDocument(); + + try + { + xmlDoc.LoadXml(result.Content); + ReleaseInfo release; + string serie_title; + + foreach (XmlNode node in xmlDoc.GetElementsByTagName("item")) + { + release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + + serie_title = node.SelectSingleNode(".//*[local-name()='rawtitle']").InnerText; + release.Title = serie_title; + + if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) + continue; + + release.Comments = new Uri(node.SelectSingleNode("link").InnerText); + int category = 0; + int.TryParse(node.SelectSingleNode("title").InnerText, out category); + release.Category = new List<int> { category }; + var test = node.SelectSingleNode("enclosure"); + release.Guid = new Uri(test.Attributes["url"].Value); + release.PublishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture); + + release.Description = node.SelectSingleNode("description").InnerText; + release.InfoHash = node.SelectSingleNode("description").InnerText; + release.Size = 0; + release.Seeders = 1; + release.Peers = 1; + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + release.MagnetUri = new Uri(node.SelectSingleNode("link").InnerText); + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(result.Content, ex); + } + + return releases; + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/SpeedCD.cs b/src/Jackett/Indexers/SpeedCD.cs index 6eae710d..5b17f105 100644 --- a/src/Jackett/Indexers/SpeedCD.cs +++ b/src/Jackett/Indexers/SpeedCD.cs @@ -179,8 +179,8 @@ namespace Jackett.Indexers if (torrentData.Find("span:contains(\"[Freeleech]\")").Any()) release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/Superbits.cs b/src/Jackett/Indexers/Superbits.cs index 8f3e53da..9a5b5df1 100644 --- a/src/Jackett/Indexers/Superbits.cs +++ b/src/Jackett/Indexers/Superbits.cs @@ -1,198 +1,198 @@ -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.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using Newtonsoft.Json; -using System.Globalization; - -namespace Jackett.Indexers -{ - public class Superbits : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } } - private string LoginUrl { get { return SiteLink + "api/v1/auth"; } } - - new ConfigurationDataBasicLogin configData - { - get { return (ConfigurationDataBasicLogin)base.configData; } - set { base.configData = value; } - } - - public Superbits(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "Superbits", - description: null, - link: "https://superbits.org/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "sv-sw"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(1, TorznabCatType.MoviesDVD, "DVD-R Swesub"); - AddCategoryMapping(2, TorznabCatType.TV, "DVD-R TV"); - AddCategoryMapping(3, TorznabCatType.BooksEbook, "eBok"); - AddCategoryMapping(4, TorznabCatType.MoviesHD, "Film 1080"); - AddCategoryMapping(5, TorznabCatType.Movies3D, "Film 3D"); - AddCategoryMapping(6, TorznabCatType.MoviesHD, "Film 720"); - AddCategoryMapping(7, TorznabCatType.MoviesBluRay, "Film Bluray"); - AddCategoryMapping(8, TorznabCatType.TV, "Svensk TV"); - AddCategoryMapping(9, TorznabCatType.AudioAudiobook, "Ljudböcker"); - AddCategoryMapping(10, TorznabCatType.AudioVideo, "Musikvideos"); - AddCategoryMapping(11, TorznabCatType.BooksMagazines, "E-tidningar"); - AddCategoryMapping(12, TorznabCatType.Audio, "Musik"); - AddCategoryMapping(13, TorznabCatType.Other, "Omslag"); - AddCategoryMapping(14, TorznabCatType.Other, "Övrigt"); - AddCategoryMapping(15, TorznabCatType.PCGames, "PC-Spel"); - AddCategoryMapping(16, TorznabCatType.PC0day, "Program"); - AddCategoryMapping(17, TorznabCatType.ConsolePS3, "PS3"); - AddCategoryMapping(18, TorznabCatType.TV, "TV"); - AddCategoryMapping(19, TorznabCatType.ConsoleWii, "Wii"); - AddCategoryMapping(20, TorznabCatType.ConsoleXbox, "Xbox"); - AddCategoryMapping(21, TorznabCatType.MoviesOther, "Xvid"); - AddCategoryMapping(22, TorznabCatType.XXX, "XXX"); - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var queryCollection = new NameValueCollection(); - +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.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using Newtonsoft.Json; +using System.Globalization; + +namespace Jackett.Indexers +{ + public class Superbits : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "api/v1/torrents"; } } + private string LoginUrl { get { return SiteLink + "api/v1/auth"; } } + + new ConfigurationDataBasicLogin configData + { + get { return (ConfigurationDataBasicLogin)base.configData; } + set { base.configData = value; } + } + + public Superbits(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "Superbits", + description: null, + link: "https://superbits.org/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "sv-sw"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(1, TorznabCatType.MoviesDVD, "DVD-R Swesub"); + AddCategoryMapping(2, TorznabCatType.TV, "DVD-R TV"); + AddCategoryMapping(3, TorznabCatType.BooksEbook, "eBok"); + AddCategoryMapping(4, TorznabCatType.MoviesHD, "Film 1080"); + AddCategoryMapping(5, TorznabCatType.Movies3D, "Film 3D"); + AddCategoryMapping(6, TorznabCatType.MoviesHD, "Film 720"); + AddCategoryMapping(7, TorznabCatType.MoviesBluRay, "Film Bluray"); + AddCategoryMapping(8, TorznabCatType.TV, "Svensk TV"); + AddCategoryMapping(9, TorznabCatType.AudioAudiobook, "Ljudböcker"); + AddCategoryMapping(10, TorznabCatType.AudioVideo, "Musikvideos"); + AddCategoryMapping(11, TorznabCatType.BooksMagazines, "E-tidningar"); + AddCategoryMapping(12, TorznabCatType.Audio, "Musik"); + AddCategoryMapping(13, TorznabCatType.Other, "Omslag"); + AddCategoryMapping(14, TorznabCatType.Other, "Övrigt"); + AddCategoryMapping(15, TorznabCatType.PCGames, "PC-Spel"); + AddCategoryMapping(16, TorznabCatType.PC0day, "Program"); + AddCategoryMapping(17, TorznabCatType.ConsolePS3, "PS3"); + AddCategoryMapping(18, TorznabCatType.TV, "TV"); + AddCategoryMapping(19, TorznabCatType.ConsoleWii, "Wii"); + AddCategoryMapping(20, TorznabCatType.ConsoleXbox, "Xbox"); + AddCategoryMapping(21, TorznabCatType.MoviesOther, "Xvid"); + AddCategoryMapping(22, TorznabCatType.XXX, "XXX"); + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var queryCollection = new NameValueCollection(); + queryCollection.Add("username", configData.Username.Value); - queryCollection.Add("password", configData.Password.Value); - - var loginUrl = LoginUrl + "?" + queryCollection.GetQueryString(); - var loginResult = await RequestStringWithCookies(loginUrl, null, SiteLink); - - await ConfigureIfOK(loginResult.Cookies, loginResult.Content.Contains("\"user\""), () => - { - throw new ExceptionWithConfigData(loginResult.Content, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - var queryCollection = new NameValueCollection(); - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - - queryCollection.Add("extendedSearch", "false"); - queryCollection.Add("freeleech", "false"); - queryCollection.Add("index", "0"); - queryCollection.Add("limit", "100"); - queryCollection.Add("order", "desc"); - queryCollection.Add("page", "search"); - if (query.ImdbID != null) - queryCollection.Add("searchText", query.ImdbID); - else - queryCollection.Add("searchText", searchString); - queryCollection.Add("sort", "d"); - queryCollection.Add("section", "all"); - queryCollection.Add("stereoscopic", "false"); - queryCollection.Add("sweaudio", "false"); - queryCollection.Add("swesub", "false"); - queryCollection.Add("watchview", "false"); - - foreach (var cat in MapTorznabCapsToTrackers(query)) - queryCollection.Add("categories[]", cat); - - searchUrl += "?" + queryCollection.GetQueryString(); - var results = await RequestStringWithCookies(searchUrl, null, SiteLink); - - try - { - //var json = JArray.Parse(results.Content); - dynamic json = JsonConvert.DeserializeObject<dynamic>(results.Content); - foreach (var row in json) - { - var release = new ReleaseInfo(); - var descriptions = new List<string>(); - var tags = new List<string>(); - - release.MinimumRatio = 1.1; - release.MinimumSeedTime = 48 * 60 * 60; - release.Title = row.name; - release.Category = MapTrackerCatToNewznab(row.category.ToString()); - release.Size = row.size; - release.Seeders = row.seeders; - release.Peers = row.leechers + release.Seeders; - release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); - release.Files = row.numfiles; - release.Grabs = row.times_completed; - - release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/"); - release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString()); - - if (row.frileech == 1) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - if (!string.IsNullOrWhiteSpace(row.customcover.ToString())) - release.BannerUrl = new Uri(SiteLink + row.customcover); - - if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt")) - { - release.Imdb = ParseUtil.CoerceLong(row.imdbid2.ToString().Substring(2)); - descriptions.Add("Title: " + row.title); - descriptions.Add("Year: " + row.year); - descriptions.Add("Genres: " + row.genres); - descriptions.Add("Tagline: " + row.tagline); - descriptions.Add("Cast: " + row.cast); - descriptions.Add("Rating: " + row.rating); - descriptions.Add("Plot: " + row.plot); - - release.BannerUrl = new Uri(SiteLink + "img/imdb/" + row.imdbid2 + ".jpg"); - } - - if ((int)row.p2p == 1) - tags.Add("P2P"); - if ((int)row.pack == 1) - tags.Add("Pack"); - if ((int)row.reqid != 0) - tags.Add("Request"); - if ((int)row.sweaudio != 0) - tags.Add("Swedish audio"); - if ((int)row.swesub != 0) - tags.Add("Swedish subtitles"); - - if (tags.Count > 0) - descriptions.Add("Tags: " + string.Join(", ", tags)); - - var preDate = row.preDate.ToString(); - if (!string.IsNullOrWhiteSpace(preDate) && preDate != "1970-01-01 01:00:00") - descriptions.Add("PRE: " + preDate); - - descriptions.Add("Section: " + row.section); - - release.Description = string.Join("<br>\n", descriptions); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } + queryCollection.Add("password", configData.Password.Value); + + var loginUrl = LoginUrl + "?" + queryCollection.GetQueryString(); + var loginResult = await RequestStringWithCookies(loginUrl, null, SiteLink); + + await ConfigureIfOK(loginResult.Cookies, loginResult.Content.Contains("\"user\""), () => + { + throw new ExceptionWithConfigData(loginResult.Content, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + var queryCollection = new NameValueCollection(); + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + + queryCollection.Add("extendedSearch", "false"); + queryCollection.Add("freeleech", "false"); + queryCollection.Add("index", "0"); + queryCollection.Add("limit", "100"); + queryCollection.Add("order", "desc"); + queryCollection.Add("page", "search"); + if (query.ImdbID != null) + queryCollection.Add("searchText", query.ImdbID); + else + queryCollection.Add("searchText", searchString); + queryCollection.Add("sort", "d"); + queryCollection.Add("section", "all"); + queryCollection.Add("stereoscopic", "false"); + queryCollection.Add("sweaudio", "false"); + queryCollection.Add("swesub", "false"); + queryCollection.Add("watchview", "false"); + + foreach (var cat in MapTorznabCapsToTrackers(query)) + queryCollection.Add("categories[]", cat); + + searchUrl += "?" + queryCollection.GetQueryString(); + var results = await RequestStringWithCookies(searchUrl, null, SiteLink); + + try + { + //var json = JArray.Parse(results.Content); + dynamic json = JsonConvert.DeserializeObject<dynamic>(results.Content); + foreach (var row in json) + { + var release = new ReleaseInfo(); + var descriptions = new List<string>(); + var tags = new List<string>(); + + release.MinimumRatio = 1.1; + release.MinimumSeedTime = 48 * 60 * 60; + release.Title = row.name; + release.Category = MapTrackerCatToNewznab(row.category.ToString()); + release.Size = row.size; + release.Seeders = row.seeders; + release.Peers = row.leechers + release.Seeders; + release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture); + release.Files = row.numfiles; + release.Grabs = row.times_completed; + + release.Comments = new Uri(SiteLink + "torrent/" + row.id.ToString() + "/"); + release.Link = new Uri(SiteLink + "api/v1/torrents/download/" + row.id.ToString()); + + if (row.frileech == 1) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + if (!string.IsNullOrWhiteSpace(row.customcover.ToString())) + release.BannerUrl = new Uri(SiteLink + row.customcover); + + if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt")) + { + release.Imdb = ParseUtil.CoerceLong(row.imdbid2.ToString().Substring(2)); + descriptions.Add("Title: " + row.title); + descriptions.Add("Year: " + row.year); + descriptions.Add("Genres: " + row.genres); + descriptions.Add("Tagline: " + row.tagline); + descriptions.Add("Cast: " + row.cast); + descriptions.Add("Rating: " + row.rating); + descriptions.Add("Plot: " + row.plot); + + release.BannerUrl = new Uri(SiteLink + "img/imdb/" + row.imdbid2 + ".jpg"); + } + + if ((int)row.p2p == 1) + tags.Add("P2P"); + if ((int)row.pack == 1) + tags.Add("Pack"); + if ((int)row.reqid != 0) + tags.Add("Request"); + if ((int)row.sweaudio != 0) + tags.Add("Swedish audio"); + if ((int)row.swesub != 0) + tags.Add("Swedish subtitles"); + + if (tags.Count > 0) + descriptions.Add("Tags: " + string.Join(", ", tags)); + + var preDate = row.preDate.ToString(); + if (!string.IsNullOrWhiteSpace(preDate) && preDate != "1970-01-01 01:00:00") + descriptions.Add("PRE: " + preDate); + + descriptions.Add("Section: " + row.section); + + release.Description = string.Join("<br>\n", descriptions); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } } \ No newline at end of file diff --git a/src/Jackett/Indexers/T411.cs b/src/Jackett/Indexers/T411.cs index 868be08b..cb5470a6 100644 --- a/src/Jackett/Indexers/T411.cs +++ b/src/Jackett/Indexers/T411.cs @@ -1,278 +1,278 @@ -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.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; - -namespace Jackett.Indexers -{ - public class T411 : BaseIndexer, IIndexer - { - const string ApiUrl = "https://api.t411.ai"; - const string AuthUrl = ApiUrl + "/auth"; - const string SearchUrl = ApiUrl + "/torrents/search/"; - const string TermsUrl = ApiUrl + "/terms/tree"; - const string DownloadUrl = ApiUrl + "/torrents/download/"; - private string CommentsUrl { get { return SiteLink + "torrents/"; } } - - new ConfigurationDataLoginTokin configData - { - get { return (ConfigurationDataLoginTokin)base.configData; } - set { base.configData = value; } - } - - private Dictionary<int, List<int>> _mediaCategoryMapping = new Dictionary<int, List<int>>(); - - public T411(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "T411", - description: "French Torrent Tracker", - link: "https://t411.ai/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataLoginTokin()) - { - Encoding = Encoding.UTF8; - Type = "semi-private"; - Language = "fr-fr"; - - // 210, FilmVidéo - AddCategoryMapping(210, 402, TorznabCatType.Movies, "Vidéoclips"); - AddCategoryMapping(210, 433, TorznabCatType.TV, "Série TV"); - AddCategoryMapping(210, 455, TorznabCatType.TVAnime, "Animation"); - AddCategoryMapping(210, 631, TorznabCatType.Movies, "Film"); - AddCategoryMapping(210, 633, TorznabCatType.Movies, "Concert"); - AddCategoryMapping(210, 634, TorznabCatType.TVDocumentary, "Documentaire"); - AddCategoryMapping(210, 635, TorznabCatType.TV, "Spectacle"); - AddCategoryMapping(210, 636, TorznabCatType.TVSport, "Sport"); - AddCategoryMapping(210, 637, TorznabCatType.TVAnime, "Animation Série"); - AddCategoryMapping(210, 639, TorznabCatType.TV, "Emission TV"); - - // 233, Application - AddCategoryMapping(233, 234, TorznabCatType.PC, "Linux"); - AddCategoryMapping(233, 235, TorznabCatType.PCMac, "MacOS"); - AddCategoryMapping(233, 236, TorznabCatType.PC, "Windows"); - AddCategoryMapping(233, 625, TorznabCatType.PCPhoneOther, "Smartphone"); - AddCategoryMapping(233, 627, TorznabCatType.PCPhoneOther, "Tablette"); - AddCategoryMapping(233, 629, TorznabCatType.PC, "Autre"); - AddCategoryMapping(233, 638, TorznabCatType.PC, "Formation"); - - // 395, Audio - AddCategoryMapping(395, 400, TorznabCatType.Audio, "Karaoke"); - AddCategoryMapping(395, 403, TorznabCatType.Audio, "Samples"); - AddCategoryMapping(395, 623, TorznabCatType.Audio, "Musique"); - AddCategoryMapping(395, 642, TorznabCatType.Audio, "Podcast Radio"); - - // 404, eBook - AddCategoryMapping(404, 405, TorznabCatType.Books, "Audio"); - AddCategoryMapping(404, 406, TorznabCatType.Books, "Bds"); - AddCategoryMapping(404, 407, TorznabCatType.Books, "Comics"); - AddCategoryMapping(404, 408, TorznabCatType.Books, "Livres"); - AddCategoryMapping(404, 409, TorznabCatType.Books, "Mangas"); - AddCategoryMapping(404, 410, TorznabCatType.Books, "Presse"); - - // 456, xXx - AddCategoryMapping(456, 461, TorznabCatType.XXX, "eBooks"); - AddCategoryMapping(456, 462, TorznabCatType.XXX, "Jeux vidéo"); - AddCategoryMapping(456, 632, TorznabCatType.XXX, "Video"); - AddCategoryMapping(456, 641, TorznabCatType.XXX, "Animation"); - - // 624, Jeu vidéo - AddCategoryMapping(624, 239, TorznabCatType.PCGames, "Linux"); - AddCategoryMapping(624, 245, TorznabCatType.PCMac, "MacOS"); - AddCategoryMapping(624, 246, TorznabCatType.PCGames, "Windows"); - AddCategoryMapping(624, 307, TorznabCatType.ConsoleNDS, "Nintendo"); - AddCategoryMapping(624, 308, TorznabCatType.ConsolePS4, "Sony"); - AddCategoryMapping(624, 309, TorznabCatType.ConsoleXbox, "Microsoft"); - AddCategoryMapping(624, 626, TorznabCatType.PCPhoneOther, "Smartphone"); - AddCategoryMapping(624, 628, TorznabCatType.PCPhoneOther, "Tablette"); - AddCategoryMapping(624, 630, TorznabCatType.ConsoleOther, "Autre"); - } - - private void AddCategoryMapping(int trackerMediaCategory, int trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) - { - AddCategoryMapping(trackerCategory, newznabCategory, trackerCategoryDesc); - if (!_mediaCategoryMapping.ContainsKey(trackerMediaCategory)) - _mediaCategoryMapping.Add(trackerMediaCategory, new List<int>()); - _mediaCategoryMapping[trackerMediaCategory].Add(trackerCategory); - } - - private KeyValuePair<int, List<int>> GetCategoryFromSubCat(int subCategory) - { - try - { - return _mediaCategoryMapping.First(pair => pair.Value.Contains(subCategory)); - } - catch (Exception) - { - return new KeyValuePair<int, List<int>>(0, new List<int>() { 0 }); //If the provided category does not exist, we return 0 (ALL) - } - } - - async Task<string> GetAuthToken(bool forceFetch = false) - { - if (!forceFetch && configData.LastTokenFetchDateTime > DateTime.Now - TimeSpan.FromHours(48)) - { - return configData.ApiToken.Value; - } - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value } - }; - - var response = await PostDataWithCookies(AuthUrl, pairs); - var responseContent = response.Content; - var jsonResponse = JObject.Parse(responseContent); - if (jsonResponse["error"] != null) - { - throw new ApplicationException((string)jsonResponse["error"]); - } - configData.ApiToken.Value = (string)jsonResponse["token"]; - configData.LastTokenFetchDateTime = DateTime.Now; - return configData.ApiToken.Value; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - configData.LoadValuesFromJson(configJson); - - Exception tokenFetchEx = null; - try - { - await GetAuthToken(true); - } - catch (Exception ex) - { - tokenFetchEx = new ExceptionWithConfigData(ex.Message, configData); - } - - await ConfigureIfOK(string.Empty, tokenFetchEx == null, () => - { - throw tokenFetchEx; - }); - - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - // API doesn't support getting the latest torrents, searching for the empty string will cause an error and all torrents returned - var searchUrl = SearchUrl + HttpUtility.UrlEncode(query.SanitizedSearchTerm).Replace("+", "%20"); - searchUrl += "?offset=0&limit=200&cat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Key; - - // handle special term search for tvsearch - var queryStringOverride = query.SanitizedSearchTerm; - switch (query.QueryType) - { - case "tvsearch": - // T411 make the difference beetween Animation Movies and TV Animation Series, while Torznab does not. - // So here we take LastOrDefault from the category ids, so if the query specify an animation tv serie, we select the correct id. - searchUrl += "&subcat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Value.LastOrDefault(); - if (query.Season >= 1 && query.Season <= 30) - { - var seasonTermValue = 967 + query.Season; - searchUrl += "&term[45][]=" + seasonTermValue; - queryStringOverride += " " + query.Season; - } - - if (query.Episode != null) - { - int episodeInt; - int episodeCategoryOffset = 936; - ParseUtil.TryCoerceInt(query.Episode, out episodeInt); - if (episodeInt >= 1 && episodeInt <= 8) - episodeCategoryOffset = 936; - else if (episodeInt >= 9 && episodeInt <= 30) - episodeCategoryOffset = 937; - else if (episodeInt >= 31) - episodeCategoryOffset = 1057; - searchUrl += "&term[46][]=" + (episodeCategoryOffset + episodeInt); - queryStringOverride += " " + query.Episode; - } - break; - case "movie": - // T411 make the difference beetween Animation Movies and TV Animation Series, while Torznab does not. - // So here we take FirstOrDefault from the category ids, so if the query specify an animation movie, we select the correct id. - searchUrl += "&subcat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Value.FirstOrDefault(); - break; - } - - var headers = new Dictionary<string, string>(); - headers.Add("Authorization", await GetAuthToken()); - - var response = await RequestStringWithCookies(searchUrl, null, null, headers); - var results = response.Content; - - var jsonStart = results.IndexOf('{'); - var jsonLength = results.Length - jsonStart; - var jsonResult = JObject.Parse(results.Substring(jsonStart)); - try - { - var items = (JArray)jsonResult["torrents"]; - foreach (var item in items) - { - if (item.GetType() == typeof(JValue)) - { - logger.Debug(string.Format("{0}: skipping torrent ID {1} (pending release without details)", ID, item.ToString())); - continue; - } - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.DownloadVolumeFactor = 0; - release.DownloadVolumeFactor = 1; - var torrentId = (string)item["id"]; - release.Link = new Uri(DownloadUrl + torrentId); - release.Title = (string)item["name"]; - - if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title, null, queryStringOverride)) - continue; - - if ((string)item["isVerified"] == "1") - release.Description = "Verified"; - release.Comments = new Uri(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"]); - release.Category = MapTrackerCatToNewznab((string)item["category"]); - release.Grabs = ParseUtil.CoerceLong((string)item["times_completed"]); - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results, ex); - } - return releases; - } - - public override async Task<byte[]> Download(Uri link) - { - var headers = new Dictionary<string, string>(); - headers.Add("Authorization", await GetAuthToken()); - - var response = await RequestBytesWithCookies(link.AbsoluteUri, null, RequestType.GET, null, null, headers); - return response.Content; - } - } -} +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.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; + +namespace Jackett.Indexers +{ + public class T411 : BaseIndexer, IIndexer + { + const string ApiUrl = "https://api.t411.ai"; + const string AuthUrl = ApiUrl + "/auth"; + const string SearchUrl = ApiUrl + "/torrents/search/"; + const string TermsUrl = ApiUrl + "/terms/tree"; + const string DownloadUrl = ApiUrl + "/torrents/download/"; + private string CommentsUrl { get { return SiteLink + "torrents/"; } } + + new ConfigurationDataLoginTokin configData + { + get { return (ConfigurationDataLoginTokin)base.configData; } + set { base.configData = value; } + } + + private Dictionary<int, List<int>> _mediaCategoryMapping = new Dictionary<int, List<int>>(); + + public T411(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "T411", + description: "French Torrent Tracker", + link: "https://t411.ai/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataLoginTokin()) + { + Encoding = Encoding.UTF8; + Type = "semi-private"; + Language = "fr-fr"; + + // 210, FilmVidéo + AddCategoryMapping(210, 402, TorznabCatType.Movies, "Vidéoclips"); + AddCategoryMapping(210, 433, TorznabCatType.TV, "Série TV"); + AddCategoryMapping(210, 455, TorznabCatType.TVAnime, "Animation"); + AddCategoryMapping(210, 631, TorznabCatType.Movies, "Film"); + AddCategoryMapping(210, 633, TorznabCatType.Movies, "Concert"); + AddCategoryMapping(210, 634, TorznabCatType.TVDocumentary, "Documentaire"); + AddCategoryMapping(210, 635, TorznabCatType.TV, "Spectacle"); + AddCategoryMapping(210, 636, TorznabCatType.TVSport, "Sport"); + AddCategoryMapping(210, 637, TorznabCatType.TVAnime, "Animation Série"); + AddCategoryMapping(210, 639, TorznabCatType.TV, "Emission TV"); + + // 233, Application + AddCategoryMapping(233, 234, TorznabCatType.PC, "Linux"); + AddCategoryMapping(233, 235, TorznabCatType.PCMac, "MacOS"); + AddCategoryMapping(233, 236, TorznabCatType.PC, "Windows"); + AddCategoryMapping(233, 625, TorznabCatType.PCPhoneOther, "Smartphone"); + AddCategoryMapping(233, 627, TorznabCatType.PCPhoneOther, "Tablette"); + AddCategoryMapping(233, 629, TorznabCatType.PC, "Autre"); + AddCategoryMapping(233, 638, TorznabCatType.PC, "Formation"); + + // 395, Audio + AddCategoryMapping(395, 400, TorznabCatType.Audio, "Karaoke"); + AddCategoryMapping(395, 403, TorznabCatType.Audio, "Samples"); + AddCategoryMapping(395, 623, TorznabCatType.Audio, "Musique"); + AddCategoryMapping(395, 642, TorznabCatType.Audio, "Podcast Radio"); + + // 404, eBook + AddCategoryMapping(404, 405, TorznabCatType.Books, "Audio"); + AddCategoryMapping(404, 406, TorznabCatType.Books, "Bds"); + AddCategoryMapping(404, 407, TorznabCatType.Books, "Comics"); + AddCategoryMapping(404, 408, TorznabCatType.Books, "Livres"); + AddCategoryMapping(404, 409, TorznabCatType.Books, "Mangas"); + AddCategoryMapping(404, 410, TorznabCatType.Books, "Presse"); + + // 456, xXx + AddCategoryMapping(456, 461, TorznabCatType.XXX, "eBooks"); + AddCategoryMapping(456, 462, TorznabCatType.XXX, "Jeux vidéo"); + AddCategoryMapping(456, 632, TorznabCatType.XXX, "Video"); + AddCategoryMapping(456, 641, TorznabCatType.XXX, "Animation"); + + // 624, Jeu vidéo + AddCategoryMapping(624, 239, TorznabCatType.PCGames, "Linux"); + AddCategoryMapping(624, 245, TorznabCatType.PCMac, "MacOS"); + AddCategoryMapping(624, 246, TorznabCatType.PCGames, "Windows"); + AddCategoryMapping(624, 307, TorznabCatType.ConsoleNDS, "Nintendo"); + AddCategoryMapping(624, 308, TorznabCatType.ConsolePS4, "Sony"); + AddCategoryMapping(624, 309, TorznabCatType.ConsoleXbox, "Microsoft"); + AddCategoryMapping(624, 626, TorznabCatType.PCPhoneOther, "Smartphone"); + AddCategoryMapping(624, 628, TorznabCatType.PCPhoneOther, "Tablette"); + AddCategoryMapping(624, 630, TorznabCatType.ConsoleOther, "Autre"); + } + + private void AddCategoryMapping(int trackerMediaCategory, int trackerCategory, TorznabCategory newznabCategory, string trackerCategoryDesc = null) + { + AddCategoryMapping(trackerCategory, newznabCategory, trackerCategoryDesc); + if (!_mediaCategoryMapping.ContainsKey(trackerMediaCategory)) + _mediaCategoryMapping.Add(trackerMediaCategory, new List<int>()); + _mediaCategoryMapping[trackerMediaCategory].Add(trackerCategory); + } + + private KeyValuePair<int, List<int>> GetCategoryFromSubCat(int subCategory) + { + try + { + return _mediaCategoryMapping.First(pair => pair.Value.Contains(subCategory)); + } + catch (Exception) + { + return new KeyValuePair<int, List<int>>(0, new List<int>() { 0 }); //If the provided category does not exist, we return 0 (ALL) + } + } + + async Task<string> GetAuthToken(bool forceFetch = false) + { + if (!forceFetch && configData.LastTokenFetchDateTime > DateTime.Now - TimeSpan.FromHours(48)) + { + return configData.ApiToken.Value; + } + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var response = await PostDataWithCookies(AuthUrl, pairs); + var responseContent = response.Content; + var jsonResponse = JObject.Parse(responseContent); + if (jsonResponse["error"] != null) + { + throw new ApplicationException((string)jsonResponse["error"]); + } + configData.ApiToken.Value = (string)jsonResponse["token"]; + configData.LastTokenFetchDateTime = DateTime.Now; + return configData.ApiToken.Value; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + + Exception tokenFetchEx = null; + try + { + await GetAuthToken(true); + } + catch (Exception ex) + { + tokenFetchEx = new ExceptionWithConfigData(ex.Message, configData); + } + + await ConfigureIfOK(string.Empty, tokenFetchEx == null, () => + { + throw tokenFetchEx; + }); + + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + // API doesn't support getting the latest torrents, searching for the empty string will cause an error and all torrents returned + var searchUrl = SearchUrl + HttpUtility.UrlEncode(query.SanitizedSearchTerm).Replace("+", "%20"); + searchUrl += "?offset=0&limit=200&cat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Key; + + // handle special term search for tvsearch + var queryStringOverride = query.SanitizedSearchTerm; + switch (query.QueryType) + { + case "tvsearch": + // T411 make the difference beetween Animation Movies and TV Animation Series, while Torznab does not. + // So here we take LastOrDefault from the category ids, so if the query specify an animation tv serie, we select the correct id. + searchUrl += "&subcat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Value.LastOrDefault(); + if (query.Season >= 1 && query.Season <= 30) + { + var seasonTermValue = 967 + query.Season; + searchUrl += "&term[45][]=" + seasonTermValue; + queryStringOverride += " " + query.Season; + } + + if (query.Episode != null) + { + int episodeInt; + int episodeCategoryOffset = 936; + ParseUtil.TryCoerceInt(query.Episode, out episodeInt); + if (episodeInt >= 1 && episodeInt <= 8) + episodeCategoryOffset = 936; + else if (episodeInt >= 9 && episodeInt <= 30) + episodeCategoryOffset = 937; + else if (episodeInt >= 31) + episodeCategoryOffset = 1057; + searchUrl += "&term[46][]=" + (episodeCategoryOffset + episodeInt); + queryStringOverride += " " + query.Episode; + } + break; + case "movie": + // T411 make the difference beetween Animation Movies and TV Animation Series, while Torznab does not. + // So here we take FirstOrDefault from the category ids, so if the query specify an animation movie, we select the correct id. + searchUrl += "&subcat=" + GetCategoryFromSubCat(query.Categories.FirstOrDefault()).Value.FirstOrDefault(); + break; + } + + var headers = new Dictionary<string, string>(); + headers.Add("Authorization", await GetAuthToken()); + + var response = await RequestStringWithCookies(searchUrl, null, null, headers); + var results = response.Content; + + var jsonStart = results.IndexOf('{'); + var jsonLength = results.Length - jsonStart; + var jsonResult = JObject.Parse(results.Substring(jsonStart)); + try + { + var items = (JArray)jsonResult["torrents"]; + foreach (var item in items) + { + if (item.GetType() == typeof(JValue)) + { + logger.Debug(string.Format("{0}: skipping torrent ID {1} (pending release without details)", ID, item.ToString())); + continue; + } + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.DownloadVolumeFactor = 0; + release.DownloadVolumeFactor = 1; + var torrentId = (string)item["id"]; + release.Link = new Uri(DownloadUrl + torrentId); + release.Title = (string)item["name"]; + + if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title, null, queryStringOverride)) + continue; + + if ((string)item["isVerified"] == "1") + release.Description = "Verified"; + release.Comments = new Uri(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"]); + release.Category = MapTrackerCatToNewznab((string)item["category"]); + release.Grabs = ParseUtil.CoerceLong((string)item["times_completed"]); + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results, ex); + } + return releases; + } + + public override async Task<byte[]> Download(Uri link) + { + var headers = new Dictionary<string, string>(); + headers.Add("Authorization", await GetAuthToken()); + + var response = await RequestBytesWithCookies(link.AbsoluteUri, null, RequestType.GET, null, null, headers); + return response.Content; + } + } +} diff --git a/src/Jackett/Indexers/TVChaosUK.cs b/src/Jackett/Indexers/TVChaosUK.cs index 22305933..421910b7 100644 --- a/src/Jackett/Indexers/TVChaosUK.cs +++ b/src/Jackett/Indexers/TVChaosUK.cs @@ -202,7 +202,7 @@ namespace Jackett.Indexers // The TVChaos UK search requires an exact match of the search string. // But it seems like they just send the unfiltered search to the SQL server in a like query (LIKE '%$searchstring%'). // So we replace any whitespace/special character with % to make the search more usable. - Regex ReplaceRegex = new Regex("[^a-zA-Z0-9]+"); + Regex ReplaceRegex = new Regex("[^a-zA-Z0-9]+"); searchString = ReplaceRegex.Replace(searchString, "%"); var searchParams = new Dictionary<string, string> { @@ -214,11 +214,11 @@ namespace Jackett.Indexers }; var searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams); - if (searchPage.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams); + if (searchPage.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams); } try @@ -258,18 +258,18 @@ namespace Jackett.Indexers // If its not apps or audio we can only mark as general TV if (release.Category.Count() == 0) release.Category.Add(5030); - - var grabs = qRow.Find("td:nth-child(6)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - if (qRow.Find("img[alt*=\"Free Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - - if (qRow.Find("img[alt*=\"x2 Torrent\"]").Length >= 1) - release.UploadVolumeFactor = 2; - else + + var grabs = qRow.Find("td:nth-child(6)").Text(); + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (qRow.Find("img[alt*=\"Free Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + + if (qRow.Find("img[alt*=\"x2 Torrent\"]").Length >= 1) + release.UploadVolumeFactor = 2; + else release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/TVVault.cs b/src/Jackett/Indexers/TVVault.cs index 6a3776ce..82a7488e 100644 --- a/src/Jackett/Indexers/TVVault.cs +++ b/src/Jackett/Indexers/TVVault.cs @@ -9,10 +9,10 @@ using System.Collections.Generic; using System; using System.Text; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using AngleSharp.Parser.Html; -using System.Text.RegularExpressions; - +using System.Collections.Specialized; +using AngleSharp.Parser.Html; +using System.Text.RegularExpressions; + namespace Jackett.Indexers { public class TVVault : BaseIndexer, IIndexer @@ -58,90 +58,90 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } - private string StripSearchString(string term) - { - // Search does not support searching with episode numbers so strip it if we have one - // Ww AND filter the result later to archive the proper result - term = Regex.Replace(term, @"[S|E]\d\d", string.Empty); - return term.Trim(); + private string StripSearchString(string term) + { + // Search does not support searching with episode numbers so strip it if we have one + // Ww AND filter the result later to archive the proper result + term = Regex.Replace(term, @"[S|E]\d\d", string.Empty); + return term.Trim(); } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - - var queryCollection = new NameValueCollection(); - queryCollection.Add("searchstr", StripSearchString(searchString)); - queryCollection.Add("order_by", "s3"); - queryCollection.Add("order_way", "desc"); - queryCollection.Add("disablegrouping", "1"); - - searchUrl += "?" + queryCollection.GetQueryString(); - + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + + var queryCollection = new NameValueCollection(); + queryCollection.Add("searchstr", StripSearchString(searchString)); + queryCollection.Add("order_by", "s3"); + queryCollection.Add("order_way", "desc"); + queryCollection.Add("disablegrouping", "1"); + + searchUrl += "?" + queryCollection.GetQueryString(); + var results = await RequestStringWithCookies(searchUrl); try { string RowsSelector = "table.torrent_table > tbody > tr.torrent"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + foreach (var Row in Rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 0; - - var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); - var DescStr = qDetailsLink.NextSibling; - var Files = Row.QuerySelector("td:nth-child(3)"); - var Added = Row.QuerySelector("td:nth-child(4)"); - var Size = Row.QuerySelector("td:nth-child(5)").FirstChild; - var Grabs = Row.QuerySelector("td:nth-child(6)"); - var Seeders = Row.QuerySelector("td:nth-child(7)"); - var Leechers = Row.QuerySelector("td:nth-child(8)"); - var FreeLeech = Row.QuerySelector("strong.freeleech_normal"); - - var TorrentIdParts = qDetailsLink.GetAttribute("href").Split('='); - var TorrentId = TorrentIdParts[TorrentIdParts.Length - 1]; - var DLLink = "torrents.php?action=download&id=" + TorrentId.ToString(); - - release.Description = DescStr.TextContent.Trim(); - release.Title = qDetailsLink.TextContent + " " + release.Description; - release.PublishDate = DateTimeUtil.FromTimeAgo(Added.TextContent); - release.Category = new List<int> { TvCategoryParser.ParseTvShowQuality(release.Description) }; - - release.Link = new Uri(SiteLink + DLLink); - release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); - release.Guid = release.Link; - - release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); - release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; - release.Size = ReleaseInfo.GetBytes(Size.TextContent); - release.Grabs = ReleaseInfo.GetBytes(Grabs.TextContent); - release.Files = ReleaseInfo.GetBytes(Files.TextContent); - - if (FreeLeech != null) - release.DownloadVolumeFactor = 0; + release.MinimumRatio = 1; + release.MinimumSeedTime = 0; + + var qDetailsLink = Row.QuerySelector("a[href^=\"torrents.php?id=\"]"); + var DescStr = qDetailsLink.NextSibling; + var Files = Row.QuerySelector("td:nth-child(3)"); + var Added = Row.QuerySelector("td:nth-child(4)"); + var Size = Row.QuerySelector("td:nth-child(5)").FirstChild; + var Grabs = Row.QuerySelector("td:nth-child(6)"); + var Seeders = Row.QuerySelector("td:nth-child(7)"); + var Leechers = Row.QuerySelector("td:nth-child(8)"); + var FreeLeech = Row.QuerySelector("strong.freeleech_normal"); + + var TorrentIdParts = qDetailsLink.GetAttribute("href").Split('='); + var TorrentId = TorrentIdParts[TorrentIdParts.Length - 1]; + var DLLink = "torrents.php?action=download&id=" + TorrentId.ToString(); + + release.Description = DescStr.TextContent.Trim(); + release.Title = qDetailsLink.TextContent + " " + release.Description; + release.PublishDate = DateTimeUtil.FromTimeAgo(Added.TextContent); + release.Category = new List<int> { TvCategoryParser.ParseTvShowQuality(release.Description) }; + + release.Link = new Uri(SiteLink + DLLink); + release.Comments = new Uri(SiteLink + qDetailsLink.GetAttribute("href")); + release.Guid = release.Link; + + release.Seeders = ParseUtil.CoerceInt(Seeders.TextContent); + release.Peers = ParseUtil.CoerceInt(Leechers.TextContent) + release.Seeders; + release.Size = ReleaseInfo.GetBytes(Size.TextContent); + release.Grabs = ReleaseInfo.GetBytes(Grabs.TextContent); + release.Files = ReleaseInfo.GetBytes(Files.TextContent); + + if (FreeLeech != null) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); - } + } } catch (Exception ex) { diff --git a/src/Jackett/Indexers/TehConnection.cs b/src/Jackett/Indexers/TehConnection.cs index ece1115e..481d5549 100644 --- a/src/Jackett/Indexers/TehConnection.cs +++ b/src/Jackett/Indexers/TehConnection.cs @@ -115,9 +115,9 @@ namespace Jackett.Indexers { movieListSearchUrl = string.Format("{0}?action=basic&searchstr={1}", SearchUrl, HttpUtility.UrlEncode(query.GetQueryString())); } - else - { - movieListSearchUrl = SearchUrl; + else + { + movieListSearchUrl = SearchUrl; } var results = await RequestStringWithCookiesAndRetry(movieListSearchUrl); @@ -165,10 +165,10 @@ namespace Jackett.Indexers var seeders = ParseUtil.CoerceInt(qRow.Find("img[title='Seeders']").First().Parent().Text().Trim()); var peers = ParseUtil.CoerceInt(qRow.Find("img[title='Leechers']").First().Parent().Text().Trim()) + seeders; var CoverElement = dom.Find("div[id='poster'] > a > img"); - if (CoverElement.Any()) - { - Uri CoverUrl = new Uri(dom.Find("div[id='poster'] > a > img").First().Attr("src").Trim()); - release.BannerUrl = CoverUrl; + if (CoverElement.Any()) + { + Uri CoverUrl = new Uri(dom.Find("div[id='poster'] > a > img").First().Attr("src").Trim()); + release.BannerUrl = CoverUrl; } bool freeleech = qRow.Find("span[class='freeleech']").Length == 1 ? true : false; @@ -181,9 +181,9 @@ namespace Jackett.Indexers { sizeStr = secondSizeStr.Replace("(", "").Replace(")", "").Trim(); } } - if(string.IsNullOrWhiteSpace(title)) - { - title = dom.Find("div.title_text").Text() + " - " + qRow.Find("div.details_title > a").Text(); + if(string.IsNullOrWhiteSpace(title)) + { + title = dom.Find("div.title_text").Text() + " - " + qRow.Find("div.details_title > a").Text(); } @@ -203,15 +203,15 @@ namespace Jackett.Indexers release.Imdb = imdb_id; } - var files = qRow.Find("div[id^=\"filelist\"] tr").Count()-1; - release.Files = files; - release.Grabs = ParseUtil.CoerceLong(grabs); - - if (freeleech) - release.DownloadVolumeFactor = 0; - else - release.DownloadVolumeFactor = 1; - + var files = qRow.Find("div[id^=\"filelist\"] tr").Count()-1; + release.Files = files; + release.Grabs = ParseUtil.CoerceLong(grabs); + + if (freeleech) + release.DownloadVolumeFactor = 0; + else + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; if (configFreeLeechOnly && !freeleech) diff --git a/src/Jackett/Indexers/TorrentBytes.cs b/src/Jackett/Indexers/TorrentBytes.cs index 728838cb..29df21b6 100644 --- a/src/Jackett/Indexers/TorrentBytes.cs +++ b/src/Jackett/Indexers/TorrentBytes.cs @@ -92,8 +92,8 @@ namespace Jackett.Indexers CQ dom = result.Content; var messageEl = dom["td.embedded"].First(); var errorMessage = messageEl.Text(); - if (string.IsNullOrWhiteSpace(errorMessage)) - errorMessage = result.Content; + if (string.IsNullOrWhiteSpace(errorMessage)) + errorMessage = result.Content; throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; @@ -136,10 +136,10 @@ namespace Jackett.Indexers { var response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); // On IP change the cookies become invalid, login again and retry - if (response.IsRedirect) - { - await ApplyConfiguration(null); - response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); + if (response.IsRedirect) + { + await ApplyConfiguration(null); + response = await RequestStringWithCookiesAndRetry(searchUrl, null, BrowseUrl); } var results = response.Content; @@ -190,11 +190,11 @@ namespace Jackett.Indexers if (grabs != "----") release.Grabs = ParseUtil.CoerceInt(grabs); - if (row.Cq().Find("font[color=\"green\"]:contains(F):contains(L)").Length >= 1) - release.DownloadVolumeFactor = 0; + if (row.Cq().Find("font[color=\"green\"]:contains(F):contains(L)").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs index b67cb81e..4250ec4a 100644 --- a/src/Jackett/Indexers/TorrentDay.cs +++ b/src/Jackett/Indexers/TorrentDay.cs @@ -1,66 +1,66 @@ -using CsQuery; -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.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - -namespace Jackett.Indexers -{ - public class TorrentDay : BaseIndexer, IIndexer - { - private string StartPageUrl { get { return SiteLink + "login.php"; } } - private string LoginUrl { get { return SiteLink + "tak3login.php"; } } - private string SearchUrl { get { return SiteLink + "browse.php"; } } - public new string[] AlternativeSiteLinks { get; protected set; } = new string[] { - "https://tdonline.org/", - "https://secure.torrentday.com/", - "https://torrentday.eu/", - "https://torrentday.it/", - "https://classic.torrentday.com/", - "https://www.torrentday.com/", - "https://td-update.com/", - "https://www.torrentday.me/", - "https://www.torrentday.ru/", - "https://www.torrentday.com/", - "https://www.td.af/", - }; - - new ConfigurationDataRecaptchaLogin configData - { - get { return (ConfigurationDataRecaptchaLogin)base.configData; } - set { base.configData = value; } - } - - public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) - : base(name: "TorrentDay", - description: "TorrentDay", - link: "https://torrentday.it/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataRecaptchaLogin()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - +using CsQuery; +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.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + public class TorrentDay : BaseIndexer, IIndexer + { + private string StartPageUrl { get { return SiteLink + "login.php"; } } + private string LoginUrl { get { return SiteLink + "tak3login.php"; } } + private string SearchUrl { get { return SiteLink + "browse.php"; } } + public new string[] AlternativeSiteLinks { get; protected set; } = new string[] { + "https://tdonline.org/", + "https://secure.torrentday.com/", + "https://torrentday.eu/", + "https://torrentday.it/", + "https://classic.torrentday.com/", + "https://www.torrentday.com/", + "https://td-update.com/", + "https://www.torrentday.me/", + "https://www.torrentday.ru/", + "https://www.torrentday.com/", + "https://www.td.af/", + }; + + new ConfigurationDataRecaptchaLogin configData + { + get { return (ConfigurationDataRecaptchaLogin)base.configData; } + set { base.configData = value; } + } + + public TorrentDay(IIndexerManagerService i, Logger l, IWebClient wc, IProtectionService ps) + : base(name: "TorrentDay", + description: "TorrentDay", + link: "https://torrentday.it/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataRecaptchaLogin()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + AddCategoryMapping(29, TorznabCatType.TVAnime); // Anime AddCategoryMapping(28, TorznabCatType.PC); // Appz/Packs AddCategoryMapping(42, TorznabCatType.AudioAudiobook); // Audio Books @@ -103,163 +103,163 @@ namespace Jackett.Indexers AddCategoryMapping(2, TorznabCatType.TVSD); // TV/XviD AddCategoryMapping(6, TorznabCatType.XXX); // XXX/Movies - AddCategoryMapping(15, TorznabCatType.XXXPacks); // XXX/Packs - } - - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(StartPageUrl, string.Empty); - if (loginPage.IsRedirect) - loginPage = await RequestStringWithCookies(loginPage.RedirectingTo, string.Empty); - if (loginPage.IsRedirect) - loginPage = await RequestStringWithCookies(loginPage.RedirectingTo, string.Empty); - CQ cq = loginPage.Content; - var result = this.configData; - result.CookieHeader.Value = loginPage.Cookies; - result.Captcha.SiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); - result.Captcha.Version = "2"; - return result; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "g-recaptcha-response", configData.Captcha.Value } - }; - - if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) - { - // Cookie was manually supplied - CookieHeader = configData.Captcha.Cookie; - try - { - var results = await PerformQuery(new TorznabQuery()); - if (results.Count() == 0) - { - throw new Exception("Your cookie did not work"); - } - - SaveConfig(); - IsConfigured = true; - return IndexerConfigurationStatus.Completed; - } - catch (Exception e) - { - IsConfigured = false; - throw new Exception("Your cookie did not work: " + e.Message); - } - } - - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CookieHeader.Value, true, SiteLink, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var messageEl = dom["#login"]; - messageEl.Children("form").Remove(); - var errorMessage = messageEl.Text().Trim(); - - if (string.IsNullOrWhiteSpace(errorMessage)) - { - errorMessage = dom.Text(); - } - - if (string.IsNullOrWhiteSpace(errorMessage) && result.IsRedirect) - { - errorMessage = string.Format("Got a redirect to {0}, please adjust your the alternative link", result.RedirectingTo); - } - - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var queryUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - - if (!string.IsNullOrWhiteSpace(query.ImdbID) && query.ImdbID.ToLower().StartsWith("tt")) - { - queryCollection.Add("search", query.ImdbID); - } - else - { - if (!string.IsNullOrWhiteSpace(searchString)) - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - queryCollection.Add("c" + cat, "1"); - - if (queryCollection.Count > 0) - queryUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(queryUrl); - - // Check for being logged out - if (results.IsRedirect) - if (results.RedirectingTo.Contains("login.php")) - throw new ExceptionWithConfigData("Login failed, please reconfigure the tracker to update the cookies", configData); - else - throw new ExceptionWithConfigData(string.Format("Got a redirect to {0}, please adjust your the alternative link", results.RedirectingTo), configData); - - try - { - CQ dom = results.Content; - var rows = dom["#torrentTable > tbody > tr.browse"]; - foreach (var row in rows) - { - CQ qRow = row.Cq(); - var release = new ReleaseInfo(); - - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.Title = qRow.Find(".torrentName").Text(); - - if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) - continue; - - release.Guid = new Uri(SiteLink + qRow.Find(".torrentName").Attr("href")); - release.Comments = release.Guid; - release.Link = new Uri(SiteLink + qRow.Find(".dlLinksInfo > a").Attr("href")); - - var sizeStr = qRow.Find(".sizeInfo").Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - var dateStr = qRow.Find(".ulInfo").Text().Split('|').Last().Trim(); - var agoIdx = dateStr.IndexOf("ago"); - if (agoIdx > -1) - { - dateStr = dateStr.Substring(0, agoIdx); - } - release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); - - release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seedersInfo").Text()); - release.Peers = ParseUtil.CoerceInt(qRow.Find(".leechersInfo").Text()) + release.Seeders; - - var cat = qRow.Find("td:eq(0) a").First().Attr("href").Split('#')[0].Substring(15);//browse.php?cat=24 - release.Category = MapTrackerCatToNewznab(cat); - - if (qRow.Find("span.flTags").Length >= 1) - release.DownloadVolumeFactor = 0; + AddCategoryMapping(15, TorznabCatType.XXXPacks); // XXX/Packs + } + + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(StartPageUrl, string.Empty); + if (loginPage.IsRedirect) + loginPage = await RequestStringWithCookies(loginPage.RedirectingTo, string.Empty); + if (loginPage.IsRedirect) + loginPage = await RequestStringWithCookies(loginPage.RedirectingTo, string.Empty); + CQ cq = loginPage.Content; + var result = this.configData; + result.CookieHeader.Value = loginPage.Cookies; + result.Captcha.SiteKey = cq.Find(".g-recaptcha").Attr("data-sitekey"); + result.Captcha.Version = "2"; + return result; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "g-recaptcha-response", configData.Captcha.Value } + }; + + if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) + { + // Cookie was manually supplied + CookieHeader = configData.Captcha.Cookie; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (results.Count() == 0) + { + throw new Exception("Your cookie did not work"); + } + + SaveConfig(); + IsConfigured = true; + return IndexerConfigurationStatus.Completed; + } + catch (Exception e) + { + IsConfigured = false; + throw new Exception("Your cookie did not work: " + e.Message); + } + } + + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, configData.CookieHeader.Value, true, SiteLink, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var messageEl = dom["#login"]; + messageEl.Children("form").Remove(); + var errorMessage = messageEl.Text().Trim(); + + if (string.IsNullOrWhiteSpace(errorMessage)) + { + errorMessage = dom.Text(); + } + + if (string.IsNullOrWhiteSpace(errorMessage) && result.IsRedirect) + { + errorMessage = string.Format("Got a redirect to {0}, please adjust your the alternative link", result.RedirectingTo); + } + + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var queryUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + + if (!string.IsNullOrWhiteSpace(query.ImdbID) && query.ImdbID.ToLower().StartsWith("tt")) + { + queryCollection.Add("search", query.ImdbID); + } + else + { + if (!string.IsNullOrWhiteSpace(searchString)) + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + queryCollection.Add("c" + cat, "1"); + + if (queryCollection.Count > 0) + queryUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(queryUrl); + + // Check for being logged out + if (results.IsRedirect) + if (results.RedirectingTo.Contains("login.php")) + throw new ExceptionWithConfigData("Login failed, please reconfigure the tracker to update the cookies", configData); + else + throw new ExceptionWithConfigData(string.Format("Got a redirect to {0}, please adjust your the alternative link", results.RedirectingTo), configData); + + try + { + CQ dom = results.Content; + var rows = dom["#torrentTable > tbody > tr.browse"]; + foreach (var row in rows) + { + CQ qRow = row.Cq(); + var release = new ReleaseInfo(); + + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.Title = qRow.Find(".torrentName").Text(); + + if ((query.ImdbID == null || !TorznabCaps.SupportsImdbSearch) && !query.MatchQueryStringAND(release.Title)) + continue; + + release.Guid = new Uri(SiteLink + qRow.Find(".torrentName").Attr("href")); + release.Comments = release.Guid; + release.Link = new Uri(SiteLink + qRow.Find(".dlLinksInfo > a").Attr("href")); + + var sizeStr = qRow.Find(".sizeInfo").Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + var dateStr = qRow.Find(".ulInfo").Text().Split('|').Last().Trim(); + var agoIdx = dateStr.IndexOf("ago"); + if (agoIdx > -1) + { + dateStr = dateStr.Substring(0, agoIdx); + } + release.PublishDate = DateTimeUtil.FromTimeAgo(dateStr); + + release.Seeders = ParseUtil.CoerceInt(qRow.Find(".seedersInfo").Text()); + release.Peers = ParseUtil.CoerceInt(qRow.Find(".leechersInfo").Text()) + release.Seeders; + + var cat = qRow.Find("td:eq(0) a").First().Attr("href").Split('#')[0].Substring(15);//browse.php?cat=24 + release.Category = MapTrackerCatToNewznab(cat); + + if (qRow.Find("span.flTags").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - return releases; - } - } -} + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + return releases; + } + } +} diff --git a/src/Jackett/Indexers/TorrentHeaven.cs b/src/Jackett/Indexers/TorrentHeaven.cs index 6057f58e..2eb7bf5f 100644 --- a/src/Jackett/Indexers/TorrentHeaven.cs +++ b/src/Jackett/Indexers/TorrentHeaven.cs @@ -10,18 +10,18 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; -using System.Linq; -using System.Text.RegularExpressions; - +using System.Collections.Specialized; +using System.Text; +using System.Linq; +using System.Text.RegularExpressions; + namespace Jackett.Indexers { public class TorrentHeaven : BaseIndexer, IIndexer { string IndexUrl { get { return SiteLink + "index.php"; } } string LoginCompleteUrl { get { return SiteLink + "index.php?strWebValue=account&strWebAction=login_complete&ancestry=verify"; } } - static readonly string certificateHash = "6F5CE30D578C2A7AECFB919D0D013976D395055F"; + static readonly string certificateHash = "6F5CE30D578C2A7AECFB919D0D013976D395055F"; new ConfigurationDataCaptchaLogin configData { @@ -39,80 +39,80 @@ namespace Jackett.Indexers logger: l, p: ps, configData: new ConfigurationDataCaptchaLogin()) - { + { Encoding = Encoding.GetEncoding("iso-8859-1"); Language = "de-de"; Type = "private"; - AddCategoryMapping(1, TorznabCatType.PCGames); // GAMES/PC - AddCategoryMapping(3, TorznabCatType.Console); // GAMES/Sonstige - AddCategoryMapping(59, TorznabCatType.ConsolePS4); // GAMES/PlayStation - AddCategoryMapping(60, TorznabCatType.ConsolePSP); // GAMES/PSP - AddCategoryMapping(63, TorznabCatType.ConsoleWii); // GAMES/Wii - AddCategoryMapping(67, TorznabCatType.ConsoleXbox360); // GAMES/XBOX 360 - AddCategoryMapping(68, TorznabCatType.PCPhoneOther); // GAMES/PDA / Handy - AddCategoryMapping(72, TorznabCatType.ConsoleNDS); // GAMES/NDS - - AddCategoryMapping(7 , TorznabCatType.MoviesDVD); // MOVIES/DVD - AddCategoryMapping(8, TorznabCatType.MoviesSD); // MOVIES/SD - AddCategoryMapping(37, TorznabCatType.MoviesDVD); // MOVIES/DVD Spezial - AddCategoryMapping(41, TorznabCatType.MoviesForeign); // MOVIES/International - AddCategoryMapping(101, TorznabCatType.MoviesHD); // MOVIES/720p - AddCategoryMapping(102, TorznabCatType.MoviesHD); // MOVIES/1080p - AddCategoryMapping(103, TorznabCatType.MoviesHD); // MOVIES/AVCHD - AddCategoryMapping(104, TorznabCatType.MoviesBluRay); // MOVIES/Bluray - AddCategoryMapping(106, TorznabCatType.Movies3D); // MOVIES/3D - - AddCategoryMapping(14, TorznabCatType.Audio); // AUDIO/Musik - AddCategoryMapping(15, TorznabCatType.AudioAudiobook); // AUDIO/Hörbücher - AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // AUDIO/Hörspiele - AddCategoryMapping(36, TorznabCatType.AudioLossless); // AUDIO/Flac - AddCategoryMapping(42, TorznabCatType.AudioOther); // AUDIO/Soundtracks - AddCategoryMapping(58, TorznabCatType.AudioVideo); // AUDIO/Musikvideos - - AddCategoryMapping(18, TorznabCatType.TVSD); // TV/Serien SD - AddCategoryMapping(19, TorznabCatType.TVHD); // TV/Serien HD 720p - AddCategoryMapping(20, TorznabCatType.TVHD); // TV/Serien HD 1080p - AddCategoryMapping(49, TorznabCatType.TVSD); // TV/Serien DVD - AddCategoryMapping(51, TorznabCatType.TVDocumentary); // TV/Doku SD - AddCategoryMapping(52, TorznabCatType.TVDocumentary); // TV/Doku HD - AddCategoryMapping(53, TorznabCatType.TV); // TV/Serien Complete Packs - AddCategoryMapping(54, TorznabCatType.TVSport); // TV/Sport - AddCategoryMapping(66, TorznabCatType.TVFOREIGN); // TV/International - - AddCategoryMapping(22, TorznabCatType.Books); // MISC/EBooks - AddCategoryMapping(24, TorznabCatType.Other); // MISC/Sonstiges - AddCategoryMapping(25, TorznabCatType.Other); // MISC/Tonspuren - AddCategoryMapping(108, TorznabCatType.TVAnime); // MISC/Anime - - AddCategoryMapping(28, TorznabCatType.PC); // APPLICATIONS/PC - AddCategoryMapping(29, TorznabCatType.PCPhoneOther); // APPLICATIONS/Mobile - AddCategoryMapping(30, TorznabCatType.PC); // APPLICATIONS/Sonstige - AddCategoryMapping(70, TorznabCatType.PC); // APPLICATIONS/Linux + AddCategoryMapping(1, TorznabCatType.PCGames); // GAMES/PC + AddCategoryMapping(3, TorznabCatType.Console); // GAMES/Sonstige + AddCategoryMapping(59, TorznabCatType.ConsolePS4); // GAMES/PlayStation + AddCategoryMapping(60, TorznabCatType.ConsolePSP); // GAMES/PSP + AddCategoryMapping(63, TorznabCatType.ConsoleWii); // GAMES/Wii + AddCategoryMapping(67, TorznabCatType.ConsoleXbox360); // GAMES/XBOX 360 + AddCategoryMapping(68, TorznabCatType.PCPhoneOther); // GAMES/PDA / Handy + AddCategoryMapping(72, TorznabCatType.ConsoleNDS); // GAMES/NDS + + AddCategoryMapping(7 , TorznabCatType.MoviesDVD); // MOVIES/DVD + AddCategoryMapping(8, TorznabCatType.MoviesSD); // MOVIES/SD + AddCategoryMapping(37, TorznabCatType.MoviesDVD); // MOVIES/DVD Spezial + AddCategoryMapping(41, TorznabCatType.MoviesForeign); // MOVIES/International + AddCategoryMapping(101, TorznabCatType.MoviesHD); // MOVIES/720p + AddCategoryMapping(102, TorznabCatType.MoviesHD); // MOVIES/1080p + AddCategoryMapping(103, TorznabCatType.MoviesHD); // MOVIES/AVCHD + AddCategoryMapping(104, TorznabCatType.MoviesBluRay); // MOVIES/Bluray + AddCategoryMapping(106, TorznabCatType.Movies3D); // MOVIES/3D + + AddCategoryMapping(14, TorznabCatType.Audio); // AUDIO/Musik + AddCategoryMapping(15, TorznabCatType.AudioAudiobook); // AUDIO/Hörbücher + AddCategoryMapping(16, TorznabCatType.AudioAudiobook); // AUDIO/Hörspiele + AddCategoryMapping(36, TorznabCatType.AudioLossless); // AUDIO/Flac + AddCategoryMapping(42, TorznabCatType.AudioOther); // AUDIO/Soundtracks + AddCategoryMapping(58, TorznabCatType.AudioVideo); // AUDIO/Musikvideos + + AddCategoryMapping(18, TorznabCatType.TVSD); // TV/Serien SD + AddCategoryMapping(19, TorznabCatType.TVHD); // TV/Serien HD 720p + AddCategoryMapping(20, TorznabCatType.TVHD); // TV/Serien HD 1080p + AddCategoryMapping(49, TorznabCatType.TVSD); // TV/Serien DVD + AddCategoryMapping(51, TorznabCatType.TVDocumentary); // TV/Doku SD + AddCategoryMapping(52, TorznabCatType.TVDocumentary); // TV/Doku HD + AddCategoryMapping(53, TorznabCatType.TV); // TV/Serien Complete Packs + AddCategoryMapping(54, TorznabCatType.TVSport); // TV/Sport + AddCategoryMapping(66, TorznabCatType.TVFOREIGN); // TV/International + + AddCategoryMapping(22, TorznabCatType.Books); // MISC/EBooks + AddCategoryMapping(24, TorznabCatType.Other); // MISC/Sonstiges + AddCategoryMapping(25, TorznabCatType.Other); // MISC/Tonspuren + AddCategoryMapping(108, TorznabCatType.TVAnime); // MISC/Anime + + AddCategoryMapping(28, TorznabCatType.PC); // APPLICATIONS/PC + AddCategoryMapping(29, TorznabCatType.PCPhoneOther); // APPLICATIONS/Mobile + AddCategoryMapping(30, TorznabCatType.PC); // APPLICATIONS/Sonstige + AddCategoryMapping(70, TorznabCatType.PC); // APPLICATIONS/Linux AddCategoryMapping(71, TorznabCatType.PCMac); // APPLICATIONS/Mac } - public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) - { - base.LoadValuesFromJson(jsonConfig, useProtectionService); - - // add self signed cert to trusted certs - webclient.AddTrustedCertificate(new Uri(SiteLink).Host, certificateHash); + public override void LoadValuesFromJson(JToken jsonConfig, bool useProtectionService = false) + { + base.LoadValuesFromJson(jsonConfig, useProtectionService); + + // add self signed cert to trusted certs + webclient.AddTrustedCertificate(new Uri(SiteLink).Host, certificateHash); } public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(IndexUrl, string.Empty); - CQ dom = loginPage.Content; - CQ qCaptchaImg = dom.Find("td.tablea > img").First(); - if(qCaptchaImg.Length == 1) { + { + var loginPage = await RequestStringWithCookies(IndexUrl, string.Empty); + CQ dom = loginPage.Content; + CQ qCaptchaImg = dom.Find("td.tablea > img").First(); + if(qCaptchaImg.Length == 1) { var CaptchaUrl = SiteLink + qCaptchaImg.Attr("src"); var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies); - configData.CaptchaImage.Value = captchaImage.Content; + configData.CaptchaImage.Value = captchaImage.Content; } - else - { - configData.CaptchaImage.Value = new byte[0]; + else + { + configData.CaptchaImage.Value = new byte[0]; } configData.CaptchaCookie.Value = loginPage.Cookies; return configData; @@ -132,19 +132,19 @@ namespace Jackett.Indexers { "password", configData.Password.Value } }; - if (!string.IsNullOrWhiteSpace(configData.CaptchaText.Value)) - { - pairs.Add("proofcode", configData.CaptchaText.Value); + if (!string.IsNullOrWhiteSpace(configData.CaptchaText.Value)) + { + pairs.Add("proofcode", configData.CaptchaText.Value); } var result = await RequestLoginAndFollowRedirect(IndexUrl, pairs, configData.CaptchaCookie.Value, true, null, IndexUrl, true); - if (result.Content == null || (!result.Content.Contains("login_complete") && !result.Content.Contains("index.php?strWebValue=account&strWebAction=logout"))) - { - CQ dom = result.Content; - var errorMessage = dom["table > tbody > tr > td[valign=top][width=100%]"].Html(); - if(errorMessage.Length == 0) - errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + if (result.Content == null || (!result.Content.Contains("login_complete") && !result.Content.Contains("index.php?strWebValue=account&strWebAction=logout"))) + { + CQ dom = result.Content; + var errorMessage = dom["table > tbody > tr > td[valign=top][width=100%]"].Html(); + if(errorMessage.Length == 0) + errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); } var result2 = await RequestStringWithCookies(LoginCompleteUrl, result.Cookies); @@ -158,36 +158,36 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = IndexUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("strWebValue", "torrent"); - queryCollection.Add("strWebAction", "search"); - queryCollection.Add("sort", "torrent_added"); - queryCollection.Add("by", "d"); - queryCollection.Add("type", "0"); - queryCollection.Add("do_search", "suchen"); - queryCollection.Add("time", "0"); - queryCollection.Add("details", "title"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("searchstring", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("dirs" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = IndexUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("strWebValue", "torrent"); + queryCollection.Add("strWebAction", "search"); + queryCollection.Add("sort", "torrent_added"); + queryCollection.Add("by", "d"); + queryCollection.Add("type", "0"); + queryCollection.Add("do_search", "suchen"); + queryCollection.Add("time", "0"); + queryCollection.Add("details", "title"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("searchstring", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("dirs" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookies(searchUrl); @@ -201,56 +201,56 @@ namespace Jackett.Indexers foreach (var row in rows.Skip(1)) { var release = new ReleaseInfo(); - release.MinimumRatio = 0.8; + release.MinimumRatio = 0.8; release.MinimumSeedTime = 0; - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=details]").First(); - release.Title = TitleRegexp.Match(qDetailsLink.Attr("onmouseover")).Groups[1].Value; - - var qCatLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=search&dir=]").First(); - var qDLLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=download&id=]").First(); - var qSeeders = qRow.Find("td.column1:eq(3)"); - var qLeechers = qRow.Find("td.column2:eq(3)"); - var qDateStr = qRow.Find("font:has(a)").First(); - var qSize = qRow.Find("td.column2[align=center]").First(); - - var catStr = qCatLink.Attr("href").Split('=')[3].Split('#')[0]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDLLink.Attr("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=details]").First(); + release.Title = TitleRegexp.Match(qDetailsLink.Attr("onmouseover")).Groups[1].Value; + + var qCatLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=search&dir=]").First(); + var qDLLink = qRow.Find("a[href^=index.php?strWebValue=torrent&strWebAction=download&id=]").First(); + var qSeeders = qRow.Find("td.column1:eq(3)"); + var qLeechers = qRow.Find("td.column2:eq(3)"); + var qDateStr = qRow.Find("font:has(a)").First(); + var qSize = qRow.Find("td.column2[align=center]").First(); + + var catStr = qCatLink.Attr("href").Split('=')[3].Split('#')[0]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDLLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text().Trim(); var dateStrParts = dateStr.Split(); - DateTime dateGerman; - if (dateStrParts[0] == "Heute") - dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStrParts[1]); - else if (dateStrParts[0] == "Gestern") - dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStrParts[1]) - TimeSpan.FromDays(1); - else - dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStrParts[0]+ dateStrParts[1], "dd.MM.yyyyHH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime dateGerman; + if (dateStrParts[0] == "Heute") + dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStrParts[1]); + else if (dateStrParts[0] == "Gestern") + dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStrParts[1]) - TimeSpan.FromDays(1); + else + dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStrParts[0]+ dateStrParts[1], "dd.MM.yyyyHH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc.ToLocalTime(); var grabs = qRow.Find("td:nth-child(7)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - if (qRow.Find("img[src=\"themes/images/freeleech.png\"]").Length >= 1) + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (qRow.Find("img[src=\"themes/images/freeleech.png\"]").Length >= 1) release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[src=\"themes/images/DL50.png\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; + else if (qRow.Find("img[src=\"themes/images/DL50.png\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/TorrentLeech.cs b/src/Jackett/Indexers/TorrentLeech.cs index 978d541f..9c35d084 100644 --- a/src/Jackett/Indexers/TorrentLeech.cs +++ b/src/Jackett/Indexers/TorrentLeech.cs @@ -85,7 +85,7 @@ namespace Jackett.Indexers AddCategoryMapping(5, TorznabCatType.Books); AddCategoryMapping(45, TorznabCatType.BooksEbook, "Books/EBooks"); AddCategoryMapping(46, TorznabCatType.BooksComics, "Books/Comics"); - + AddCategoryMapping(23, TorznabCatType.PCISO); AddCategoryMapping(24, TorznabCatType.PCMac); AddCategoryMapping(25, TorznabCatType.PCPhoneOther); @@ -120,7 +120,7 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); + var searchString = query.GetQueryString(); searchString = searchString.Replace('-', ' '); // remove dashes as they exclude search strings var searchUrl = SearchUrl; @@ -140,10 +140,10 @@ namespace Jackett.Indexers searchUrl += ","; searchUrl += cat; } - } - else - { - searchUrl += "newfilter/2"; // include 0day and music + } + else + { + searchUrl += "newfilter/2"; // include 0day and music } var results = await RequestStringWithCookiesAndRetry(searchUrl); @@ -177,7 +177,7 @@ namespace Jackett.Indexers release.Comments = release.Guid; release.Title = qLink.Text(); - if (!query.MatchQueryStringAND(release.Title)) + if (!query.MatchQueryStringAND(release.Title)) continue; release.Link = new Uri(qRow.Find(".quickdownload > a").Attr("href")); @@ -197,7 +197,7 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(6)").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - release.DownloadVolumeFactor = 1; + release.DownloadVolumeFactor = 1; release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/TorrentNetwork.cs b/src/Jackett/Indexers/TorrentNetwork.cs index 6f0ad19e..53c3b18f 100644 --- a/src/Jackett/Indexers/TorrentNetwork.cs +++ b/src/Jackett/Indexers/TorrentNetwork.cs @@ -10,9 +10,9 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; - +using System.Collections.Specialized; +using System.Text; + namespace Jackett.Indexers { public class TorrentNetwork : BaseIndexer, IIndexer @@ -41,45 +41,45 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - AddCategoryMapping(1, TorznabCatType.AudioAudiobook); // aBook - AddCategoryMapping(4, TorznabCatType.PCMac); // App|Mac - AddCategoryMapping(5, TorznabCatType.PC); // App|Win - AddCategoryMapping(7, TorznabCatType.TVDocumentary); // Docu|HD - AddCategoryMapping(6, TorznabCatType.TVDocumentary); // Docu|SD - AddCategoryMapping(8, TorznabCatType.Books); // eBook - AddCategoryMapping(10, TorznabCatType.PCGames); // Game|PC - AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Game|PSX - AddCategoryMapping(12, TorznabCatType.ConsoleWii); // Game|Wii - AddCategoryMapping(14, TorznabCatType.ConsoleXbox); // Game|XBOX - AddCategoryMapping(30, TorznabCatType.Other); // Misc - AddCategoryMapping(17, TorznabCatType.MoviesHD); // Movie|DE|1080p - AddCategoryMapping(20, TorznabCatType.MoviesHD); // Movie|DE|2160p - AddCategoryMapping(36, TorznabCatType.Movies3D); // Movie|DE|3D - AddCategoryMapping(18, TorznabCatType.MoviesHD); // Movie|DE|720p - AddCategoryMapping(34, TorznabCatType.TVAnime); // Movie|DE|Anime - AddCategoryMapping(19, TorznabCatType.MoviesBluRay); // Movie|DE|BluRay - AddCategoryMapping(45, TorznabCatType.Movies); // Movie|DE|Remux - AddCategoryMapping(24, TorznabCatType.MoviesSD); // Movie|DE|SD - AddCategoryMapping(39, TorznabCatType.Movies); // Movie|EN/JP|Anime - AddCategoryMapping(43, TorznabCatType.MoviesHD); // Movie|EN|1080p - AddCategoryMapping(37, TorznabCatType.MoviesHD); // Movie|EN|2160p - AddCategoryMapping(35, TorznabCatType.MoviesHD); // Movie|EN|720p - AddCategoryMapping(38, TorznabCatType.MoviesBluRay); // Movie|EN|BluRay - AddCategoryMapping(46, TorznabCatType.Movies); // Movie|EN|Remux - AddCategoryMapping(22, TorznabCatType.MoviesSD); // Movie|EN|SD - AddCategoryMapping(44, TorznabCatType.AudioLossless); // Music|Flac - AddCategoryMapping(25, TorznabCatType.AudioMP3); // Music|MP3 - AddCategoryMapping(26, TorznabCatType.AudioVideo); // Music|Video - AddCategoryMapping(31, TorznabCatType.TVSport); // Sport - AddCategoryMapping(2, TorznabCatType.TVAnime); // TV|DE|Anime - AddCategoryMapping(28, TorznabCatType.TVHD); // TV|DE|HD - AddCategoryMapping(16, TorznabCatType.TV); // TV|DE|Pack - AddCategoryMapping(27, TorznabCatType.TVSD); // TV|DE|SD - AddCategoryMapping(41, TorznabCatType.TVAnime); // TV|EN/JP|Anime - AddCategoryMapping(40, TorznabCatType.TVHD); // TV|EN|HD - AddCategoryMapping(42, TorznabCatType.TV); // TV|EN|Pack - AddCategoryMapping(29, TorznabCatType.TVSD); // TV|EN|SD - AddCategoryMapping(33, TorznabCatType.XXX); // XXX|HD + AddCategoryMapping(1, TorznabCatType.AudioAudiobook); // aBook + AddCategoryMapping(4, TorznabCatType.PCMac); // App|Mac + AddCategoryMapping(5, TorznabCatType.PC); // App|Win + AddCategoryMapping(7, TorznabCatType.TVDocumentary); // Docu|HD + AddCategoryMapping(6, TorznabCatType.TVDocumentary); // Docu|SD + AddCategoryMapping(8, TorznabCatType.Books); // eBook + AddCategoryMapping(10, TorznabCatType.PCGames); // Game|PC + AddCategoryMapping(13, TorznabCatType.ConsolePS4); // Game|PSX + AddCategoryMapping(12, TorznabCatType.ConsoleWii); // Game|Wii + AddCategoryMapping(14, TorznabCatType.ConsoleXbox); // Game|XBOX + AddCategoryMapping(30, TorznabCatType.Other); // Misc + AddCategoryMapping(17, TorznabCatType.MoviesHD); // Movie|DE|1080p + AddCategoryMapping(20, TorznabCatType.MoviesHD); // Movie|DE|2160p + AddCategoryMapping(36, TorznabCatType.Movies3D); // Movie|DE|3D + AddCategoryMapping(18, TorznabCatType.MoviesHD); // Movie|DE|720p + AddCategoryMapping(34, TorznabCatType.TVAnime); // Movie|DE|Anime + AddCategoryMapping(19, TorznabCatType.MoviesBluRay); // Movie|DE|BluRay + AddCategoryMapping(45, TorznabCatType.Movies); // Movie|DE|Remux + AddCategoryMapping(24, TorznabCatType.MoviesSD); // Movie|DE|SD + AddCategoryMapping(39, TorznabCatType.Movies); // Movie|EN/JP|Anime + AddCategoryMapping(43, TorznabCatType.MoviesHD); // Movie|EN|1080p + AddCategoryMapping(37, TorznabCatType.MoviesHD); // Movie|EN|2160p + AddCategoryMapping(35, TorznabCatType.MoviesHD); // Movie|EN|720p + AddCategoryMapping(38, TorznabCatType.MoviesBluRay); // Movie|EN|BluRay + AddCategoryMapping(46, TorznabCatType.Movies); // Movie|EN|Remux + AddCategoryMapping(22, TorznabCatType.MoviesSD); // Movie|EN|SD + AddCategoryMapping(44, TorznabCatType.AudioLossless); // Music|Flac + AddCategoryMapping(25, TorznabCatType.AudioMP3); // Music|MP3 + AddCategoryMapping(26, TorznabCatType.AudioVideo); // Music|Video + AddCategoryMapping(31, TorznabCatType.TVSport); // Sport + AddCategoryMapping(2, TorznabCatType.TVAnime); // TV|DE|Anime + AddCategoryMapping(28, TorznabCatType.TVHD); // TV|DE|HD + AddCategoryMapping(16, TorznabCatType.TV); // TV|DE|Pack + AddCategoryMapping(27, TorznabCatType.TVSD); // TV|DE|SD + AddCategoryMapping(41, TorznabCatType.TVAnime); // TV|EN/JP|Anime + AddCategoryMapping(40, TorznabCatType.TVHD); // TV|EN|HD + AddCategoryMapping(42, TorznabCatType.TV); // TV|EN|Pack + AddCategoryMapping(29, TorznabCatType.TVSD); // TV|EN|SD + AddCategoryMapping(33, TorznabCatType.XXX); // XXX|HD AddCategoryMapping(32, TorznabCatType.XXX); // XXX|SD } @@ -94,44 +94,44 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => - { - CQ dom = result.Content; - var errorMessage = dom["table.tableinborder"].Html(); - errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), () => + { + CQ dom = result.Content; + var errorMessage = dom["table.tableinborder"].Html(); + errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("incldead", "1"); - queryCollection.Add("_by", "0"); - queryCollection.Add("sort", "4"); - queryCollection.Add("type", "desc"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("incldead", "1"); + queryCollection.Add("_by", "0"); + queryCollection.Add("sort", "4"); + queryCollection.Add("type", "desc"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookies(searchUrl); @@ -144,39 +144,39 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 0.8; + release.MinimumRatio = 0.8; release.MinimumSeedTime = 48 * 60 * 60; - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); - var qTitle = qDetailsLink.Find("b").First(); - release.Title = qTitle.Text(); - - var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); - var qDLLink = qRow.Find("a.download").First(); - var qSeeders = qRow.Find("td.torrenttable:eq(7)"); - var qLeechers = qRow.Find("td.torrenttable:eq(8)"); - var qDateStr = qRow.Find("td.torrenttable:eq(4)").First(); - var qSize = qRow.Find("td.torrenttable:eq(5)").First(); - - var catStr = qCatLink.Attr("href").Split('=')[1].Split('\'')[0]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDLLink.Attr("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=details.php?id=]").First(); + var qTitle = qDetailsLink.Find("b").First(); + release.Title = qTitle.Text(); + + var qCatLink = qRow.Find("a[href^=browse.php?cat=]").First(); + var qDLLink = qRow.Find("a.download").First(); + var qSeeders = qRow.Find("td.torrenttable:eq(7)"); + var qLeechers = qRow.Find("td.torrenttable:eq(8)"); + var qDateStr = qRow.Find("td.torrenttable:eq(4)").First(); + var qSize = qRow.Find("td.torrenttable:eq(5)").First(); + + var catStr = qCatLink.Attr("href").Split('=')[1].Split('\'')[0]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDLLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text().Trim(); - DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "MMM d yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc.ToLocalTime(); var files = qRow.Find("td:nth-child(4)").Text(); @@ -185,13 +185,13 @@ namespace Jackett.Indexers var grabs = qRow.Find("td:nth-child(8)").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[src=\"pic/torrent_ou.gif\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (qRow.Find("font[color=\"gray\"]:contains(50% Down)").Length >= 1) - release.DownloadVolumeFactor = 0.5; + if (qRow.Find("img[src=\"pic/torrent_ou.gif\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("font[color=\"gray\"]:contains(50% Down)").Length >= 1) + release.DownloadVolumeFactor = 0.5; else - release.DownloadVolumeFactor = 1; - + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; releases.Add(release); diff --git a/src/Jackett/Indexers/TorrentSyndikat.cs b/src/Jackett/Indexers/TorrentSyndikat.cs index fc852453..872d4b7e 100644 --- a/src/Jackett/Indexers/TorrentSyndikat.cs +++ b/src/Jackett/Indexers/TorrentSyndikat.cs @@ -1,221 +1,221 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Globalization; -using System.Text.RegularExpressions; - -namespace Jackett.Indexers -{ - public class TorrentSyndikat : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "eing2.php"; } } - private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } - TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time"); - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public TorrentSyndikat(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "Torrent-Syndikat", - description: "A German general tracker", - link: "https://torrent-syndikat.org/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "de-de"; - Type = "private"; - - this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; - this.configData.DisplayText.Name = "Notice"; - - AddCategoryMapping(2, TorznabCatType.PC); // Apps / Windows - AddCategoryMapping(13, TorznabCatType.PC); // Apps / Linux - AddCategoryMapping(4, TorznabCatType.PCMac); // Apps / Mac - AddCategoryMapping(6, TorznabCatType.PC); // Apps / Misc - - AddCategoryMapping(12, TorznabCatType.PCGames); // Spiele / PC - AddCategoryMapping(8, TorznabCatType.ConsolePSP); // Spiele / PSX/PSP - AddCategoryMapping(7, TorznabCatType.ConsoleWii); // Spiele / Wii - AddCategoryMapping(32, TorznabCatType.ConsoleXbox); // Spiele / XBOX - AddCategoryMapping(41, TorznabCatType.ConsoleNDS); // Spiele / Nintendo DS - - AddCategoryMapping(22, TorznabCatType.Movies3D); // Filme / 3D - AddCategoryMapping(3, TorznabCatType.MoviesBluRay); // Filme / BluRay - AddCategoryMapping(11, TorznabCatType.MoviesOther); // Filme / REMUX - AddCategoryMapping(42, TorznabCatType.MoviesHD); // Filme / 2160p - AddCategoryMapping(9, TorznabCatType.MoviesHD); // Filme / 1080p - AddCategoryMapping(20, TorznabCatType.MoviesHD); // Filme / 720p - AddCategoryMapping(21, TorznabCatType.MoviesDVD); // Filme / DVD - AddCategoryMapping(10, TorznabCatType.MoviesSD); // Filme / SD - AddCategoryMapping(31, TorznabCatType.MoviesOther); // Filme / Anime - AddCategoryMapping(37, TorznabCatType.MoviesForeign); // Filme / Englisch - - AddCategoryMapping(16, TorznabCatType.TVHD); // TV / Serien/HD - AddCategoryMapping(15, TorznabCatType.TVSD); // TV / Serien/SD - AddCategoryMapping(44, TorznabCatType.TVHD); // TV / Packs/UHD - AddCategoryMapping(23, TorznabCatType.TVHD); // TV / Packs/HD - AddCategoryMapping(27, TorznabCatType.TVSD); // TV / Packs/SD - AddCategoryMapping(28, TorznabCatType.TVDocumentary); // TV / Dokus/SD - AddCategoryMapping(29, TorznabCatType.TVDocumentary); // TV / Dokus/HD - AddCategoryMapping(30, TorznabCatType.TVSport); // TV / Sport - AddCategoryMapping(40, TorznabCatType.TVAnime); // TV / Anime - AddCategoryMapping(36, TorznabCatType.TVFOREIGN); // TV / Englisch - - AddCategoryMapping(24, TorznabCatType.AudioLossless); // Audio / FLAC - AddCategoryMapping(25, TorznabCatType.AudioMP3); // Audio / MP3 - AddCategoryMapping(35, TorznabCatType.AudioOther); // Audio / Other - AddCategoryMapping(26, TorznabCatType.Audio); // Audio / Packs - AddCategoryMapping(18, TorznabCatType.AudioAudiobook); // Audio / aBooks - AddCategoryMapping(33, TorznabCatType.AudioVideo); // Audio / Videos - - AddCategoryMapping(17, TorznabCatType.Books); // Misc / eBooks - AddCategoryMapping(5, TorznabCatType.PCPhoneOther); // Misc / Mobile - AddCategoryMapping(39, TorznabCatType.Other); // Misc / Bildung - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var result1 = await RequestStringWithCookies(CaptchaUrl); - var json1 = JObject.Parse(result1.Content); - var captchaSelection = json1["images"][0]["hash"]; - - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "captchaSelection", (string)captchaSelection }, - { "submitme", "X" } - }; - - var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); - - await ConfigureIfOK(result2.Cookies, result2.Content.Contains("/logout.php"), () => - { - var errorMessage = result2.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("searchin", "title"); - queryCollection.Add("incldead", "1"); - queryCollection.Add("rel_type", "0"); // Alle - if (!string.IsNullOrWhiteSpace(searchString)) - { - // use AND+wildcard operator to avoid getting to many useless results - var searchStringArray = Regex.Split(searchString.Trim(), "[ _.-]+", RegexOptions.Compiled).ToList(); - searchStringArray = searchStringArray.Where(x => x.Length >= 3).ToList(); // remove words with less than 3 characters - searchStringArray = searchStringArray.Where(x => !new string[] { "der", "die", "das", "the" }.Contains(x.ToLower())).ToList(); // remove words with less than 3 characters - searchStringArray = searchStringArray.Select(x => "+" + x + "*").ToList(); // add AND operators+wildcards - var searchStringFinal = String.Join(" ", searchStringArray); - queryCollection.Add("search", searchStringFinal); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - try - { - CQ dom = results.Content; - var rows = dom["table.torrent_table > tbody > tr"]; - var globalFreeleech = dom.Find("legend:contains(\"Freeleech\")+ul > li > b:contains(\"Freeleech\")").Any(); - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 96*60*60; - - var qRow = row.Cq(); - - var catStr = row.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - var qLink = row.ChildElements.ElementAt(2).FirstElementChild.Cq(); - release.Link = new Uri(SiteLink + qLink.Attr("href")); - var torrentId = qLink.Attr("href").Split('=').Last(); - - var descCol = row.ChildElements.ElementAt(1); - var qCommentLink = descCol.FirstElementChild.Cq(); - var torrentTag = descCol.Cq().Find("span.torrent-tag"); - var torrentTags = torrentTag.Elements.Select(x => x.InnerHTML).ToList(); - release.Title = qCommentLink.Attr("title"); - release.Description = String.Join(", ", torrentTags); - release.Comments = new Uri(SiteLink + "/" + qCommentLink.Attr("href").Replace("&hit=1", "")); - release.Guid = release.Comments; - - var torrent_details = descCol.ChildElements.Last(); - var dateStr = torrent_details.ChildNodes.ElementAt(torrent_details.ChildNodes.Length-3).Cq().Text().Replace(" von ", "").Trim(); - DateTime dateGerman; - if (dateStr.StartsWith("Heute ")) - dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStr.Split(' ')[1]); - else if (dateStr.StartsWith("Gestern ")) - dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStr.Split(' ')[1]) - TimeSpan.FromDays(1); - else - dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); - release.PublishDate = pubDateUtc.ToLocalTime(); - - var sizeStr = row.ChildElements.ElementAt(5).Cq().Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()); - release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()) + release.Seeders; +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Jackett.Indexers +{ + public class TorrentSyndikat : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "eing2.php"; } } + private string CaptchaUrl { get { return SiteLink + "simpleCaptcha.php?numImages=1"; } } + TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "W. Europe Standard Time", "W. Europe Standard Time"); + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get { return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public TorrentSyndikat(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "Torrent-Syndikat", + description: "A German general tracker", + link: "https://torrent-syndikat.org/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "de-de"; + Type = "private"; + + this.configData.DisplayText.Value = "Only the results from the first search result page are shown, adjust your profile settings to show the maximum."; + this.configData.DisplayText.Name = "Notice"; + + AddCategoryMapping(2, TorznabCatType.PC); // Apps / Windows + AddCategoryMapping(13, TorznabCatType.PC); // Apps / Linux + AddCategoryMapping(4, TorznabCatType.PCMac); // Apps / Mac + AddCategoryMapping(6, TorznabCatType.PC); // Apps / Misc + + AddCategoryMapping(12, TorznabCatType.PCGames); // Spiele / PC + AddCategoryMapping(8, TorznabCatType.ConsolePSP); // Spiele / PSX/PSP + AddCategoryMapping(7, TorznabCatType.ConsoleWii); // Spiele / Wii + AddCategoryMapping(32, TorznabCatType.ConsoleXbox); // Spiele / XBOX + AddCategoryMapping(41, TorznabCatType.ConsoleNDS); // Spiele / Nintendo DS + + AddCategoryMapping(22, TorznabCatType.Movies3D); // Filme / 3D + AddCategoryMapping(3, TorznabCatType.MoviesBluRay); // Filme / BluRay + AddCategoryMapping(11, TorznabCatType.MoviesOther); // Filme / REMUX + AddCategoryMapping(42, TorznabCatType.MoviesHD); // Filme / 2160p + AddCategoryMapping(9, TorznabCatType.MoviesHD); // Filme / 1080p + AddCategoryMapping(20, TorznabCatType.MoviesHD); // Filme / 720p + AddCategoryMapping(21, TorznabCatType.MoviesDVD); // Filme / DVD + AddCategoryMapping(10, TorznabCatType.MoviesSD); // Filme / SD + AddCategoryMapping(31, TorznabCatType.MoviesOther); // Filme / Anime + AddCategoryMapping(37, TorznabCatType.MoviesForeign); // Filme / Englisch + + AddCategoryMapping(16, TorznabCatType.TVHD); // TV / Serien/HD + AddCategoryMapping(15, TorznabCatType.TVSD); // TV / Serien/SD + AddCategoryMapping(44, TorznabCatType.TVHD); // TV / Packs/UHD + AddCategoryMapping(23, TorznabCatType.TVHD); // TV / Packs/HD + AddCategoryMapping(27, TorznabCatType.TVSD); // TV / Packs/SD + AddCategoryMapping(28, TorznabCatType.TVDocumentary); // TV / Dokus/SD + AddCategoryMapping(29, TorznabCatType.TVDocumentary); // TV / Dokus/HD + AddCategoryMapping(30, TorznabCatType.TVSport); // TV / Sport + AddCategoryMapping(40, TorznabCatType.TVAnime); // TV / Anime + AddCategoryMapping(36, TorznabCatType.TVFOREIGN); // TV / Englisch + + AddCategoryMapping(24, TorznabCatType.AudioLossless); // Audio / FLAC + AddCategoryMapping(25, TorznabCatType.AudioMP3); // Audio / MP3 + AddCategoryMapping(35, TorznabCatType.AudioOther); // Audio / Other + AddCategoryMapping(26, TorznabCatType.Audio); // Audio / Packs + AddCategoryMapping(18, TorznabCatType.AudioAudiobook); // Audio / aBooks + AddCategoryMapping(33, TorznabCatType.AudioVideo); // Audio / Videos + + AddCategoryMapping(17, TorznabCatType.Books); // Misc / eBooks + AddCategoryMapping(5, TorznabCatType.PCPhoneOther); // Misc / Mobile + AddCategoryMapping(39, TorznabCatType.Other); // Misc / Bildung + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var result1 = await RequestStringWithCookies(CaptchaUrl); + var json1 = JObject.Parse(result1.Content); + var captchaSelection = json1["images"][0]["hash"]; + + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "captchaSelection", (string)captchaSelection }, + { "submitme", "X" } + }; + + var result2 = await RequestLoginAndFollowRedirect(LoginUrl, pairs, result1.Cookies, true, null, null, true); + + await ConfigureIfOK(result2.Cookies, result2.Content.Contains("/logout.php"), () => + { + var errorMessage = result2.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("searchin", "title"); + queryCollection.Add("incldead", "1"); + queryCollection.Add("rel_type", "0"); // Alle + if (!string.IsNullOrWhiteSpace(searchString)) + { + // use AND+wildcard operator to avoid getting to many useless results + var searchStringArray = Regex.Split(searchString.Trim(), "[ _.-]+", RegexOptions.Compiled).ToList(); + searchStringArray = searchStringArray.Where(x => x.Length >= 3).ToList(); // remove words with less than 3 characters + searchStringArray = searchStringArray.Where(x => !new string[] { "der", "die", "das", "the" }.Contains(x.ToLower())).ToList(); // remove words with less than 3 characters + searchStringArray = searchStringArray.Select(x => "+" + x + "*").ToList(); // add AND operators+wildcards + var searchStringFinal = String.Join(" ", searchStringArray); + queryCollection.Add("search", searchStringFinal); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + var rows = dom["table.torrent_table > tbody > tr"]; + var globalFreeleech = dom.Find("legend:contains(\"Freeleech\")+ul > li > b:contains(\"Freeleech\")").Any(); + foreach (var row in rows.Skip(1)) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 96*60*60; + + var qRow = row.Cq(); + + var catStr = row.ChildElements.ElementAt(0).FirstElementChild.GetAttribute("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + var qLink = row.ChildElements.ElementAt(2).FirstElementChild.Cq(); + release.Link = new Uri(SiteLink + qLink.Attr("href")); + var torrentId = qLink.Attr("href").Split('=').Last(); + + var descCol = row.ChildElements.ElementAt(1); + var qCommentLink = descCol.FirstElementChild.Cq(); + var torrentTag = descCol.Cq().Find("span.torrent-tag"); + var torrentTags = torrentTag.Elements.Select(x => x.InnerHTML).ToList(); + release.Title = qCommentLink.Attr("title"); + release.Description = String.Join(", ", torrentTags); + release.Comments = new Uri(SiteLink + "/" + qCommentLink.Attr("href").Replace("&hit=1", "")); + release.Guid = release.Comments; + + var torrent_details = descCol.ChildElements.Last(); + var dateStr = torrent_details.ChildNodes.ElementAt(torrent_details.ChildNodes.Length-3).Cq().Text().Replace(" von ", "").Trim(); + DateTime dateGerman; + if (dateStr.StartsWith("Heute ")) + dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStr.Split(' ')[1]); + else if (dateStr.StartsWith("Gestern ")) + dateGerman = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified) + TimeSpan.Parse(dateStr.Split(' ')[1]) - TimeSpan.FromDays(1); + else + dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yyyy HH:mm", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + release.PublishDate = pubDateUtc.ToLocalTime(); + + var sizeStr = row.ChildElements.ElementAt(5).Cq().Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(row.ChildElements.ElementAt(7).Cq().Text()); + release.Peers = ParseUtil.CoerceInt(row.ChildElements.ElementAt(8).Cq().Text()) + release.Seeders; var grabs = qRow.Find("td:nth-child(7)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (globalFreeleech) + if (globalFreeleech) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("span.torrent-tag-free").Length >= 1) release.DownloadVolumeFactor = 0; - else if (qRow.Find("span.torrent-tag-free").Length >= 1) - release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Torrentech.cs b/src/Jackett/Indexers/Torrentech.cs index 9dd30fe7..ae69f25c 100644 --- a/src/Jackett/Indexers/Torrentech.cs +++ b/src/Jackett/Indexers/Torrentech.cs @@ -10,12 +10,12 @@ using System; using System.Text; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using AngleSharp.Parser.Html; -using AngleSharp.Dom; -using System.Text.RegularExpressions; -using System.Web; - +using System.Collections.Specialized; +using AngleSharp.Parser.Html; +using AngleSharp.Dom; +using System.Text.RegularExpressions; +using System.Web; + namespace Jackett.Indexers { public class Torrentech : BaseIndexer, IIndexer @@ -39,7 +39,7 @@ namespace Jackett.Indexers logger: l, p: ps, configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { + { Encoding = Encoding.UTF8; Language = "en-us"; Type = "private"; @@ -60,10 +60,10 @@ namespace Jackett.Indexers }; var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("Logged in as: "), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("Logged in as: "), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } @@ -71,122 +71,122 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - WebClientStringResult results = null; - var queryCollection = new NameValueCollection(); - - queryCollection.Add("act", "search"); - queryCollection.Add("forums", "all"); - queryCollection.Add("torrents", "1"); - queryCollection.Add("search_in", "titles"); - queryCollection.Add("result_type", "topics"); - - // if the search string is empty use the getnew view - if (string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("CODE", "getnew"); - queryCollection.Add("active", "1"); + var searchString = query.GetQueryString(); + + WebClientStringResult results = null; + var queryCollection = new NameValueCollection(); + + queryCollection.Add("act", "search"); + queryCollection.Add("forums", "all"); + queryCollection.Add("torrents", "1"); + queryCollection.Add("search_in", "titles"); + queryCollection.Add("result_type", "topics"); + + // if the search string is empty use the getnew view + if (string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("CODE", "getnew"); + queryCollection.Add("active", "1"); } - else // use the normal search - { - searchString = searchString.Replace("-", " "); - queryCollection.Add("CODE", "01"); - queryCollection.Add("keywords", searchString); + else // use the normal search + { + searchString = searchString.Replace("-", " "); + queryCollection.Add("CODE", "01"); + queryCollection.Add("keywords", searchString); } var searchUrl = IndexUrl + "?" + queryCollection.GetQueryString(); - results = await RequestStringWithCookies(searchUrl); - if (results.IsRedirect && results.RedirectingTo.Contains("CODE=show")) - { - results = await RequestStringWithCookies(results.RedirectingTo); - } + results = await RequestStringWithCookies(searchUrl); + if (results.IsRedirect && results.RedirectingTo.Contains("CODE=show")) + { + results = await RequestStringWithCookies(results.RedirectingTo); + } try { string RowsSelector = "div.borderwrap:has(div.maintitle) > table > tbody > tr:has(a[href*=\"index.php?showtopic=\"])"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + foreach (var Row in Rows) { - try + try { var release = new ReleaseInfo(); - var StatsElements = Row.QuerySelector("td:nth-child(5)"); - var stats = StatsElements.TextContent.Split('·'); - if (stats.Length != 3) // not a torrent - continue; - - release.Seeders = ParseUtil.CoerceInt(stats[0]); - release.Peers = ParseUtil.CoerceInt(stats[1]) + release.Seeders; + var StatsElements = Row.QuerySelector("td:nth-child(5)"); + var stats = StatsElements.TextContent.Split('·'); + if (stats.Length != 3) // not a torrent + continue; + + release.Seeders = ParseUtil.CoerceInt(stats[0]); + release.Peers = ParseUtil.CoerceInt(stats[1]) + release.Seeders; release.Grabs = ParseUtil.CoerceInt(stats[2]); - release.MinimumRatio = 0.51; + release.MinimumRatio = 0.51; release.MinimumSeedTime = 0; - - var qDetailsLink = Row.QuerySelector("a[onmouseover][href*=\"index.php?showtopic=\"]"); - release.Title = qDetailsLink.TextContent; - release.Comments = new Uri(qDetailsLink.GetAttribute("href")); - release.Link = release.Comments; - release.Guid = release.Link; - - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - var id = HttpUtility.ParseQueryString(release.Comments.Query).Get("showtopic"); - - var desc = Row.QuerySelector("span.desc"); - var forange = desc.QuerySelector("font.forange"); - if (forange != null) - { - var DownloadVolumeFactor = forange.QuerySelector("i:contains(\"freeleech\")"); - if (DownloadVolumeFactor != null) - release.DownloadVolumeFactor = 0; - - var UploadVolumeFactor = forange.QuerySelector("i:contains(\"x upload]\")"); - if (UploadVolumeFactor != null) - release.UploadVolumeFactor = ParseUtil.CoerceDouble(UploadVolumeFactor.TextContent.Split(' ')[0].Substring(1).Replace("x", "")); - forange.Remove(); - } - var format = desc.TextContent; - release.Title += " [" + format + "]"; - - var preview = SearchResultDocument.QuerySelector("div#d21-tph-preview-data-" + id); - if (preview != null) - { - release.Description = ""; - foreach (var e in preview.ChildNodes) - { - if (e.NodeType == NodeType.Text) - release.Description += e.NodeValue; - else - release.Description += e.TextContent + "\n"; - } - } - release.Description = HttpUtility.HtmlEncode(release.Description.Trim()); - release.Description = release.Description.Replace("\n", "<br>"); - - if (format.Contains("MP3")) - release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; - else if (format.Contains("AAC")) - release.Category = new List<int> { TorznabCatType.AudioOther.ID }; - else if (format.Contains("Lossless")) - release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; - else - release.Category = new List<int> { TorznabCatType.AudioOther.ID }; - - var lastAction = Row.QuerySelector("td:nth-child(9) > span").FirstChild.NodeValue; - release.PublishDate = DateTimeUtil.FromUnknown(lastAction, "UK"); - - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); + + var qDetailsLink = Row.QuerySelector("a[onmouseover][href*=\"index.php?showtopic=\"]"); + release.Title = qDetailsLink.TextContent; + release.Comments = new Uri(qDetailsLink.GetAttribute("href")); + release.Link = release.Comments; + release.Guid = release.Link; + + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + var id = HttpUtility.ParseQueryString(release.Comments.Query).Get("showtopic"); + + var desc = Row.QuerySelector("span.desc"); + var forange = desc.QuerySelector("font.forange"); + if (forange != null) + { + var DownloadVolumeFactor = forange.QuerySelector("i:contains(\"freeleech\")"); + if (DownloadVolumeFactor != null) + release.DownloadVolumeFactor = 0; + + var UploadVolumeFactor = forange.QuerySelector("i:contains(\"x upload]\")"); + if (UploadVolumeFactor != null) + release.UploadVolumeFactor = ParseUtil.CoerceDouble(UploadVolumeFactor.TextContent.Split(' ')[0].Substring(1).Replace("x", "")); + forange.Remove(); + } + var format = desc.TextContent; + release.Title += " [" + format + "]"; + + var preview = SearchResultDocument.QuerySelector("div#d21-tph-preview-data-" + id); + if (preview != null) + { + release.Description = ""; + foreach (var e in preview.ChildNodes) + { + if (e.NodeType == NodeType.Text) + release.Description += e.NodeValue; + else + release.Description += e.TextContent + "\n"; + } + } + release.Description = HttpUtility.HtmlEncode(release.Description.Trim()); + release.Description = release.Description.Replace("\n", "<br>"); + + if (format.Contains("MP3")) + release.Category = new List<int> { TorznabCatType.AudioMP3.ID }; + else if (format.Contains("AAC")) + release.Category = new List<int> { TorznabCatType.AudioOther.ID }; + else if (format.Contains("Lossless")) + release.Category = new List<int> { TorznabCatType.AudioLossless.ID }; + else + release.Category = new List<int> { TorznabCatType.AudioOther.ID }; + + var lastAction = Row.QuerySelector("td:nth-child(9) > span").FirstChild.NodeValue; + release.PublishDate = DateTimeUtil.FromUnknown(lastAction, "UK"); + + releases.Add(release); } - } + catch (Exception ex) + { + logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); + } + } } catch (Exception ex) { @@ -196,26 +196,26 @@ namespace Jackett.Indexers return releases; } - public override async Task<byte[]> Download(Uri link) - { - var response = await RequestStringWithCookies(link.ToString()); - var results = response.Content; - var SearchResultParser = new HtmlParser(); - var SearchResultDocument = SearchResultParser.Parse(results); - var downloadSelector = "a[title=\"Download attachment\"]"; - var DlUri = SearchResultDocument.QuerySelector(downloadSelector); - if (DlUri != null) - { - logger.Debug(string.Format("{0}: Download selector {1} matched:{2}", ID, downloadSelector, DlUri.OuterHtml)); - var href = DlUri.GetAttribute("href"); - link = new Uri(href); - } - else - { - logger.Error(string.Format("{0}: Download selector {1} didn't match:\n{2}", ID, downloadSelector, results)); - throw new Exception(string.Format("Download selector {0} didn't match", downloadSelector)); - } - return await base.Download(link); + public override async Task<byte[]> Download(Uri link) + { + var response = await RequestStringWithCookies(link.ToString()); + var results = response.Content; + var SearchResultParser = new HtmlParser(); + var SearchResultDocument = SearchResultParser.Parse(results); + var downloadSelector = "a[title=\"Download attachment\"]"; + var DlUri = SearchResultDocument.QuerySelector(downloadSelector); + if (DlUri != null) + { + logger.Debug(string.Format("{0}: Download selector {1} matched:{2}", ID, downloadSelector, DlUri.OuterHtml)); + var href = DlUri.GetAttribute("href"); + link = new Uri(href); + } + else + { + logger.Error(string.Format("{0}: Download selector {1} didn't match:\n{2}", ID, downloadSelector, results)); + throw new Exception(string.Format("Download selector {0} didn't match", downloadSelector)); + } + return await base.Download(link); } } } diff --git a/src/Jackett/Indexers/TransmitheNet.cs b/src/Jackett/Indexers/TransmitheNet.cs index ac304dd0..c86c4414 100644 --- a/src/Jackett/Indexers/TransmitheNet.cs +++ b/src/Jackett/Indexers/TransmitheNet.cs @@ -148,16 +148,16 @@ namespace Jackett.Indexers release.Files = ParseUtil.CoerceLong(row.QuerySelector("td > div:contains(\"Files:\")").TextContent.Split(':')[1].Trim()); release.Grabs = ParseUtil.CoerceLong(row.QuerySelector("td:nth-last-child(3)").TextContent); - if (globalFreeleech) - release.DownloadVolumeFactor = 0; - else if (row.QuerySelector("img[alt=\"Freeleech\"]") != null) - release.DownloadVolumeFactor = 0; + if (globalFreeleech) + release.DownloadVolumeFactor = 0; + else if (row.QuerySelector("img[alt=\"Freeleech\"]") != null) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - - release.UploadVolumeFactor = 1; - - + release.DownloadVolumeFactor = 1; + + release.UploadVolumeFactor = 1; + + releases.Add(release); } } diff --git a/src/Jackett/Indexers/XSpeeds.cs b/src/Jackett/Indexers/XSpeeds.cs index d783f5e8..020868d0 100644 --- a/src/Jackett/Indexers/XSpeeds.cs +++ b/src/Jackett/Indexers/XSpeeds.cs @@ -1,58 +1,58 @@ -using CsQuery; -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.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Text.RegularExpressions; -using System.Xml.Linq; -using static Jackett.Utils.ParseUtil; -using static Jackett.Models.IndexerConfig.ConfigurationData; - -namespace Jackett.Indexers -{ - public class XSpeeds : BaseIndexer, IIndexer - { - string LandingUrl => SiteLink + "login.php"; - string LoginUrl => SiteLink + "takelogin.php"; - string GetRSSKeyUrl => SiteLink + "getrss.php"; - string SearchUrl => SiteLink + "browse.php"; - string RSSUrl => SiteLink + "rss.php?secret_key={0}&feedtype=download&timezone=0&showrows=50&categories=all"; - string CommentUrl => SiteLink + "details.php?id={0}"; - string DownloadUrl => SiteLink + "download.php?id={0}"; - - new ConfigurationDataBasicLoginWithRSSAndDisplay configData - { - get {return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } - set { base.configData = value; } - } - - public XSpeeds(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) - : base(name: "XSpeeds", - description: "XSpeeds", - link: "https://www.xspeeds.eu/", - caps: TorznabUtil.CreateDefaultTorznabTVCaps(), - manager: i, - client: wc, - logger: l, - p: ps, - configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) - { - Encoding = Encoding.GetEncoding("UTF-8"); - Language = "en-us"; - Type = "private"; - - configData.DisplayText.Value = "Expect an initial delay (often around 10 seconds) due to XSpeeds CloudFlare DDoS protection"; - configData.DisplayText.Name = "Notice"; - +using CsQuery; +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.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using static Jackett.Utils.ParseUtil; +using static Jackett.Models.IndexerConfig.ConfigurationData; + +namespace Jackett.Indexers +{ + public class XSpeeds : BaseIndexer, IIndexer + { + string LandingUrl => SiteLink + "login.php"; + string LoginUrl => SiteLink + "takelogin.php"; + string GetRSSKeyUrl => SiteLink + "getrss.php"; + string SearchUrl => SiteLink + "browse.php"; + string RSSUrl => SiteLink + "rss.php?secret_key={0}&feedtype=download&timezone=0&showrows=50&categories=all"; + string CommentUrl => SiteLink + "details.php?id={0}"; + string DownloadUrl => SiteLink + "download.php?id={0}"; + + new ConfigurationDataBasicLoginWithRSSAndDisplay configData + { + get {return (ConfigurationDataBasicLoginWithRSSAndDisplay)base.configData; } + set { base.configData = value; } + } + + public XSpeeds(IIndexerManagerService i, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "XSpeeds", + description: "XSpeeds", + link: "https://www.xspeeds.eu/", + caps: TorznabUtil.CreateDefaultTorznabTVCaps(), + manager: i, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataBasicLoginWithRSSAndDisplay()) + { + Encoding = Encoding.GetEncoding("UTF-8"); + Language = "en-us"; + Type = "private"; + + configData.DisplayText.Value = "Expect an initial delay (often around 10 seconds) due to XSpeeds CloudFlare DDoS protection"; + configData.DisplayText.Name = "Notice"; + AddCategoryMapping(70, TorznabCatType.TVAnime); // Anime AddCategoryMapping(4, TorznabCatType.PC); // Apps AddCategoryMapping(82, TorznabCatType.PCMac); // Mac @@ -77,8 +77,8 @@ namespace Jackett.Indexers AddCategoryMapping(71, TorznabCatType.TV); // PPV AddCategoryMapping(54, TorznabCatType.TV); // Soaps AddCategoryMapping(20, TorznabCatType.TVSport); // Sports - AddCategoryMapping(86, TorznabCatType.TVSport); // MotorSports - AddCategoryMapping(89, TorznabCatType.TVSport); // Olympics 2016 + AddCategoryMapping(86, TorznabCatType.TVSport); // MotorSports + AddCategoryMapping(89, TorznabCatType.TVSport); // Olympics 2016 AddCategoryMapping(88, TorznabCatType.TVSport); // World Cup AddCategoryMapping(83, TorznabCatType.Movies); // TOTM AddCategoryMapping(21, TorznabCatType.TVSD); // TV Boxsets @@ -87,275 +87,275 @@ namespace Jackett.Indexers AddCategoryMapping(16, TorznabCatType.TVSD); // TV-SD AddCategoryMapping(7, TorznabCatType.ConsoleWii); // Wii Games AddCategoryMapping(43, TorznabCatType.TVSport); // Wrestling - AddCategoryMapping(8, TorznabCatType.ConsoleXbox); // Xbox Games - - // RSS Textual categories - AddCategoryMapping("Anime", TorznabCatType.TVAnime); - AddCategoryMapping("Apps", TorznabCatType.PC); - AddCategoryMapping("Mac", TorznabCatType.PCMac); - AddCategoryMapping("Audiobooks", TorznabCatType.AudioAudiobook); - AddCategoryMapping("Blu-Ray", TorznabCatType.MoviesBluRay); - AddCategoryMapping("Books Magazines", TorznabCatType.Books); - AddCategoryMapping("Cams/TS", TorznabCatType.MoviesOther); - AddCategoryMapping("Documentaries", TorznabCatType.TVDocumentary); - AddCategoryMapping("DVDR", TorznabCatType.MoviesDVD); - AddCategoryMapping("Foreign", TorznabCatType.MoviesForeign); - AddCategoryMapping("Kids", TorznabCatType.TVOTHER); - AddCategoryMapping("MMA", TorznabCatType.TVSport); - AddCategoryMapping("Movie Boxsets", TorznabCatType.Movies); - AddCategoryMapping("Movies", TorznabCatType.Movies); - AddCategoryMapping("Music", TorznabCatType.Audio); - AddCategoryMapping("Music Videos", TorznabCatType.AudioVideo); - AddCategoryMapping("NDS Games", TorznabCatType.ConsoleNDS); - AddCategoryMapping("Other", TorznabCatType.Other); - AddCategoryMapping("PC Games", TorznabCatType.PCGames); - AddCategoryMapping("Pictures", TorznabCatType.Other); - AddCategoryMapping("Playstation", TorznabCatType.ConsolePS4); - AddCategoryMapping("PPV", TorznabCatType.TV); - AddCategoryMapping("Soaps", TorznabCatType.TV); - AddCategoryMapping("Sports", TorznabCatType.TVSport); - AddCategoryMapping("MotorSports", TorznabCatType.TVSport); - AddCategoryMapping("Olympics 2016", TorznabCatType.TVSport); - AddCategoryMapping("World Cup", TorznabCatType.TVSport); - AddCategoryMapping("TOTM", TorznabCatType.Movies); - AddCategoryMapping("TV Boxsets", TorznabCatType.TVSD); - AddCategoryMapping("HD Boxsets", TorznabCatType.TVHD); - AddCategoryMapping("TV-HD", TorznabCatType.TVHD); - AddCategoryMapping("TV-SD", TorznabCatType.TVSD); - AddCategoryMapping("Wii Games", TorznabCatType.ConsoleWii); - AddCategoryMapping("Wrestling", TorznabCatType.TVSport); - AddCategoryMapping("Xbox Games", TorznabCatType.ConsoleXbox); - } - + AddCategoryMapping(8, TorznabCatType.ConsoleXbox); // Xbox Games + + // RSS Textual categories + AddCategoryMapping("Anime", TorznabCatType.TVAnime); + AddCategoryMapping("Apps", TorznabCatType.PC); + AddCategoryMapping("Mac", TorznabCatType.PCMac); + AddCategoryMapping("Audiobooks", TorznabCatType.AudioAudiobook); + AddCategoryMapping("Blu-Ray", TorznabCatType.MoviesBluRay); + AddCategoryMapping("Books Magazines", TorznabCatType.Books); + AddCategoryMapping("Cams/TS", TorznabCatType.MoviesOther); + AddCategoryMapping("Documentaries", TorznabCatType.TVDocumentary); + AddCategoryMapping("DVDR", TorznabCatType.MoviesDVD); + AddCategoryMapping("Foreign", TorznabCatType.MoviesForeign); + AddCategoryMapping("Kids", TorznabCatType.TVOTHER); + AddCategoryMapping("MMA", TorznabCatType.TVSport); + AddCategoryMapping("Movie Boxsets", TorznabCatType.Movies); + AddCategoryMapping("Movies", TorznabCatType.Movies); + AddCategoryMapping("Music", TorznabCatType.Audio); + AddCategoryMapping("Music Videos", TorznabCatType.AudioVideo); + AddCategoryMapping("NDS Games", TorznabCatType.ConsoleNDS); + AddCategoryMapping("Other", TorznabCatType.Other); + AddCategoryMapping("PC Games", TorznabCatType.PCGames); + AddCategoryMapping("Pictures", TorznabCatType.Other); + AddCategoryMapping("Playstation", TorznabCatType.ConsolePS4); + AddCategoryMapping("PPV", TorznabCatType.TV); + AddCategoryMapping("Soaps", TorznabCatType.TV); + AddCategoryMapping("Sports", TorznabCatType.TVSport); + AddCategoryMapping("MotorSports", TorznabCatType.TVSport); + AddCategoryMapping("Olympics 2016", TorznabCatType.TVSport); + AddCategoryMapping("World Cup", TorznabCatType.TVSport); + AddCategoryMapping("TOTM", TorznabCatType.Movies); + AddCategoryMapping("TV Boxsets", TorznabCatType.TVSD); + AddCategoryMapping("HD Boxsets", TorznabCatType.TVHD); + AddCategoryMapping("TV-HD", TorznabCatType.TVHD); + AddCategoryMapping("TV-SD", TorznabCatType.TVSD); + AddCategoryMapping("Wii Games", TorznabCatType.ConsoleWii); + AddCategoryMapping("Wrestling", TorznabCatType.TVSport); + AddCategoryMapping("Xbox Games", TorznabCatType.ConsoleXbox); + } + public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LandingUrl); - CQ dom = loginPage.Content; - CQ qCaptchaImg = dom.Find("img#regimage").First(); - if (qCaptchaImg.Length > 0) - { - + { + var loginPage = await RequestStringWithCookies(LandingUrl); + CQ dom = loginPage.Content; + CQ qCaptchaImg = dom.Find("img#regimage").First(); + if (qCaptchaImg.Length > 0) + { + var CaptchaUrl = qCaptchaImg.Attr("src"); var captchaImage = await RequestBytesWithCookies(CaptchaUrl, loginPage.Cookies, RequestType.GET, LandingUrl); - - var CaptchaImage = new ImageItem { Name = "Captcha Image" }; - var CaptchaText = new StringItem { Name = "Captcha Text" }; - - CaptchaImage.Value = captchaImage.Content; - - configData.AddDynamic("CaptchaImage", CaptchaImage); - configData.AddDynamic("CaptchaText", CaptchaText); - } - else - { - logger.Debug(string.Format("{0}: No captcha image found", ID)); + + var CaptchaImage = new ImageItem { Name = "Captcha Image" }; + var CaptchaText = new StringItem { Name = "Captcha Text" }; + + CaptchaImage.Value = captchaImage.Content; + + configData.AddDynamic("CaptchaImage", CaptchaImage); + configData.AddDynamic("CaptchaText", CaptchaText); + } + else + { + logger.Debug(string.Format("{0}: No captcha image found", ID)); } return configData; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - - var pairs = new Dictionary<string, string> - { - {"username", configData.Username.Value}, - {"password", configData.Password.Value} - }; - - var CaptchaText = (StringItem)configData.GetDynamic("CaptchaText"); - if (CaptchaText != null) - { - pairs.Add("imagestring", CaptchaText.Value); - } - - //var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink, true); - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, LandingUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), - () => - { - CQ dom = result.Content; - var errorMessage = dom[".left_side table:eq(0) tr:eq(1)"].Text().Trim().Replace("\n\t", " "); - throw new ExceptionWithConfigData(errorMessage, configData); - }); - - try - { - // Get RSS key - var rssParams = new Dictionary<string, string> - { - {"feedtype", "download"}, - {"timezone", "0"}, - {"showrows", "50"} - }; - var rssPage = await PostDataWithCookies(GetRSSKeyUrl, rssParams, result.Cookies); - var match = Regex.Match(rssPage.Content, "(?<=secret_key\\=)([a-zA-z0-9]*)"); - configData.RSSKey.Value = match.Success ? match.Value : string.Empty; - if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) - throw new Exception("Failed to get RSS Key"); - SaveConfig(); - } - catch - { - IsConfigured = false; - throw; - } - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var prevCook = CookieHeader + ""; - - // If we have no query use the RSS Page as their server is slow enough at times! - if (query.IsTest || string.IsNullOrWhiteSpace(searchString)) - { - - var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value)); - try - { - if (rssPage.Content.EndsWith("\0")) { - rssPage.Content = rssPage.Content.Substring(0, rssPage.Content.Length - 1); - } - rssPage.Content = RemoveInvalidXmlChars(rssPage.Content); - var rssDoc = XDocument.Parse(rssPage.Content); - - foreach (var item in rssDoc.Descendants("item")) - { - var title = item.Descendants("title").First().Value; - var description = item.Descendants("description").First().Value; - var link = item.Descendants("link").First().Value; - var category = item.Descendants("category").First().Value; - var date = item.Descendants("pubDate").First().Value; - - var torrentIdMatch = Regex.Match(link, "(?<=id=)(\\d)*"); - var torrentId = torrentIdMatch.Success ? torrentIdMatch.Value : string.Empty; - if (string.IsNullOrWhiteSpace(torrentId)) - throw new Exception("Missing torrent id"); - - var infoMatch = Regex.Match(description, @"Category:\W(?<cat>.*)\W\/\WSeeders:\W(?<seeders>[\d\,]*)\W\/\WLeechers:\W(?<leechers>[\d\,]*)\W\/\WSize:\W(?<size>[\d\.]*\W\S*)"); - if (!infoMatch.Success) - throw new Exception("Unable to find info"); - - var release = new ReleaseInfo - { - Title = title, - Description = title, - Guid = new Uri(string.Format(DownloadUrl, torrentId)), - Comments = new Uri(string.Format(CommentUrl, torrentId)), - PublishDate = DateTime.ParseExact(date, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 - Link = new Uri(string.Format(DownloadUrl, torrentId)), - Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value), - Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value), - Size = ReleaseInfo.GetBytes(infoMatch.Groups["size"].Value), - Category = MapTrackerCatToNewznab(category) - }; - - release.Peers += release.Seeders; - releases.Add(release); - } - } - catch (Exception ex) - { - logger.Error("XSpeeds: Error while parsing the RSS feed:"); - logger.Error(rssPage.Content); - throw ex; - } - - } - if (query.IsTest || !string.IsNullOrWhiteSpace(searchString)) - { - if (searchString.Length < 3 && !query.IsTest) - { - OnParseError("", new Exception("Minimum search length is 3")); - return releases; - } - var searchParams = new Dictionary<string, string> { - { "do", "search" }, - { "keywords", searchString }, - { "search_type", "t_name" }, - { "category", "0" }, - { "include_dead_torrents", "no" } - }; - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value } - }; - - var searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); - // Occasionally the cookies become invalid, login again if that happens - if (searchPage.IsRedirect) - { - await ApplyConfiguration(null); - searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); - } - - try - { - CQ dom = searchPage.Content; - var rows = dom["table#sortabletable > tbody > tr:has(div > a[href*=\"details.php?id=\"])"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - var qRow = row.Cq(); - - var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long - var qTitle = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip - if(!qTitle.Any()) // fallback to Details link if there's no tooltip - { - qTitle = qDetails; - } - release.Title = qTitle.Text(); - - release.Guid = new Uri(qRow.Find("td:eq(2) a").Attr("href")); - release.Link = release.Guid; - release.Comments = new Uri(qDetails.Attr("href")); - release.PublishDate = DateTime.ParseExact(qRow.Find("td:eq(1) div").Last().Text().Trim(), "dd-MM-yyyy H:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); //08-08-2015 12:51 - release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text()); - release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()); - release.Size = ReleaseInfo.GetBytes(qRow.Find("td:eq(4)").Text().Trim()); - - var qBanner = qRow.Find("td:eq(1) .tooltip-content img").First(); - if (qBanner.Length > 0) - release.BannerUrl = new Uri(qBanner.Attr("src")); - - var cat = row.Cq().Find("td:eq(0) a").First().Attr("href"); - var catSplit = cat.LastIndexOf('='); - if (catSplit > -1) - cat = cat.Substring(catSplit + 1); - release.Category = MapTrackerCatToNewznab(cat); - - var grabs = qRow.Find("td:nth-child(6)").Text(); - release.Grabs = ParseUtil.CoerceInt(grabs); - - if (qRow.Find("img[alt^=\"Free Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0; - else if (qRow.Find("img[alt^=\"Silver Torrent\"]").Length >= 1) - release.DownloadVolumeFactor = 0.5; - else - release.DownloadVolumeFactor = 1; - - if (qRow.Find("img[alt^=\"x2 Torrent\"]").Length >= 1) - release.UploadVolumeFactor = 2; - else - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(searchPage.Content, ex); - } - } - if (!CookieHeader.Trim().Equals(prevCook.Trim())) - { - SaveConfig(); - } - return releases; - } - } -} + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + var pairs = new Dictionary<string, string> + { + {"username", configData.Username.Value}, + {"password", configData.Password.Value} + }; + + var CaptchaText = (StringItem)configData.GetDynamic("CaptchaText"); + if (CaptchaText != null) + { + pairs.Add("imagestring", CaptchaText.Value); + } + + //var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, SiteLink, true); + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, SearchUrl, LandingUrl, true); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("logout.php"), + () => + { + CQ dom = result.Content; + var errorMessage = dom[".left_side table:eq(0) tr:eq(1)"].Text().Trim().Replace("\n\t", " "); + throw new ExceptionWithConfigData(errorMessage, configData); + }); + + try + { + // Get RSS key + var rssParams = new Dictionary<string, string> + { + {"feedtype", "download"}, + {"timezone", "0"}, + {"showrows", "50"} + }; + var rssPage = await PostDataWithCookies(GetRSSKeyUrl, rssParams, result.Cookies); + var match = Regex.Match(rssPage.Content, "(?<=secret_key\\=)([a-zA-z0-9]*)"); + configData.RSSKey.Value = match.Success ? match.Value : string.Empty; + if (string.IsNullOrWhiteSpace(configData.RSSKey.Value)) + throw new Exception("Failed to get RSS Key"); + SaveConfig(); + } + catch + { + IsConfigured = false; + throw; + } + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + var searchString = query.GetQueryString(); + var prevCook = CookieHeader + ""; + + // If we have no query use the RSS Page as their server is slow enough at times! + if (query.IsTest || string.IsNullOrWhiteSpace(searchString)) + { + + var rssPage = await RequestStringWithCookiesAndRetry(string.Format(RSSUrl, configData.RSSKey.Value)); + try + { + if (rssPage.Content.EndsWith("\0")) { + rssPage.Content = rssPage.Content.Substring(0, rssPage.Content.Length - 1); + } + rssPage.Content = RemoveInvalidXmlChars(rssPage.Content); + var rssDoc = XDocument.Parse(rssPage.Content); + + foreach (var item in rssDoc.Descendants("item")) + { + var title = item.Descendants("title").First().Value; + var description = item.Descendants("description").First().Value; + var link = item.Descendants("link").First().Value; + var category = item.Descendants("category").First().Value; + var date = item.Descendants("pubDate").First().Value; + + var torrentIdMatch = Regex.Match(link, "(?<=id=)(\\d)*"); + var torrentId = torrentIdMatch.Success ? torrentIdMatch.Value : string.Empty; + if (string.IsNullOrWhiteSpace(torrentId)) + throw new Exception("Missing torrent id"); + + var infoMatch = Regex.Match(description, @"Category:\W(?<cat>.*)\W\/\WSeeders:\W(?<seeders>[\d\,]*)\W\/\WLeechers:\W(?<leechers>[\d\,]*)\W\/\WSize:\W(?<size>[\d\.]*\W\S*)"); + if (!infoMatch.Success) + throw new Exception("Unable to find info"); + + var release = new ReleaseInfo + { + Title = title, + Description = title, + Guid = new Uri(string.Format(DownloadUrl, torrentId)), + Comments = new Uri(string.Format(CommentUrl, torrentId)), + PublishDate = DateTime.ParseExact(date, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture), //2015-08-08 21:20:31 + Link = new Uri(string.Format(DownloadUrl, torrentId)), + Seeders = ParseUtil.CoerceInt(infoMatch.Groups["seeders"].Value), + Peers = ParseUtil.CoerceInt(infoMatch.Groups["leechers"].Value), + Size = ReleaseInfo.GetBytes(infoMatch.Groups["size"].Value), + Category = MapTrackerCatToNewznab(category) + }; + + release.Peers += release.Seeders; + releases.Add(release); + } + } + catch (Exception ex) + { + logger.Error("XSpeeds: Error while parsing the RSS feed:"); + logger.Error(rssPage.Content); + throw ex; + } + + } + if (query.IsTest || !string.IsNullOrWhiteSpace(searchString)) + { + if (searchString.Length < 3 && !query.IsTest) + { + OnParseError("", new Exception("Minimum search length is 3")); + return releases; + } + var searchParams = new Dictionary<string, string> { + { "do", "search" }, + { "keywords", searchString }, + { "search_type", "t_name" }, + { "category", "0" }, + { "include_dead_torrents", "no" } + }; + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value } + }; + + var searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); + // Occasionally the cookies become invalid, login again if that happens + if (searchPage.IsRedirect) + { + await ApplyConfiguration(null); + searchPage = await PostDataWithCookiesAndRetry(SearchUrl, searchParams, CookieHeader); + } + + try + { + CQ dom = searchPage.Content; + var rows = dom["table#sortabletable > tbody > tr:has(div > a[href*=\"details.php?id=\"])"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + var qRow = row.Cq(); + + var qDetails = qRow.Find("div > a[href*=\"details.php?id=\"]"); // details link, release name get's shortened if it's to long + var qTitle = qRow.Find("td:eq(1) .tooltip-content div:eq(0)"); // use Title from tooltip + if(!qTitle.Any()) // fallback to Details link if there's no tooltip + { + qTitle = qDetails; + } + release.Title = qTitle.Text(); + + release.Guid = new Uri(qRow.Find("td:eq(2) a").Attr("href")); + release.Link = release.Guid; + release.Comments = new Uri(qDetails.Attr("href")); + release.PublishDate = DateTime.ParseExact(qRow.Find("td:eq(1) div").Last().Text().Trim(), "dd-MM-yyyy H:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); //08-08-2015 12:51 + release.Seeders = ParseUtil.CoerceInt(qRow.Find("td:eq(6)").Text()); + release.Peers = release.Seeders + ParseUtil.CoerceInt(qRow.Find("td:eq(7)").Text().Trim()); + release.Size = ReleaseInfo.GetBytes(qRow.Find("td:eq(4)").Text().Trim()); + + var qBanner = qRow.Find("td:eq(1) .tooltip-content img").First(); + if (qBanner.Length > 0) + release.BannerUrl = new Uri(qBanner.Attr("src")); + + var cat = row.Cq().Find("td:eq(0) a").First().Attr("href"); + var catSplit = cat.LastIndexOf('='); + if (catSplit > -1) + cat = cat.Substring(catSplit + 1); + release.Category = MapTrackerCatToNewznab(cat); + + var grabs = qRow.Find("td:nth-child(6)").Text(); + release.Grabs = ParseUtil.CoerceInt(grabs); + + if (qRow.Find("img[alt^=\"Free Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0; + else if (qRow.Find("img[alt^=\"Silver Torrent\"]").Length >= 1) + release.DownloadVolumeFactor = 0.5; + else + release.DownloadVolumeFactor = 1; + + if (qRow.Find("img[alt^=\"x2 Torrent\"]").Length >= 1) + release.UploadVolumeFactor = 2; + else + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(searchPage.Content, ex); + } + } + if (!CookieHeader.Trim().Equals(prevCook.Trim())) + { + SaveConfig(); + } + return releases; + } + } +} diff --git a/src/Jackett/Indexers/Xthor.cs b/src/Jackett/Indexers/Xthor.cs index ca124d84..f1d602e1 100644 --- a/src/Jackett/Indexers/Xthor.cs +++ b/src/Jackett/Indexers/Xthor.cs @@ -1,608 +1,608 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Text; -using System.Reflection; -using System.Threading.Tasks; -using System.Web; -using Jackett.Models; -using Jackett.Models.IndexerConfig.Bespoke; -using Jackett.Services; -using Jackett.Utils; -using Jackett.Utils.Clients; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NLog; - -namespace Jackett.Indexers -{ - /// <summary> - /// Provider for Xthor Private French Tracker - /// </summary> - 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<string, string> EmulatedBrowserHeaders { get; } = new Dictionary<string, string>(); - 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()) - { - Encoding = Encoding.UTF8; - Language = "fr-fr"; - Type = "private"; - - // 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 - - AddCategoryMapping(36, TorznabCatType.XXX); // XxX / Films - AddCategoryMapping(105, TorznabCatType.XXX); // XxX / Séries - AddCategoryMapping(114, TorznabCatType.XXX); // XxX / Lesbiennes - AddCategoryMapping(115, TorznabCatType.XXX); // XxX / Gays - AddCategoryMapping(113, TorznabCatType.XXX); // XxX / Hentai - } - - /// <summary> - /// Configure our Provider - /// </summary> - /// <param name="configJson">Our params in Json</param> - /// <returns>Configuration state</returns> - #pragma warning disable 1998 - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - #pragma warning restore 1998 - { - // Provider not yet configured - IsConfigured = false; - - // Retrieve config values set by Jackett's user - 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; - } - - /// <summary> - /// Execute our search query - /// </summary> - /// <param name="query">Query</param> - /// <returns>Releases</returns> - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - var releases = new List<ReleaseInfo>(); - 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<XthorResponse>(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, - Grabs = torrent.times_completed, - Files = torrent.numfiles, - UploadVolumeFactor = 1, - DownloadVolumeFactor = (torrent.freeleech == 1 ? 0 : 1), - 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; - } - - /// <summary> - /// Response from Tracker's API - /// </summary> - public class XthorResponse - { - public XthorError error { get; set; } - public XthorUser user { get; set; } - public List<XthorTorrent> torrents { get; set; } - } - - /// <summary> - /// State of API - /// </summary> - public class XthorError - { - public int code { get; set; } - public string descr { get; set; } - } - - /// <summary> - /// User Informations - /// </summary> - 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; } - } - - /// <summary> - /// Torrent Informations - /// </summary> - 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; } - } - - /// <summary> - /// Build query to process - /// </summary> - /// <param name="term">Term to search</param> - /// <param name="query">Torznab Query for categories mapping</param> - /// <param name="url">Search url for provider</param> - /// <returns>URL to query for parsing and processing results</returns> - 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; - } - - /// <summary> - /// Switch Method for Querying - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> 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; - } - - /// <summary> - /// Get Torrents Page from Cache by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> 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<WebClientStringResult>(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; - } - - /// <summary> - /// Get Torrents Page from Tracker by Query Provided - /// </summary> - /// <param name="request">URL created by Query Builder</param> - /// <returns>Results from query</returns> - private async Task<WebClientStringResult> 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, - Encoding = Encoding, - Headers = EmulatedBrowserHeaders - }; - - // Request our first page - var results = await webclient.GetString(myIndexRequest); - - // Return results from tracker - return results; - } - - /// <summary> - /// Check API's state - /// </summary> - /// <param name="state">State of API</param> - 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); - } - } - - /// <summary> - /// Clean Hard Drive Cache Storage - /// </summary> - /// <param name="force">Force Provider Folder deletion</param> - 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."); - } - } - } - - /// <summary> - /// Output message for logging or developpment (console) - /// </summary> - /// <param name="message">Message to output</param> - /// <param name="level">Level for Logger</param> - 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; - } - } - } - - /// <summary> - /// Validate Config entered by user on Jackett - /// </summary> - 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); - } - } - } +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Threading.Tasks; +using System.Web; +using Jackett.Models; +using Jackett.Models.IndexerConfig.Bespoke; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; + +namespace Jackett.Indexers +{ + /// <summary> + /// Provider for Xthor Private French Tracker + /// </summary> + 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<string, string> EmulatedBrowserHeaders { get; } = new Dictionary<string, string>(); + 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()) + { + Encoding = Encoding.UTF8; + Language = "fr-fr"; + Type = "private"; + + // 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 + + AddCategoryMapping(36, TorznabCatType.XXX); // XxX / Films + AddCategoryMapping(105, TorznabCatType.XXX); // XxX / Séries + AddCategoryMapping(114, TorznabCatType.XXX); // XxX / Lesbiennes + AddCategoryMapping(115, TorznabCatType.XXX); // XxX / Gays + AddCategoryMapping(113, TorznabCatType.XXX); // XxX / Hentai + } + + /// <summary> + /// Configure our Provider + /// </summary> + /// <param name="configJson">Our params in Json</param> + /// <returns>Configuration state</returns> + #pragma warning disable 1998 + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + #pragma warning restore 1998 + { + // Provider not yet configured + IsConfigured = false; + + // Retrieve config values set by Jackett's user + 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; + } + + /// <summary> + /// Execute our search query + /// </summary> + /// <param name="query">Query</param> + /// <returns>Releases</returns> + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + var releases = new List<ReleaseInfo>(); + 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<XthorResponse>(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, + Grabs = torrent.times_completed, + Files = torrent.numfiles, + UploadVolumeFactor = 1, + DownloadVolumeFactor = (torrent.freeleech == 1 ? 0 : 1), + 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; + } + + /// <summary> + /// Response from Tracker's API + /// </summary> + public class XthorResponse + { + public XthorError error { get; set; } + public XthorUser user { get; set; } + public List<XthorTorrent> torrents { get; set; } + } + + /// <summary> + /// State of API + /// </summary> + public class XthorError + { + public int code { get; set; } + public string descr { get; set; } + } + + /// <summary> + /// User Informations + /// </summary> + 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; } + } + + /// <summary> + /// Torrent Informations + /// </summary> + 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; } + } + + /// <summary> + /// Build query to process + /// </summary> + /// <param name="term">Term to search</param> + /// <param name="query">Torznab Query for categories mapping</param> + /// <param name="url">Search url for provider</param> + /// <returns>URL to query for parsing and processing results</returns> + 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; + } + + /// <summary> + /// Switch Method for Querying + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> 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; + } + + /// <summary> + /// Get Torrents Page from Cache by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> 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<WebClientStringResult>(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; + } + + /// <summary> + /// Get Torrents Page from Tracker by Query Provided + /// </summary> + /// <param name="request">URL created by Query Builder</param> + /// <returns>Results from query</returns> + private async Task<WebClientStringResult> 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, + Encoding = Encoding, + Headers = EmulatedBrowserHeaders + }; + + // Request our first page + var results = await webclient.GetString(myIndexRequest); + + // Return results from tracker + return results; + } + + /// <summary> + /// Check API's state + /// </summary> + /// <param name="state">State of API</param> + 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); + } + } + + /// <summary> + /// Clean Hard Drive Cache Storage + /// </summary> + /// <param name="force">Force Provider Folder deletion</param> + 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."); + } + } + } + + /// <summary> + /// Output message for logging or developpment (console) + /// </summary> + /// <param name="message">Message to output</param> + /// <param name="level">Level for Logger</param> + 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; + } + } + } + + /// <summary> + /// Validate Config entered by user on Jackett + /// </summary> + 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/Indexers/cgpeers.cs b/src/Jackett/Indexers/cgpeers.cs index 84615c4e..501fbe61 100644 --- a/src/Jackett/Indexers/cgpeers.cs +++ b/src/Jackett/Indexers/cgpeers.cs @@ -2,8 +2,8 @@ using NLog; using Jackett.Services; using Jackett.Utils.Clients; -using Jackett.Indexers.Abstract; - +using Jackett.Indexers.Abstract; + namespace Jackett.Indexers { public class CGPeers : GazelleTracker, IIndexer @@ -21,13 +21,13 @@ namespace Jackett.Indexers Language = "en-us"; Type = "private"; - AddCategoryMapping(1, TorznabCatType.PCISO, "Full Applications"); - AddCategoryMapping(2, TorznabCatType.PC0day, "Plugins"); - AddCategoryMapping(3, TorznabCatType.Other, "Tutorials"); - AddCategoryMapping(4, TorznabCatType.Other, "Models"); - AddCategoryMapping(5, TorznabCatType.Other, "Materials"); - AddCategoryMapping(6, TorznabCatType.OtherMisc, "Misc"); - AddCategoryMapping(7, TorznabCatType.Other, "GameDev"); + AddCategoryMapping(1, TorznabCatType.PCISO, "Full Applications"); + AddCategoryMapping(2, TorznabCatType.PC0day, "Plugins"); + AddCategoryMapping(3, TorznabCatType.Other, "Tutorials"); + AddCategoryMapping(4, TorznabCatType.Other, "Models"); + AddCategoryMapping(5, TorznabCatType.Other, "Materials"); + AddCategoryMapping(6, TorznabCatType.OtherMisc, "Misc"); + AddCategoryMapping(7, TorznabCatType.Other, "GameDev"); } } } \ No newline at end of file diff --git a/src/Jackett/Indexers/myAmity.cs b/src/Jackett/Indexers/myAmity.cs index 75823878..8bc14b18 100644 --- a/src/Jackett/Indexers/myAmity.cs +++ b/src/Jackett/Indexers/myAmity.cs @@ -10,9 +10,9 @@ using CsQuery; using System; using System.Globalization; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using System.Text; - +using System.Collections.Specialized; +using System.Text; + namespace Jackett.Indexers { public class myAmity : BaseIndexer, IIndexer @@ -41,23 +41,23 @@ namespace Jackett.Indexers Language = "de-de"; Type = "private"; - AddCategoryMapping(20, TorznabCatType.PC); // Apps - PC - AddCategoryMapping(24, TorznabCatType.AudioAudiobook); // Audio - Hoerbuch/-spiel - AddCategoryMapping(22, TorznabCatType.Audio); // Audio - Musik - AddCategoryMapping(52, TorznabCatType.Movies3D); // Filme - 3D - AddCategoryMapping(51, TorznabCatType.MoviesBluRay); // Filme - BluRay Complete - AddCategoryMapping(1, TorznabCatType.MoviesDVD); // Filme - DVD - AddCategoryMapping(54, TorznabCatType.MoviesHD); // Filme - HD/1080p - AddCategoryMapping(3, TorznabCatType.MoviesHD); // Filme - HD/720p - AddCategoryMapping(48, TorznabCatType.XXX); // Filme - Heimatfilme.XXX - AddCategoryMapping(50, TorznabCatType.Movies); // Filme - x264/H.264 - AddCategoryMapping(2, TorznabCatType.MoviesSD); // Filme - XViD - AddCategoryMapping(11, TorznabCatType.Console); // Games - Konsolen - AddCategoryMapping(10, TorznabCatType.PCGames); // Games - PC - AddCategoryMapping(53, TorznabCatType.Other); // International - Complete - AddCategoryMapping(36, TorznabCatType.Books); // Sonstige - E-Books - AddCategoryMapping(38, TorznabCatType.Other); // Sonstige - Handy - AddCategoryMapping(7, TorznabCatType.TVDocumentary); // TV/HDTV - Dokus + AddCategoryMapping(20, TorznabCatType.PC); // Apps - PC + AddCategoryMapping(24, TorznabCatType.AudioAudiobook); // Audio - Hoerbuch/-spiel + AddCategoryMapping(22, TorznabCatType.Audio); // Audio - Musik + AddCategoryMapping(52, TorznabCatType.Movies3D); // Filme - 3D + AddCategoryMapping(51, TorznabCatType.MoviesBluRay); // Filme - BluRay Complete + AddCategoryMapping(1, TorznabCatType.MoviesDVD); // Filme - DVD + AddCategoryMapping(54, TorznabCatType.MoviesHD); // Filme - HD/1080p + AddCategoryMapping(3, TorznabCatType.MoviesHD); // Filme - HD/720p + AddCategoryMapping(48, TorznabCatType.XXX); // Filme - Heimatfilme.XXX + AddCategoryMapping(50, TorznabCatType.Movies); // Filme - x264/H.264 + AddCategoryMapping(2, TorznabCatType.MoviesSD); // Filme - XViD + AddCategoryMapping(11, TorznabCatType.Console); // Games - Konsolen + AddCategoryMapping(10, TorznabCatType.PCGames); // Games - PC + AddCategoryMapping(53, TorznabCatType.Other); // International - Complete + AddCategoryMapping(36, TorznabCatType.Books); // Sonstige - E-Books + AddCategoryMapping(38, TorznabCatType.Other); // Sonstige - Handy + AddCategoryMapping(7, TorznabCatType.TVDocumentary); // TV/HDTV - Dokus AddCategoryMapping(8, TorznabCatType.TV); // TV/HDTV - Serien } @@ -71,53 +71,53 @@ namespace Jackett.Indexers { "password", configData.Password.Value } }; - var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); - - await ConfigureIfOK(result.Cookies, result.Content != null && result.Cookies.Contains("pass=") && !result.Cookies.Contains("deleted"), () => - { - CQ dom = result.Content; - var errorMessage = dom["div.myFrame-content"].Html(); - throw new ExceptionWithConfigData(errorMessage, configData); + var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, null, true, null, LoginUrl, true); + + await ConfigureIfOK(result.Cookies, result.Content != null && result.Cookies.Contains("pass=") && !result.Cookies.Contains("deleted"), () => + { + CQ dom = result.Content; + var errorMessage = dom["div.myFrame-content"].Html(); + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { - TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); - TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); - TimeSpan delta = new TimeSpan(1, 0, 0); - TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); - TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; + TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 3, 5, DayOfWeek.Sunday); + TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0), 10, 5, DayOfWeek.Sunday); + TimeSpan delta = new TimeSpan(1, 0, 0); + TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition); + TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment }; TimeZoneInfo germanyTz = TimeZoneInfo.CreateCustomTimeZone("W. Europe Standard Time", new TimeSpan(1, 0, 0), "(GMT+01:00) W. Europe Standard Time", "W. Europe Standard Time", "W. Europe DST Time", adjustments); var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - var searchUrl = BrowseUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("incldead", "1"); - queryCollection.Add("freeleech", "0"); - queryCollection.Add("inclexternal", "0"); - queryCollection.Add("lang", "0"); - - if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } + var searchString = query.GetQueryString(); + var searchUrl = BrowseUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("incldead", "1"); + queryCollection.Add("freeleech", "0"); + queryCollection.Add("inclexternal", "0"); + queryCollection.Add("lang", "0"); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } searchUrl += "?" + queryCollection.GetQueryString(); var response = await RequestStringWithCookies(searchUrl); - if (response.IsRedirect) - { - // re-login - await ApplyConfiguration(null); - response = await RequestStringWithCookies(searchUrl); + if (response.IsRedirect) + { + // re-login + await ApplyConfiguration(null); + response = await RequestStringWithCookies(searchUrl); } var results = response.Content; @@ -129,48 +129,48 @@ namespace Jackett.Indexers foreach (var row in rows) { var release = new ReleaseInfo(); - release.MinimumRatio = 1; + release.MinimumRatio = 1; release.MinimumSeedTime = 90 * 60; - var qRow = row.Cq(); - - var qDetailsLink = qRow.Find("a[href^=torrents-details.php?id=]").First(); - release.Title = qDetailsLink.Attr("title"); - - if (!query.MatchQueryStringAND(release.Title)) - continue; - - var qCatLink = qRow.Find("a[href^=torrents.php?cat=]").First(); - var qDLLink = qRow.Find("a[href^=download.php]").First(); - var qSeeders = qRow.Find("td:eq(6)"); - var qLeechers = qRow.Find("td:eq(7)"); - var qDateStr = qRow.Find("td:eq(9)").First(); - var qSize = qRow.Find("td:eq(4)").First(); - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDLLink.Attr("href")); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + var qRow = row.Cq(); + + var qDetailsLink = qRow.Find("a[href^=torrents-details.php?id=]").First(); + release.Title = qDetailsLink.Attr("title"); + + if (!query.MatchQueryStringAND(release.Title)) + continue; + + var qCatLink = qRow.Find("a[href^=torrents.php?cat=]").First(); + var qDLLink = qRow.Find("a[href^=download.php]").First(); + var qSeeders = qRow.Find("td:eq(6)"); + var qLeechers = qRow.Find("td:eq(7)"); + var qDateStr = qRow.Find("td:eq(9)").First(); + var qSize = qRow.Find("td:eq(4)").First(); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDLLink.Attr("href")); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; var dateStr = qDateStr.Text().Trim(); - DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); - - DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); + DateTime dateGerman = DateTime.SpecifyKind(DateTime.ParseExact(dateStr, "dd.MM.yy HH:mm:ss", CultureInfo.InvariantCulture), DateTimeKind.Unspecified); + + DateTime pubDateUtc = TimeZoneInfo.ConvertTimeToUtc(dateGerman, germanyTz); release.PublishDate = pubDateUtc.ToLocalTime(); var grabs = qRow.Find("td:nth-child(6)").Text(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (qRow.Find("img[src=\"images/free.gif\"]").Length >= 1) - release.DownloadVolumeFactor = 0; + if (qRow.Find("img[src=\"images/free.gif\"]").Length >= 1) + release.DownloadVolumeFactor = 0; else release.DownloadVolumeFactor = 1; diff --git a/src/Jackett/Indexers/notwhatcd.cs b/src/Jackett/Indexers/notwhatcd.cs index ba6e7e3f..cfec3298 100644 --- a/src/Jackett/Indexers/notwhatcd.cs +++ b/src/Jackett/Indexers/notwhatcd.cs @@ -2,8 +2,8 @@ using NLog; using Jackett.Services; using Jackett.Utils.Clients; -using Jackett.Indexers.Abstract; - +using Jackett.Indexers.Abstract; + namespace Jackett.Indexers { public class notwhatcd : GazelleTracker, IIndexer @@ -22,12 +22,12 @@ namespace Jackett.Indexers Type = "private"; AddCategoryMapping(1, TorznabCatType.Audio, "Music"); - AddCategoryMapping(2, TorznabCatType.PC, "Applications"); - AddCategoryMapping(3, TorznabCatType.Books, "E-Books"); - AddCategoryMapping(4, TorznabCatType.AudioAudiobook, "Audiobooks"); - AddCategoryMapping(5, TorznabCatType.Movies, "E-Learning Videos"); - AddCategoryMapping(6, TorznabCatType.TV, "Comedy"); - AddCategoryMapping(7, TorznabCatType.Books, "Comics"); + AddCategoryMapping(2, TorznabCatType.PC, "Applications"); + AddCategoryMapping(3, TorznabCatType.Books, "E-Books"); + AddCategoryMapping(4, TorznabCatType.AudioAudiobook, "Audiobooks"); + AddCategoryMapping(5, TorznabCatType.Movies, "E-Learning Videos"); + AddCategoryMapping(6, TorznabCatType.TV, "Comedy"); + AddCategoryMapping(7, TorznabCatType.Books, "Comics"); } } } \ No newline at end of file diff --git a/src/Jackett/Indexers/rutracker.cs b/src/Jackett/Indexers/rutracker.cs index 1a6f0fa6..79b4c731 100644 --- a/src/Jackett/Indexers/rutracker.cs +++ b/src/Jackett/Indexers/rutracker.cs @@ -9,9 +9,9 @@ using System.Collections.Generic; using System; using System.Text; using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; -using AngleSharp.Parser.Html; - +using System.Collections.Specialized; +using AngleSharp.Parser.Html; + namespace Jackett.Indexers { public class RuTracker : BaseIndexer, IIndexer @@ -38,1422 +38,1422 @@ namespace Jackett.Indexers logger: l, p: ps, configData: new ConfigurationDataCaptchaLogin()) - { + { Encoding = Encoding.GetEncoding("windows-1251"); - Language = "ru-ru"; - Type = "semi-private"; - - // Новости - AddCategoryMapping(2317, TorznabCatType.Other, "NEW YEAR'S SECTION"); - AddCategoryMapping(1241, TorznabCatType.Other, " | - New competitions"); - AddCategoryMapping(2338, TorznabCatType.TV, " | - Entertainment shows and Documentaries"); - AddCategoryMapping(1464, TorznabCatType.Movies, " | - Movies and Cartoons"); - AddCategoryMapping(860, TorznabCatType.Books, " | - Books, Journals, Notes"); - AddCategoryMapping(1340, TorznabCatType.Audio, " | - Music"); - AddCategoryMapping(1346, TorznabCatType.AudioVideo, " | - Music video"); - AddCategoryMapping(1239, TorznabCatType.Console, " | - Games"); - AddCategoryMapping(1299, TorznabCatType.Other, " | - Miscellaneous (postcards, wallpapers, video, etc.)."); - AddCategoryMapping(1289, TorznabCatType.Other, "Rutracker Awards (events and competitions)"); - AddCategoryMapping(1579, TorznabCatType.Other, "| - Photo club. The whole world is in the palm of your hand."); - AddCategoryMapping(2214, TorznabCatType.Other, " | - Rutracker Awards (distribution)"); - - // Кино, Видео и ТВ - AddCategoryMapping(7, TorznabCatType.MoviesForeign, "Foreign movies"); - AddCategoryMapping(187, TorznabCatType.MoviesForeign, " | - Classic of world cinema"); - AddCategoryMapping(2090, TorznabCatType.MoviesForeign, " | - Movies before 1990"); - AddCategoryMapping(2221, TorznabCatType.MoviesForeign, " | - Movies 1991-2000"); - AddCategoryMapping(2091, TorznabCatType.MoviesForeign, " | - Movies 2001-2005"); - AddCategoryMapping(2092, TorznabCatType.MoviesForeign, " | - Movies 2006-2010"); - AddCategoryMapping(2093, TorznabCatType.MoviesForeign, " | - Movies 2011-2015"); - AddCategoryMapping(2200, TorznabCatType.MoviesForeign, " | - Movies 2016"); - AddCategoryMapping(934, TorznabCatType.MoviesForeign, " | - Asian movies"); - AddCategoryMapping(505, TorznabCatType.MoviesForeign, " | - Indian Cinema"); - AddCategoryMapping(212, TorznabCatType.MoviesForeign, " | - Movie Collections"); - AddCategoryMapping(2459, TorznabCatType.MoviesForeign, " | - Shorts"); - AddCategoryMapping(1235, TorznabCatType.MoviesForeign, " | - Grindhouse"); - AddCategoryMapping(185, TorznabCatType.MoviesForeign, " | - Soundtracks and Translations"); - AddCategoryMapping(22, TorznabCatType.Movies, "our film"); - AddCategoryMapping(941, TorznabCatType.Movies, " | - Cinema of the USSR"); - AddCategoryMapping(1666, TorznabCatType.Movies, " | - Children's domestic films"); - AddCategoryMapping(376, TorznabCatType.Movies, " | - Author Debuts"); - AddCategoryMapping(124, TorznabCatType.Movies, "Art-house cinema and author"); - AddCategoryMapping(1543, TorznabCatType.Movies, " | - Shorts (Art-house cinema and author)"); - AddCategoryMapping(709, TorznabCatType.Movies, " | - Documentaries (Art-house cinema and author)"); - AddCategoryMapping(1577, TorznabCatType.Movies, " | - Animation (Art-house cinema and author)"); - AddCategoryMapping(511, TorznabCatType.Movies, "Theater"); - AddCategoryMapping(656, TorznabCatType.Movies, "| - Benefit. Master of Arts domestic theater and cinema"); - AddCategoryMapping(93, TorznabCatType.Movies, "DVD Video"); - AddCategoryMapping(905, TorznabCatType.Movies, " | - Classic of world cinema (DVD Video)"); - AddCategoryMapping(1576, TorznabCatType.Movies, " | - Asian movies (DVD Video)"); - AddCategoryMapping(101, TorznabCatType.Movies, " | - Foreign movies (DVD)"); - AddCategoryMapping(100, TorznabCatType.Movies, " | - Our cinema (DVD)"); - AddCategoryMapping(572, TorznabCatType.Movies, " | - Art-house and auteur cinema (DVD)"); - AddCategoryMapping(2220, TorznabCatType.Movies, " | - Indian Cinema DVD and HD Video"); - AddCategoryMapping(1670, TorznabCatType.Movies, " |- Грайндхаус DVD и HD Video"); - AddCategoryMapping(2198, TorznabCatType.MoviesHD, "HD Video"); - AddCategoryMapping(2199, TorznabCatType.MoviesHD, " | - Classic of world cinema (HD Video)"); - AddCategoryMapping(313, TorznabCatType.MoviesHD, " | - Foreign movies (HD Video)"); - AddCategoryMapping(2201, TorznabCatType.MoviesHD, " | - Asian movies (HD Video)"); - AddCategoryMapping(312, TorznabCatType.MoviesHD, " | - Our cinema (HD Video)"); - AddCategoryMapping(2339, TorznabCatType.MoviesHD, " | - Art-house and auteur cinema (HD Video)"); - AddCategoryMapping(352, TorznabCatType.Movies3D, "3D / Stereo Film, Video, TV & Sports"); - AddCategoryMapping(549, TorznabCatType.Movies3D, " | - 3D Movies"); - AddCategoryMapping(1213, TorznabCatType.Movies3D, " | - 3D Animation"); - AddCategoryMapping(2109, TorznabCatType.Movies3D, " | - 3D Documentary"); - AddCategoryMapping(514, TorznabCatType.Movies3D, " | - 3D Спорт"); - AddCategoryMapping(2097, TorznabCatType.Movies3D, " | - 3D Clips, Music Videos, Movie Trailers"); - AddCategoryMapping(4, TorznabCatType.Movies, "Cartoons"); - AddCategoryMapping(2343, TorznabCatType.Movies, " | - Animation (Announcements HD Video)"); - AddCategoryMapping(930, TorznabCatType.Movies, " | - Animation (HD Video)"); - AddCategoryMapping(2365, TorznabCatType.Movies, " | - Short Film (HD Video)"); - AddCategoryMapping(1900, TorznabCatType.Movies, " | - Domestic cartoons (DVD)"); - AddCategoryMapping(521, TorznabCatType.Movies, " | - Foreign cartoons (DVD)"); - AddCategoryMapping(2258, TorznabCatType.Movies, " | - Foreign Short Film (DVD)"); - AddCategoryMapping(208, TorznabCatType.Movies, " | - Domestic cartoons"); - AddCategoryMapping(539, TorznabCatType.Movies, " | - Domestic full-length cartoons"); - AddCategoryMapping(209, TorznabCatType.Movies, " | - Foreign cartoons"); - AddCategoryMapping(484, TorznabCatType.Movies, " | - Foreign short cartoons"); - AddCategoryMapping(822, TorznabCatType.Movies, " | - Cartoon Collection"); - AddCategoryMapping(921, TorznabCatType.TV, "Serial cartoons"); - AddCategoryMapping(922, TorznabCatType.TV, " | - Avatar"); - AddCategoryMapping(1247, TorznabCatType.TV, " | - Griffiny / Family guy"); - AddCategoryMapping(923, TorznabCatType.TV, " | - SpongeBob SquarePants"); - AddCategoryMapping(924, TorznabCatType.TV, " | - The Simpsons"); - AddCategoryMapping(1991, TorznabCatType.TV, " | - Skubi-du / Scooby-Doo"); - AddCategoryMapping(925, TorznabCatType.TV, " | - Tom and Jerry"); - AddCategoryMapping(1165, TorznabCatType.TV, " | - Transformers"); - AddCategoryMapping(1245, TorznabCatType.TV, " | - DuckTales / DuckTales"); - AddCategoryMapping(928, TorznabCatType.TV, " | - Futurama / Futurama"); - AddCategoryMapping(926, TorznabCatType.TV, " | - Spider-Man / The Spectacular Spider-Man"); - AddCategoryMapping(1246, TorznabCatType.TV, " | - Turtles Mutant Ninja / Teenage Mutant Ninja Turtles"); - AddCategoryMapping(1250, TorznabCatType.TV, " |- Чип и Дейл / Chip And Dale"); - AddCategoryMapping(927, TorznabCatType.TV, " | - South Park / South Park"); - AddCategoryMapping(1248, TorznabCatType.TV, " | - For sub-standard hands"); - AddCategoryMapping(33, TorznabCatType.TVAnime, "Anime"); - AddCategoryMapping(281, TorznabCatType.TVAnime, " | - Manga"); - AddCategoryMapping(1386, TorznabCatType.TVAnime, " | - Wallpapers, artbook, and others."); - AddCategoryMapping(1387, TorznabCatType.TVAnime, " | -. AMV and other rollers"); - AddCategoryMapping(1388, TorznabCatType.TVAnime, " |- OST (lossless)"); - AddCategoryMapping(282, TorznabCatType.TVAnime, " | - OST (mp3 and others lossy-format)"); - AddCategoryMapping(599, TorznabCatType.TVAnime, " | - Anime (DVD)"); - AddCategoryMapping(1105, TorznabCatType.TVAnime, " |- Аниме (HD Video)"); - AddCategoryMapping(1389, TorznabCatType.TVAnime, " | - Anime (main subsection)"); - AddCategoryMapping(1391, TorznabCatType.TVAnime, " | - Anime (pleerny subsection)"); - AddCategoryMapping(2491, TorznabCatType.TVAnime, " | - Anime (QC subsection)"); - AddCategoryMapping(404, TorznabCatType.TVAnime, " | - Pokemony"); - AddCategoryMapping(1390, TorznabCatType.TVAnime, " | - Naruto"); - AddCategoryMapping(1642, TorznabCatType.TVAnime, " | - Trade"); - AddCategoryMapping(893, TorznabCatType.TVAnime, " | - Japanese cartoons"); - AddCategoryMapping(1478, TorznabCatType.TVAnime, " | - For sub-standard hands"); - - // Документалистика и юмор - AddCategoryMapping(670, TorznabCatType.TVDocumentary, "Faith and Religion"); - AddCategoryMapping(1475, TorznabCatType.TVDocumentary, " | - Christianity"); - AddCategoryMapping(2107, TorznabCatType.TVDocumentary, " | - Islam"); - AddCategoryMapping(294, TorznabCatType.TVDocumentary, " | - Religions of India, Tibet and East Asia"); - AddCategoryMapping(1453, TorznabCatType.TVDocumentary, " | - Cults and new religious movements"); - AddCategoryMapping(46, TorznabCatType.TVDocumentary, "Documentary movies and TV shows"); - AddCategoryMapping(103, TorznabCatType.TVDocumentary, " | - Documentary (DVD)"); - AddCategoryMapping(671, TorznabCatType.TVDocumentary, "| - Biographies. Personality and idols"); - AddCategoryMapping(2177, TorznabCatType.TVDocumentary, " | - Cinema and animation"); - AddCategoryMapping(2538, TorznabCatType.TVDocumentary, " | - Art, Art History"); - AddCategoryMapping(2159, TorznabCatType.TVDocumentary, " | - Music"); - AddCategoryMapping(251, TorznabCatType.TVDocumentary, " | - Kriminalynaya documentary"); - AddCategoryMapping(98, TorznabCatType.TVDocumentary, " | - Secrets of the Ages / Special Services / Conspiracy Theory"); - AddCategoryMapping(97, TorznabCatType.TVDocumentary, " | - Military"); - AddCategoryMapping(851, TorznabCatType.TVDocumentary, " | - World War II"); - AddCategoryMapping(2178, TorznabCatType.TVDocumentary, " | - Accidents / Accidents / Disasters"); - AddCategoryMapping(821, TorznabCatType.TVDocumentary, " | - Aviation"); - AddCategoryMapping(2076, TorznabCatType.TVDocumentary, " | - Space"); - AddCategoryMapping(56, TorznabCatType.TVDocumentary, " | - Scientific-popular movies"); - AddCategoryMapping(2123, TorznabCatType.TVDocumentary, " | - Flora and fauna"); - AddCategoryMapping(876, TorznabCatType.TVDocumentary, " | - Travel and Tourism"); - AddCategoryMapping(2380, TorznabCatType.TVDocumentary, " | - Social talk show"); - AddCategoryMapping(1467, TorznabCatType.TVDocumentary, " | - Information-analytical and socio-political etc. .."); - AddCategoryMapping(1469, TorznabCatType.TVDocumentary, " | - Architecture and Construction"); - AddCategoryMapping(672, TorznabCatType.TVDocumentary, " | - All about home, life and design"); - AddCategoryMapping(249, TorznabCatType.TVDocumentary, " |- BBC"); - AddCategoryMapping(552, TorznabCatType.TVDocumentary, " |- Discovery"); - AddCategoryMapping(500, TorznabCatType.TVDocumentary, " |- National Geographic"); - AddCategoryMapping(2112, TorznabCatType.TVDocumentary, " | - History: Ancient World / Antiquity / Middle Ages"); - AddCategoryMapping(1327, TorznabCatType.TVDocumentary, " | - History: modern and contemporary times"); - AddCategoryMapping(1468, TorznabCatType.TVDocumentary, " | - The Age of the USSR"); - AddCategoryMapping(1280, TorznabCatType.TVDocumentary, " | - The Battle of psychics / Theory improbability / Seekers / G .."); - AddCategoryMapping(752, TorznabCatType.TVDocumentary, " | - Russian sensation / Program Maximum / Profession report .."); - AddCategoryMapping(1114, TorznabCatType.TVDocumentary, " | - Paranormal"); - AddCategoryMapping(2168, TorznabCatType.TVDocumentary, " | - Alternative history and science"); - AddCategoryMapping(2160, TorznabCatType.TVDocumentary, " | - Vnezhanrovaya documentary"); - AddCategoryMapping(2176, TorznabCatType.TVDocumentary, " | - Other / nekonditsiya"); - AddCategoryMapping(314, TorznabCatType.TVDocumentary, "Documentary (HD Video)"); - AddCategoryMapping(2323, TorznabCatType.TVDocumentary, " | - Information-analytical and socio-political etc. .."); - AddCategoryMapping(1278, TorznabCatType.TVDocumentary, "| - Biographies. Personality and idols (HD Video)"); - AddCategoryMapping(1281, TorznabCatType.TVDocumentary, " | - Military Science (HD Video)"); - AddCategoryMapping(2110, TorznabCatType.TVDocumentary, " | - Natural History, Science and Technology (HD Video)"); - AddCategoryMapping(979, TorznabCatType.TVDocumentary, " | - Travel and Tourism (HD Video)"); - AddCategoryMapping(2169, TorznabCatType.TVDocumentary, " |- Флора и фауна (HD Video)"); - AddCategoryMapping(2166, TorznabCatType.TVDocumentary, " | - History (HD Video)"); - AddCategoryMapping(2164, TorznabCatType.TVDocumentary, " |- BBC, Discovery, National Geographic (HD Video)"); - AddCategoryMapping(2163, TorznabCatType.TVDocumentary, " | - Kriminalynaya documentary (HD Video)"); - AddCategoryMapping(24, TorznabCatType.TV, "Entertaining TV programs and shows, fun and humor"); - AddCategoryMapping(1959, TorznabCatType.TV, " | - Mind games and quizzes"); - AddCategoryMapping(939, TorznabCatType.TV, " | - Reality and talk show host / category / impressions"); - AddCategoryMapping(1481, TorznabCatType.TV, " | - Children's TV Show"); - AddCategoryMapping(113, TorznabCatType.TV, " | - KVN"); - AddCategoryMapping(115, TorznabCatType.TV, " | - Post KVN"); - AddCategoryMapping(882, TorznabCatType.TV, " | - Distorting Mirror / town / in the town"); - AddCategoryMapping(1482, TorznabCatType.TV, " | - Ice show"); - AddCategoryMapping(393, TorznabCatType.TV, " | - Musical Show"); - AddCategoryMapping(1569, TorznabCatType.TV, " | - Dinner Party"); - AddCategoryMapping(373, TorznabCatType.TV, " | - Good Jokes"); - AddCategoryMapping(1186, TorznabCatType.TV, " | - Evening Quarter"); - AddCategoryMapping(137, TorznabCatType.TV, " | - Movies with a funny transfer (parody)"); - AddCategoryMapping(2537, TorznabCatType.TV, " |- Stand-up comedy"); - AddCategoryMapping(532, TorznabCatType.TV, " | - Ukrainian Shows"); - AddCategoryMapping(827, TorznabCatType.TV, " | - Dance shows, concerts, performances"); - AddCategoryMapping(1484, TorznabCatType.TV, " | - The Circus"); - AddCategoryMapping(1485, TorznabCatType.TV, " | - The School for Scandal"); - AddCategoryMapping(114, TorznabCatType.TV, " | - Satirist, and humorists"); - AddCategoryMapping(1332, TorznabCatType.TV, " | - Humorous Audio Transmissions"); - AddCategoryMapping(1495, TorznabCatType.TV, " | - Audio and video clips (Jokes and humor)"); - - // Спорт - AddCategoryMapping(255, TorznabCatType.TVSport, "Sports tournaments, films and programs"); - AddCategoryMapping(256, TorznabCatType.TVSport, " | - Motorsports"); - AddCategoryMapping(1986, TorznabCatType.TVSport, " | - Motorsports"); - AddCategoryMapping(660, TorznabCatType.TVSport, " | - Formula-1 2016"); - AddCategoryMapping(1551, TorznabCatType.TVSport, " | - Formula-1 2012-2015"); - AddCategoryMapping(626, TorznabCatType.TVSport, " | - Formula 1"); - AddCategoryMapping(262, TorznabCatType.TVSport, " | - Cycling"); - AddCategoryMapping(1326, TorznabCatType.TVSport, " | - Volleyball / Handball"); - AddCategoryMapping(978, TorznabCatType.TVSport, " | - Billiards"); - AddCategoryMapping(1287, TorznabCatType.TVSport, " | - Poker"); - AddCategoryMapping(1188, TorznabCatType.TVSport, " | - Bodybuilding / Power Sports"); - AddCategoryMapping(1667, TorznabCatType.TVSport, " | - Boxing"); - AddCategoryMapping(1675, TorznabCatType.TVSport, " | - Classical arts"); - AddCategoryMapping(257, TorznabCatType.TVSport, " | - MMA and K-1"); - AddCategoryMapping(875, TorznabCatType.TVSport, " | - College Football"); - AddCategoryMapping(263, TorznabCatType.TVSport, " | - Rugby"); - AddCategoryMapping(2073, TorznabCatType.TVSport, " | - Baseball"); - AddCategoryMapping(550, TorznabCatType.TVSport, " | - Tennis"); - AddCategoryMapping(2124, TorznabCatType.TVSport, " | - Badminton / Table Tennis"); - AddCategoryMapping(1470, TorznabCatType.TVSport, " | - Gymnastics / Dance Competitions"); - AddCategoryMapping(528, TorznabCatType.TVSport, " | - Athletics / Water Sports"); - AddCategoryMapping(486, TorznabCatType.TVSport, " | - Winter Sports"); - AddCategoryMapping(854, TorznabCatType.TVSport, " | - Figure skating"); - AddCategoryMapping(2079, TorznabCatType.TVSport, " | - Biathlon"); - AddCategoryMapping(260, TorznabCatType.TVSport, " | - Extreme"); - AddCategoryMapping(1319, TorznabCatType.TVSport, " | - Sports (video)"); - AddCategoryMapping(1608, TorznabCatType.TVSport, "football"); - AddCategoryMapping(1952, TorznabCatType.TVSport, " | - Russia 2016-2017"); - AddCategoryMapping(2075, TorznabCatType.TVSport, " | - Russia 2015-2016"); - AddCategoryMapping(1613, TorznabCatType.TVSport, " | - Russia / USSR"); - AddCategoryMapping(1614, TorznabCatType.TVSport, " | - England"); - AddCategoryMapping(1623, TorznabCatType.TVSport, " | - Spain"); - AddCategoryMapping(1615, TorznabCatType.TVSport, " | - Italy"); - AddCategoryMapping(1630, TorznabCatType.TVSport, " | - Germany"); - AddCategoryMapping(2425, TorznabCatType.TVSport, " | - France"); - AddCategoryMapping(2514, TorznabCatType.TVSport, " | - Ukraine"); - AddCategoryMapping(1616, TorznabCatType.TVSport, " | - Other national championships and cups"); - AddCategoryMapping(2014, TorznabCatType.TVSport, " | - International Events"); - AddCategoryMapping(2171, TorznabCatType.TVSport, " | - European Cups 2016-2017"); - AddCategoryMapping(1491, TorznabCatType.TVSport, " | - European Cups 2015-2016"); - AddCategoryMapping(1987, TorznabCatType.TVSport, " | - European Cups 2011-2015"); - AddCategoryMapping(1617, TorznabCatType.TVSport, " | - European Cups"); - AddCategoryMapping(1610, TorznabCatType.TVSport, " | - European Football Championship 2016"); - AddCategoryMapping(1620, TorznabCatType.TVSport, " | - European Championships"); - AddCategoryMapping(1668, TorznabCatType.TVSport, " | - World Cup 2018"); - AddCategoryMapping(1621, TorznabCatType.TVSport, " | - World Championships"); - AddCategoryMapping(1998, TorznabCatType.TVSport, " | - Friendly tournaments and matches"); - AddCategoryMapping(1343, TorznabCatType.TVSport, " | - The survey and analytical programs 2014-2017"); - AddCategoryMapping(751, TorznabCatType.TVSport, " | - The survey and analytical programs"); - AddCategoryMapping(1697, TorznabCatType.TVSport, " | - Mini football / Football"); - AddCategoryMapping(2004, TorznabCatType.TVSport, "basketball"); - AddCategoryMapping(2001, TorznabCatType.TVSport, " | - International Competitions"); - AddCategoryMapping(2002, TorznabCatType.TVSport, " |- NBA / NCAA (до 2000 г.)"); - AddCategoryMapping(283, TorznabCatType.TVSport, " | - NBA / NCAA (2000-2010 biennium)."); - AddCategoryMapping(1997, TorznabCatType.TVSport, " | - NBA / NCAA (2010-2017 biennium)."); - AddCategoryMapping(2003, TorznabCatType.TVSport, " | - European club basketball"); - AddCategoryMapping(2009, TorznabCatType.TVSport, "Hockey"); - AddCategoryMapping(2010, TorznabCatType.TVSport, " | - Hockey / Bandy"); - AddCategoryMapping(2006, TorznabCatType.TVSport, " | - International Events"); - AddCategoryMapping(2007, TorznabCatType.TVSport, " | - KHL"); - AddCategoryMapping(2005, TorznabCatType.TVSport, " | - NHL (until 2011/12)"); - AddCategoryMapping(259, TorznabCatType.TVSport, " | - NHL (2013)"); - AddCategoryMapping(2008, TorznabCatType.TVSport, " | - USSR - Canada"); - AddCategoryMapping(126, TorznabCatType.TVSport, " | - Documentaries and Analysis"); - AddCategoryMapping(845, TorznabCatType.TVSport, "Wrestling"); - AddCategoryMapping(343, TorznabCatType.TVSport, " |- Professional Wrestling"); - AddCategoryMapping(2111, TorznabCatType.TVSport, " |- Independent Wrestling"); - AddCategoryMapping(1527, TorznabCatType.TVSport, " |- International Wrestling"); - AddCategoryMapping(2069, TorznabCatType.TVSport, " |- Oldschool Wrestling"); - AddCategoryMapping(1323, TorznabCatType.TVSport, " |- Documentary Wrestling"); - - // Сериалы - AddCategoryMapping(9, TorznabCatType.TV, "Russion serials"); - AddCategoryMapping(104, TorznabCatType.TV, " | - Secrets of the investigation"); - AddCategoryMapping(1408, TorznabCatType.TV, " | - National Security Agent"); - AddCategoryMapping(1535, TorznabCatType.TV, " | - Lawyer"); - AddCategoryMapping(91, TorznabCatType.TV, " | - Gangster Petersburg"); - AddCategoryMapping(1356, TorznabCatType.TV, " | - Return of Mukhtar"); - AddCategoryMapping(990, TorznabCatType.TV, " | - Hounds"); - AddCategoryMapping(856, TorznabCatType.TV, " | - Capercaillie / Pyatnitskii / Karpov"); - AddCategoryMapping(188, TorznabCatType.TV, " | - Darya Dontsova"); - AddCategoryMapping(310, TorznabCatType.TV, " | - Kadetstvo / Kremlëvskie kursanty"); - AddCategoryMapping(202, TorznabCatType.TV, " | - Kamenskaya"); - AddCategoryMapping(935, TorznabCatType.TV, " | - Code of Honor"); - AddCategoryMapping(172, TorznabCatType.TV, " | - A cop-in-law"); - AddCategoryMapping(805, TorznabCatType.TV, " | - Cop War"); - AddCategoryMapping(80, TorznabCatType.TV, " | - My Fair Nanny"); - AddCategoryMapping(119, TorznabCatType.TV, " | - Careful, Modern!"); - AddCategoryMapping(812, TorznabCatType.TV, " | - Web"); - AddCategoryMapping(175, TorznabCatType.TV, " | - After"); - AddCategoryMapping(79, TorznabCatType.TV, " | - Soldiers and others."); - AddCategoryMapping(123, TorznabCatType.TV, " | - Stopping Power / Cops / Opera"); - AddCategoryMapping(189, TorznabCatType.TV, "Foreign TV series"); - AddCategoryMapping(842, TorznabCatType.TV, " | - News and TV shows in the display stage"); - AddCategoryMapping(235, TorznabCatType.TV, " | - TV Shows US and Canada"); - AddCategoryMapping(242, TorznabCatType.TV, " | - TV Shows UK and Ireland"); - AddCategoryMapping(819, TorznabCatType.TV, " | - Scandinavian series"); - AddCategoryMapping(1531, TorznabCatType.TV, " | - Spanish series"); - AddCategoryMapping(721, TorznabCatType.TV, " | - Italian series"); - AddCategoryMapping(1102, TorznabCatType.TV, " | - European series"); - AddCategoryMapping(1120, TorznabCatType.TV, " | - TV Shows in Africa, Middle East"); - AddCategoryMapping(1214, TorznabCatType.TV, " | - TV Shows Australia and New Zealand"); - AddCategoryMapping(387, TorznabCatType.TV, " | - Serials joint production of several countries"); - AddCategoryMapping(1359, TorznabCatType.TV, " | - Web series, webisodes and TV series for the pilot episode .."); - AddCategoryMapping(271, TorznabCatType.TV, " | - 24 hours / 24"); - AddCategoryMapping(273, TorznabCatType.TV, " |- Альф / ALF"); - AddCategoryMapping(743, TorznabCatType.TV, " | - Grey's Anatomy / Grey's Anatomy + Private Practice / Priv .."); - AddCategoryMapping(184, TorznabCatType.TV, " | - Buffy - the Vampire Slayer / Buffy + Angel / Angel"); - AddCategoryMapping(194, TorznabCatType.TV, " | - Bludlivaya California / Californication"); - AddCategoryMapping(85, TorznabCatType.TV, " |- Вавилон 5 / Babylon 5"); - AddCategoryMapping(1171, TorznabCatType.TV, " |- Викинги / Vikings"); - AddCategoryMapping(1417, TorznabCatType.TV, " | - Breaking Bad / Breaking Bad"); - AddCategoryMapping(1144, TorznabCatType.TV, " | - The Return of Sherlock Holmes / Return of Sherlock Holmes"); - AddCategoryMapping(595, TorznabCatType.TV, " |- Герои / Heroes"); - AddCategoryMapping(1288, TorznabCatType.TV, " | - Dexter / Dexter"); - AddCategoryMapping(1605, TorznabCatType.TV, " | - Two and a Half Men / Two and a Half Men"); - AddCategoryMapping(1694, TorznabCatType.TV, " |- Династия / Dynasty"); - AddCategoryMapping(1690, TorznabCatType.TV, " | - The Vampire Diaries / The Vampire Diaries + True Blood .."); - AddCategoryMapping(820, TorznabCatType.TV, " |- Доктор Кто / Doctor Who + Торчвуд / Torchwood"); - AddCategoryMapping(625, TorznabCatType.TV, " |- Доктор Хаус / House M.D."); - AddCategoryMapping(84, TorznabCatType.TV, " | - Druzyya / Friends + Joey / Joey"); - AddCategoryMapping(623, TorznabCatType.TV, " | - Fringe / Fringe"); - AddCategoryMapping(1798, TorznabCatType.TV, "| - Stargate: Atlantis; Universe / Stargate: Atlanti .."); - AddCategoryMapping(106, TorznabCatType.TV, " | - Stargate: SG-1 / Stargate: SG1"); - AddCategoryMapping(166, TorznabCatType.TV, " | - Battlestar Galactica / Battlestar Galactica + Copper .."); - AddCategoryMapping(236, TorznabCatType.TV, " | - Star Trek / Star Trek"); - AddCategoryMapping(1449, TorznabCatType.TV, " |- Игра престолов / Game of Thrones"); - AddCategoryMapping(507, TorznabCatType.TV, " | - How I Met Your Mother The Big Bang Theory +"); - AddCategoryMapping(504, TorznabCatType.TV, " |- Клан Сопрано / The Sopranos"); - AddCategoryMapping(536, TorznabCatType.TV, " |- Клиника / Scrubs"); - AddCategoryMapping(173, TorznabCatType.TV, " | - Коломбо / Columbo"); - AddCategoryMapping(918, TorznabCatType.TV, " | - Inspector Rex / Komissar Rex"); - AddCategoryMapping(920, TorznabCatType.TV, " | - Bones / Bones"); - AddCategoryMapping(203, TorznabCatType.TV, " | - Weeds / Weeds"); - AddCategoryMapping(1243, TorznabCatType.TV, "| - Cool Walker. Justice in Texas / Walker, Texas Ran .."); - AddCategoryMapping(140, TorznabCatType.TV, " | - Masters of Horror / Masters of Horror"); - AddCategoryMapping(636, TorznabCatType.TV, " | - Mentalist / The Mentalist + Castle / Castle"); - AddCategoryMapping(606, TorznabCatType.TV, " | - Crime / CSI Location: Crime Scene Investigation"); - AddCategoryMapping(776, TorznabCatType.TV, " |- Мисс Марпл / Miss Marple"); - AddCategoryMapping(181, TorznabCatType.TV, "| - NCIS; Los Angeles; New Orleans"); - AddCategoryMapping(1499, TorznabCatType.TV, " | - Murder, She Wrote / Murder, She Wrote + Perry Mason .."); - AddCategoryMapping(81, TorznabCatType.TV, " | - Survivors / LOST"); - AddCategoryMapping(266, TorznabCatType.TV, " | - Desperate Housewives / Desperate Housewives"); - AddCategoryMapping(252, TorznabCatType.TV, " | - Jailbreak / Prison Break"); - AddCategoryMapping(196, TorznabCatType.TV, " |- Санта Барбара / Santa Barbara"); - AddCategoryMapping(372, TorznabCatType.TV, " | - Supernatural / Supernatural"); - AddCategoryMapping(110, TorznabCatType.TV, " | - The X-Files / The X-Files"); - AddCategoryMapping(193, TorznabCatType.TV, " | - Sex and the City / Sex And The City"); - AddCategoryMapping(237, TorznabCatType.TV, " | - Sliding / Sliders"); - AddCategoryMapping(265, TorznabCatType.TV, " | - Ambulance / ER"); - AddCategoryMapping(1117, TorznabCatType.TV, " | - Octopus / La Piovra"); - AddCategoryMapping(497, TorznabCatType.TV, " | - Smallville / Smallville"); - AddCategoryMapping(121, TorznabCatType.TV, " | - Twin Peaks / Twin Peaks"); - AddCategoryMapping(134, TorznabCatType.TV, " | - Hercule Poirot / Hercule Poirot"); - AddCategoryMapping(195, TorznabCatType.TV, " | - For sub-standard hands"); - AddCategoryMapping(2366, TorznabCatType.TV, "Foreign TV shows (HD Video)"); - AddCategoryMapping(2401, TorznabCatType.TV, " |- Блудливая Калифорния / Californication (HD Video)"); - AddCategoryMapping(2390, TorznabCatType.TV, " | - Two and a Half Men / Two and a Half Men (HD Video)"); - AddCategoryMapping(1669, TorznabCatType.TV, " |- Викинги / Vikings (HD Video)"); - AddCategoryMapping(2391, TorznabCatType.TV, " |- Декстер / Dexter (HD Video)"); - AddCategoryMapping(2392, TorznabCatType.TV, " | - Friends / Friends (HD Video)"); - AddCategoryMapping(2407, TorznabCatType.TV, " |- Доктор Кто / Doctor Who; Торчвуд / Torchwood (HD Video)"); - AddCategoryMapping(2393, TorznabCatType.TV, " |- Доктор Хаус / House M.D. (HD Video)"); - AddCategoryMapping(2370, TorznabCatType.TV, " | - Fringe / Fringe (HD Video)"); - AddCategoryMapping(2394, TorznabCatType.TV, "| - Stargate: a C1; Atlantis; The Universe (HD Video)"); - AddCategoryMapping(2408, TorznabCatType.TV, "| - Battlestar Galactica / Battlestar Galactica; Capri .."); - AddCategoryMapping(2395, TorznabCatType.TV, " | - Star Trek / Star Trek (HD Video)"); - AddCategoryMapping(2396, TorznabCatType.TV, "| - How I Met Your Mother; The Big Bang Theory (HD Vi .."); - AddCategoryMapping(2397, TorznabCatType.TV, " |- Кости / Bones (HD Video)"); - AddCategoryMapping(2398, TorznabCatType.TV, " | - Weeds / Weeds (HD Video)"); - AddCategoryMapping(2399, TorznabCatType.TV, "| - Mentalist / The Mentalist; Castle / Castle (HD Video)"); - AddCategoryMapping(2400, TorznabCatType.TV, " | - Crime / CSI Location: Crime Scene Investigation (HD .."); - AddCategoryMapping(2402, TorznabCatType.TV, " | - Survivors / LOST (HD Video)"); - AddCategoryMapping(2403, TorznabCatType.TV, " | - Jailbreak / Prison Break (HD Video)"); - AddCategoryMapping(2404, TorznabCatType.TV, " |- Сверхъестественное / Supernatural (HD Video)"); - AddCategoryMapping(2405, TorznabCatType.TV, " | - The X-Files / The X-Files (HD Video)"); - AddCategoryMapping(2406, TorznabCatType.TV, " |- Тайны Смолвиля / Smallville (HD Video)"); - AddCategoryMapping(911, TorznabCatType.TV, "Soaps Latin America, Turkey and India"); - AddCategoryMapping(1493, TorznabCatType.TV, " | - Actors and actresses of Latin American soap operas"); - AddCategoryMapping(1301, TorznabCatType.TV, " | - Indian series"); - AddCategoryMapping(704, TorznabCatType.TV, " | - Turkish serials"); - AddCategoryMapping(1940, TorznabCatType.TV, " | - Official brief version of Latin American soap operas"); - AddCategoryMapping(1574, TorznabCatType.TV, " | - Latin American soap operas with the voice acting (folders distribution)"); - AddCategoryMapping(1539, TorznabCatType.TV, " | - Latin American serials with subtitles"); - AddCategoryMapping(1500, TorznabCatType.TV, " |- OST"); - AddCategoryMapping(823, TorznabCatType.TV, " | - Богатые тоже плачут / The Rich Also Cry"); - AddCategoryMapping(1006, TorznabCatType.TV, " | - Вдова бланко / La Viuda de Blanco"); - AddCategoryMapping(877, TorznabCatType.TV, " | - Великолепный век / Magnificent Century"); - AddCategoryMapping(972, TorznabCatType.TV, " | - In the name of love / Por Amor"); - AddCategoryMapping(781, TorznabCatType.TV, " | - A girl named Fate / Milagros"); - AddCategoryMapping(1300, TorznabCatType.TV, " |- Дикий ангел / Muneca Brava"); - AddCategoryMapping(1803, TorznabCatType.TV, " | - Донья Барбара / Female Barbara"); - AddCategoryMapping(1298, TorznabCatType.TV, " | - Дороги Индии / Passage to India"); - AddCategoryMapping(825, TorznabCatType.TV, " | - Durnuška Betti / Yo Soy Betty la Fea"); - AddCategoryMapping(1606, TorznabCatType.TV, " | - The wife of Judas (wine of love) / La Mujer de Judas"); - AddCategoryMapping(1458, TorznabCatType.TV, " | - Cruel Angel / Anjo Mau"); - AddCategoryMapping(1463, TorznabCatType.TV, " | - Замарашка / Cara Sucia"); - AddCategoryMapping(1459, TorznabCatType.TV, " | - A Cinderella Story (Beautiful Loser) / Bella Calamidade .."); - AddCategoryMapping(1461, TorznabCatType.TV, " | - Kacorri / Kachorra"); - AddCategoryMapping(718, TorznabCatType.TV, " |- Клон / O Clone"); - AddCategoryMapping(1498, TorznabCatType.TV, " | - Клятва / The Oath"); - AddCategoryMapping(907, TorznabCatType.TV, " | - Lalo / Lalola"); - AddCategoryMapping(992, TorznabCatType.TV, " | - Morena Clara / Clara Morena"); - AddCategoryMapping(607, TorznabCatType.TV, " | - Mi Segunda Madre / Mi segunda Madre"); - AddCategoryMapping(594, TorznabCatType.TV, " | - The rebellious spirit / Rebelde Way"); - AddCategoryMapping(775, TorznabCatType.TV, " | - Наследница / The Heiress"); - AddCategoryMapping(534, TorznabCatType.TV, " | - Nobody but you / Tu o Nadie"); - AddCategoryMapping(1462, TorznabCatType.TV, " | - Падре Корахе / Father Courage"); - AddCategoryMapping(1678, TorznabCatType.TV, " | - Падший ангел / Mas Sabe el Diablo"); - AddCategoryMapping(904, TorznabCatType.TV, " | - Предательство / The Betrayal"); - AddCategoryMapping(1460, TorznabCatType.TV, " | - Призрак Элены / The Phantom of Elena"); - AddCategoryMapping(816, TorznabCatType.TV, " | - Live your life / Viver a vida"); - AddCategoryMapping(815, TorznabCatType.TV, " | - Just Maria / Simplemente Maria"); - AddCategoryMapping(325, TorznabCatType.TV, " | - Rabыnya Isaura / Escrava Isaura"); - AddCategoryMapping(1457, TorznabCatType.TV, " | - Реванш 2000 / Retaliation 2000"); - AddCategoryMapping(1692, TorznabCatType.TV, " | - Family Ties / Lacos de Familia"); - AddCategoryMapping(1540, TorznabCatType.TV, " | - Perfect Beauty / Beleza pura"); - AddCategoryMapping(694, TorznabCatType.TV, " | - Secrets of Love / Los Misterios del Amor"); - AddCategoryMapping(1949, TorznabCatType.TV, " | - Фаворитка / A Favorita"); - AddCategoryMapping(1541, TorznabCatType.TV, " | - Цыганская кровь / Soy gitano"); - AddCategoryMapping(1941, TorznabCatType.TV, " | - Шторм / Storm"); - AddCategoryMapping(1537, TorznabCatType.TV, " | - For sub-standard hands"); - AddCategoryMapping(2100, TorznabCatType.TV, "Asian series"); - AddCategoryMapping(717, TorznabCatType.TV, " | - Chinese serials with subtitles"); - AddCategoryMapping(915, TorznabCatType.TV, " | - Korean TV shows with voice acting"); - AddCategoryMapping(1242, TorznabCatType.TV, " | - Korean serials with subtitles"); - AddCategoryMapping(2412, TorznabCatType.TV, " | - Other Asian series with the voice acting"); - AddCategoryMapping(1938, TorznabCatType.TV, " | - Taiwanese serials with subtitles"); - AddCategoryMapping(2104, TorznabCatType.TV, " | - Japanese serials with subtitles"); - AddCategoryMapping(1939, TorznabCatType.TV, " | - Japanese TV series with the voice acting"); - AddCategoryMapping(2102, TorznabCatType.TV, " | -. VMV and other videos"); - AddCategoryMapping(2103, TorznabCatType.TV, " |- OST"); - - // Книги и журналы - AddCategoryMapping(1411, TorznabCatType.Books, " | - Scanning, processing skanov"); - AddCategoryMapping(21, TorznabCatType.Books, "books"); - AddCategoryMapping(2157, TorznabCatType.Books, " | - Film, TV, animation"); - AddCategoryMapping(765, TorznabCatType.Books, " | - Design, Graphic Design"); - AddCategoryMapping(2019, TorznabCatType.Books, " | - Photography and video"); - AddCategoryMapping(31, TorznabCatType.Books, " | - Magazines and newspapers (general section)"); - AddCategoryMapping(1427, TorznabCatType.Books, " | - Esoteric Tarot, Feng Shui"); - AddCategoryMapping(2422, TorznabCatType.Books, " | - Astrology"); - AddCategoryMapping(2195, TorznabCatType.Books, "| - Beauty. Care. housekeeping"); - AddCategoryMapping(2521, TorznabCatType.Books, "| - Fashion. Style. Etiquette"); - AddCategoryMapping(2223, TorznabCatType.Books, " | - Travel and Tourism"); - AddCategoryMapping(2447, TorznabCatType.Books, " | - Celebrity idols"); - AddCategoryMapping(39, TorznabCatType.Books, " | - Miscellaneous"); - AddCategoryMapping(1101, TorznabCatType.Books, "For children, parents and teachers"); - AddCategoryMapping(745, TorznabCatType.Books, " | - Textbooks for kindergarten and primary school (.."); - AddCategoryMapping(1689, TorznabCatType.Books, " | - Textbooks for high school (grades 5-11)"); - AddCategoryMapping(2336, TorznabCatType.Books, " | - Teachers and educators"); - AddCategoryMapping(2337, TorznabCatType.Books, " | - Scientific-popular and informative literature (for children .."); - AddCategoryMapping(1353, TorznabCatType.Books, " | - Leisure and creativity"); - AddCategoryMapping(1400, TorznabCatType.Books, " | - Education and development"); - AddCategoryMapping(1415, TorznabCatType.Books, "| - Hood. lit-ra for preschool and elementary grades"); - AddCategoryMapping(2046, TorznabCatType.Books, "| - Hood. lit-ra for the middle and upper classes"); - AddCategoryMapping(1802, TorznabCatType.Books, "Sports, physical training, martial arts"); - AddCategoryMapping(2189, TorznabCatType.Books, " | - Football"); - AddCategoryMapping(2190, TorznabCatType.Books, " | - Hockey"); - AddCategoryMapping(2443, TorznabCatType.Books, " | - Team sports"); - AddCategoryMapping(1477, TorznabCatType.Books, "| - Athletics. Swimming. Gymnastics. Weightlifting..."); - AddCategoryMapping(669, TorznabCatType.Books, "| - Motorsport. Motorcycling. cycle racing"); - AddCategoryMapping(2196, TorznabCatType.Books, "| - Chess. Checkers"); - AddCategoryMapping(2056, TorznabCatType.Books, " | - Martial Arts, Martial Arts"); - AddCategoryMapping(1436, TorznabCatType.Books, " | - Extreme"); - AddCategoryMapping(2191, TorznabCatType.Books, " | - Fitness, fitness, bodybuilding"); - AddCategoryMapping(2477, TorznabCatType.Books, " | - Sports press"); - AddCategoryMapping(1680, TorznabCatType.Books, "Humanitarian sciences"); - AddCategoryMapping(1684, TorznabCatType.Books, "| - Arts. Cultural"); - AddCategoryMapping(2446, TorznabCatType.Books, "| - Folklore. Epic. Mythology"); - AddCategoryMapping(2524, TorznabCatType.Books, " | - Literature"); - AddCategoryMapping(2525, TorznabCatType.Books, " | - Linguistics"); - AddCategoryMapping(995, TorznabCatType.Books, " | - Philosophy"); - AddCategoryMapping(2022, TorznabCatType.Books, " | - Political Science"); - AddCategoryMapping(2471, TorznabCatType.Books, " | - Sociology"); - AddCategoryMapping(2375, TorznabCatType.Books, " | - Journalism, Journalism"); - AddCategoryMapping(764, TorznabCatType.Books, " | - Business, Management"); - AddCategoryMapping(1685, TorznabCatType.Books, " | - Marketing"); - AddCategoryMapping(1688, TorznabCatType.Books, " | - Economy"); - AddCategoryMapping(2472, TorznabCatType.Books, " | - Finance"); - AddCategoryMapping(1687, TorznabCatType.Books, "| - Jurisprudence. Right. criminalistics"); - AddCategoryMapping(2020, TorznabCatType.Books, "Historical sciences"); - AddCategoryMapping(1349, TorznabCatType.Books, " | - Philosophy and Methodology of Historical Science"); - AddCategoryMapping(1967, TorznabCatType.Books, " | - Historical sources"); - AddCategoryMapping(2049, TorznabCatType.Books, " | - Historic Person"); - AddCategoryMapping(1681, TorznabCatType.Books, " | - Alternative historical theories"); - AddCategoryMapping(2319, TorznabCatType.Books, " | - Archaeology"); - AddCategoryMapping(2434, TorznabCatType.Books, "| - Ancient World. Antiquity"); - AddCategoryMapping(1683, TorznabCatType.Books, " | - The Middle Ages"); - AddCategoryMapping(2444, TorznabCatType.Books, " | - History of modern and contemporary"); - AddCategoryMapping(2427, TorznabCatType.Books, " | - European History"); - AddCategoryMapping(2452, TorznabCatType.Books, " | - History of Asia and Africa"); - AddCategoryMapping(2445, TorznabCatType.Books, " | - History of America, Australia, Oceania"); - AddCategoryMapping(2435, TorznabCatType.Books, " | - History of Russia"); - AddCategoryMapping(2436, TorznabCatType.Books, " | - The Age of the USSR"); - AddCategoryMapping(2453, TorznabCatType.Books, " | - History of the countries of the former USSR"); - AddCategoryMapping(2320, TorznabCatType.Books, " | - Ethnography, anthropology"); - AddCategoryMapping(1801, TorznabCatType.Books, "| - International relations. Diplomacy"); - AddCategoryMapping(2023, TorznabCatType.Books, "Accurate, natural and engineering sciences"); - AddCategoryMapping(2024, TorznabCatType.Books, " | - Aviation / Cosmonautics"); - AddCategoryMapping(2026, TorznabCatType.Books, " | - Physics"); - AddCategoryMapping(2192, TorznabCatType.Books, " | - Astronomy"); - AddCategoryMapping(2027, TorznabCatType.Books, " | - Biology / Ecology"); - AddCategoryMapping(295, TorznabCatType.Books, " | - Chemistry / Biochemistry"); - AddCategoryMapping(2028, TorznabCatType.Books, " | - Mathematics"); - AddCategoryMapping(2029, TorznabCatType.Books, " | - Geography / Geology / Geodesy"); - AddCategoryMapping(1325, TorznabCatType.Books, " | - Electronics / Radio"); - AddCategoryMapping(2386, TorznabCatType.Books, " | - Diagrams and service manuals (original documents)"); - AddCategoryMapping(2031, TorznabCatType.Books, " | - Architecture / Construction / Engineering networks"); - AddCategoryMapping(2030, TorznabCatType.Books, " | - Engineering"); - AddCategoryMapping(2526, TorznabCatType.Books, " | - Welding / Soldering / Non-Destructive Testing"); - AddCategoryMapping(2527, TorznabCatType.Books, " | - Automation / Robotics"); - AddCategoryMapping(2254, TorznabCatType.Books, " | - Metallurgy / Materials"); - AddCategoryMapping(2376, TorznabCatType.Books, " | - Mechanics, strength of materials"); - AddCategoryMapping(2054, TorznabCatType.Books, " | - Power engineering / electrical"); - AddCategoryMapping(770, TorznabCatType.Books, " | - Oil, Gas and Chemicals"); - AddCategoryMapping(2476, TorznabCatType.Books, " | - Agriculture and food industry"); - AddCategoryMapping(2494, TorznabCatType.Books, " | - Railway case"); - AddCategoryMapping(1528, TorznabCatType.Books, " | - Normative documentation"); - AddCategoryMapping(2032, TorznabCatType.Books, " | - Journals: scientific, popular, radio and others."); - AddCategoryMapping(768, TorznabCatType.Books, "Warfare"); - AddCategoryMapping(2099, TorznabCatType.Books, " | - Militaria"); - AddCategoryMapping(2021, TorznabCatType.Books, " | - Military History"); - AddCategoryMapping(2437, TorznabCatType.Books, " | - History of the Second World War"); - AddCategoryMapping(1447, TorznabCatType.Books, " | - Military equipment"); - AddCategoryMapping(2468, TorznabCatType.Books, " | - Small arms"); - AddCategoryMapping(2469, TorznabCatType.Books, " | - Educational literature"); - AddCategoryMapping(2470, TorznabCatType.Books, " | - Special forces of the world"); - AddCategoryMapping(1686, TorznabCatType.Books, "Faith and Religion"); - AddCategoryMapping(2215, TorznabCatType.Books, " | - Christianity"); - AddCategoryMapping(2216, TorznabCatType.Books, " | - Islam"); - AddCategoryMapping(2217, TorznabCatType.Books, " | - Religions of India, Tibet and East Asia / Judaism"); - AddCategoryMapping(2218, TorznabCatType.Books, " | - Non-traditional religious, spiritual and mystical teachings .."); - AddCategoryMapping(2252, TorznabCatType.Books, "| - Religion. History of Religions. Atheism"); - AddCategoryMapping(767, TorznabCatType.Books, "psychology"); - AddCategoryMapping(2515, TorznabCatType.Books, " | - General and Applied Psychology"); - AddCategoryMapping(2516, TorznabCatType.Books, " | - Psychotherapy and Counseling"); - AddCategoryMapping(2517, TorznabCatType.Books, " | - Psychodiagnostics and psyhokorrektsyya"); - AddCategoryMapping(2518, TorznabCatType.Books, " | - Social psychology and psychology of relationships"); - AddCategoryMapping(2519, TorznabCatType.Books, " | - Training and Coaching"); - AddCategoryMapping(2520, TorznabCatType.Books, " | - Personal development and self-improvement"); - AddCategoryMapping(1696, TorznabCatType.Books, " | - Popular Psychology"); - AddCategoryMapping(2253, TorznabCatType.Books, "| - Sexology. Relations between the sexes"); - AddCategoryMapping(2033, TorznabCatType.Books, "Collecting, hobby and hobbies"); - AddCategoryMapping(1412, TorznabCatType.Books, "| - Collecting and auxiliary ist. discipline"); - AddCategoryMapping(1446, TorznabCatType.Books, " | - Embroidery"); - AddCategoryMapping(753, TorznabCatType.Books, " | - Knitting"); - AddCategoryMapping(2037, TorznabCatType.Books, " | - Sewing, Patchwork"); - AddCategoryMapping(2224, TorznabCatType.Books, " | - Lace"); - AddCategoryMapping(2194, TorznabCatType.Books, "| - Beading. Yuvelirika. Jewellery wire."); - AddCategoryMapping(2418, TorznabCatType.Books, " | - Paper Art"); - AddCategoryMapping(1410, TorznabCatType.Books, " | - Other arts and crafts"); - AddCategoryMapping(2034, TorznabCatType.Books, " | - Pets and aquariums"); - AddCategoryMapping(2433, TorznabCatType.Books, " | - Hunting and fishing"); - AddCategoryMapping(1961, TorznabCatType.Books, " | - Cooking (Book)"); - AddCategoryMapping(2432, TorznabCatType.Books, " | - Cooking (newspapers and magazines)"); - AddCategoryMapping(565, TorznabCatType.Books, " | - Modelling"); - AddCategoryMapping(1523, TorznabCatType.Books, " | - Farmland / Floriculture"); - AddCategoryMapping(1575, TorznabCatType.Books, " | - Repair, private construction, design of interiors"); - AddCategoryMapping(1520, TorznabCatType.Books, " | - Woodworking"); - AddCategoryMapping(2424, TorznabCatType.Books, " | - Board Games"); - AddCategoryMapping(769, TorznabCatType.Books, " | - Other Hobbies"); - AddCategoryMapping(2038, TorznabCatType.Books, "Fiction"); - AddCategoryMapping(2043, TorznabCatType.Books, " | - Russian literature"); - AddCategoryMapping(2042, TorznabCatType.Books, " | - Foreign literature (up to 1900)"); - AddCategoryMapping(2041, TorznabCatType.Books, " | - Foreign literature (XX and XXI century)"); - AddCategoryMapping(2044, TorznabCatType.Books, " | - Detective, Action"); - AddCategoryMapping(2039, TorznabCatType.Books, " | - Female Novel"); - AddCategoryMapping(2045, TorznabCatType.Books, " | - Domestic science fiction / fantasy / mystic"); - AddCategoryMapping(2080, TorznabCatType.Books, " | - International science fiction / fantasy / mystic"); - AddCategoryMapping(2047, TorznabCatType.Books, " | - Adventure"); - AddCategoryMapping(2193, TorznabCatType.Books, " | - Literary Magazines"); - AddCategoryMapping(1418, TorznabCatType.Books, "Computer books"); - AddCategoryMapping(1422, TorznabCatType.Books, " | - Software from Microsoft"); - AddCategoryMapping(1423, TorznabCatType.Books, " | - Other software"); - AddCategoryMapping(1424, TorznabCatType.Books, " |- Mac OS; Linux, FreeBSD и прочие *NIX"); - AddCategoryMapping(1445, TorznabCatType.Books, " | - RDBMS"); - AddCategoryMapping(1425, TorznabCatType.Books, " | - Web Design and Programming"); - AddCategoryMapping(1426, TorznabCatType.Books, " | - Programming"); - AddCategoryMapping(1428, TorznabCatType.Books, " | - Graphics, Video Processing"); - AddCategoryMapping(1429, TorznabCatType.Books, " | - Network / VoIP"); - AddCategoryMapping(1430, TorznabCatType.Books, " | - Hacking and Security"); - AddCategoryMapping(1431, TorznabCatType.Books, " | - Iron (book on a PC)"); - AddCategoryMapping(1433, TorznabCatType.Books, " | - Engineering and scientific programs"); - AddCategoryMapping(1432, TorznabCatType.Books, " | - Computer magazines and annexes"); - AddCategoryMapping(2202, TorznabCatType.Books, " | - Disc applications to gaming magazines"); - AddCategoryMapping(862, TorznabCatType.Books, "Comics"); - AddCategoryMapping(2461, TorznabCatType.Books, " | - Comics in Russian"); - AddCategoryMapping(2462, TorznabCatType.Books, " | - Marvel Comics publishing"); - AddCategoryMapping(2463, TorznabCatType.Books, " | - DC Comics publishing"); - AddCategoryMapping(2464, TorznabCatType.Books, " | - Comics from other publishers"); - AddCategoryMapping(2473, TorznabCatType.Books, " | - Comics in other languages"); - AddCategoryMapping(2465, TorznabCatType.Books, " | - Manga (in foreign languages)"); - AddCategoryMapping(2048, TorznabCatType.Books, "Collections of books and libraries"); - AddCategoryMapping(1238, TorznabCatType.Books, " | - Library (mirror network libraries / collections)"); - AddCategoryMapping(2055, TorznabCatType.Books, " | - Thematic collections (collections)"); - AddCategoryMapping(754, TorznabCatType.Books, " | - Multidisciplinary collections (collections)"); - AddCategoryMapping(2114, TorznabCatType.Books, "Multimedia and online publications"); - AddCategoryMapping(2438, TorznabCatType.Books, " | - Multimedia Encyclopedia"); - AddCategoryMapping(2439, TorznabCatType.Books, " | - Interactive tutorials and educational materials"); - AddCategoryMapping(2440, TorznabCatType.Books, " | - Educational publications for children"); - AddCategoryMapping(2441, TorznabCatType.Books, "| - Cooking. Floriculture. housekeeping"); - AddCategoryMapping(2442, TorznabCatType.Books, "| - Culture. Art. History"); - - // Обучение иностранным языкам - AddCategoryMapping(2362, TorznabCatType.Books, "Foreign Language for Adults"); - AddCategoryMapping(1265, TorznabCatType.Books, " | - English (for adults)"); - AddCategoryMapping(1266, TorznabCatType.Books, " | - German"); - AddCategoryMapping(1267, TorznabCatType.Books, " | - French"); - AddCategoryMapping(1358, TorznabCatType.Books, " | - Spanish"); - AddCategoryMapping(2363, TorznabCatType.Books, " | - Italian"); - AddCategoryMapping(1268, TorznabCatType.Books, " | - Other European languages"); - AddCategoryMapping(1673, TorznabCatType.Books, " | - Arabic"); - AddCategoryMapping(1269, TorznabCatType.Books, " | - Chinese"); - AddCategoryMapping(1270, TorznabCatType.Books, " | - Japanese"); - AddCategoryMapping(1275, TorznabCatType.Books, " | - Other Asian languages"); - AddCategoryMapping(2364, TorznabCatType.Books, " | - Russian as a foreign language"); - AddCategoryMapping(1276, TorznabCatType.Books, " | - Multilanguage collections"); - AddCategoryMapping(1274, TorznabCatType.Books, " | - Other (foreign languages)"); - AddCategoryMapping(2094, TorznabCatType.Books, " | - LIM-courses"); - AddCategoryMapping(1264, TorznabCatType.Books, "Foreign languages ​​for children"); - AddCategoryMapping(2358, TorznabCatType.Books, " | - English (for children)"); - AddCategoryMapping(2359, TorznabCatType.Books, " | - Other European languages ​​(for children)"); - AddCategoryMapping(2360, TorznabCatType.Books, " | - Eastern languages ​​(for children)"); - AddCategoryMapping(2361, TorznabCatType.Books, " | - School textbooks, exam (for children)"); - AddCategoryMapping(2057, TorznabCatType.Books, "Fiction"); - AddCategoryMapping(2355, TorznabCatType.Books, " | - Fiction in English"); - AddCategoryMapping(2474, TorznabCatType.Books, " | - Fiction French"); - AddCategoryMapping(2356, TorznabCatType.Books, " | - Fiction in other European languages"); - AddCategoryMapping(2357, TorznabCatType.Books, " | - Fiction in oriental languages"); - AddCategoryMapping(2413, TorznabCatType.Books, "Audio Books in foreign languages"); - AddCategoryMapping(1501, TorznabCatType.Books, " | - Audiobooks in English"); - AddCategoryMapping(1580, TorznabCatType.Books, " | - Audiobooks in German"); - AddCategoryMapping(525, TorznabCatType.Books, " | - Audiobooks in other languages"); - - // Обучающее видео - AddCategoryMapping(610, TorznabCatType.Books, "Video tutorials and interactive training DVD"); - AddCategoryMapping(1568, TorznabCatType.Books, " | - Cooking"); - AddCategoryMapping(1542, TorznabCatType.Books, " | - Sport"); - AddCategoryMapping(2335, TorznabCatType.Books, " | - Fitness - Cardio, Strength Training"); - AddCategoryMapping(1544, TorznabCatType.Books, " | - Fitness - Mind and Body"); - AddCategoryMapping(1545, TorznabCatType.Books, " | - Extreme"); - AddCategoryMapping(1546, TorznabCatType.Books, " | - Bodybuilding"); - AddCategoryMapping(1549, TorznabCatType.Books, " | - Health Practice"); - AddCategoryMapping(1597, TorznabCatType.Books, " | - Yoga"); - AddCategoryMapping(1552, TorznabCatType.Books, " | - Video and Snapshots"); - AddCategoryMapping(1550, TorznabCatType.Books, " | - Personal care"); - AddCategoryMapping(1553, TorznabCatType.Books, " | - Drawing"); - AddCategoryMapping(1554, TorznabCatType.Books, " | - Playing the guitar"); - AddCategoryMapping(617, TorznabCatType.Books, " | - Percussion"); - AddCategoryMapping(1555, TorznabCatType.Books, " | - Other musical instruments"); - AddCategoryMapping(2017, TorznabCatType.Books, " | - Play the bass guitar"); - AddCategoryMapping(1257, TorznabCatType.Books, " | - Ballroom dancing"); - AddCategoryMapping(1258, TorznabCatType.Books, " | - Belly Dance"); - AddCategoryMapping(2208, TorznabCatType.Books, " | - The street and club dancing"); - AddCategoryMapping(677, TorznabCatType.Books, " | - Dancing, miscellaneous"); - AddCategoryMapping(1255, TorznabCatType.Books, " | - Hunting"); - AddCategoryMapping(1479, TorznabCatType.Books, " | - Fishing and spearfishing"); - AddCategoryMapping(1261, TorznabCatType.Books, " | - Tricks and stunts"); - AddCategoryMapping(614, TorznabCatType.Books, " | - Education"); - AddCategoryMapping(1259, TorznabCatType.Books, " | - Business, Economics and Finance"); - AddCategoryMapping(2065, TorznabCatType.Books, " | - Pregnancy, childbirth, motherhood"); - AddCategoryMapping(1254, TorznabCatType.Books, " | - Training videos for children"); - AddCategoryMapping(1260, TorznabCatType.Books, " | - Psychology"); - AddCategoryMapping(2209, TorznabCatType.Books, " | - Esoteric, self-development"); - AddCategoryMapping(2210, TorznabCatType.Books, " | - Van, dating"); - AddCategoryMapping(1547, TorznabCatType.Books, " | - Construction, repair and design"); - AddCategoryMapping(1548, TorznabCatType.Books, " | - Wood and metal"); - AddCategoryMapping(2211, TorznabCatType.Books, " | - Plants and Animals"); - AddCategoryMapping(615, TorznabCatType.Books, " | - Miscellaneous"); - AddCategoryMapping(1581, TorznabCatType.Books, "Martial Arts (Video Tutorials)"); - AddCategoryMapping(1590, TorznabCatType.Books, " | - Aikido and Aiki-jutsu"); - AddCategoryMapping(1587, TorznabCatType.Books, " | - Vin Chun"); - AddCategoryMapping(1594, TorznabCatType.Books, " | - Jiu-Jitsu"); - AddCategoryMapping(1591, TorznabCatType.Books, " | - Judo and Sambo"); - AddCategoryMapping(1588, TorznabCatType.Books, " | - Karate"); - AddCategoryMapping(1596, TorznabCatType.Books, " | - Knife Fight"); - AddCategoryMapping(1585, TorznabCatType.Books, " | - Work with weapon"); - AddCategoryMapping(1586, TorznabCatType.Books, " | - Russian style"); - AddCategoryMapping(2078, TorznabCatType.Books, " | - Dogfight"); - AddCategoryMapping(1929, TorznabCatType.Books, " | - Mixed styles"); - AddCategoryMapping(1593, TorznabCatType.Books, " | - Percussion styles"); - AddCategoryMapping(1592, TorznabCatType.Books, " | - This is a"); - AddCategoryMapping(1595, TorznabCatType.Books, " | - Miscellaneous"); - AddCategoryMapping(1556, TorznabCatType.Books, "Computer video tutorials and interactive training DVD"); - AddCategoryMapping(1560, TorznabCatType.Books, " | - Networks and Security"); - AddCategoryMapping(1561, TorznabCatType.Books, " | - OS and Microsoft Server Software"); - AddCategoryMapping(1653, TorznabCatType.Books, " | - Microsoft Office program"); - AddCategoryMapping(1570, TorznabCatType.Books, " | - OS and UNIX family program"); - AddCategoryMapping(1654, TorznabCatType.Books, " | - Adobe Photoshop"); - AddCategoryMapping(1655, TorznabCatType.Books, " |- Autodesk Maya"); - AddCategoryMapping(1656, TorznabCatType.Books, " | - Autodesk 3ds Max"); - AddCategoryMapping(1930, TorznabCatType.Books, " |- Autodesk Softimage (XSI)"); - AddCategoryMapping(1931, TorznabCatType.Books, " |- ZBrush"); - AddCategoryMapping(1932, TorznabCatType.Books, " |- Flash, Flex и ActionScript"); - AddCategoryMapping(1562, TorznabCatType.Books, " | - 2D-графика"); - AddCategoryMapping(1563, TorznabCatType.Books, " | - 3D-графика"); - AddCategoryMapping(1626, TorznabCatType.Books, " | - Engineering and scientific programs"); - AddCategoryMapping(1564, TorznabCatType.Books, " | - Web-design"); - AddCategoryMapping(1565, TorznabCatType.Books, " | - Programming"); - AddCategoryMapping(1559, TorznabCatType.Books, " | - Software for Mac OS"); - AddCategoryMapping(1566, TorznabCatType.Books, " | - Working with video"); - AddCategoryMapping(1573, TorznabCatType.Books, " | - Working with sound"); - AddCategoryMapping(1567, TorznabCatType.Books, " | - Other (Computer video tutorials)"); - - // Аудиокниги - AddCategoryMapping(2326, TorznabCatType.Audio, "Auditions, history, memoirs"); - AddCategoryMapping(574, TorznabCatType.Audio, " | - [Audio] Auditions and readings"); - AddCategoryMapping(1036, TorznabCatType.Audio, " | - [Audio] Lots of great people"); - AddCategoryMapping(400, TorznabCatType.Audio, " | - [Audio] Historical Book"); - AddCategoryMapping(2389, TorznabCatType.Audio, "Science fiction, fantasy, mystery, horror, fanfiction"); - AddCategoryMapping(2388, TorznabCatType.Audio, " | - [Audio] Foreign fiction, fantasy, mystery, horror, .."); - AddCategoryMapping(2387, TorznabCatType.Audio, " | - [Audio] Russian fiction, fantasy, mystery, horror, .."); - AddCategoryMapping(2348, TorznabCatType.Audio, " | - [Audio] Puzzle / Miscellaneous Science Fiction, Fantasy, Mystery, too .."); - AddCategoryMapping(2327, TorznabCatType.Audio, "Fiction"); - AddCategoryMapping(695, TorznabCatType.Audio, " | - [Audio] Poetry"); - AddCategoryMapping(399, TorznabCatType.Audio, " | - [Audio] Foreign literature"); - AddCategoryMapping(402, TorznabCatType.Audio, " | - [Audio] Russian literature"); - AddCategoryMapping(490, TorznabCatType.Audio, " | - [Audio] Children's Books"); - AddCategoryMapping(499, TorznabCatType.Audio, " | - [Audio] Detectives, Adventure, Thriller, Action"); - AddCategoryMapping(2324, TorznabCatType.Audio, "religion"); - AddCategoryMapping(2325, TorznabCatType.Audio, " | - [Audio] Orthodoxy"); - AddCategoryMapping(2342, TorznabCatType.Audio, " | - [Audio] Islam"); - AddCategoryMapping(530, TorznabCatType.Audio, " | - [Audio] Other traditional religion"); - AddCategoryMapping(2152, TorznabCatType.Audio, " | - [Audio] Non-traditional religious and philosophical teachings"); - AddCategoryMapping(2328, TorznabCatType.Audio, "other literature"); - AddCategoryMapping(403, TorznabCatType.Audio, " | - [Audio] academic and popular literature"); - AddCategoryMapping(1279, TorznabCatType.Audio, " | - [Audio] lossless-audio books"); - AddCategoryMapping(716, TorznabCatType.Audio, " | - [Audio] Business"); - AddCategoryMapping(2165, TorznabCatType.Audio, " | - [Audio] Miscellaneous"); - AddCategoryMapping(401, TorznabCatType.Audio, " | - [Audio], sub-standard distribution"); - - // Все по авто и мото - AddCategoryMapping(1964, TorznabCatType.Books, "Repair and maintenance of vehicles"); - AddCategoryMapping(1973, TorznabCatType.Books, " | - Original catalogs on selection of spare parts"); - AddCategoryMapping(1974, TorznabCatType.Books, " | - Non-original spare parts catalogs for selection"); - AddCategoryMapping(1975, TorznabCatType.Books, " | - Diagnostic and repair programs"); - AddCategoryMapping(1976, TorznabCatType.Books, " | - Tuning, chip tuning, tuning"); - AddCategoryMapping(1977, TorznabCatType.Books, " | - Books for the repair / maintenance / operation of the vehicle"); - AddCategoryMapping(1203, TorznabCatType.Books, " | - Multimediyki repair / maintenance / operation of the vehicle"); - AddCategoryMapping(1978, TorznabCatType.Books, " | - Accounting, utilities, etc."); - AddCategoryMapping(1979, TorznabCatType.Books, " | - Virtual Driving School"); - AddCategoryMapping(1980, TorznabCatType.Books, " | - Video lessons on driving vehicles"); - AddCategoryMapping(1981, TorznabCatType.Books, " | - Tutorials repair vehicles"); - AddCategoryMapping(1970, TorznabCatType.Books, " | - Journals by car / moto"); - AddCategoryMapping(334, TorznabCatType.Books, " | - Water transport"); - AddCategoryMapping(1202, TorznabCatType.Books, "Movies and transfer by car / moto"); - AddCategoryMapping(1985, TorznabCatType.Books, " | - Documentary / educational films"); - AddCategoryMapping(1982, TorznabCatType.Books, " | - Entertainment shows"); - AddCategoryMapping(2151, TorznabCatType.Books, " |- Top Gear/Топ Гир"); - AddCategoryMapping(1983, TorznabCatType.Books, " | - Test Drive / Reviews / Motor"); - AddCategoryMapping(1984, TorznabCatType.Books, " | - Tuning / Fast and the Furious"); - - // Музыка - AddCategoryMapping(409, TorznabCatType.Audio, "Classical and contemporary academic music"); - AddCategoryMapping(1660, TorznabCatType.Audio, " | - In-house digitizing (Classical Music)"); - AddCategoryMapping(1164, TorznabCatType.Audio, " | - Multi-channel music (classical and modern classics in .."); - AddCategoryMapping(1884, TorznabCatType.Audio, " | - Hi-Res stereo (classic and modern classic in obrabot .."); - AddCategoryMapping(445, TorznabCatType.Audio, " | - Classical music (Video)"); - AddCategoryMapping(984, TorznabCatType.Audio, " | - Classical music (DVD and HD Video)"); - AddCategoryMapping(702, TorznabCatType.Audio, " | - Opera (Video)"); - AddCategoryMapping(983, TorznabCatType.Audio, " |- Опера (DVD и HD Видео)"); - AddCategoryMapping(1990, TorznabCatType.Audio, " | - Ballet and contemporary dance (Video, DVD and HD Video)"); - AddCategoryMapping(560, TorznabCatType.Audio, " | - Complete collection of works and multi-disc edition (lossl .."); - AddCategoryMapping(794, TorznabCatType.Audio, " |- Опера (lossless)"); - AddCategoryMapping(556, TorznabCatType.Audio, " | - Vocal music (lossless)"); - AddCategoryMapping(2307, TorznabCatType.Audio, " | - Horovaya Music (lossless)"); - AddCategoryMapping(557, TorznabCatType.Audio, " | - Orchestral music (lossless)"); - AddCategoryMapping(2308, TorznabCatType.Audio, " | - Concerto for Orchestra Instrument (lossless)"); - AddCategoryMapping(558, TorznabCatType.Audio, " | - Chamber instrumental music (lossless)"); - AddCategoryMapping(793, TorznabCatType.Audio, " | - Solo instrumental music (lossless)"); - AddCategoryMapping(436, TorznabCatType.Audio, " | - Complete collection of works and multi-disc edition (lossy .."); - AddCategoryMapping(2309, TorznabCatType.Audio, " | - Vocal and choral music (lossy)"); - AddCategoryMapping(2310, TorznabCatType.Audio, " | - Orchestral music (lossy)"); - AddCategoryMapping(2311, TorznabCatType.Audio, " | - Chamber and solo instrumental music (lossy)"); - AddCategoryMapping(969, TorznabCatType.Audio, " | - Classics in modern processing, Classical Crossover (l .."); - AddCategoryMapping(1125, TorznabCatType.Audio, "Folklore, Folk and World Music"); - AddCategoryMapping(1130, TorznabCatType.Audio, " |- Восточноевропейский фолк (lossy)"); - AddCategoryMapping(1131, TorznabCatType.Audio, " | - Eastern European Folk (lossless)"); - AddCategoryMapping(1132, TorznabCatType.Audio, " |- Западноевропейский фолк (lossy)"); - AddCategoryMapping(1133, TorznabCatType.Audio, " |- Западноевропейский фолк (lossless)"); - AddCategoryMapping(2084, TorznabCatType.Audio, " | - Klezmer and Jewish folklore (lossy and lossless)"); - AddCategoryMapping(1128, TorznabCatType.Audio, " | - World Music Siberia, Central Asia and East Asia (loss .."); - AddCategoryMapping(1129, TorznabCatType.Audio, " | - World Music Siberia, Central Asia and East Asia (loss .."); - AddCategoryMapping(1856, TorznabCatType.Audio, " | - World Music India (lossy)"); - AddCategoryMapping(2430, TorznabCatType.Audio, " | - World Music India (lossless)"); - AddCategoryMapping(1283, TorznabCatType.Audio, " | - World Music Africa and the Middle East (lossy)"); - AddCategoryMapping(2085, TorznabCatType.Audio, " | - World Music Africa and the Middle East (lossless)"); - AddCategoryMapping(1282, TorznabCatType.Audio, " | - Ethnic Music of the Caucasus and Transcaucasia (lossy and lossless .."); - AddCategoryMapping(1284, TorznabCatType.Audio, " | - World Music Americas (lossy)"); - AddCategoryMapping(1285, TorznabCatType.Audio, " | - World Music Americas (lossless)"); - AddCategoryMapping(1138, TorznabCatType.Audio, " | - World Music Australia, the Pacific and Indian oceans .."); - AddCategoryMapping(1136, TorznabCatType.Audio, " |- Country, Bluegrass (lossy)"); - AddCategoryMapping(1137, TorznabCatType.Audio, " |- Country, Bluegrass (lossless)"); - AddCategoryMapping(1141, TorznabCatType.Audio, " | - Folklore, Folk and World Music (Video)"); - AddCategoryMapping(1142, TorznabCatType.Audio, " | - Folklore, Folk and World Music (DVD Video)"); - AddCategoryMapping(2530, TorznabCatType.Audio, " | - Folklore, Folk and World Music (HD Video)"); - AddCategoryMapping(506, TorznabCatType.Audio, " | - Folklore, Folk and World Music (own otsif .."); - AddCategoryMapping(1849, TorznabCatType.Audio, "New Age, Relax, Meditative & Flamenco"); - AddCategoryMapping(1126, TorznabCatType.Audio, " |- NewAge & Meditative (lossy)"); - AddCategoryMapping(1127, TorznabCatType.Audio, " |- NewAge & Meditative (lossless)"); - AddCategoryMapping(1134, TorznabCatType.Audio, " | - Flamenco and acoustic guitar (lossy)"); - AddCategoryMapping(1135, TorznabCatType.Audio, " | - Flamenco and acoustic guitar (lossless)"); - AddCategoryMapping(2352, TorznabCatType.Audio, " |- New Age, Relax, Meditative & Flamenco (Видео)"); - AddCategoryMapping(2351, TorznabCatType.Audio, " |- New Age, Relax, Meditative & Flamenco (DVD и HD Видео)"); - AddCategoryMapping(855, TorznabCatType.Audio, " | - Sounds of Nature"); - AddCategoryMapping(408, TorznabCatType.Audio, "Рэп, Хип-Хоп, R'n'B"); - AddCategoryMapping(441, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop (lossy)"); - AddCategoryMapping(1173, TorznabCatType.Audio, " |- Отечественный R'n'B (lossy)"); - AddCategoryMapping(1486, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop, R'n'B (lossless)"); - AddCategoryMapping(1172, TorznabCatType.Audio, " |- Зарубежный R'n'B (lossy)"); - AddCategoryMapping(446, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (lossy)"); - AddCategoryMapping(909, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (lossless)"); - AddCategoryMapping(1665, TorznabCatType.Audio, " |- Зарубежный R'n'B (lossless)"); - AddCategoryMapping(1835, TorznabCatType.Audio, " | - Rap, Hip-Hop, R'n'B (own digitization)"); - AddCategoryMapping(1189, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop (Video)"); - AddCategoryMapping(1455, TorznabCatType.Audio, " | - Domestic R'n'B (Video)"); - AddCategoryMapping(442, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (Video)"); - AddCategoryMapping(1174, TorznabCatType.Audio, " | - Foreign R'n'B (Video)"); - AddCategoryMapping(1107, TorznabCatType.Audio, " |- Рэп, Хип-Хоп, R'n'B (DVD Video)"); - AddCategoryMapping(2529, TorznabCatType.Audio, " |- Рэп, Хип-Хоп, R'n'B (HD Видео)"); - AddCategoryMapping(1760, TorznabCatType.Audio, "Reggae, Ska, Dub"); - AddCategoryMapping(1764, TorznabCatType.Audio, " | - Rocksteady, Early Reggae, Ska-Jazz, Trad.Ska (lossy и lo .."); - AddCategoryMapping(1766, TorznabCatType.Audio, " |- Punky-Reggae, Rocksteady-Punk, Ska Revival (lossy)"); - AddCategoryMapping(1767, TorznabCatType.Audio, " | - 3rd Wave Ska (lossy)"); - AddCategoryMapping(1769, TorznabCatType.Audio, " | - Ska-Punk, Ska-Core (lossy)"); - AddCategoryMapping(1765, TorznabCatType.Audio, " |- Reggae (lossy)"); - AddCategoryMapping(1771, TorznabCatType.Audio, " |- Dub (lossy)"); - AddCategoryMapping(1770, TorznabCatType.Audio, " |- Dancehall, Raggamuffin (lossy)"); - AddCategoryMapping(1768, TorznabCatType.Audio, " |- Reggae, Dancehall, Dub (lossless)"); - AddCategoryMapping(1774, TorznabCatType.Audio, " | - Ska Ska-Punk, Ska-Jazz (lossless)"); - AddCategoryMapping(1772, TorznabCatType.Audio, " | - Domestic reggae, dub (lossy and lossless)"); - AddCategoryMapping(1773, TorznabCatType.Audio, " | - Patriotic ska music (lossy and lossless)"); - AddCategoryMapping(2233, TorznabCatType.Audio, " | - Reggae, Ska, Dub (компиляции) (lossy и lossless)"); - AddCategoryMapping(2232, TorznabCatType.Audio, " | - Reggae, Ska, Dub (own digitization)"); - AddCategoryMapping(1775, TorznabCatType.Audio, " | - Reggae, Ska, Dub (Видео)"); - AddCategoryMapping(1777, TorznabCatType.Audio, " | - Reggae, Ska, Dub (DVD и HD Video)"); - AddCategoryMapping(416, TorznabCatType.Audio, "Soundtracks and Karaoke"); - AddCategoryMapping(782, TorznabCatType.Audio, " | - Karaoke (Audio)"); - AddCategoryMapping(2377, TorznabCatType.Audio, " | - Karaoke (Video)"); - AddCategoryMapping(468, TorznabCatType.Audio, " |- Минусовки (lossy и lossless)"); - AddCategoryMapping(1625, TorznabCatType.Audio, " | - Soundtracks (own digitization)"); - AddCategoryMapping(691, TorznabCatType.Audio, " | - Soundtracks for domestic films (lossless)"); - AddCategoryMapping(469, TorznabCatType.Audio, " | - Soundtracks for domestic films (lossy)"); - AddCategoryMapping(786, TorznabCatType.Audio, " | - Soundtracks for foreign films (lossless)"); - AddCategoryMapping(785, TorznabCatType.Audio, " | - Soundtracks for foreign films (lossy)"); - AddCategoryMapping(796, TorznabCatType.Audio, " | - Informal soundtracks for films and TV series (lossy)"); - AddCategoryMapping(784, TorznabCatType.Audio, " | - Soundtracks for games (lossless)"); - AddCategoryMapping(783, TorznabCatType.Audio, " | - Soundtracks for games (lossy)"); - AddCategoryMapping(2331, TorznabCatType.Audio, " | - Informal soundtracks for games (lossy)"); - AddCategoryMapping(2431, TorznabCatType.Audio, " | - The arrangements of music from the game (lossy and lossless)"); - AddCategoryMapping(1397, TorznabCatType.Audio, " | - Hi-Res stereo and multi-channel music (Soundtracks)"); - AddCategoryMapping(1215, TorznabCatType.Audio, "Chanson, Author and military songs"); - AddCategoryMapping(1220, TorznabCatType.Audio, " | - The domestic chanson (lossless)"); - AddCategoryMapping(1221, TorznabCatType.Audio, " | - The domestic chanson (lossy)"); - AddCategoryMapping(1334, TorznabCatType.Audio, " | - Compilations domestic chanson (lossy)"); - AddCategoryMapping(1216, TorznabCatType.Audio, " | - War Song (lossless)"); - AddCategoryMapping(1223, TorznabCatType.Audio, " | - War Song (lossy)"); - AddCategoryMapping(1224, TorznabCatType.Audio, " | - Chanson (lossless)"); - AddCategoryMapping(1225, TorznabCatType.Audio, " | - Chanson (lossy)"); - AddCategoryMapping(1226, TorznabCatType.Audio, " |- Менестрели и ролевики (lossy и lossless)"); - AddCategoryMapping(1217, TorznabCatType.Audio, " | - In-house digitizing (Chanson, and Bards) lossles .."); - AddCategoryMapping(1227, TorznabCatType.Audio, " | - Video (Chanson, and Bards)"); - AddCategoryMapping(1228, TorznabCatType.Audio, " | - DVD Video (Chanson, and Bards)"); - AddCategoryMapping(413, TorznabCatType.Audio, "Music of other genres"); - AddCategoryMapping(974, TorznabCatType.Audio, " | - In-house digitizing (Music from other genres)"); - AddCategoryMapping(463, TorznabCatType.Audio, " | - Patriotic music of other genres (lossy)"); - AddCategoryMapping(464, TorznabCatType.Audio, " | - Patriotic music of other genres (lossless)"); - AddCategoryMapping(466, TorznabCatType.Audio, " | - International music of other genres (lossy)"); - AddCategoryMapping(465, TorznabCatType.Audio, " | - International music of other genres (lossless)"); - AddCategoryMapping(2018, TorznabCatType.Audio, " | - Music for ballroom dancing (lossy and lossless)"); - AddCategoryMapping(1396, TorznabCatType.Audio, " | - Orthodox chants (lossy)"); - AddCategoryMapping(1395, TorznabCatType.Audio, " | - Orthodox chants (lossless)"); - AddCategoryMapping(1351, TorznabCatType.Audio, " | - A collection of songs for children (lossy and lossless)"); - AddCategoryMapping(475, TorznabCatType.Audio, " | - Video (Music from other genres)"); - AddCategoryMapping(988, TorznabCatType.Audio, " | - DVD Video (Music from other genres)"); - AddCategoryMapping(880, TorznabCatType.Audio, " | - The Musical (lossy and lossless)"); - AddCategoryMapping(655, TorznabCatType.Audio, " | - The Musical (Video and DVD Video)"); - AddCategoryMapping(965, TorznabCatType.Audio, " | - Informal and vnezhanrovye collections (lossy)"); - AddCategoryMapping(919, TorznabCatType.Audio, "Sheet Music literature"); - AddCategoryMapping(944, TorznabCatType.Audio, " | - Academic Music (Notes and Media CD)"); - AddCategoryMapping(980, TorznabCatType.Audio, " | - Other destinations (notes, tablature)"); - AddCategoryMapping(946, TorznabCatType.Audio, " | - Tutorials and Schools"); - AddCategoryMapping(977, TorznabCatType.Audio, " | - Songbooks (Songbooks)"); - AddCategoryMapping(2074, TorznabCatType.Audio, " | - Music Literature and Theory"); - AddCategoryMapping(2349, TorznabCatType.Audio, " | - Music Magazines"); - - // Популярная музыка - AddCategoryMapping(2495, TorznabCatType.Audio, "Domestic Pop"); - AddCategoryMapping(424, TorznabCatType.Audio, " | - Patriotic Pop (lossy)"); - AddCategoryMapping(1361, TorznabCatType.Audio, " | - Patriotic Pop music (collections) (lossy)"); - AddCategoryMapping(425, TorznabCatType.Audio, " | - Patriotic Pop (lossless)"); - AddCategoryMapping(1635, TorznabCatType.Audio, " | - Soviet pop music, retro (lossy)"); - AddCategoryMapping(1634, TorznabCatType.Audio, " | - Soviet pop music, retro (lossless)"); - AddCategoryMapping(2497, TorznabCatType.Audio, "Foreign pop music"); - AddCategoryMapping(428, TorznabCatType.Audio, " | - Foreign pop music (lossy)"); - AddCategoryMapping(1362, TorznabCatType.Audio, " | - Foreign pop music (collections) (lossy)"); - AddCategoryMapping(429, TorznabCatType.Audio, " | - International Pop (lossless)"); - AddCategoryMapping(1219, TorznabCatType.Audio, " | - Foreign chanson (lossy)"); - AddCategoryMapping(1452, TorznabCatType.Audio, " | - Foreign chanson (lossless)"); - AddCategoryMapping(1331, TorznabCatType.Audio, " | - East Asian pop music (lossy)"); - AddCategoryMapping(1330, TorznabCatType.Audio, " | - East Asian Pop (lossless)"); - AddCategoryMapping(2499, TorznabCatType.Audio, "Eurodance, Disco, Hi-NRG"); - AddCategoryMapping(2503, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (lossy)"); - AddCategoryMapping(2504, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (сборники) (lossy)"); - AddCategoryMapping(2502, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (lossless)"); - AddCategoryMapping(2501, TorznabCatType.Audio, " |- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossy)"); - AddCategoryMapping(2505, TorznabCatType.Audio, " | - Disco, Italo-Disco, Euro-Disco, Hi-NRG (сборники) (lossy .."); - AddCategoryMapping(2500, TorznabCatType.Audio, " |- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossless)"); - AddCategoryMapping(2507, TorznabCatType.Audio, "Видео, DVD Video, HD Video (поп-музыка)"); - AddCategoryMapping(1121, TorznabCatType.Audio, " | - Patriotic Pop (Video)"); - AddCategoryMapping(1122, TorznabCatType.Audio, " | - Patriotic Pop (DVD Video)"); - AddCategoryMapping(2510, TorznabCatType.Audio, " | - Soviet pop music, retro (video)"); - AddCategoryMapping(2509, TorznabCatType.Audio, " | - Soviet pop music, retro (DVD Video)"); - AddCategoryMapping(431, TorznabCatType.Audio, " | - Foreign pop music (Video)"); - AddCategoryMapping(986, TorznabCatType.Audio, " | - Foreign pop music (DVD Video)"); - AddCategoryMapping(2532, TorznabCatType.Audio, " |- Eurodance, Disco (видео)"); - AddCategoryMapping(2531, TorznabCatType.Audio, " |- Eurodance, Disco (DVD Video)"); - AddCategoryMapping(2378, TorznabCatType.Audio, " | - East Asian pop music (Video)"); - AddCategoryMapping(2379, TorznabCatType.Audio, " | - East Asian pop music (DVD Video)"); - AddCategoryMapping(2383, TorznabCatType.Audio, " | - Foreign chanson (Video)"); - AddCategoryMapping(2384, TorznabCatType.Audio, " | - Foreign chanson (DVD Video)"); - AddCategoryMapping(2088, TorznabCatType.Audio, " | - Patriotic Pop (National concerts, video dock.) .."); - AddCategoryMapping(2089, TorznabCatType.Audio, " | - Foreign pop music (National concerts, video dock.) (Bu .."); - AddCategoryMapping(2426, TorznabCatType.Audio, " | - Patriotic Pop Music, Chanson, Eurodance, Disco (HD V .."); - AddCategoryMapping(2508, TorznabCatType.Audio, " | - International Pop Music, Chanson, Eurodance, Disco (HD Vide .."); - AddCategoryMapping(2512, TorznabCatType.Audio, "The multi-channel music and own digitization (pop music)"); - AddCategoryMapping(1444, TorznabCatType.Audio, " | - Foreign pop music (own digitization)"); - AddCategoryMapping(1785, TorznabCatType.Audio, " | - Eastern pop music (own digitization)"); - AddCategoryMapping(239, TorznabCatType.Audio, " | - Patriotic Pop (own digitization)"); - AddCategoryMapping(450, TorznabCatType.Audio, " | - Instrumental Pop (own digitization)"); - AddCategoryMapping(1163, TorznabCatType.Audio, " | - Multi-channel music (pop music)"); - AddCategoryMapping(1885, TorznabCatType.Audio, " |- Hi-Res stereo (Поп-музыка)"); - - // Джазовая и Блюзовая музыка - AddCategoryMapping(2267, TorznabCatType.Audio, "foreign jazz"); - AddCategoryMapping(2277, TorznabCatType.Audio, " |- Early Jazz, Swing, Gypsy (lossless)"); - AddCategoryMapping(2278, TorznabCatType.Audio, " |- Bop (lossless)"); - AddCategoryMapping(2279, TorznabCatType.Audio, " |- Mainstream Jazz, Cool (lossless)"); - AddCategoryMapping(2280, TorznabCatType.Audio, " |- Jazz Fusion (lossless)"); - AddCategoryMapping(2281, TorznabCatType.Audio, " |- World Fusion, Ethnic Jazz (lossless)"); - AddCategoryMapping(2282, TorznabCatType.Audio, " |- Avant-Garde Jazz, Free Improvisation (lossless)"); - AddCategoryMapping(2353, TorznabCatType.Audio, " |- Modern Creative, Third Stream (lossless)"); - AddCategoryMapping(2284, TorznabCatType.Audio, " |- Smooth, Jazz-Pop (lossless)"); - AddCategoryMapping(2285, TorznabCatType.Audio, " |- Vocal Jazz (lossless)"); - AddCategoryMapping(2283, TorznabCatType.Audio, " |- Funk, Soul, R&B (lossless)"); - AddCategoryMapping(2286, TorznabCatType.Audio, " | - Compilations foreign jazz (lossless)"); - AddCategoryMapping(2287, TorznabCatType.Audio, " | - Foreign jazz (lossy)"); - AddCategoryMapping(2268, TorznabCatType.Audio, "foreign blues"); - AddCategoryMapping(2293, TorznabCatType.Audio, " |- Blues (Texas, Chicago, Modern and Others) (lossless)"); - AddCategoryMapping(2292, TorznabCatType.Audio, " |- Blues-rock (lossless)"); - AddCategoryMapping(2290, TorznabCatType.Audio, " |- Roots, Pre-War Blues, Early R&B, Gospel (lossless)"); - AddCategoryMapping(2289, TorznabCatType.Audio, " | - Foreign blues (collections; Tribute VA) (lossless)"); - AddCategoryMapping(2288, TorznabCatType.Audio, " | - Foreign blues (lossy)"); - AddCategoryMapping(2269, TorznabCatType.Audio, "Domestic jazz and blues"); - AddCategoryMapping(2297, TorznabCatType.Audio, " | - Domestic Jazz (lossless)"); - AddCategoryMapping(2295, TorznabCatType.Audio, " | - Domestic jazz (lossy)"); - AddCategoryMapping(2296, TorznabCatType.Audio, " | - Domestic Blues (lossless)"); - AddCategoryMapping(2298, TorznabCatType.Audio, " | - Domestic Blues (lossy)"); - AddCategoryMapping(2270, TorznabCatType.Audio, "The multi-channel music and own digitization (Jazz and Blues)"); - AddCategoryMapping(2303, TorznabCatType.Audio, " | - Multi-channel music (Jazz and Blues)"); - AddCategoryMapping(2302, TorznabCatType.Audio, " | - Hi-Res stereo (Jazz and Blues)"); - AddCategoryMapping(2301, TorznabCatType.Audio, " | - In-house digitizing (Jazz and Blues)"); - AddCategoryMapping(2271, TorznabCatType.Audio, "Video, DVD Video, HD Video (Jazz and Blues)"); - AddCategoryMapping(2305, TorznabCatType.Audio, " | - Jazz and Blues (Video)"); - AddCategoryMapping(2304, TorznabCatType.Audio, " | - Jazz and Blues (DVD Video)"); - AddCategoryMapping(2306, TorznabCatType.Audio, " | - Jazz and Blues (HD Video)"); - - // Рок-музыка - AddCategoryMapping(1698, TorznabCatType.Audio, "foreign Rock"); - AddCategoryMapping(1702, TorznabCatType.Audio, " |- Classic Rock & Hard Rock (lossless)"); - AddCategoryMapping(1703, TorznabCatType.Audio, " |- Classic Rock & Hard Rock (lossy)"); - AddCategoryMapping(1704, TorznabCatType.Audio, " |- Progressive & Art-Rock (lossless)"); - AddCategoryMapping(1705, TorznabCatType.Audio, " |- Progressive & Art-Rock (lossy)"); - AddCategoryMapping(1706, TorznabCatType.Audio, " |- Folk-Rock (lossless)"); - AddCategoryMapping(1707, TorznabCatType.Audio, " |- Folk-Rock (lossy)"); - AddCategoryMapping(2329, TorznabCatType.Audio, " |- AOR (Melodic Hard Rock, Arena rock) (lossless)"); - AddCategoryMapping(2330, TorznabCatType.Audio, " |- AOR (Melodic Hard Rock, Arena rock) (lossy)"); - AddCategoryMapping(1708, TorznabCatType.Audio, " |- Pop-Rock & Soft Rock (lossless)"); - AddCategoryMapping(1709, TorznabCatType.Audio, " |- Pop-Rock & Soft Rock (lossy)"); - AddCategoryMapping(1710, TorznabCatType.Audio, " |- Instrumental Guitar Rock (lossless)"); - AddCategoryMapping(1711, TorznabCatType.Audio, " |- Instrumental Guitar Rock (lossy)"); - AddCategoryMapping(1712, TorznabCatType.Audio, " |- Rockabilly, Psychobilly, Rock'n'Roll (lossless)"); - AddCategoryMapping(1713, TorznabCatType.Audio, " |- Rockabilly, Psychobilly, Rock'n'Roll (lossy)"); - AddCategoryMapping(731, TorznabCatType.Audio, " | - Compilations foreign rock (lossless)"); - AddCategoryMapping(1799, TorznabCatType.Audio, " | - Compilations foreign rock (lossy)"); - AddCategoryMapping(1714, TorznabCatType.Audio, " | - East Asian Rock (lossless)"); - AddCategoryMapping(1715, TorznabCatType.Audio, " | - East Asian rock (lossy)"); - AddCategoryMapping(1716, TorznabCatType.Audio, "foreign Metal"); - AddCategoryMapping(1796, TorznabCatType.Audio, " |- Avant-garde, Experimental Metal (lossless)"); - AddCategoryMapping(1797, TorznabCatType.Audio, " |- Avant-garde, Experimental Metal (lossy)"); - AddCategoryMapping(1719, TorznabCatType.Audio, " |- Black (lossless)"); - AddCategoryMapping(1778, TorznabCatType.Audio, " |- Black (lossy)"); - AddCategoryMapping(1779, TorznabCatType.Audio, " |- Death, Doom (lossless)"); - AddCategoryMapping(1780, TorznabCatType.Audio, " |- Death, Doom (lossy)"); - AddCategoryMapping(1720, TorznabCatType.Audio, " |- Folk, Pagan, Viking (lossless)"); - AddCategoryMapping(798, TorznabCatType.Audio, " |- Folk, Pagan, Viking (lossy)"); - AddCategoryMapping(1724, TorznabCatType.Audio, " |- Gothic Metal (lossless)"); - AddCategoryMapping(1725, TorznabCatType.Audio, " |- Gothic Metal (lossy)"); - AddCategoryMapping(1730, TorznabCatType.Audio, " |- Grind, Brutal Death (lossless)"); - AddCategoryMapping(1731, TorznabCatType.Audio, " |- Grind, Brutal Death (lossy)"); - AddCategoryMapping(1726, TorznabCatType.Audio, " |- Heavy, Power, Progressive (lossless)"); - AddCategoryMapping(1727, TorznabCatType.Audio, " |- Heavy, Power, Progressive (lossy)"); - AddCategoryMapping(1815, TorznabCatType.Audio, " |- Sludge, Stoner, Post-Metal (lossless)"); - AddCategoryMapping(1816, TorznabCatType.Audio, " |- Sludge, Stoner, Post-Metal (lossy)"); - AddCategoryMapping(1728, TorznabCatType.Audio, " |- Thrash, Speed (lossless)"); - AddCategoryMapping(1729, TorznabCatType.Audio, " |- Thrash, Speed (lossy)"); - AddCategoryMapping(2230, TorznabCatType.Audio, " | - Compilations (lossless)"); - AddCategoryMapping(2231, TorznabCatType.Audio, " | - Compilations (lossy)"); - AddCategoryMapping(1732, TorznabCatType.Audio, "Foreign Alternative, Punk, Independent"); - AddCategoryMapping(1736, TorznabCatType.Audio, " |- Alternative & Nu-metal (lossless)"); - AddCategoryMapping(1737, TorznabCatType.Audio, " |- Alternative & Nu-metal (lossy)"); - AddCategoryMapping(1738, TorznabCatType.Audio, " |- Punk (lossless)"); - AddCategoryMapping(1739, TorznabCatType.Audio, " |- Punk (lossy)"); - AddCategoryMapping(1740, TorznabCatType.Audio, " |- Hardcore (lossless)"); - AddCategoryMapping(1741, TorznabCatType.Audio, " |- Hardcore (lossy)"); - AddCategoryMapping(1742, TorznabCatType.Audio, " |- Indie, Post-Rock & Post-Punk (lossless)"); - AddCategoryMapping(1743, TorznabCatType.Audio, " |- Indie, Post-Rock & Post-Punk (lossy)"); - AddCategoryMapping(1744, TorznabCatType.Audio, " |- Industrial & Post-industrial (lossless)"); - AddCategoryMapping(1745, TorznabCatType.Audio, " |- Industrial & Post-industrial (lossy)"); - AddCategoryMapping(1746, TorznabCatType.Audio, " |- Emocore, Post-hardcore, Metalcore (lossless)"); - AddCategoryMapping(1747, TorznabCatType.Audio, " |- Emocore, Post-hardcore, Metalcore (lossy)"); - AddCategoryMapping(1748, TorznabCatType.Audio, " |- Gothic Rock & Dark Folk (lossless)"); - AddCategoryMapping(1749, TorznabCatType.Audio, " |- Gothic Rock & Dark Folk (lossy)"); - AddCategoryMapping(2175, TorznabCatType.Audio, " |- Avant-garde, Experimental Rock (lossless)"); - AddCategoryMapping(2174, TorznabCatType.Audio, " |- Avant-garde, Experimental Rock (lossy)"); - AddCategoryMapping(722, TorznabCatType.Audio, "Domestic Rock"); - AddCategoryMapping(737, TorznabCatType.Audio, " | - Rock, Punk, Alternative (lossless)"); - AddCategoryMapping(738, TorznabCatType.Audio, " | - Rock, Punk, Alternative (lossy)"); - AddCategoryMapping(739, TorznabCatType.Audio, " |- Металл (lossless)"); - AddCategoryMapping(740, TorznabCatType.Audio, " |- Металл (lossy)"); - AddCategoryMapping(951, TorznabCatType.Audio, " | - Rock in the languages ​​of xUSSR (lossless)"); - AddCategoryMapping(952, TorznabCatType.Audio, " | - Rock in the languages ​​of xUSSR (lossy)"); - AddCategoryMapping(1752, TorznabCatType.Audio, "The multi-channel music and own digitization (Rock)"); - AddCategoryMapping(1756, TorznabCatType.Audio, " | - Foreign rock (own digitization)"); - AddCategoryMapping(1758, TorznabCatType.Audio, " | - Domestic Rock (own digitization)"); - AddCategoryMapping(1757, TorznabCatType.Audio, " | - Multi-channel music (rock)"); - AddCategoryMapping(1755, TorznabCatType.Audio, " |- Hi-Res stereo (рок)"); - AddCategoryMapping(453, TorznabCatType.Audio, " | - Conversions Quadraphonic (multichannel music)"); - AddCategoryMapping(1170, TorznabCatType.Audio, " | - Conversions SACD (multi-channel music)"); - AddCategoryMapping(1759, TorznabCatType.Audio, " | - Conversions from the Blu-Ray (multichannel music)"); - AddCategoryMapping(1852, TorznabCatType.Audio, " |- Апмиксы-Upmixes/Даунмиксы-Downmix (многоканальная и Hi-R.."); - AddCategoryMapping(1781, TorznabCatType.Audio, "Видео, DVD Video, HD Video (Рок-музыка)"); - AddCategoryMapping(1782, TorznabCatType.Audio, " |- Rock (Видео)"); - AddCategoryMapping(1783, TorznabCatType.Audio, " |- Rock (DVD Video)"); - AddCategoryMapping(2261, TorznabCatType.Audio, " | - Rock (Unofficial DVD Video)"); - AddCategoryMapping(1787, TorznabCatType.Audio, " |- Metal (Видео)"); - AddCategoryMapping(1788, TorznabCatType.Audio, " |- Metal (DVD Video)"); - AddCategoryMapping(2262, TorznabCatType.Audio, " | - Metal (Unofficial DVD Video)"); - AddCategoryMapping(1789, TorznabCatType.Audio, " |- Alternative, Punk, Independent (Видео)"); - AddCategoryMapping(1790, TorznabCatType.Audio, " |- Alternative, Punk, Independent (DVD Video)"); - AddCategoryMapping(2263, TorznabCatType.Audio, " |- Alternative, Punk, Independent (Неофициальные DVD Video)"); - AddCategoryMapping(1791, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative (Video)"); - AddCategoryMapping(1792, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative (DVD Video)"); - AddCategoryMapping(1793, TorznabCatType.Audio, " | - Domestic Metal (Video)"); - AddCategoryMapping(1794, TorznabCatType.Audio, " | - Domestic Metal (DVD Video)"); - AddCategoryMapping(2264, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative, Metal (Neofitsial .."); - AddCategoryMapping(1795, TorznabCatType.Audio, " | - Rock (HD Video)"); - - // Электронная музыка - AddCategoryMapping(1821, TorznabCatType.Audio, "Trance, Goa Trance, Psy-Trance, PsyChill, Ambient, Dub"); - AddCategoryMapping(1844, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance (lossless)"); - AddCategoryMapping(1822, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance (lossy)"); - AddCategoryMapping(1894, TorznabCatType.Audio, " |- PsyChill, Ambient, Dub (lossless)"); - AddCategoryMapping(1895, TorznabCatType.Audio, " |- PsyChill, Ambient, Dub (lossy)"); - AddCategoryMapping(460, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance, PsyChill, Ambient, Dub (Live Set.."); - AddCategoryMapping(1818, TorznabCatType.Audio, " |- Trance (lossless)"); - AddCategoryMapping(1819, TorznabCatType.Audio, " |- Trance (lossy)"); - AddCategoryMapping(1847, TorznabCatType.Audio, " |- Trance (Singles, EPs) (lossy)"); - AddCategoryMapping(1824, TorznabCatType.Audio, " |- Trance (Radioshows, Podcasts, Live Sets, Mixes) (lossy)"); - AddCategoryMapping(1807, TorznabCatType.Audio, "House, Techno, Hardcore, Hardstyle, Jumpstyle"); - AddCategoryMapping(1829, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (lossless)"); - AddCategoryMapping(1830, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (lossy)"); - AddCategoryMapping(1831, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (vinyl, web)"); - AddCategoryMapping(1857, TorznabCatType.Audio, " |- House (lossless)"); - AddCategoryMapping(1859, TorznabCatType.Audio, " |- House (Radioshow, Podcast, Liveset, Mixes)"); - AddCategoryMapping(1858, TorznabCatType.Audio, " |- House (lossy)"); - AddCategoryMapping(840, TorznabCatType.Audio, " | - House (Promorelyzы, collections of)"); - AddCategoryMapping(1860, TorznabCatType.Audio, " |- House (Singles, EPs) (lossy)"); - AddCategoryMapping(1825, TorznabCatType.Audio, " |- Techno (lossless)"); - AddCategoryMapping(1826, TorznabCatType.Audio, " |- Techno (lossy)"); - AddCategoryMapping(1827, TorznabCatType.Audio, " |- Techno (Radioshows, Podcasts, Livesets, Mixes)"); - AddCategoryMapping(1828, TorznabCatType.Audio, " |- Techno (Singles, EPs) (lossy)"); - AddCategoryMapping(1808, TorznabCatType.Audio, "Drum & Bass, Jungle, Breakbeat, Dubstep, IDM, Electro"); - AddCategoryMapping(797, TorznabCatType.Audio, " |- Electro, Electro-Freestyle, Nu Electro (lossless)"); - AddCategoryMapping(1805, TorznabCatType.Audio, " |- Electro, Electro-Freestyle, Nu Electro (lossy)"); - AddCategoryMapping(1832, TorznabCatType.Audio, " |- Drum & Bass, Jungle (lossless)"); - AddCategoryMapping(1833, TorznabCatType.Audio, " |- Drum & Bass, Jungle (lossy)"); - AddCategoryMapping(1834, TorznabCatType.Audio, " |- Drum & Bass, Jungle (Radioshows, Podcasts, Livesets, Mix.."); - AddCategoryMapping(1836, TorznabCatType.Audio, " |- Breakbeat (lossless)"); - AddCategoryMapping(1837, TorznabCatType.Audio, " |- Breakbeat (lossy)"); - AddCategoryMapping(1839, TorznabCatType.Audio, " |- Dubstep (lossless)"); - AddCategoryMapping(454, TorznabCatType.Audio, " |- Dubstep (lossy)"); - AddCategoryMapping(1838, TorznabCatType.Audio, " |- Breakbeat, Dubstep (Radioshows, Podcasts, Livesets, Mixe.."); - AddCategoryMapping(1840, TorznabCatType.Audio, " |- IDM (lossless)"); - AddCategoryMapping(1841, TorznabCatType.Audio, " |- IDM (lossy)"); - AddCategoryMapping(2229, TorznabCatType.Audio, " |- IDM Discography & Collections (lossy)"); - AddCategoryMapping(1809, TorznabCatType.Audio, "Chillout, Lounge, Downtempo, Trip-Hop"); - AddCategoryMapping(1861, TorznabCatType.Audio, " |- Chillout, Lounge, Downtempo (lossless)"); - AddCategoryMapping(1862, TorznabCatType.Audio, " |- Chillout, Lounge, Downtempo (lossy)"); - AddCategoryMapping(1947, TorznabCatType.Audio, " |- Nu Jazz, Acid Jazz, Future Jazz (lossless)"); - AddCategoryMapping(1946, TorznabCatType.Audio, " |- Nu Jazz, Acid Jazz, Future Jazz (lossy)"); - AddCategoryMapping(1945, TorznabCatType.Audio, " |- Trip Hop, Abstract Hip-Hop (lossless)"); - AddCategoryMapping(1944, TorznabCatType.Audio, " |- Trip Hop, Abstract Hip-Hop (lossy)"); - AddCategoryMapping(1810, TorznabCatType.Audio, "Traditional Electronic, Ambient, Modern Classical, Electroac.."); - AddCategoryMapping(1864, TorznabCatType.Audio, " |- Traditional Electronic, Ambient (lossless)"); - AddCategoryMapping(1865, TorznabCatType.Audio, " |- Traditional Electronic, Ambient (lossy)"); - AddCategoryMapping(1871, TorznabCatType.Audio, " |- Modern Classical, Electroacoustic (lossless)"); - AddCategoryMapping(1867, TorznabCatType.Audio, " |- Modern Classical, Electroacoustic (lossy)"); - AddCategoryMapping(1869, TorznabCatType.Audio, " |- Experimental (lossless)"); - AddCategoryMapping(1873, TorznabCatType.Audio, " |- Experimental (lossy)"); - AddCategoryMapping(1907, TorznabCatType.Audio, " |- 8-bit, Chiptune (lossy & lossless)"); - AddCategoryMapping(1811, TorznabCatType.Audio, "Industrial, Noise, EBM, Dark Electro, Aggrotech, Synthpop, N.."); - AddCategoryMapping(1868, TorznabCatType.Audio, " | - EBM, Dark Electro, Aggrotech (lossless)"); - AddCategoryMapping(1875, TorznabCatType.Audio, " | - EBM, Dark Electro, Aggrotech (lossy)"); - AddCategoryMapping(1877, TorznabCatType.Audio, " |- Industrial, Noise (lossless)"); - AddCategoryMapping(1878, TorznabCatType.Audio, " |- Industrial, Noise (lossy)"); - AddCategoryMapping(1880, TorznabCatType.Audio, " |- Synthpop, New Wave (lossless)"); - AddCategoryMapping(1881, TorznabCatType.Audio, " |- Synthpop, New Wave (lossy)"); - AddCategoryMapping(1866, TorznabCatType.Audio, " |- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossles.."); - AddCategoryMapping(406, TorznabCatType.Audio, " |- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossy)"); - AddCategoryMapping(1842, TorznabCatType.Audio, "Label Packs (lossless)"); - AddCategoryMapping(1648, TorznabCatType.Audio, "Label packs, Scene packs (lossy)"); - AddCategoryMapping(1812, TorznabCatType.Audio, "Электронная музыка (Видео, DVD Video/Audio, HD Video, DTS, S.."); - AddCategoryMapping(1886, TorznabCatType.Audio, " | - Electronic music (Official DVD Video)"); - AddCategoryMapping(1887, TorznabCatType.Audio, " | - Electronic music (Informal amateur DVD Vide .."); - AddCategoryMapping(1912, TorznabCatType.Audio, " | - Electronic music (Video)"); - AddCategoryMapping(1893, TorznabCatType.Audio, " | - Hi-Res stereo (electronic music)"); - AddCategoryMapping(1890, TorznabCatType.Audio, " | - Multi-channel music (electronic music)"); - AddCategoryMapping(1913, TorznabCatType.Audio, " | - Electronic music (HD Video)"); - AddCategoryMapping(1754, TorznabCatType.Audio, " | - Electronic music (own digitization)"); - - // Игры - AddCategoryMapping(5, TorznabCatType.PCGames, "Games for Windows (download)"); - AddCategoryMapping(635, TorznabCatType.PCGames, " | - Hot New Releases"); - AddCategoryMapping(127, TorznabCatType.PCGames, " | - Arcade"); - AddCategoryMapping(2204, TorznabCatType.PCGames, " | - Puzzle Games"); - AddCategoryMapping(53, TorznabCatType.PCGames, " | - Adventure and quests"); - AddCategoryMapping(1008, TorznabCatType.PCGames, " | - Quest-style \"search objects\""); - AddCategoryMapping(51, TorznabCatType.PCGames, " | - Strategy"); - AddCategoryMapping(961, TorznabCatType.PCGames, " | - Space and flight simulators"); - AddCategoryMapping(962, TorznabCatType.PCGames, " | - Autos and Racing"); - AddCategoryMapping(2187, TorznabCatType.PCGames, " | - Racing Simulators"); - AddCategoryMapping(54, TorznabCatType.PCGames, " | - Other simulators"); - AddCategoryMapping(55, TorznabCatType.PCGames, " |- Action"); - AddCategoryMapping(2203, TorznabCatType.PCGames, " | - Fighting"); - AddCategoryMapping(52, TorznabCatType.PCGames, " |- RPG"); - AddCategoryMapping(900, TorznabCatType.PCGames, " | - Anime games"); - AddCategoryMapping(246, TorznabCatType.PCGames, " | - Erotic Games"); - AddCategoryMapping(278, TorznabCatType.PCGames, " | - Chess"); - AddCategoryMapping(128, TorznabCatType.PCGames, " | - For the little ones"); - AddCategoryMapping(637, TorznabCatType.PCGames, "Old Games"); - AddCategoryMapping(642, TorznabCatType.PCGames, " | - Arcade (Old Games)"); - AddCategoryMapping(2385, TorznabCatType.PCGames, " | - Puzzle games (old games)"); - AddCategoryMapping(643, TorznabCatType.PCGames, " | - Adventure and quests (Old Games)"); - AddCategoryMapping(644, TorznabCatType.PCGames, " | - Strategies (Old Games)"); - AddCategoryMapping(2226, TorznabCatType.PCGames, " | - Space and flight simulators (Old Games)"); - AddCategoryMapping(2227, TorznabCatType.PCGames, " | - Autos and Racing (Old Games)"); - AddCategoryMapping(2225, TorznabCatType.PCGames, " | - Racing Simulators (Old Games)"); - AddCategoryMapping(645, TorznabCatType.PCGames, " | - Other simulators (Old Games)"); - AddCategoryMapping(646, TorznabCatType.PCGames, " | - Action (Old Games)"); - AddCategoryMapping(647, TorznabCatType.PCGames, " | - RPG (Old Games)"); - AddCategoryMapping(649, TorznabCatType.PCGames, " | - Erotic Games (Old Games)"); - AddCategoryMapping(650, TorznabCatType.PCGames, " | - For the little ones (Old Games)"); - AddCategoryMapping(1098, TorznabCatType.PCGames, " | - Game Collection (Old Games)"); - AddCategoryMapping(2228, TorznabCatType.PCGames, " | - IBM PC incompatible (Old Games)"); - AddCategoryMapping(2115, TorznabCatType.PCGames, "Online Games"); - AddCategoryMapping(2117, TorznabCatType.PCGames, " |- World of Warcraft"); - AddCategoryMapping(2155, TorznabCatType.PCGames, " |- Lineage II"); - AddCategoryMapping(2118, TorznabCatType.PCGames, " | - MMO (Official)"); - AddCategoryMapping(2119, TorznabCatType.PCGames, " | - MMO (Neoficialʹnye)"); - AddCategoryMapping(2489, TorznabCatType.PCGames, " | - Multiplayer games"); - AddCategoryMapping(2142, TorznabCatType.PCGames, "Microsoft Flight Simulator add-ons, and for him"); - AddCategoryMapping(2143, TorznabCatType.PCGames, " | - Scripts, meshes and airports [FS2004]"); - AddCategoryMapping(2060, TorznabCatType.PCGames, " |- Сценарии (FSX-P3D)"); - AddCategoryMapping(2145, TorznabCatType.PCGames, " | - Aircraft [FS2004]"); - AddCategoryMapping(2012, TorznabCatType.PCGames, " | - Planes, helicopters (FSX-P3D)"); - AddCategoryMapping(2146, TorznabCatType.PCGames, " | - Mission, traffic sounds, packs and tools"); - AddCategoryMapping(139, TorznabCatType.PCGames, "Others for Windows-based games"); - AddCategoryMapping(2478, TorznabCatType.PCGames, " | - Official patches"); - AddCategoryMapping(2479, TorznabCatType.PCGames, " | - Official Fashion, plug-ins, add-ons"); - AddCategoryMapping(2480, TorznabCatType.PCGames, " | - Informal fashion, plugins, add-ons"); - AddCategoryMapping(2481, TorznabCatType.PCGames, " | - Fun"); - AddCategoryMapping(761, TorznabCatType.PCGames, " | - Editors, emulators and other gaming utility"); - AddCategoryMapping(2482, TorznabCatType.PCGames, " |- NoCD / NoDVD"); - AddCategoryMapping(2533, TorznabCatType.PCGames, " | - Conservation games"); - AddCategoryMapping(2483, TorznabCatType.PCGames, " | - Cheat program and trainers"); - AddCategoryMapping(2484, TorznabCatType.PCGames, " | - Guides and passing"); - AddCategoryMapping(2485, TorznabCatType.PCGames, " | - The bonus discs for games"); - AddCategoryMapping(240, TorznabCatType.PCGames, "video Game"); - AddCategoryMapping(2415, TorznabCatType.PCGames, " | - Walkthroughs"); - AddCategoryMapping(2067, TorznabCatType.PCGames, " |- Lineage II Movies"); - AddCategoryMapping(2147, TorznabCatType.PCGames, " |- World of Warcraft Movies"); - AddCategoryMapping(960, TorznabCatType.PCGames, " |- Counter Strike Movies"); - AddCategoryMapping(548, TorznabCatType.Console, "Games for consoles"); - AddCategoryMapping(129, TorznabCatType.Console, " | - Portable and Console (Games)"); - AddCategoryMapping(908, TorznabCatType.ConsolePS3, " |- PS"); - AddCategoryMapping(357, TorznabCatType.ConsolePS3, " |- PS2"); - AddCategoryMapping(886, TorznabCatType.ConsolePS3, " |- PS3"); - AddCategoryMapping(1352, TorznabCatType.ConsolePSP, " |- PSP"); - AddCategoryMapping(1116, TorznabCatType.ConsolePSP, " | - PS1 games for PSP"); - AddCategoryMapping(973, TorznabCatType.ConsolePSVita, " |- PSVITA"); - AddCategoryMapping(887, TorznabCatType.ConsoleXbox, " | - Original Xbox"); - AddCategoryMapping(510, TorznabCatType.ConsoleXbox360, " |- Xbox 360"); - AddCategoryMapping(773, TorznabCatType.ConsoleWii, " |- Wii"); - AddCategoryMapping(774, TorznabCatType.ConsoleNDS, " |- NDS"); - AddCategoryMapping(968, TorznabCatType.ConsoleOther, " |- Dreamcast"); - AddCategoryMapping(546, TorznabCatType.ConsoleOther, " | - Games for the DVD player"); - AddCategoryMapping(2185, TorznabCatType.Console, "Video consoles"); - AddCategoryMapping(2487, TorznabCatType.ConsolePSVita, " | - Video for PSVita"); - AddCategoryMapping(2182, TorznabCatType.ConsolePSP, " | - Movies for PSP"); - AddCategoryMapping(2181, TorznabCatType.ConsolePSP, " | - For PSP TV Shows"); - AddCategoryMapping(2180, TorznabCatType.ConsolePSP, " | - Cartoons for PSP"); - AddCategoryMapping(2179, TorznabCatType.ConsolePSP, " | - Drama for PSP"); - AddCategoryMapping(2186, TorznabCatType.ConsolePSP, " | - Anime for PSP"); - AddCategoryMapping(700, TorznabCatType.ConsolePSP, " | - Video to PSP"); - AddCategoryMapping(1926, TorznabCatType.ConsolePS3, " | - Videos for the PS3 and other consoles"); - AddCategoryMapping(899, TorznabCatType.PCGames, "Games for Linux"); - AddCategoryMapping(1992, TorznabCatType.PCGames, " | - Native games for Linux"); - AddCategoryMapping(2059, TorznabCatType.PCGames, " | - Game Ported to Linux"); - - // Программы и Дизайн - AddCategoryMapping(1012, TorznabCatType.PC0day, "Operating systems from Microsoft"); - AddCategoryMapping(1019, TorznabCatType.PC0day, " | - Desktop operating system from Microsoft (released prior to Windows XP)"); - AddCategoryMapping(2153, TorznabCatType.PC0day, " | - Desktop operating system from Microsoft (since Windows XP)"); - AddCategoryMapping(1021, TorznabCatType.PC0day, " | - Server operating system from Microsoft"); - AddCategoryMapping(1025, TorznabCatType.PC0day, " | - Other (Operating Systems from Microsoft)"); - AddCategoryMapping(1376, TorznabCatType.PC0day, "Linux, Unix and other operating systems"); - AddCategoryMapping(1379, TorznabCatType.PC0day, " | - Operating Systems (Linux, Unix)"); - AddCategoryMapping(1381, TorznabCatType.PC0day, " | - Software (Linux, Unix)"); - AddCategoryMapping(1473, TorznabCatType.PC0day, " | - Other operating systems and software for them"); - AddCategoryMapping(1195, TorznabCatType.PC0day, "Test drives to adjust the audio / video equipment"); - AddCategoryMapping(1013, TorznabCatType.PC0day, "System programs"); - AddCategoryMapping(1028, TorznabCatType.PC0day, " | - Work with hard drive"); - AddCategoryMapping(1029, TorznabCatType.PC0day, " | - Backup"); - AddCategoryMapping(1030, TorznabCatType.PC0day, " | - Archivers and File Managers"); - AddCategoryMapping(1031, TorznabCatType.PC0day, " | - Software to configure and optimize the operating system"); - AddCategoryMapping(1032, TorznabCatType.PC0day, " | - Service computer service"); - AddCategoryMapping(1033, TorznabCatType.PC0day, " | - Work with data carriers"); - AddCategoryMapping(1034, TorznabCatType.PC0day, " | - Information and Diagnostics"); - AddCategoryMapping(1066, TorznabCatType.PC0day, " | - Software for Internet and networks"); - AddCategoryMapping(1035, TorznabCatType.PC0day, " | - Software to protect your computer (antivirus software, firewalls)"); - AddCategoryMapping(1038, TorznabCatType.PC0day, " | - Anti-spyware and anti-trojan"); - AddCategoryMapping(1039, TorznabCatType.PC0day, " | - Software to protect information"); - AddCategoryMapping(1536, TorznabCatType.PC0day, " | - Drivers and Firmware"); - AddCategoryMapping(1051, TorznabCatType.PC0day, " | - The original disks to computers and accessories"); - AddCategoryMapping(1040, TorznabCatType.PC0day, " | - Server software for Windows"); - AddCategoryMapping(1041, TorznabCatType.PC0day, " | - Change the Windows interface"); - AddCategoryMapping(1636, TorznabCatType.PC0day, " | - Screensavers"); - AddCategoryMapping(1042, TorznabCatType.PC0day, " | - Other (System programs on Windows)"); - AddCategoryMapping(1014, TorznabCatType.PC0day, "Systems for business, office, research and project work"); - AddCategoryMapping(1060, TorznabCatType.PC0day, " | - Everything for the home: dressmaking, sewing, cooking"); - AddCategoryMapping(1061, TorznabCatType.PC0day, " | - Office Systems"); - AddCategoryMapping(1062, TorznabCatType.PC0day, " | - Business Systems"); - AddCategoryMapping(1067, TorznabCatType.PC0day, " | - Recognition of text, sound and speech synthesis"); - AddCategoryMapping(1086, TorznabCatType.PC0day, " | - Work with PDF and DjVu"); - AddCategoryMapping(1068, TorznabCatType.PC0day, " | - Dictionaries, translators"); - AddCategoryMapping(1063, TorznabCatType.PC0day, " | - System for scientific work"); - AddCategoryMapping(1087, TorznabCatType.PC0day, " | - CAD (general and engineering)"); - AddCategoryMapping(1192, TorznabCatType.PC0day, " | - CAD (electronics, automation, GAP)"); - AddCategoryMapping(1088, TorznabCatType.PC0day, " | - Software for architects and builders"); - AddCategoryMapping(1193, TorznabCatType.PC0day, " | - Library and projects for architects and designers inter .."); - AddCategoryMapping(1071, TorznabCatType.PC0day, " | - Other reference systems"); - AddCategoryMapping(1073, TorznabCatType.PC0day, " | - Miscellaneous (business systems, office, research and design .."); - AddCategoryMapping(1052, TorznabCatType.PC0day, "Web Development and Programming"); - AddCategoryMapping(1053, TorznabCatType.PC0day, " | - WYSIWYG editors for web diz"); - AddCategoryMapping(1054, TorznabCatType.PC0day, " | - Text editors Illuminated"); - AddCategoryMapping(1055, TorznabCatType.PC0day, " | - Programming environments, compilers and support, etc. .."); - AddCategoryMapping(1056, TorznabCatType.PC0day, " | - Components for programming environments"); - AddCategoryMapping(2077, TorznabCatType.PC0day, " | - Database Management Systems"); - AddCategoryMapping(1057, TorznabCatType.PC0day, " | - Scripts and engines sites, CMS and extensions to it"); - AddCategoryMapping(1018, TorznabCatType.PC0day, " | - Templates for websites and CMS"); - AddCategoryMapping(1058, TorznabCatType.PC0day, " | - Miscellaneous (Web Development and Programming)"); - AddCategoryMapping(1016, TorznabCatType.PC0day, "Programs to work with multimedia and 3D"); - AddCategoryMapping(1079, TorznabCatType.PC0day, " | - Software Kits"); - AddCategoryMapping(1080, TorznabCatType.PC0day, " | - Plug-ins for Adobe's programs"); - AddCategoryMapping(1081, TorznabCatType.PC0day, " | - Graphic Editors"); - AddCategoryMapping(1082, TorznabCatType.PC0day, " | - Software for typesetting, printing, and working with fonts"); - AddCategoryMapping(1083, TorznabCatType.PC0day, " | - 3D modeling, rendering and plugins for them"); - AddCategoryMapping(1084, TorznabCatType.PC0day, " | - Animation"); - AddCategoryMapping(1085, TorznabCatType.PC0day, " | - Creating a BD / HD / DVD-Video"); - AddCategoryMapping(1089, TorznabCatType.PC0day, " | - Video Editors"); - AddCategoryMapping(1090, TorznabCatType.PC0day, " | - Video converters Audio"); - AddCategoryMapping(1065, TorznabCatType.PC0day, " | - Audio and video, CD- players and catalogers"); - AddCategoryMapping(1064, TorznabCatType.PC0day, " | - Cataloging and graphics viewers"); - AddCategoryMapping(1092, TorznabCatType.PC0day, " | - Miscellaneous (Programme for multimedia and 3D)"); - AddCategoryMapping(1204, TorznabCatType.PC0day, " | - Virtual Studios, sequencers and audio editor"); - AddCategoryMapping(1027, TorznabCatType.PC0day, " | - Virtual Instruments & Synthesizers"); - AddCategoryMapping(1199, TorznabCatType.PC0day, " | - Plug-ins for sound processing"); - AddCategoryMapping(1091, TorznabCatType.PC0day, " | - Miscellaneous (Programs for working with audio)"); - AddCategoryMapping(828, TorznabCatType.PC0day, "Materials for Multimedia and Design"); - AddCategoryMapping(1357, TorznabCatType.PC0day, " | - Authoring"); - AddCategoryMapping(890, TorznabCatType.PC0day, " | - Official compilations vector clipart"); - AddCategoryMapping(830, TorznabCatType.PC0day, " | - Other vector cliparts"); - AddCategoryMapping(1290, TorznabCatType.PC0day, " |- Photostoсks"); - AddCategoryMapping(1962, TorznabCatType.PC0day, " | - Photoshop Costumes"); - AddCategoryMapping(831, TorznabCatType.PC0day, " | - Frames and Vignettes for processing photos"); - AddCategoryMapping(829, TorznabCatType.PC0day, " | - Other raster clipart"); - AddCategoryMapping(633, TorznabCatType.PC0day, " | - 3D models, scenes and materials"); - AddCategoryMapping(1009, TorznabCatType.PC0day, " | - Footage"); - AddCategoryMapping(1963, TorznabCatType.PC0day, " | - Other collections footage"); - AddCategoryMapping(1954, TorznabCatType.PC0day, " | - Music Library"); - AddCategoryMapping(1010, TorznabCatType.PC0day, " | - Sound Effects"); - AddCategoryMapping(1674, TorznabCatType.PC0day, " | - Sample Libraries"); - AddCategoryMapping(2421, TorznabCatType.PC0day, " | - Library and saundbanki for samplers, presets for sy .."); - AddCategoryMapping(2492, TorznabCatType.PC0day, " |- Multitracks"); - AddCategoryMapping(839, TorznabCatType.PC0day, " | - Materials for creating menus and DVD covers"); - AddCategoryMapping(1679, TorznabCatType.PC0day, " | - Styles, brushes, shapes and patterns for Adobe Photoshop"); - AddCategoryMapping(1011, TorznabCatType.PC0day, " | - Fonts"); - AddCategoryMapping(835, TorznabCatType.PC0day, " | - Miscellaneous (Materials for Multimedia and Design)"); - AddCategoryMapping(1503, TorznabCatType.PC0day, "GIS, navigation systems and maps"); - AddCategoryMapping(1507, TorznabCatType.PC0day, " | - GIS (Geoinformatsionnыe sistemы)"); - AddCategoryMapping(1526, TorznabCatType.PC0day, " | - Maps provided with the program shell"); - AddCategoryMapping(1508, TorznabCatType.PC0day, " | - Atlases and maps modern (after 1950)"); - AddCategoryMapping(1509, TorznabCatType.PC0day, " | - Atlases and antique maps (up to 1950)"); - AddCategoryMapping(1510, TorznabCatType.PC0day, " | - Other Maps (astronomical, historical, topically .."); - AddCategoryMapping(1511, TorznabCatType.PC0day, " | - Built-in car navigation"); - AddCategoryMapping(1512, TorznabCatType.PC0day, " |- Garmin"); - AddCategoryMapping(1513, TorznabCatType.PC0day, " | -"); - AddCategoryMapping(1514, TorznabCatType.PC0day, " |- TomTom"); - AddCategoryMapping(1515, TorznabCatType.PC0day, " |- Navigon / Navitel"); - AddCategoryMapping(1516, TorznabCatType.PC0day, " |- Igo"); - AddCategoryMapping(1517, TorznabCatType.PC0day, " | - Miscellaneous - navigation and maps"); - - // Мобильные устройства - AddCategoryMapping(285, TorznabCatType.PCPhoneOther, "Games, applications and so on. Mobile"); - AddCategoryMapping(2149, TorznabCatType.PCPhoneAndroid, " | - Games for Android OS"); - AddCategoryMapping(2154, TorznabCatType.PCPhoneAndroid, " | - Applications for Android OS"); - AddCategoryMapping(2419, TorznabCatType.PCPhoneOther, " | - Applications for Windows Phone 7,8"); - AddCategoryMapping(2420, TorznabCatType.PCPhoneOther, " | - Games for Windows Phone 7,8"); - AddCategoryMapping(1004, TorznabCatType.PCPhoneOther, " | - Games for Symbian"); - AddCategoryMapping(289, TorznabCatType.PCPhoneOther, " | - Applications for Symbian"); - AddCategoryMapping(1001, TorznabCatType.PCPhoneOther, " | - Games for Java"); - AddCategoryMapping(1005, TorznabCatType.PCPhoneOther, " | - Applications for Java"); - AddCategoryMapping(1002, TorznabCatType.PCPhoneOther, " | - Games for Windows Mobile, Palm OS, BlackBerry and so on."); - AddCategoryMapping(290, TorznabCatType.PCPhoneOther, " | - Applications for Windows Mobile, Palm OS, BlackBerry and so on."); - AddCategoryMapping(288, TorznabCatType.PCPhoneOther, " | - Software for your phone"); - AddCategoryMapping(292, TorznabCatType.PCPhoneOther, " | - Firmware for phones"); - AddCategoryMapping(291, TorznabCatType.PCPhoneOther, " | - Wallpapers and Themes"); - AddCategoryMapping(957, TorznabCatType.PCPhoneOther, "Video for mobile devices"); - AddCategoryMapping(287, TorznabCatType.PCPhoneOther, " | - Video for Smartphones and PDAs"); - AddCategoryMapping(286, TorznabCatType.PCPhoneOther, " | - Mobile Video (3GP)"); - - // Apple - AddCategoryMapping(1366, TorznabCatType.PCMac, "Apple Macintosh"); - AddCategoryMapping(1368, TorznabCatType.PCMac, " |- Mac OS (для Macintosh)"); - AddCategoryMapping(1383, TorznabCatType.PCMac, " | - Mac OS (for RS-Hakintoš)"); - AddCategoryMapping(537, TorznabCatType.PCMac, " | - Game Mac OS"); - AddCategoryMapping(1394, TorznabCatType.PCMac, " | - Software for viewing and video processing"); - AddCategoryMapping(1370, TorznabCatType.PCMac, " | - Software to build and graphics processing"); - AddCategoryMapping(2237, TorznabCatType.PCMac, " | - Plug-ins for Adobe's programs"); - AddCategoryMapping(1372, TorznabCatType.PCMac, " | - Audio editor and converter"); - AddCategoryMapping(1373, TorznabCatType.PCMac, " | - System software"); - AddCategoryMapping(1375, TorznabCatType.PCMac, " | - Office software"); - AddCategoryMapping(1371, TorznabCatType.PCMac, " | - Software for the Internet and network"); - AddCategoryMapping(1374, TorznabCatType.PCMac, " | - Other software"); - AddCategoryMapping(1933, TorznabCatType.PCMac, "iOS"); - AddCategoryMapping(1935, TorznabCatType.PCMac, " | - Software for iOS"); - AddCategoryMapping(1003, TorznabCatType.PCMac, " | - Games for iOS"); - AddCategoryMapping(1937, TorznabCatType.PCMac, " | - Miscellaneous for iOS"); - AddCategoryMapping(2235, TorznabCatType.PCMac, "Video"); - AddCategoryMapping(1908, TorznabCatType.PCMac, " | - Movies for iPod, iPhone, iPad"); - AddCategoryMapping(864, TorznabCatType.PCMac, " | - TV Shows for iPod, iPhone, iPad"); - AddCategoryMapping(863, TorznabCatType.PCMac, " | - Cartoons for iPod, iPhone, iPad"); - AddCategoryMapping(2535, TorznabCatType.PCMac, " | - Anime for iPod, iPhone, iPad"); - AddCategoryMapping(2534, TorznabCatType.PCMac, " | - The music video to iPod, iPhone, iPad"); - AddCategoryMapping(2238, TorznabCatType.PCMac, "Видео HD"); - AddCategoryMapping(1936, TorznabCatType.PCMac, " | - HD Movies to Apple TV"); - AddCategoryMapping(315, TorznabCatType.PCMac, " | - HD TV Shows on Apple TV"); - AddCategoryMapping(1363, TorznabCatType.PCMac, " | - HD Animation for Apple TV"); - AddCategoryMapping(2082, TorznabCatType.PCMac, " | - Documentary HD video for Apple TV"); - AddCategoryMapping(2241, TorznabCatType.PCMac, " | - Musical HD video for Apple TV"); - AddCategoryMapping(2236, TorznabCatType.PCMac, "audio"); - AddCategoryMapping(1909, TorznabCatType.PCMac, " | - Audiobooks (AAC, ALAC)"); - AddCategoryMapping(1927, TorznabCatType.PCMac, " | - Music Lossless (ALAC)"); - AddCategoryMapping(2240, TorznabCatType.PCMac, " |- Музыка Lossy (AAC-iTunes)"); - AddCategoryMapping(2248, TorznabCatType.PCMac, " |- Музыка Lossy (AAC)"); - AddCategoryMapping(2244, TorznabCatType.PCMac, " |- Музыка Lossy (AAC) (Singles, EPs)"); - AddCategoryMapping(2243, TorznabCatType.PCMac, "F.A.Q."); - - // Медицина и здоровье - AddCategoryMapping(2125, TorznabCatType.Books, "Books, magazines and programs"); - AddCategoryMapping(2133, TorznabCatType.Books, " | - Clinical Medicine until 1980"); - AddCategoryMapping(2130, TorznabCatType.Books, " | - Clinical Medicine from 1980 to 2000"); - AddCategoryMapping(2313, TorznabCatType.Books, " | - Clinical Medicine since 2000"); - AddCategoryMapping(2314, TorznabCatType.Books, " | - Popular medical periodicals (newspapers and magazines)"); - AddCategoryMapping(2528, TorznabCatType.Books, " | - Scientific medical periodicals (newspapers and magazines)"); - AddCategoryMapping(2129, TorznabCatType.Books, " | - Life Sciences"); - AddCategoryMapping(2141, TorznabCatType.Books, " | - Pharmacy and Pharmacology"); - AddCategoryMapping(2132, TorznabCatType.Books, " | - Non-traditional, traditional medicine and popular books on the s .."); - AddCategoryMapping(2131, TorznabCatType.Books, " | - Veterinary Medicine, Miscellaneous"); - AddCategoryMapping(2315, TorznabCatType.Books, " | - Thematic collection of books"); - AddCategoryMapping(1350, TorznabCatType.Books, " | - Audio Books on medicine"); - AddCategoryMapping(2134, TorznabCatType.Books, " | - Medical software"); - AddCategoryMapping(2126, TorznabCatType.Books, "Tutorials, Doc. movies and TV shows on medicine"); - AddCategoryMapping(2135, TorznabCatType.Books, " | - Medicine and Dentistry"); - AddCategoryMapping(2140, TorznabCatType.Books, " | - Psychotherapy and clinical psychology"); - AddCategoryMapping(2136, TorznabCatType.Books, " | - Massage"); - AddCategoryMapping(2138, TorznabCatType.Books, " | - Health"); - AddCategoryMapping(2139, TorznabCatType.Books, " | - Documentary movies and TV shows on medicine"); - - // Разное - AddCategoryMapping(10, TorznabCatType.Other, "Miscellaneous"); - AddCategoryMapping(865, TorznabCatType.Other, " | - Psihoaktivnye audioprogrammy"); - AddCategoryMapping(1100, TorznabCatType.Other, " | - Avatars, Icons, Smileys"); - AddCategoryMapping(1643, TorznabCatType.Other, " | - Painting, Graphics, Sculpture, Digital Art"); - AddCategoryMapping(848, TorznabCatType.Other, " | - Pictures"); - AddCategoryMapping(808, TorznabCatType.Other, " | - Amateur Photos"); - AddCategoryMapping(630, TorznabCatType.Other, " | - Wallpapers"); - AddCategoryMapping(1664, TorznabCatType.Other, " | - Celebrity Photos"); - AddCategoryMapping(148, TorznabCatType.Other, " | - Audio"); - AddCategoryMapping(807, TorznabCatType.Other, " | - Video"); - AddCategoryMapping(147, TorznabCatType.Other, " | - Publications and educational materials (texts)"); - AddCategoryMapping(847, TorznabCatType.Other, " | - Trailers and additional materials for films"); + Language = "ru-ru"; + Type = "semi-private"; + + // Новости + AddCategoryMapping(2317, TorznabCatType.Other, "NEW YEAR'S SECTION"); + AddCategoryMapping(1241, TorznabCatType.Other, " | - New competitions"); + AddCategoryMapping(2338, TorznabCatType.TV, " | - Entertainment shows and Documentaries"); + AddCategoryMapping(1464, TorznabCatType.Movies, " | - Movies and Cartoons"); + AddCategoryMapping(860, TorznabCatType.Books, " | - Books, Journals, Notes"); + AddCategoryMapping(1340, TorznabCatType.Audio, " | - Music"); + AddCategoryMapping(1346, TorznabCatType.AudioVideo, " | - Music video"); + AddCategoryMapping(1239, TorznabCatType.Console, " | - Games"); + AddCategoryMapping(1299, TorznabCatType.Other, " | - Miscellaneous (postcards, wallpapers, video, etc.)."); + AddCategoryMapping(1289, TorznabCatType.Other, "Rutracker Awards (events and competitions)"); + AddCategoryMapping(1579, TorznabCatType.Other, "| - Photo club. The whole world is in the palm of your hand."); + AddCategoryMapping(2214, TorznabCatType.Other, " | - Rutracker Awards (distribution)"); + + // Кино, Видео и ТВ + AddCategoryMapping(7, TorznabCatType.MoviesForeign, "Foreign movies"); + AddCategoryMapping(187, TorznabCatType.MoviesForeign, " | - Classic of world cinema"); + AddCategoryMapping(2090, TorznabCatType.MoviesForeign, " | - Movies before 1990"); + AddCategoryMapping(2221, TorznabCatType.MoviesForeign, " | - Movies 1991-2000"); + AddCategoryMapping(2091, TorznabCatType.MoviesForeign, " | - Movies 2001-2005"); + AddCategoryMapping(2092, TorznabCatType.MoviesForeign, " | - Movies 2006-2010"); + AddCategoryMapping(2093, TorznabCatType.MoviesForeign, " | - Movies 2011-2015"); + AddCategoryMapping(2200, TorznabCatType.MoviesForeign, " | - Movies 2016"); + AddCategoryMapping(934, TorznabCatType.MoviesForeign, " | - Asian movies"); + AddCategoryMapping(505, TorznabCatType.MoviesForeign, " | - Indian Cinema"); + AddCategoryMapping(212, TorznabCatType.MoviesForeign, " | - Movie Collections"); + AddCategoryMapping(2459, TorznabCatType.MoviesForeign, " | - Shorts"); + AddCategoryMapping(1235, TorznabCatType.MoviesForeign, " | - Grindhouse"); + AddCategoryMapping(185, TorznabCatType.MoviesForeign, " | - Soundtracks and Translations"); + AddCategoryMapping(22, TorznabCatType.Movies, "our film"); + AddCategoryMapping(941, TorznabCatType.Movies, " | - Cinema of the USSR"); + AddCategoryMapping(1666, TorznabCatType.Movies, " | - Children's domestic films"); + AddCategoryMapping(376, TorznabCatType.Movies, " | - Author Debuts"); + AddCategoryMapping(124, TorznabCatType.Movies, "Art-house cinema and author"); + AddCategoryMapping(1543, TorznabCatType.Movies, " | - Shorts (Art-house cinema and author)"); + AddCategoryMapping(709, TorznabCatType.Movies, " | - Documentaries (Art-house cinema and author)"); + AddCategoryMapping(1577, TorznabCatType.Movies, " | - Animation (Art-house cinema and author)"); + AddCategoryMapping(511, TorznabCatType.Movies, "Theater"); + AddCategoryMapping(656, TorznabCatType.Movies, "| - Benefit. Master of Arts domestic theater and cinema"); + AddCategoryMapping(93, TorznabCatType.Movies, "DVD Video"); + AddCategoryMapping(905, TorznabCatType.Movies, " | - Classic of world cinema (DVD Video)"); + AddCategoryMapping(1576, TorznabCatType.Movies, " | - Asian movies (DVD Video)"); + AddCategoryMapping(101, TorznabCatType.Movies, " | - Foreign movies (DVD)"); + AddCategoryMapping(100, TorznabCatType.Movies, " | - Our cinema (DVD)"); + AddCategoryMapping(572, TorznabCatType.Movies, " | - Art-house and auteur cinema (DVD)"); + AddCategoryMapping(2220, TorznabCatType.Movies, " | - Indian Cinema DVD and HD Video"); + AddCategoryMapping(1670, TorznabCatType.Movies, " |- Грайндхаус DVD и HD Video"); + AddCategoryMapping(2198, TorznabCatType.MoviesHD, "HD Video"); + AddCategoryMapping(2199, TorznabCatType.MoviesHD, " | - Classic of world cinema (HD Video)"); + AddCategoryMapping(313, TorznabCatType.MoviesHD, " | - Foreign movies (HD Video)"); + AddCategoryMapping(2201, TorznabCatType.MoviesHD, " | - Asian movies (HD Video)"); + AddCategoryMapping(312, TorznabCatType.MoviesHD, " | - Our cinema (HD Video)"); + AddCategoryMapping(2339, TorznabCatType.MoviesHD, " | - Art-house and auteur cinema (HD Video)"); + AddCategoryMapping(352, TorznabCatType.Movies3D, "3D / Stereo Film, Video, TV & Sports"); + AddCategoryMapping(549, TorznabCatType.Movies3D, " | - 3D Movies"); + AddCategoryMapping(1213, TorznabCatType.Movies3D, " | - 3D Animation"); + AddCategoryMapping(2109, TorznabCatType.Movies3D, " | - 3D Documentary"); + AddCategoryMapping(514, TorznabCatType.Movies3D, " | - 3D Спорт"); + AddCategoryMapping(2097, TorznabCatType.Movies3D, " | - 3D Clips, Music Videos, Movie Trailers"); + AddCategoryMapping(4, TorznabCatType.Movies, "Cartoons"); + AddCategoryMapping(2343, TorznabCatType.Movies, " | - Animation (Announcements HD Video)"); + AddCategoryMapping(930, TorznabCatType.Movies, " | - Animation (HD Video)"); + AddCategoryMapping(2365, TorznabCatType.Movies, " | - Short Film (HD Video)"); + AddCategoryMapping(1900, TorznabCatType.Movies, " | - Domestic cartoons (DVD)"); + AddCategoryMapping(521, TorznabCatType.Movies, " | - Foreign cartoons (DVD)"); + AddCategoryMapping(2258, TorznabCatType.Movies, " | - Foreign Short Film (DVD)"); + AddCategoryMapping(208, TorznabCatType.Movies, " | - Domestic cartoons"); + AddCategoryMapping(539, TorznabCatType.Movies, " | - Domestic full-length cartoons"); + AddCategoryMapping(209, TorznabCatType.Movies, " | - Foreign cartoons"); + AddCategoryMapping(484, TorznabCatType.Movies, " | - Foreign short cartoons"); + AddCategoryMapping(822, TorznabCatType.Movies, " | - Cartoon Collection"); + AddCategoryMapping(921, TorznabCatType.TV, "Serial cartoons"); + AddCategoryMapping(922, TorznabCatType.TV, " | - Avatar"); + AddCategoryMapping(1247, TorznabCatType.TV, " | - Griffiny / Family guy"); + AddCategoryMapping(923, TorznabCatType.TV, " | - SpongeBob SquarePants"); + AddCategoryMapping(924, TorznabCatType.TV, " | - The Simpsons"); + AddCategoryMapping(1991, TorznabCatType.TV, " | - Skubi-du / Scooby-Doo"); + AddCategoryMapping(925, TorznabCatType.TV, " | - Tom and Jerry"); + AddCategoryMapping(1165, TorznabCatType.TV, " | - Transformers"); + AddCategoryMapping(1245, TorznabCatType.TV, " | - DuckTales / DuckTales"); + AddCategoryMapping(928, TorznabCatType.TV, " | - Futurama / Futurama"); + AddCategoryMapping(926, TorznabCatType.TV, " | - Spider-Man / The Spectacular Spider-Man"); + AddCategoryMapping(1246, TorznabCatType.TV, " | - Turtles Mutant Ninja / Teenage Mutant Ninja Turtles"); + AddCategoryMapping(1250, TorznabCatType.TV, " |- Чип и Дейл / Chip And Dale"); + AddCategoryMapping(927, TorznabCatType.TV, " | - South Park / South Park"); + AddCategoryMapping(1248, TorznabCatType.TV, " | - For sub-standard hands"); + AddCategoryMapping(33, TorznabCatType.TVAnime, "Anime"); + AddCategoryMapping(281, TorznabCatType.TVAnime, " | - Manga"); + AddCategoryMapping(1386, TorznabCatType.TVAnime, " | - Wallpapers, artbook, and others."); + AddCategoryMapping(1387, TorznabCatType.TVAnime, " | -. AMV and other rollers"); + AddCategoryMapping(1388, TorznabCatType.TVAnime, " |- OST (lossless)"); + AddCategoryMapping(282, TorznabCatType.TVAnime, " | - OST (mp3 and others lossy-format)"); + AddCategoryMapping(599, TorznabCatType.TVAnime, " | - Anime (DVD)"); + AddCategoryMapping(1105, TorznabCatType.TVAnime, " |- Аниме (HD Video)"); + AddCategoryMapping(1389, TorznabCatType.TVAnime, " | - Anime (main subsection)"); + AddCategoryMapping(1391, TorznabCatType.TVAnime, " | - Anime (pleerny subsection)"); + AddCategoryMapping(2491, TorznabCatType.TVAnime, " | - Anime (QC subsection)"); + AddCategoryMapping(404, TorznabCatType.TVAnime, " | - Pokemony"); + AddCategoryMapping(1390, TorznabCatType.TVAnime, " | - Naruto"); + AddCategoryMapping(1642, TorznabCatType.TVAnime, " | - Trade"); + AddCategoryMapping(893, TorznabCatType.TVAnime, " | - Japanese cartoons"); + AddCategoryMapping(1478, TorznabCatType.TVAnime, " | - For sub-standard hands"); + + // Документалистика и юмор + AddCategoryMapping(670, TorznabCatType.TVDocumentary, "Faith and Religion"); + AddCategoryMapping(1475, TorznabCatType.TVDocumentary, " | - Christianity"); + AddCategoryMapping(2107, TorznabCatType.TVDocumentary, " | - Islam"); + AddCategoryMapping(294, TorznabCatType.TVDocumentary, " | - Religions of India, Tibet and East Asia"); + AddCategoryMapping(1453, TorznabCatType.TVDocumentary, " | - Cults and new religious movements"); + AddCategoryMapping(46, TorznabCatType.TVDocumentary, "Documentary movies and TV shows"); + AddCategoryMapping(103, TorznabCatType.TVDocumentary, " | - Documentary (DVD)"); + AddCategoryMapping(671, TorznabCatType.TVDocumentary, "| - Biographies. Personality and idols"); + AddCategoryMapping(2177, TorznabCatType.TVDocumentary, " | - Cinema and animation"); + AddCategoryMapping(2538, TorznabCatType.TVDocumentary, " | - Art, Art History"); + AddCategoryMapping(2159, TorznabCatType.TVDocumentary, " | - Music"); + AddCategoryMapping(251, TorznabCatType.TVDocumentary, " | - Kriminalynaya documentary"); + AddCategoryMapping(98, TorznabCatType.TVDocumentary, " | - Secrets of the Ages / Special Services / Conspiracy Theory"); + AddCategoryMapping(97, TorznabCatType.TVDocumentary, " | - Military"); + AddCategoryMapping(851, TorznabCatType.TVDocumentary, " | - World War II"); + AddCategoryMapping(2178, TorznabCatType.TVDocumentary, " | - Accidents / Accidents / Disasters"); + AddCategoryMapping(821, TorznabCatType.TVDocumentary, " | - Aviation"); + AddCategoryMapping(2076, TorznabCatType.TVDocumentary, " | - Space"); + AddCategoryMapping(56, TorznabCatType.TVDocumentary, " | - Scientific-popular movies"); + AddCategoryMapping(2123, TorznabCatType.TVDocumentary, " | - Flora and fauna"); + AddCategoryMapping(876, TorznabCatType.TVDocumentary, " | - Travel and Tourism"); + AddCategoryMapping(2380, TorznabCatType.TVDocumentary, " | - Social talk show"); + AddCategoryMapping(1467, TorznabCatType.TVDocumentary, " | - Information-analytical and socio-political etc. .."); + AddCategoryMapping(1469, TorznabCatType.TVDocumentary, " | - Architecture and Construction"); + AddCategoryMapping(672, TorznabCatType.TVDocumentary, " | - All about home, life and design"); + AddCategoryMapping(249, TorznabCatType.TVDocumentary, " |- BBC"); + AddCategoryMapping(552, TorznabCatType.TVDocumentary, " |- Discovery"); + AddCategoryMapping(500, TorznabCatType.TVDocumentary, " |- National Geographic"); + AddCategoryMapping(2112, TorznabCatType.TVDocumentary, " | - History: Ancient World / Antiquity / Middle Ages"); + AddCategoryMapping(1327, TorznabCatType.TVDocumentary, " | - History: modern and contemporary times"); + AddCategoryMapping(1468, TorznabCatType.TVDocumentary, " | - The Age of the USSR"); + AddCategoryMapping(1280, TorznabCatType.TVDocumentary, " | - The Battle of psychics / Theory improbability / Seekers / G .."); + AddCategoryMapping(752, TorznabCatType.TVDocumentary, " | - Russian sensation / Program Maximum / Profession report .."); + AddCategoryMapping(1114, TorznabCatType.TVDocumentary, " | - Paranormal"); + AddCategoryMapping(2168, TorznabCatType.TVDocumentary, " | - Alternative history and science"); + AddCategoryMapping(2160, TorznabCatType.TVDocumentary, " | - Vnezhanrovaya documentary"); + AddCategoryMapping(2176, TorznabCatType.TVDocumentary, " | - Other / nekonditsiya"); + AddCategoryMapping(314, TorznabCatType.TVDocumentary, "Documentary (HD Video)"); + AddCategoryMapping(2323, TorznabCatType.TVDocumentary, " | - Information-analytical and socio-political etc. .."); + AddCategoryMapping(1278, TorznabCatType.TVDocumentary, "| - Biographies. Personality and idols (HD Video)"); + AddCategoryMapping(1281, TorznabCatType.TVDocumentary, " | - Military Science (HD Video)"); + AddCategoryMapping(2110, TorznabCatType.TVDocumentary, " | - Natural History, Science and Technology (HD Video)"); + AddCategoryMapping(979, TorznabCatType.TVDocumentary, " | - Travel and Tourism (HD Video)"); + AddCategoryMapping(2169, TorznabCatType.TVDocumentary, " |- Флора и фауна (HD Video)"); + AddCategoryMapping(2166, TorznabCatType.TVDocumentary, " | - History (HD Video)"); + AddCategoryMapping(2164, TorznabCatType.TVDocumentary, " |- BBC, Discovery, National Geographic (HD Video)"); + AddCategoryMapping(2163, TorznabCatType.TVDocumentary, " | - Kriminalynaya documentary (HD Video)"); + AddCategoryMapping(24, TorznabCatType.TV, "Entertaining TV programs and shows, fun and humor"); + AddCategoryMapping(1959, TorznabCatType.TV, " | - Mind games and quizzes"); + AddCategoryMapping(939, TorznabCatType.TV, " | - Reality and talk show host / category / impressions"); + AddCategoryMapping(1481, TorznabCatType.TV, " | - Children's TV Show"); + AddCategoryMapping(113, TorznabCatType.TV, " | - KVN"); + AddCategoryMapping(115, TorznabCatType.TV, " | - Post KVN"); + AddCategoryMapping(882, TorznabCatType.TV, " | - Distorting Mirror / town / in the town"); + AddCategoryMapping(1482, TorznabCatType.TV, " | - Ice show"); + AddCategoryMapping(393, TorznabCatType.TV, " | - Musical Show"); + AddCategoryMapping(1569, TorznabCatType.TV, " | - Dinner Party"); + AddCategoryMapping(373, TorznabCatType.TV, " | - Good Jokes"); + AddCategoryMapping(1186, TorznabCatType.TV, " | - Evening Quarter"); + AddCategoryMapping(137, TorznabCatType.TV, " | - Movies with a funny transfer (parody)"); + AddCategoryMapping(2537, TorznabCatType.TV, " |- Stand-up comedy"); + AddCategoryMapping(532, TorznabCatType.TV, " | - Ukrainian Shows"); + AddCategoryMapping(827, TorznabCatType.TV, " | - Dance shows, concerts, performances"); + AddCategoryMapping(1484, TorznabCatType.TV, " | - The Circus"); + AddCategoryMapping(1485, TorznabCatType.TV, " | - The School for Scandal"); + AddCategoryMapping(114, TorznabCatType.TV, " | - Satirist, and humorists"); + AddCategoryMapping(1332, TorznabCatType.TV, " | - Humorous Audio Transmissions"); + AddCategoryMapping(1495, TorznabCatType.TV, " | - Audio and video clips (Jokes and humor)"); + + // Спорт + AddCategoryMapping(255, TorznabCatType.TVSport, "Sports tournaments, films and programs"); + AddCategoryMapping(256, TorznabCatType.TVSport, " | - Motorsports"); + AddCategoryMapping(1986, TorznabCatType.TVSport, " | - Motorsports"); + AddCategoryMapping(660, TorznabCatType.TVSport, " | - Formula-1 2016"); + AddCategoryMapping(1551, TorznabCatType.TVSport, " | - Formula-1 2012-2015"); + AddCategoryMapping(626, TorznabCatType.TVSport, " | - Formula 1"); + AddCategoryMapping(262, TorznabCatType.TVSport, " | - Cycling"); + AddCategoryMapping(1326, TorznabCatType.TVSport, " | - Volleyball / Handball"); + AddCategoryMapping(978, TorznabCatType.TVSport, " | - Billiards"); + AddCategoryMapping(1287, TorznabCatType.TVSport, " | - Poker"); + AddCategoryMapping(1188, TorznabCatType.TVSport, " | - Bodybuilding / Power Sports"); + AddCategoryMapping(1667, TorznabCatType.TVSport, " | - Boxing"); + AddCategoryMapping(1675, TorznabCatType.TVSport, " | - Classical arts"); + AddCategoryMapping(257, TorznabCatType.TVSport, " | - MMA and K-1"); + AddCategoryMapping(875, TorznabCatType.TVSport, " | - College Football"); + AddCategoryMapping(263, TorznabCatType.TVSport, " | - Rugby"); + AddCategoryMapping(2073, TorznabCatType.TVSport, " | - Baseball"); + AddCategoryMapping(550, TorznabCatType.TVSport, " | - Tennis"); + AddCategoryMapping(2124, TorznabCatType.TVSport, " | - Badminton / Table Tennis"); + AddCategoryMapping(1470, TorznabCatType.TVSport, " | - Gymnastics / Dance Competitions"); + AddCategoryMapping(528, TorznabCatType.TVSport, " | - Athletics / Water Sports"); + AddCategoryMapping(486, TorznabCatType.TVSport, " | - Winter Sports"); + AddCategoryMapping(854, TorznabCatType.TVSport, " | - Figure skating"); + AddCategoryMapping(2079, TorznabCatType.TVSport, " | - Biathlon"); + AddCategoryMapping(260, TorznabCatType.TVSport, " | - Extreme"); + AddCategoryMapping(1319, TorznabCatType.TVSport, " | - Sports (video)"); + AddCategoryMapping(1608, TorznabCatType.TVSport, "football"); + AddCategoryMapping(1952, TorznabCatType.TVSport, " | - Russia 2016-2017"); + AddCategoryMapping(2075, TorznabCatType.TVSport, " | - Russia 2015-2016"); + AddCategoryMapping(1613, TorznabCatType.TVSport, " | - Russia / USSR"); + AddCategoryMapping(1614, TorznabCatType.TVSport, " | - England"); + AddCategoryMapping(1623, TorznabCatType.TVSport, " | - Spain"); + AddCategoryMapping(1615, TorznabCatType.TVSport, " | - Italy"); + AddCategoryMapping(1630, TorznabCatType.TVSport, " | - Germany"); + AddCategoryMapping(2425, TorznabCatType.TVSport, " | - France"); + AddCategoryMapping(2514, TorznabCatType.TVSport, " | - Ukraine"); + AddCategoryMapping(1616, TorznabCatType.TVSport, " | - Other national championships and cups"); + AddCategoryMapping(2014, TorznabCatType.TVSport, " | - International Events"); + AddCategoryMapping(2171, TorznabCatType.TVSport, " | - European Cups 2016-2017"); + AddCategoryMapping(1491, TorznabCatType.TVSport, " | - European Cups 2015-2016"); + AddCategoryMapping(1987, TorznabCatType.TVSport, " | - European Cups 2011-2015"); + AddCategoryMapping(1617, TorznabCatType.TVSport, " | - European Cups"); + AddCategoryMapping(1610, TorznabCatType.TVSport, " | - European Football Championship 2016"); + AddCategoryMapping(1620, TorznabCatType.TVSport, " | - European Championships"); + AddCategoryMapping(1668, TorznabCatType.TVSport, " | - World Cup 2018"); + AddCategoryMapping(1621, TorznabCatType.TVSport, " | - World Championships"); + AddCategoryMapping(1998, TorznabCatType.TVSport, " | - Friendly tournaments and matches"); + AddCategoryMapping(1343, TorznabCatType.TVSport, " | - The survey and analytical programs 2014-2017"); + AddCategoryMapping(751, TorznabCatType.TVSport, " | - The survey and analytical programs"); + AddCategoryMapping(1697, TorznabCatType.TVSport, " | - Mini football / Football"); + AddCategoryMapping(2004, TorznabCatType.TVSport, "basketball"); + AddCategoryMapping(2001, TorznabCatType.TVSport, " | - International Competitions"); + AddCategoryMapping(2002, TorznabCatType.TVSport, " |- NBA / NCAA (до 2000 г.)"); + AddCategoryMapping(283, TorznabCatType.TVSport, " | - NBA / NCAA (2000-2010 biennium)."); + AddCategoryMapping(1997, TorznabCatType.TVSport, " | - NBA / NCAA (2010-2017 biennium)."); + AddCategoryMapping(2003, TorznabCatType.TVSport, " | - European club basketball"); + AddCategoryMapping(2009, TorznabCatType.TVSport, "Hockey"); + AddCategoryMapping(2010, TorznabCatType.TVSport, " | - Hockey / Bandy"); + AddCategoryMapping(2006, TorznabCatType.TVSport, " | - International Events"); + AddCategoryMapping(2007, TorznabCatType.TVSport, " | - KHL"); + AddCategoryMapping(2005, TorznabCatType.TVSport, " | - NHL (until 2011/12)"); + AddCategoryMapping(259, TorznabCatType.TVSport, " | - NHL (2013)"); + AddCategoryMapping(2008, TorznabCatType.TVSport, " | - USSR - Canada"); + AddCategoryMapping(126, TorznabCatType.TVSport, " | - Documentaries and Analysis"); + AddCategoryMapping(845, TorznabCatType.TVSport, "Wrestling"); + AddCategoryMapping(343, TorznabCatType.TVSport, " |- Professional Wrestling"); + AddCategoryMapping(2111, TorznabCatType.TVSport, " |- Independent Wrestling"); + AddCategoryMapping(1527, TorznabCatType.TVSport, " |- International Wrestling"); + AddCategoryMapping(2069, TorznabCatType.TVSport, " |- Oldschool Wrestling"); + AddCategoryMapping(1323, TorznabCatType.TVSport, " |- Documentary Wrestling"); + + // Сериалы + AddCategoryMapping(9, TorznabCatType.TV, "Russion serials"); + AddCategoryMapping(104, TorznabCatType.TV, " | - Secrets of the investigation"); + AddCategoryMapping(1408, TorznabCatType.TV, " | - National Security Agent"); + AddCategoryMapping(1535, TorznabCatType.TV, " | - Lawyer"); + AddCategoryMapping(91, TorznabCatType.TV, " | - Gangster Petersburg"); + AddCategoryMapping(1356, TorznabCatType.TV, " | - Return of Mukhtar"); + AddCategoryMapping(990, TorznabCatType.TV, " | - Hounds"); + AddCategoryMapping(856, TorznabCatType.TV, " | - Capercaillie / Pyatnitskii / Karpov"); + AddCategoryMapping(188, TorznabCatType.TV, " | - Darya Dontsova"); + AddCategoryMapping(310, TorznabCatType.TV, " | - Kadetstvo / Kremlëvskie kursanty"); + AddCategoryMapping(202, TorznabCatType.TV, " | - Kamenskaya"); + AddCategoryMapping(935, TorznabCatType.TV, " | - Code of Honor"); + AddCategoryMapping(172, TorznabCatType.TV, " | - A cop-in-law"); + AddCategoryMapping(805, TorznabCatType.TV, " | - Cop War"); + AddCategoryMapping(80, TorznabCatType.TV, " | - My Fair Nanny"); + AddCategoryMapping(119, TorznabCatType.TV, " | - Careful, Modern!"); + AddCategoryMapping(812, TorznabCatType.TV, " | - Web"); + AddCategoryMapping(175, TorznabCatType.TV, " | - After"); + AddCategoryMapping(79, TorznabCatType.TV, " | - Soldiers and others."); + AddCategoryMapping(123, TorznabCatType.TV, " | - Stopping Power / Cops / Opera"); + AddCategoryMapping(189, TorznabCatType.TV, "Foreign TV series"); + AddCategoryMapping(842, TorznabCatType.TV, " | - News and TV shows in the display stage"); + AddCategoryMapping(235, TorznabCatType.TV, " | - TV Shows US and Canada"); + AddCategoryMapping(242, TorznabCatType.TV, " | - TV Shows UK and Ireland"); + AddCategoryMapping(819, TorznabCatType.TV, " | - Scandinavian series"); + AddCategoryMapping(1531, TorznabCatType.TV, " | - Spanish series"); + AddCategoryMapping(721, TorznabCatType.TV, " | - Italian series"); + AddCategoryMapping(1102, TorznabCatType.TV, " | - European series"); + AddCategoryMapping(1120, TorznabCatType.TV, " | - TV Shows in Africa, Middle East"); + AddCategoryMapping(1214, TorznabCatType.TV, " | - TV Shows Australia and New Zealand"); + AddCategoryMapping(387, TorznabCatType.TV, " | - Serials joint production of several countries"); + AddCategoryMapping(1359, TorznabCatType.TV, " | - Web series, webisodes and TV series for the pilot episode .."); + AddCategoryMapping(271, TorznabCatType.TV, " | - 24 hours / 24"); + AddCategoryMapping(273, TorznabCatType.TV, " |- Альф / ALF"); + AddCategoryMapping(743, TorznabCatType.TV, " | - Grey's Anatomy / Grey's Anatomy + Private Practice / Priv .."); + AddCategoryMapping(184, TorznabCatType.TV, " | - Buffy - the Vampire Slayer / Buffy + Angel / Angel"); + AddCategoryMapping(194, TorznabCatType.TV, " | - Bludlivaya California / Californication"); + AddCategoryMapping(85, TorznabCatType.TV, " |- Вавилон 5 / Babylon 5"); + AddCategoryMapping(1171, TorznabCatType.TV, " |- Викинги / Vikings"); + AddCategoryMapping(1417, TorznabCatType.TV, " | - Breaking Bad / Breaking Bad"); + AddCategoryMapping(1144, TorznabCatType.TV, " | - The Return of Sherlock Holmes / Return of Sherlock Holmes"); + AddCategoryMapping(595, TorznabCatType.TV, " |- Герои / Heroes"); + AddCategoryMapping(1288, TorznabCatType.TV, " | - Dexter / Dexter"); + AddCategoryMapping(1605, TorznabCatType.TV, " | - Two and a Half Men / Two and a Half Men"); + AddCategoryMapping(1694, TorznabCatType.TV, " |- Династия / Dynasty"); + AddCategoryMapping(1690, TorznabCatType.TV, " | - The Vampire Diaries / The Vampire Diaries + True Blood .."); + AddCategoryMapping(820, TorznabCatType.TV, " |- Доктор Кто / Doctor Who + Торчвуд / Torchwood"); + AddCategoryMapping(625, TorznabCatType.TV, " |- Доктор Хаус / House M.D."); + AddCategoryMapping(84, TorznabCatType.TV, " | - Druzyya / Friends + Joey / Joey"); + AddCategoryMapping(623, TorznabCatType.TV, " | - Fringe / Fringe"); + AddCategoryMapping(1798, TorznabCatType.TV, "| - Stargate: Atlantis; Universe / Stargate: Atlanti .."); + AddCategoryMapping(106, TorznabCatType.TV, " | - Stargate: SG-1 / Stargate: SG1"); + AddCategoryMapping(166, TorznabCatType.TV, " | - Battlestar Galactica / Battlestar Galactica + Copper .."); + AddCategoryMapping(236, TorznabCatType.TV, " | - Star Trek / Star Trek"); + AddCategoryMapping(1449, TorznabCatType.TV, " |- Игра престолов / Game of Thrones"); + AddCategoryMapping(507, TorznabCatType.TV, " | - How I Met Your Mother The Big Bang Theory +"); + AddCategoryMapping(504, TorznabCatType.TV, " |- Клан Сопрано / The Sopranos"); + AddCategoryMapping(536, TorznabCatType.TV, " |- Клиника / Scrubs"); + AddCategoryMapping(173, TorznabCatType.TV, " | - Коломбо / Columbo"); + AddCategoryMapping(918, TorznabCatType.TV, " | - Inspector Rex / Komissar Rex"); + AddCategoryMapping(920, TorznabCatType.TV, " | - Bones / Bones"); + AddCategoryMapping(203, TorznabCatType.TV, " | - Weeds / Weeds"); + AddCategoryMapping(1243, TorznabCatType.TV, "| - Cool Walker. Justice in Texas / Walker, Texas Ran .."); + AddCategoryMapping(140, TorznabCatType.TV, " | - Masters of Horror / Masters of Horror"); + AddCategoryMapping(636, TorznabCatType.TV, " | - Mentalist / The Mentalist + Castle / Castle"); + AddCategoryMapping(606, TorznabCatType.TV, " | - Crime / CSI Location: Crime Scene Investigation"); + AddCategoryMapping(776, TorznabCatType.TV, " |- Мисс Марпл / Miss Marple"); + AddCategoryMapping(181, TorznabCatType.TV, "| - NCIS; Los Angeles; New Orleans"); + AddCategoryMapping(1499, TorznabCatType.TV, " | - Murder, She Wrote / Murder, She Wrote + Perry Mason .."); + AddCategoryMapping(81, TorznabCatType.TV, " | - Survivors / LOST"); + AddCategoryMapping(266, TorznabCatType.TV, " | - Desperate Housewives / Desperate Housewives"); + AddCategoryMapping(252, TorznabCatType.TV, " | - Jailbreak / Prison Break"); + AddCategoryMapping(196, TorznabCatType.TV, " |- Санта Барбара / Santa Barbara"); + AddCategoryMapping(372, TorznabCatType.TV, " | - Supernatural / Supernatural"); + AddCategoryMapping(110, TorznabCatType.TV, " | - The X-Files / The X-Files"); + AddCategoryMapping(193, TorznabCatType.TV, " | - Sex and the City / Sex And The City"); + AddCategoryMapping(237, TorznabCatType.TV, " | - Sliding / Sliders"); + AddCategoryMapping(265, TorznabCatType.TV, " | - Ambulance / ER"); + AddCategoryMapping(1117, TorznabCatType.TV, " | - Octopus / La Piovra"); + AddCategoryMapping(497, TorznabCatType.TV, " | - Smallville / Smallville"); + AddCategoryMapping(121, TorznabCatType.TV, " | - Twin Peaks / Twin Peaks"); + AddCategoryMapping(134, TorznabCatType.TV, " | - Hercule Poirot / Hercule Poirot"); + AddCategoryMapping(195, TorznabCatType.TV, " | - For sub-standard hands"); + AddCategoryMapping(2366, TorznabCatType.TV, "Foreign TV shows (HD Video)"); + AddCategoryMapping(2401, TorznabCatType.TV, " |- Блудливая Калифорния / Californication (HD Video)"); + AddCategoryMapping(2390, TorznabCatType.TV, " | - Two and a Half Men / Two and a Half Men (HD Video)"); + AddCategoryMapping(1669, TorznabCatType.TV, " |- Викинги / Vikings (HD Video)"); + AddCategoryMapping(2391, TorznabCatType.TV, " |- Декстер / Dexter (HD Video)"); + AddCategoryMapping(2392, TorznabCatType.TV, " | - Friends / Friends (HD Video)"); + AddCategoryMapping(2407, TorznabCatType.TV, " |- Доктор Кто / Doctor Who; Торчвуд / Torchwood (HD Video)"); + AddCategoryMapping(2393, TorznabCatType.TV, " |- Доктор Хаус / House M.D. (HD Video)"); + AddCategoryMapping(2370, TorznabCatType.TV, " | - Fringe / Fringe (HD Video)"); + AddCategoryMapping(2394, TorznabCatType.TV, "| - Stargate: a C1; Atlantis; The Universe (HD Video)"); + AddCategoryMapping(2408, TorznabCatType.TV, "| - Battlestar Galactica / Battlestar Galactica; Capri .."); + AddCategoryMapping(2395, TorznabCatType.TV, " | - Star Trek / Star Trek (HD Video)"); + AddCategoryMapping(2396, TorznabCatType.TV, "| - How I Met Your Mother; The Big Bang Theory (HD Vi .."); + AddCategoryMapping(2397, TorznabCatType.TV, " |- Кости / Bones (HD Video)"); + AddCategoryMapping(2398, TorznabCatType.TV, " | - Weeds / Weeds (HD Video)"); + AddCategoryMapping(2399, TorznabCatType.TV, "| - Mentalist / The Mentalist; Castle / Castle (HD Video)"); + AddCategoryMapping(2400, TorznabCatType.TV, " | - Crime / CSI Location: Crime Scene Investigation (HD .."); + AddCategoryMapping(2402, TorznabCatType.TV, " | - Survivors / LOST (HD Video)"); + AddCategoryMapping(2403, TorznabCatType.TV, " | - Jailbreak / Prison Break (HD Video)"); + AddCategoryMapping(2404, TorznabCatType.TV, " |- Сверхъестественное / Supernatural (HD Video)"); + AddCategoryMapping(2405, TorznabCatType.TV, " | - The X-Files / The X-Files (HD Video)"); + AddCategoryMapping(2406, TorznabCatType.TV, " |- Тайны Смолвиля / Smallville (HD Video)"); + AddCategoryMapping(911, TorznabCatType.TV, "Soaps Latin America, Turkey and India"); + AddCategoryMapping(1493, TorznabCatType.TV, " | - Actors and actresses of Latin American soap operas"); + AddCategoryMapping(1301, TorznabCatType.TV, " | - Indian series"); + AddCategoryMapping(704, TorznabCatType.TV, " | - Turkish serials"); + AddCategoryMapping(1940, TorznabCatType.TV, " | - Official brief version of Latin American soap operas"); + AddCategoryMapping(1574, TorznabCatType.TV, " | - Latin American soap operas with the voice acting (folders distribution)"); + AddCategoryMapping(1539, TorznabCatType.TV, " | - Latin American serials with subtitles"); + AddCategoryMapping(1500, TorznabCatType.TV, " |- OST"); + AddCategoryMapping(823, TorznabCatType.TV, " | - Богатые тоже плачут / The Rich Also Cry"); + AddCategoryMapping(1006, TorznabCatType.TV, " | - Вдова бланко / La Viuda de Blanco"); + AddCategoryMapping(877, TorznabCatType.TV, " | - Великолепный век / Magnificent Century"); + AddCategoryMapping(972, TorznabCatType.TV, " | - In the name of love / Por Amor"); + AddCategoryMapping(781, TorznabCatType.TV, " | - A girl named Fate / Milagros"); + AddCategoryMapping(1300, TorznabCatType.TV, " |- Дикий ангел / Muneca Brava"); + AddCategoryMapping(1803, TorznabCatType.TV, " | - Донья Барбара / Female Barbara"); + AddCategoryMapping(1298, TorznabCatType.TV, " | - Дороги Индии / Passage to India"); + AddCategoryMapping(825, TorznabCatType.TV, " | - Durnuška Betti / Yo Soy Betty la Fea"); + AddCategoryMapping(1606, TorznabCatType.TV, " | - The wife of Judas (wine of love) / La Mujer de Judas"); + AddCategoryMapping(1458, TorznabCatType.TV, " | - Cruel Angel / Anjo Mau"); + AddCategoryMapping(1463, TorznabCatType.TV, " | - Замарашка / Cara Sucia"); + AddCategoryMapping(1459, TorznabCatType.TV, " | - A Cinderella Story (Beautiful Loser) / Bella Calamidade .."); + AddCategoryMapping(1461, TorznabCatType.TV, " | - Kacorri / Kachorra"); + AddCategoryMapping(718, TorznabCatType.TV, " |- Клон / O Clone"); + AddCategoryMapping(1498, TorznabCatType.TV, " | - Клятва / The Oath"); + AddCategoryMapping(907, TorznabCatType.TV, " | - Lalo / Lalola"); + AddCategoryMapping(992, TorznabCatType.TV, " | - Morena Clara / Clara Morena"); + AddCategoryMapping(607, TorznabCatType.TV, " | - Mi Segunda Madre / Mi segunda Madre"); + AddCategoryMapping(594, TorznabCatType.TV, " | - The rebellious spirit / Rebelde Way"); + AddCategoryMapping(775, TorznabCatType.TV, " | - Наследница / The Heiress"); + AddCategoryMapping(534, TorznabCatType.TV, " | - Nobody but you / Tu o Nadie"); + AddCategoryMapping(1462, TorznabCatType.TV, " | - Падре Корахе / Father Courage"); + AddCategoryMapping(1678, TorznabCatType.TV, " | - Падший ангел / Mas Sabe el Diablo"); + AddCategoryMapping(904, TorznabCatType.TV, " | - Предательство / The Betrayal"); + AddCategoryMapping(1460, TorznabCatType.TV, " | - Призрак Элены / The Phantom of Elena"); + AddCategoryMapping(816, TorznabCatType.TV, " | - Live your life / Viver a vida"); + AddCategoryMapping(815, TorznabCatType.TV, " | - Just Maria / Simplemente Maria"); + AddCategoryMapping(325, TorznabCatType.TV, " | - Rabыnya Isaura / Escrava Isaura"); + AddCategoryMapping(1457, TorznabCatType.TV, " | - Реванш 2000 / Retaliation 2000"); + AddCategoryMapping(1692, TorznabCatType.TV, " | - Family Ties / Lacos de Familia"); + AddCategoryMapping(1540, TorznabCatType.TV, " | - Perfect Beauty / Beleza pura"); + AddCategoryMapping(694, TorznabCatType.TV, " | - Secrets of Love / Los Misterios del Amor"); + AddCategoryMapping(1949, TorznabCatType.TV, " | - Фаворитка / A Favorita"); + AddCategoryMapping(1541, TorznabCatType.TV, " | - Цыганская кровь / Soy gitano"); + AddCategoryMapping(1941, TorznabCatType.TV, " | - Шторм / Storm"); + AddCategoryMapping(1537, TorznabCatType.TV, " | - For sub-standard hands"); + AddCategoryMapping(2100, TorznabCatType.TV, "Asian series"); + AddCategoryMapping(717, TorznabCatType.TV, " | - Chinese serials with subtitles"); + AddCategoryMapping(915, TorznabCatType.TV, " | - Korean TV shows with voice acting"); + AddCategoryMapping(1242, TorznabCatType.TV, " | - Korean serials with subtitles"); + AddCategoryMapping(2412, TorznabCatType.TV, " | - Other Asian series with the voice acting"); + AddCategoryMapping(1938, TorznabCatType.TV, " | - Taiwanese serials with subtitles"); + AddCategoryMapping(2104, TorznabCatType.TV, " | - Japanese serials with subtitles"); + AddCategoryMapping(1939, TorznabCatType.TV, " | - Japanese TV series with the voice acting"); + AddCategoryMapping(2102, TorznabCatType.TV, " | -. VMV and other videos"); + AddCategoryMapping(2103, TorznabCatType.TV, " |- OST"); + + // Книги и журналы + AddCategoryMapping(1411, TorznabCatType.Books, " | - Scanning, processing skanov"); + AddCategoryMapping(21, TorznabCatType.Books, "books"); + AddCategoryMapping(2157, TorznabCatType.Books, " | - Film, TV, animation"); + AddCategoryMapping(765, TorznabCatType.Books, " | - Design, Graphic Design"); + AddCategoryMapping(2019, TorznabCatType.Books, " | - Photography and video"); + AddCategoryMapping(31, TorznabCatType.Books, " | - Magazines and newspapers (general section)"); + AddCategoryMapping(1427, TorznabCatType.Books, " | - Esoteric Tarot, Feng Shui"); + AddCategoryMapping(2422, TorznabCatType.Books, " | - Astrology"); + AddCategoryMapping(2195, TorznabCatType.Books, "| - Beauty. Care. housekeeping"); + AddCategoryMapping(2521, TorznabCatType.Books, "| - Fashion. Style. Etiquette"); + AddCategoryMapping(2223, TorznabCatType.Books, " | - Travel and Tourism"); + AddCategoryMapping(2447, TorznabCatType.Books, " | - Celebrity idols"); + AddCategoryMapping(39, TorznabCatType.Books, " | - Miscellaneous"); + AddCategoryMapping(1101, TorznabCatType.Books, "For children, parents and teachers"); + AddCategoryMapping(745, TorznabCatType.Books, " | - Textbooks for kindergarten and primary school (.."); + AddCategoryMapping(1689, TorznabCatType.Books, " | - Textbooks for high school (grades 5-11)"); + AddCategoryMapping(2336, TorznabCatType.Books, " | - Teachers and educators"); + AddCategoryMapping(2337, TorznabCatType.Books, " | - Scientific-popular and informative literature (for children .."); + AddCategoryMapping(1353, TorznabCatType.Books, " | - Leisure and creativity"); + AddCategoryMapping(1400, TorznabCatType.Books, " | - Education and development"); + AddCategoryMapping(1415, TorznabCatType.Books, "| - Hood. lit-ra for preschool and elementary grades"); + AddCategoryMapping(2046, TorznabCatType.Books, "| - Hood. lit-ra for the middle and upper classes"); + AddCategoryMapping(1802, TorznabCatType.Books, "Sports, physical training, martial arts"); + AddCategoryMapping(2189, TorznabCatType.Books, " | - Football"); + AddCategoryMapping(2190, TorznabCatType.Books, " | - Hockey"); + AddCategoryMapping(2443, TorznabCatType.Books, " | - Team sports"); + AddCategoryMapping(1477, TorznabCatType.Books, "| - Athletics. Swimming. Gymnastics. Weightlifting..."); + AddCategoryMapping(669, TorznabCatType.Books, "| - Motorsport. Motorcycling. cycle racing"); + AddCategoryMapping(2196, TorznabCatType.Books, "| - Chess. Checkers"); + AddCategoryMapping(2056, TorznabCatType.Books, " | - Martial Arts, Martial Arts"); + AddCategoryMapping(1436, TorznabCatType.Books, " | - Extreme"); + AddCategoryMapping(2191, TorznabCatType.Books, " | - Fitness, fitness, bodybuilding"); + AddCategoryMapping(2477, TorznabCatType.Books, " | - Sports press"); + AddCategoryMapping(1680, TorznabCatType.Books, "Humanitarian sciences"); + AddCategoryMapping(1684, TorznabCatType.Books, "| - Arts. Cultural"); + AddCategoryMapping(2446, TorznabCatType.Books, "| - Folklore. Epic. Mythology"); + AddCategoryMapping(2524, TorznabCatType.Books, " | - Literature"); + AddCategoryMapping(2525, TorznabCatType.Books, " | - Linguistics"); + AddCategoryMapping(995, TorznabCatType.Books, " | - Philosophy"); + AddCategoryMapping(2022, TorznabCatType.Books, " | - Political Science"); + AddCategoryMapping(2471, TorznabCatType.Books, " | - Sociology"); + AddCategoryMapping(2375, TorznabCatType.Books, " | - Journalism, Journalism"); + AddCategoryMapping(764, TorznabCatType.Books, " | - Business, Management"); + AddCategoryMapping(1685, TorznabCatType.Books, " | - Marketing"); + AddCategoryMapping(1688, TorznabCatType.Books, " | - Economy"); + AddCategoryMapping(2472, TorznabCatType.Books, " | - Finance"); + AddCategoryMapping(1687, TorznabCatType.Books, "| - Jurisprudence. Right. criminalistics"); + AddCategoryMapping(2020, TorznabCatType.Books, "Historical sciences"); + AddCategoryMapping(1349, TorznabCatType.Books, " | - Philosophy and Methodology of Historical Science"); + AddCategoryMapping(1967, TorznabCatType.Books, " | - Historical sources"); + AddCategoryMapping(2049, TorznabCatType.Books, " | - Historic Person"); + AddCategoryMapping(1681, TorznabCatType.Books, " | - Alternative historical theories"); + AddCategoryMapping(2319, TorznabCatType.Books, " | - Archaeology"); + AddCategoryMapping(2434, TorznabCatType.Books, "| - Ancient World. Antiquity"); + AddCategoryMapping(1683, TorznabCatType.Books, " | - The Middle Ages"); + AddCategoryMapping(2444, TorznabCatType.Books, " | - History of modern and contemporary"); + AddCategoryMapping(2427, TorznabCatType.Books, " | - European History"); + AddCategoryMapping(2452, TorznabCatType.Books, " | - History of Asia and Africa"); + AddCategoryMapping(2445, TorznabCatType.Books, " | - History of America, Australia, Oceania"); + AddCategoryMapping(2435, TorznabCatType.Books, " | - History of Russia"); + AddCategoryMapping(2436, TorznabCatType.Books, " | - The Age of the USSR"); + AddCategoryMapping(2453, TorznabCatType.Books, " | - History of the countries of the former USSR"); + AddCategoryMapping(2320, TorznabCatType.Books, " | - Ethnography, anthropology"); + AddCategoryMapping(1801, TorznabCatType.Books, "| - International relations. Diplomacy"); + AddCategoryMapping(2023, TorznabCatType.Books, "Accurate, natural and engineering sciences"); + AddCategoryMapping(2024, TorznabCatType.Books, " | - Aviation / Cosmonautics"); + AddCategoryMapping(2026, TorznabCatType.Books, " | - Physics"); + AddCategoryMapping(2192, TorznabCatType.Books, " | - Astronomy"); + AddCategoryMapping(2027, TorznabCatType.Books, " | - Biology / Ecology"); + AddCategoryMapping(295, TorznabCatType.Books, " | - Chemistry / Biochemistry"); + AddCategoryMapping(2028, TorznabCatType.Books, " | - Mathematics"); + AddCategoryMapping(2029, TorznabCatType.Books, " | - Geography / Geology / Geodesy"); + AddCategoryMapping(1325, TorznabCatType.Books, " | - Electronics / Radio"); + AddCategoryMapping(2386, TorznabCatType.Books, " | - Diagrams and service manuals (original documents)"); + AddCategoryMapping(2031, TorznabCatType.Books, " | - Architecture / Construction / Engineering networks"); + AddCategoryMapping(2030, TorznabCatType.Books, " | - Engineering"); + AddCategoryMapping(2526, TorznabCatType.Books, " | - Welding / Soldering / Non-Destructive Testing"); + AddCategoryMapping(2527, TorznabCatType.Books, " | - Automation / Robotics"); + AddCategoryMapping(2254, TorznabCatType.Books, " | - Metallurgy / Materials"); + AddCategoryMapping(2376, TorznabCatType.Books, " | - Mechanics, strength of materials"); + AddCategoryMapping(2054, TorznabCatType.Books, " | - Power engineering / electrical"); + AddCategoryMapping(770, TorznabCatType.Books, " | - Oil, Gas and Chemicals"); + AddCategoryMapping(2476, TorznabCatType.Books, " | - Agriculture and food industry"); + AddCategoryMapping(2494, TorznabCatType.Books, " | - Railway case"); + AddCategoryMapping(1528, TorznabCatType.Books, " | - Normative documentation"); + AddCategoryMapping(2032, TorznabCatType.Books, " | - Journals: scientific, popular, radio and others."); + AddCategoryMapping(768, TorznabCatType.Books, "Warfare"); + AddCategoryMapping(2099, TorznabCatType.Books, " | - Militaria"); + AddCategoryMapping(2021, TorznabCatType.Books, " | - Military History"); + AddCategoryMapping(2437, TorznabCatType.Books, " | - History of the Second World War"); + AddCategoryMapping(1447, TorznabCatType.Books, " | - Military equipment"); + AddCategoryMapping(2468, TorznabCatType.Books, " | - Small arms"); + AddCategoryMapping(2469, TorznabCatType.Books, " | - Educational literature"); + AddCategoryMapping(2470, TorznabCatType.Books, " | - Special forces of the world"); + AddCategoryMapping(1686, TorznabCatType.Books, "Faith and Religion"); + AddCategoryMapping(2215, TorznabCatType.Books, " | - Christianity"); + AddCategoryMapping(2216, TorznabCatType.Books, " | - Islam"); + AddCategoryMapping(2217, TorznabCatType.Books, " | - Religions of India, Tibet and East Asia / Judaism"); + AddCategoryMapping(2218, TorznabCatType.Books, " | - Non-traditional religious, spiritual and mystical teachings .."); + AddCategoryMapping(2252, TorznabCatType.Books, "| - Religion. History of Religions. Atheism"); + AddCategoryMapping(767, TorznabCatType.Books, "psychology"); + AddCategoryMapping(2515, TorznabCatType.Books, " | - General and Applied Psychology"); + AddCategoryMapping(2516, TorznabCatType.Books, " | - Psychotherapy and Counseling"); + AddCategoryMapping(2517, TorznabCatType.Books, " | - Psychodiagnostics and psyhokorrektsyya"); + AddCategoryMapping(2518, TorznabCatType.Books, " | - Social psychology and psychology of relationships"); + AddCategoryMapping(2519, TorznabCatType.Books, " | - Training and Coaching"); + AddCategoryMapping(2520, TorznabCatType.Books, " | - Personal development and self-improvement"); + AddCategoryMapping(1696, TorznabCatType.Books, " | - Popular Psychology"); + AddCategoryMapping(2253, TorznabCatType.Books, "| - Sexology. Relations between the sexes"); + AddCategoryMapping(2033, TorznabCatType.Books, "Collecting, hobby and hobbies"); + AddCategoryMapping(1412, TorznabCatType.Books, "| - Collecting and auxiliary ist. discipline"); + AddCategoryMapping(1446, TorznabCatType.Books, " | - Embroidery"); + AddCategoryMapping(753, TorznabCatType.Books, " | - Knitting"); + AddCategoryMapping(2037, TorznabCatType.Books, " | - Sewing, Patchwork"); + AddCategoryMapping(2224, TorznabCatType.Books, " | - Lace"); + AddCategoryMapping(2194, TorznabCatType.Books, "| - Beading. Yuvelirika. Jewellery wire."); + AddCategoryMapping(2418, TorznabCatType.Books, " | - Paper Art"); + AddCategoryMapping(1410, TorznabCatType.Books, " | - Other arts and crafts"); + AddCategoryMapping(2034, TorznabCatType.Books, " | - Pets and aquariums"); + AddCategoryMapping(2433, TorznabCatType.Books, " | - Hunting and fishing"); + AddCategoryMapping(1961, TorznabCatType.Books, " | - Cooking (Book)"); + AddCategoryMapping(2432, TorznabCatType.Books, " | - Cooking (newspapers and magazines)"); + AddCategoryMapping(565, TorznabCatType.Books, " | - Modelling"); + AddCategoryMapping(1523, TorznabCatType.Books, " | - Farmland / Floriculture"); + AddCategoryMapping(1575, TorznabCatType.Books, " | - Repair, private construction, design of interiors"); + AddCategoryMapping(1520, TorznabCatType.Books, " | - Woodworking"); + AddCategoryMapping(2424, TorznabCatType.Books, " | - Board Games"); + AddCategoryMapping(769, TorznabCatType.Books, " | - Other Hobbies"); + AddCategoryMapping(2038, TorznabCatType.Books, "Fiction"); + AddCategoryMapping(2043, TorznabCatType.Books, " | - Russian literature"); + AddCategoryMapping(2042, TorznabCatType.Books, " | - Foreign literature (up to 1900)"); + AddCategoryMapping(2041, TorznabCatType.Books, " | - Foreign literature (XX and XXI century)"); + AddCategoryMapping(2044, TorznabCatType.Books, " | - Detective, Action"); + AddCategoryMapping(2039, TorznabCatType.Books, " | - Female Novel"); + AddCategoryMapping(2045, TorznabCatType.Books, " | - Domestic science fiction / fantasy / mystic"); + AddCategoryMapping(2080, TorznabCatType.Books, " | - International science fiction / fantasy / mystic"); + AddCategoryMapping(2047, TorznabCatType.Books, " | - Adventure"); + AddCategoryMapping(2193, TorznabCatType.Books, " | - Literary Magazines"); + AddCategoryMapping(1418, TorznabCatType.Books, "Computer books"); + AddCategoryMapping(1422, TorznabCatType.Books, " | - Software from Microsoft"); + AddCategoryMapping(1423, TorznabCatType.Books, " | - Other software"); + AddCategoryMapping(1424, TorznabCatType.Books, " |- Mac OS; Linux, FreeBSD и прочие *NIX"); + AddCategoryMapping(1445, TorznabCatType.Books, " | - RDBMS"); + AddCategoryMapping(1425, TorznabCatType.Books, " | - Web Design and Programming"); + AddCategoryMapping(1426, TorznabCatType.Books, " | - Programming"); + AddCategoryMapping(1428, TorznabCatType.Books, " | - Graphics, Video Processing"); + AddCategoryMapping(1429, TorznabCatType.Books, " | - Network / VoIP"); + AddCategoryMapping(1430, TorznabCatType.Books, " | - Hacking and Security"); + AddCategoryMapping(1431, TorznabCatType.Books, " | - Iron (book on a PC)"); + AddCategoryMapping(1433, TorznabCatType.Books, " | - Engineering and scientific programs"); + AddCategoryMapping(1432, TorznabCatType.Books, " | - Computer magazines and annexes"); + AddCategoryMapping(2202, TorznabCatType.Books, " | - Disc applications to gaming magazines"); + AddCategoryMapping(862, TorznabCatType.Books, "Comics"); + AddCategoryMapping(2461, TorznabCatType.Books, " | - Comics in Russian"); + AddCategoryMapping(2462, TorznabCatType.Books, " | - Marvel Comics publishing"); + AddCategoryMapping(2463, TorznabCatType.Books, " | - DC Comics publishing"); + AddCategoryMapping(2464, TorznabCatType.Books, " | - Comics from other publishers"); + AddCategoryMapping(2473, TorznabCatType.Books, " | - Comics in other languages"); + AddCategoryMapping(2465, TorznabCatType.Books, " | - Manga (in foreign languages)"); + AddCategoryMapping(2048, TorznabCatType.Books, "Collections of books and libraries"); + AddCategoryMapping(1238, TorznabCatType.Books, " | - Library (mirror network libraries / collections)"); + AddCategoryMapping(2055, TorznabCatType.Books, " | - Thematic collections (collections)"); + AddCategoryMapping(754, TorznabCatType.Books, " | - Multidisciplinary collections (collections)"); + AddCategoryMapping(2114, TorznabCatType.Books, "Multimedia and online publications"); + AddCategoryMapping(2438, TorznabCatType.Books, " | - Multimedia Encyclopedia"); + AddCategoryMapping(2439, TorznabCatType.Books, " | - Interactive tutorials and educational materials"); + AddCategoryMapping(2440, TorznabCatType.Books, " | - Educational publications for children"); + AddCategoryMapping(2441, TorznabCatType.Books, "| - Cooking. Floriculture. housekeeping"); + AddCategoryMapping(2442, TorznabCatType.Books, "| - Culture. Art. History"); + + // Обучение иностранным языкам + AddCategoryMapping(2362, TorznabCatType.Books, "Foreign Language for Adults"); + AddCategoryMapping(1265, TorznabCatType.Books, " | - English (for adults)"); + AddCategoryMapping(1266, TorznabCatType.Books, " | - German"); + AddCategoryMapping(1267, TorznabCatType.Books, " | - French"); + AddCategoryMapping(1358, TorznabCatType.Books, " | - Spanish"); + AddCategoryMapping(2363, TorznabCatType.Books, " | - Italian"); + AddCategoryMapping(1268, TorznabCatType.Books, " | - Other European languages"); + AddCategoryMapping(1673, TorznabCatType.Books, " | - Arabic"); + AddCategoryMapping(1269, TorznabCatType.Books, " | - Chinese"); + AddCategoryMapping(1270, TorznabCatType.Books, " | - Japanese"); + AddCategoryMapping(1275, TorznabCatType.Books, " | - Other Asian languages"); + AddCategoryMapping(2364, TorznabCatType.Books, " | - Russian as a foreign language"); + AddCategoryMapping(1276, TorznabCatType.Books, " | - Multilanguage collections"); + AddCategoryMapping(1274, TorznabCatType.Books, " | - Other (foreign languages)"); + AddCategoryMapping(2094, TorznabCatType.Books, " | - LIM-courses"); + AddCategoryMapping(1264, TorznabCatType.Books, "Foreign languages ​​for children"); + AddCategoryMapping(2358, TorznabCatType.Books, " | - English (for children)"); + AddCategoryMapping(2359, TorznabCatType.Books, " | - Other European languages ​​(for children)"); + AddCategoryMapping(2360, TorznabCatType.Books, " | - Eastern languages ​​(for children)"); + AddCategoryMapping(2361, TorznabCatType.Books, " | - School textbooks, exam (for children)"); + AddCategoryMapping(2057, TorznabCatType.Books, "Fiction"); + AddCategoryMapping(2355, TorznabCatType.Books, " | - Fiction in English"); + AddCategoryMapping(2474, TorznabCatType.Books, " | - Fiction French"); + AddCategoryMapping(2356, TorznabCatType.Books, " | - Fiction in other European languages"); + AddCategoryMapping(2357, TorznabCatType.Books, " | - Fiction in oriental languages"); + AddCategoryMapping(2413, TorznabCatType.Books, "Audio Books in foreign languages"); + AddCategoryMapping(1501, TorznabCatType.Books, " | - Audiobooks in English"); + AddCategoryMapping(1580, TorznabCatType.Books, " | - Audiobooks in German"); + AddCategoryMapping(525, TorznabCatType.Books, " | - Audiobooks in other languages"); + + // Обучающее видео + AddCategoryMapping(610, TorznabCatType.Books, "Video tutorials and interactive training DVD"); + AddCategoryMapping(1568, TorznabCatType.Books, " | - Cooking"); + AddCategoryMapping(1542, TorznabCatType.Books, " | - Sport"); + AddCategoryMapping(2335, TorznabCatType.Books, " | - Fitness - Cardio, Strength Training"); + AddCategoryMapping(1544, TorznabCatType.Books, " | - Fitness - Mind and Body"); + AddCategoryMapping(1545, TorznabCatType.Books, " | - Extreme"); + AddCategoryMapping(1546, TorznabCatType.Books, " | - Bodybuilding"); + AddCategoryMapping(1549, TorznabCatType.Books, " | - Health Practice"); + AddCategoryMapping(1597, TorznabCatType.Books, " | - Yoga"); + AddCategoryMapping(1552, TorznabCatType.Books, " | - Video and Snapshots"); + AddCategoryMapping(1550, TorznabCatType.Books, " | - Personal care"); + AddCategoryMapping(1553, TorznabCatType.Books, " | - Drawing"); + AddCategoryMapping(1554, TorznabCatType.Books, " | - Playing the guitar"); + AddCategoryMapping(617, TorznabCatType.Books, " | - Percussion"); + AddCategoryMapping(1555, TorznabCatType.Books, " | - Other musical instruments"); + AddCategoryMapping(2017, TorznabCatType.Books, " | - Play the bass guitar"); + AddCategoryMapping(1257, TorznabCatType.Books, " | - Ballroom dancing"); + AddCategoryMapping(1258, TorznabCatType.Books, " | - Belly Dance"); + AddCategoryMapping(2208, TorznabCatType.Books, " | - The street and club dancing"); + AddCategoryMapping(677, TorznabCatType.Books, " | - Dancing, miscellaneous"); + AddCategoryMapping(1255, TorznabCatType.Books, " | - Hunting"); + AddCategoryMapping(1479, TorznabCatType.Books, " | - Fishing and spearfishing"); + AddCategoryMapping(1261, TorznabCatType.Books, " | - Tricks and stunts"); + AddCategoryMapping(614, TorznabCatType.Books, " | - Education"); + AddCategoryMapping(1259, TorznabCatType.Books, " | - Business, Economics and Finance"); + AddCategoryMapping(2065, TorznabCatType.Books, " | - Pregnancy, childbirth, motherhood"); + AddCategoryMapping(1254, TorznabCatType.Books, " | - Training videos for children"); + AddCategoryMapping(1260, TorznabCatType.Books, " | - Psychology"); + AddCategoryMapping(2209, TorznabCatType.Books, " | - Esoteric, self-development"); + AddCategoryMapping(2210, TorznabCatType.Books, " | - Van, dating"); + AddCategoryMapping(1547, TorznabCatType.Books, " | - Construction, repair and design"); + AddCategoryMapping(1548, TorznabCatType.Books, " | - Wood and metal"); + AddCategoryMapping(2211, TorznabCatType.Books, " | - Plants and Animals"); + AddCategoryMapping(615, TorznabCatType.Books, " | - Miscellaneous"); + AddCategoryMapping(1581, TorznabCatType.Books, "Martial Arts (Video Tutorials)"); + AddCategoryMapping(1590, TorznabCatType.Books, " | - Aikido and Aiki-jutsu"); + AddCategoryMapping(1587, TorznabCatType.Books, " | - Vin Chun"); + AddCategoryMapping(1594, TorznabCatType.Books, " | - Jiu-Jitsu"); + AddCategoryMapping(1591, TorznabCatType.Books, " | - Judo and Sambo"); + AddCategoryMapping(1588, TorznabCatType.Books, " | - Karate"); + AddCategoryMapping(1596, TorznabCatType.Books, " | - Knife Fight"); + AddCategoryMapping(1585, TorznabCatType.Books, " | - Work with weapon"); + AddCategoryMapping(1586, TorznabCatType.Books, " | - Russian style"); + AddCategoryMapping(2078, TorznabCatType.Books, " | - Dogfight"); + AddCategoryMapping(1929, TorznabCatType.Books, " | - Mixed styles"); + AddCategoryMapping(1593, TorznabCatType.Books, " | - Percussion styles"); + AddCategoryMapping(1592, TorznabCatType.Books, " | - This is a"); + AddCategoryMapping(1595, TorznabCatType.Books, " | - Miscellaneous"); + AddCategoryMapping(1556, TorznabCatType.Books, "Computer video tutorials and interactive training DVD"); + AddCategoryMapping(1560, TorznabCatType.Books, " | - Networks and Security"); + AddCategoryMapping(1561, TorznabCatType.Books, " | - OS and Microsoft Server Software"); + AddCategoryMapping(1653, TorznabCatType.Books, " | - Microsoft Office program"); + AddCategoryMapping(1570, TorznabCatType.Books, " | - OS and UNIX family program"); + AddCategoryMapping(1654, TorznabCatType.Books, " | - Adobe Photoshop"); + AddCategoryMapping(1655, TorznabCatType.Books, " |- Autodesk Maya"); + AddCategoryMapping(1656, TorznabCatType.Books, " | - Autodesk 3ds Max"); + AddCategoryMapping(1930, TorznabCatType.Books, " |- Autodesk Softimage (XSI)"); + AddCategoryMapping(1931, TorznabCatType.Books, " |- ZBrush"); + AddCategoryMapping(1932, TorznabCatType.Books, " |- Flash, Flex и ActionScript"); + AddCategoryMapping(1562, TorznabCatType.Books, " | - 2D-графика"); + AddCategoryMapping(1563, TorznabCatType.Books, " | - 3D-графика"); + AddCategoryMapping(1626, TorznabCatType.Books, " | - Engineering and scientific programs"); + AddCategoryMapping(1564, TorznabCatType.Books, " | - Web-design"); + AddCategoryMapping(1565, TorznabCatType.Books, " | - Programming"); + AddCategoryMapping(1559, TorznabCatType.Books, " | - Software for Mac OS"); + AddCategoryMapping(1566, TorznabCatType.Books, " | - Working with video"); + AddCategoryMapping(1573, TorznabCatType.Books, " | - Working with sound"); + AddCategoryMapping(1567, TorznabCatType.Books, " | - Other (Computer video tutorials)"); + + // Аудиокниги + AddCategoryMapping(2326, TorznabCatType.Audio, "Auditions, history, memoirs"); + AddCategoryMapping(574, TorznabCatType.Audio, " | - [Audio] Auditions and readings"); + AddCategoryMapping(1036, TorznabCatType.Audio, " | - [Audio] Lots of great people"); + AddCategoryMapping(400, TorznabCatType.Audio, " | - [Audio] Historical Book"); + AddCategoryMapping(2389, TorznabCatType.Audio, "Science fiction, fantasy, mystery, horror, fanfiction"); + AddCategoryMapping(2388, TorznabCatType.Audio, " | - [Audio] Foreign fiction, fantasy, mystery, horror, .."); + AddCategoryMapping(2387, TorznabCatType.Audio, " | - [Audio] Russian fiction, fantasy, mystery, horror, .."); + AddCategoryMapping(2348, TorznabCatType.Audio, " | - [Audio] Puzzle / Miscellaneous Science Fiction, Fantasy, Mystery, too .."); + AddCategoryMapping(2327, TorznabCatType.Audio, "Fiction"); + AddCategoryMapping(695, TorznabCatType.Audio, " | - [Audio] Poetry"); + AddCategoryMapping(399, TorznabCatType.Audio, " | - [Audio] Foreign literature"); + AddCategoryMapping(402, TorznabCatType.Audio, " | - [Audio] Russian literature"); + AddCategoryMapping(490, TorznabCatType.Audio, " | - [Audio] Children's Books"); + AddCategoryMapping(499, TorznabCatType.Audio, " | - [Audio] Detectives, Adventure, Thriller, Action"); + AddCategoryMapping(2324, TorznabCatType.Audio, "religion"); + AddCategoryMapping(2325, TorznabCatType.Audio, " | - [Audio] Orthodoxy"); + AddCategoryMapping(2342, TorznabCatType.Audio, " | - [Audio] Islam"); + AddCategoryMapping(530, TorznabCatType.Audio, " | - [Audio] Other traditional religion"); + AddCategoryMapping(2152, TorznabCatType.Audio, " | - [Audio] Non-traditional religious and philosophical teachings"); + AddCategoryMapping(2328, TorznabCatType.Audio, "other literature"); + AddCategoryMapping(403, TorznabCatType.Audio, " | - [Audio] academic and popular literature"); + AddCategoryMapping(1279, TorznabCatType.Audio, " | - [Audio] lossless-audio books"); + AddCategoryMapping(716, TorznabCatType.Audio, " | - [Audio] Business"); + AddCategoryMapping(2165, TorznabCatType.Audio, " | - [Audio] Miscellaneous"); + AddCategoryMapping(401, TorznabCatType.Audio, " | - [Audio], sub-standard distribution"); + + // Все по авто и мото + AddCategoryMapping(1964, TorznabCatType.Books, "Repair and maintenance of vehicles"); + AddCategoryMapping(1973, TorznabCatType.Books, " | - Original catalogs on selection of spare parts"); + AddCategoryMapping(1974, TorznabCatType.Books, " | - Non-original spare parts catalogs for selection"); + AddCategoryMapping(1975, TorznabCatType.Books, " | - Diagnostic and repair programs"); + AddCategoryMapping(1976, TorznabCatType.Books, " | - Tuning, chip tuning, tuning"); + AddCategoryMapping(1977, TorznabCatType.Books, " | - Books for the repair / maintenance / operation of the vehicle"); + AddCategoryMapping(1203, TorznabCatType.Books, " | - Multimediyki repair / maintenance / operation of the vehicle"); + AddCategoryMapping(1978, TorznabCatType.Books, " | - Accounting, utilities, etc."); + AddCategoryMapping(1979, TorznabCatType.Books, " | - Virtual Driving School"); + AddCategoryMapping(1980, TorznabCatType.Books, " | - Video lessons on driving vehicles"); + AddCategoryMapping(1981, TorznabCatType.Books, " | - Tutorials repair vehicles"); + AddCategoryMapping(1970, TorznabCatType.Books, " | - Journals by car / moto"); + AddCategoryMapping(334, TorznabCatType.Books, " | - Water transport"); + AddCategoryMapping(1202, TorznabCatType.Books, "Movies and transfer by car / moto"); + AddCategoryMapping(1985, TorznabCatType.Books, " | - Documentary / educational films"); + AddCategoryMapping(1982, TorznabCatType.Books, " | - Entertainment shows"); + AddCategoryMapping(2151, TorznabCatType.Books, " |- Top Gear/Топ Гир"); + AddCategoryMapping(1983, TorznabCatType.Books, " | - Test Drive / Reviews / Motor"); + AddCategoryMapping(1984, TorznabCatType.Books, " | - Tuning / Fast and the Furious"); + + // Музыка + AddCategoryMapping(409, TorznabCatType.Audio, "Classical and contemporary academic music"); + AddCategoryMapping(1660, TorznabCatType.Audio, " | - In-house digitizing (Classical Music)"); + AddCategoryMapping(1164, TorznabCatType.Audio, " | - Multi-channel music (classical and modern classics in .."); + AddCategoryMapping(1884, TorznabCatType.Audio, " | - Hi-Res stereo (classic and modern classic in obrabot .."); + AddCategoryMapping(445, TorznabCatType.Audio, " | - Classical music (Video)"); + AddCategoryMapping(984, TorznabCatType.Audio, " | - Classical music (DVD and HD Video)"); + AddCategoryMapping(702, TorznabCatType.Audio, " | - Opera (Video)"); + AddCategoryMapping(983, TorznabCatType.Audio, " |- Опера (DVD и HD Видео)"); + AddCategoryMapping(1990, TorznabCatType.Audio, " | - Ballet and contemporary dance (Video, DVD and HD Video)"); + AddCategoryMapping(560, TorznabCatType.Audio, " | - Complete collection of works and multi-disc edition (lossl .."); + AddCategoryMapping(794, TorznabCatType.Audio, " |- Опера (lossless)"); + AddCategoryMapping(556, TorznabCatType.Audio, " | - Vocal music (lossless)"); + AddCategoryMapping(2307, TorznabCatType.Audio, " | - Horovaya Music (lossless)"); + AddCategoryMapping(557, TorznabCatType.Audio, " | - Orchestral music (lossless)"); + AddCategoryMapping(2308, TorznabCatType.Audio, " | - Concerto for Orchestra Instrument (lossless)"); + AddCategoryMapping(558, TorznabCatType.Audio, " | - Chamber instrumental music (lossless)"); + AddCategoryMapping(793, TorznabCatType.Audio, " | - Solo instrumental music (lossless)"); + AddCategoryMapping(436, TorznabCatType.Audio, " | - Complete collection of works and multi-disc edition (lossy .."); + AddCategoryMapping(2309, TorznabCatType.Audio, " | - Vocal and choral music (lossy)"); + AddCategoryMapping(2310, TorznabCatType.Audio, " | - Orchestral music (lossy)"); + AddCategoryMapping(2311, TorznabCatType.Audio, " | - Chamber and solo instrumental music (lossy)"); + AddCategoryMapping(969, TorznabCatType.Audio, " | - Classics in modern processing, Classical Crossover (l .."); + AddCategoryMapping(1125, TorznabCatType.Audio, "Folklore, Folk and World Music"); + AddCategoryMapping(1130, TorznabCatType.Audio, " |- Восточноевропейский фолк (lossy)"); + AddCategoryMapping(1131, TorznabCatType.Audio, " | - Eastern European Folk (lossless)"); + AddCategoryMapping(1132, TorznabCatType.Audio, " |- Западноевропейский фолк (lossy)"); + AddCategoryMapping(1133, TorznabCatType.Audio, " |- Западноевропейский фолк (lossless)"); + AddCategoryMapping(2084, TorznabCatType.Audio, " | - Klezmer and Jewish folklore (lossy and lossless)"); + AddCategoryMapping(1128, TorznabCatType.Audio, " | - World Music Siberia, Central Asia and East Asia (loss .."); + AddCategoryMapping(1129, TorznabCatType.Audio, " | - World Music Siberia, Central Asia and East Asia (loss .."); + AddCategoryMapping(1856, TorznabCatType.Audio, " | - World Music India (lossy)"); + AddCategoryMapping(2430, TorznabCatType.Audio, " | - World Music India (lossless)"); + AddCategoryMapping(1283, TorznabCatType.Audio, " | - World Music Africa and the Middle East (lossy)"); + AddCategoryMapping(2085, TorznabCatType.Audio, " | - World Music Africa and the Middle East (lossless)"); + AddCategoryMapping(1282, TorznabCatType.Audio, " | - Ethnic Music of the Caucasus and Transcaucasia (lossy and lossless .."); + AddCategoryMapping(1284, TorznabCatType.Audio, " | - World Music Americas (lossy)"); + AddCategoryMapping(1285, TorznabCatType.Audio, " | - World Music Americas (lossless)"); + AddCategoryMapping(1138, TorznabCatType.Audio, " | - World Music Australia, the Pacific and Indian oceans .."); + AddCategoryMapping(1136, TorznabCatType.Audio, " |- Country, Bluegrass (lossy)"); + AddCategoryMapping(1137, TorznabCatType.Audio, " |- Country, Bluegrass (lossless)"); + AddCategoryMapping(1141, TorznabCatType.Audio, " | - Folklore, Folk and World Music (Video)"); + AddCategoryMapping(1142, TorznabCatType.Audio, " | - Folklore, Folk and World Music (DVD Video)"); + AddCategoryMapping(2530, TorznabCatType.Audio, " | - Folklore, Folk and World Music (HD Video)"); + AddCategoryMapping(506, TorznabCatType.Audio, " | - Folklore, Folk and World Music (own otsif .."); + AddCategoryMapping(1849, TorznabCatType.Audio, "New Age, Relax, Meditative & Flamenco"); + AddCategoryMapping(1126, TorznabCatType.Audio, " |- NewAge & Meditative (lossy)"); + AddCategoryMapping(1127, TorznabCatType.Audio, " |- NewAge & Meditative (lossless)"); + AddCategoryMapping(1134, TorznabCatType.Audio, " | - Flamenco and acoustic guitar (lossy)"); + AddCategoryMapping(1135, TorznabCatType.Audio, " | - Flamenco and acoustic guitar (lossless)"); + AddCategoryMapping(2352, TorznabCatType.Audio, " |- New Age, Relax, Meditative & Flamenco (Видео)"); + AddCategoryMapping(2351, TorznabCatType.Audio, " |- New Age, Relax, Meditative & Flamenco (DVD и HD Видео)"); + AddCategoryMapping(855, TorznabCatType.Audio, " | - Sounds of Nature"); + AddCategoryMapping(408, TorznabCatType.Audio, "Рэп, Хип-Хоп, R'n'B"); + AddCategoryMapping(441, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop (lossy)"); + AddCategoryMapping(1173, TorznabCatType.Audio, " |- Отечественный R'n'B (lossy)"); + AddCategoryMapping(1486, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop, R'n'B (lossless)"); + AddCategoryMapping(1172, TorznabCatType.Audio, " |- Зарубежный R'n'B (lossy)"); + AddCategoryMapping(446, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (lossy)"); + AddCategoryMapping(909, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (lossless)"); + AddCategoryMapping(1665, TorznabCatType.Audio, " |- Зарубежный R'n'B (lossless)"); + AddCategoryMapping(1835, TorznabCatType.Audio, " | - Rap, Hip-Hop, R'n'B (own digitization)"); + AddCategoryMapping(1189, TorznabCatType.Audio, " | - Domestic Rap, Hip-Hop (Video)"); + AddCategoryMapping(1455, TorznabCatType.Audio, " | - Domestic R'n'B (Video)"); + AddCategoryMapping(442, TorznabCatType.Audio, " | - Foreign Rap, Hip-Hop (Video)"); + AddCategoryMapping(1174, TorznabCatType.Audio, " | - Foreign R'n'B (Video)"); + AddCategoryMapping(1107, TorznabCatType.Audio, " |- Рэп, Хип-Хоп, R'n'B (DVD Video)"); + AddCategoryMapping(2529, TorznabCatType.Audio, " |- Рэп, Хип-Хоп, R'n'B (HD Видео)"); + AddCategoryMapping(1760, TorznabCatType.Audio, "Reggae, Ska, Dub"); + AddCategoryMapping(1764, TorznabCatType.Audio, " | - Rocksteady, Early Reggae, Ska-Jazz, Trad.Ska (lossy и lo .."); + AddCategoryMapping(1766, TorznabCatType.Audio, " |- Punky-Reggae, Rocksteady-Punk, Ska Revival (lossy)"); + AddCategoryMapping(1767, TorznabCatType.Audio, " | - 3rd Wave Ska (lossy)"); + AddCategoryMapping(1769, TorznabCatType.Audio, " | - Ska-Punk, Ska-Core (lossy)"); + AddCategoryMapping(1765, TorznabCatType.Audio, " |- Reggae (lossy)"); + AddCategoryMapping(1771, TorznabCatType.Audio, " |- Dub (lossy)"); + AddCategoryMapping(1770, TorznabCatType.Audio, " |- Dancehall, Raggamuffin (lossy)"); + AddCategoryMapping(1768, TorznabCatType.Audio, " |- Reggae, Dancehall, Dub (lossless)"); + AddCategoryMapping(1774, TorznabCatType.Audio, " | - Ska Ska-Punk, Ska-Jazz (lossless)"); + AddCategoryMapping(1772, TorznabCatType.Audio, " | - Domestic reggae, dub (lossy and lossless)"); + AddCategoryMapping(1773, TorznabCatType.Audio, " | - Patriotic ska music (lossy and lossless)"); + AddCategoryMapping(2233, TorznabCatType.Audio, " | - Reggae, Ska, Dub (компиляции) (lossy и lossless)"); + AddCategoryMapping(2232, TorznabCatType.Audio, " | - Reggae, Ska, Dub (own digitization)"); + AddCategoryMapping(1775, TorznabCatType.Audio, " | - Reggae, Ska, Dub (Видео)"); + AddCategoryMapping(1777, TorznabCatType.Audio, " | - Reggae, Ska, Dub (DVD и HD Video)"); + AddCategoryMapping(416, TorznabCatType.Audio, "Soundtracks and Karaoke"); + AddCategoryMapping(782, TorznabCatType.Audio, " | - Karaoke (Audio)"); + AddCategoryMapping(2377, TorznabCatType.Audio, " | - Karaoke (Video)"); + AddCategoryMapping(468, TorznabCatType.Audio, " |- Минусовки (lossy и lossless)"); + AddCategoryMapping(1625, TorznabCatType.Audio, " | - Soundtracks (own digitization)"); + AddCategoryMapping(691, TorznabCatType.Audio, " | - Soundtracks for domestic films (lossless)"); + AddCategoryMapping(469, TorznabCatType.Audio, " | - Soundtracks for domestic films (lossy)"); + AddCategoryMapping(786, TorznabCatType.Audio, " | - Soundtracks for foreign films (lossless)"); + AddCategoryMapping(785, TorznabCatType.Audio, " | - Soundtracks for foreign films (lossy)"); + AddCategoryMapping(796, TorznabCatType.Audio, " | - Informal soundtracks for films and TV series (lossy)"); + AddCategoryMapping(784, TorznabCatType.Audio, " | - Soundtracks for games (lossless)"); + AddCategoryMapping(783, TorznabCatType.Audio, " | - Soundtracks for games (lossy)"); + AddCategoryMapping(2331, TorznabCatType.Audio, " | - Informal soundtracks for games (lossy)"); + AddCategoryMapping(2431, TorznabCatType.Audio, " | - The arrangements of music from the game (lossy and lossless)"); + AddCategoryMapping(1397, TorznabCatType.Audio, " | - Hi-Res stereo and multi-channel music (Soundtracks)"); + AddCategoryMapping(1215, TorznabCatType.Audio, "Chanson, Author and military songs"); + AddCategoryMapping(1220, TorznabCatType.Audio, " | - The domestic chanson (lossless)"); + AddCategoryMapping(1221, TorznabCatType.Audio, " | - The domestic chanson (lossy)"); + AddCategoryMapping(1334, TorznabCatType.Audio, " | - Compilations domestic chanson (lossy)"); + AddCategoryMapping(1216, TorznabCatType.Audio, " | - War Song (lossless)"); + AddCategoryMapping(1223, TorznabCatType.Audio, " | - War Song (lossy)"); + AddCategoryMapping(1224, TorznabCatType.Audio, " | - Chanson (lossless)"); + AddCategoryMapping(1225, TorznabCatType.Audio, " | - Chanson (lossy)"); + AddCategoryMapping(1226, TorznabCatType.Audio, " |- Менестрели и ролевики (lossy и lossless)"); + AddCategoryMapping(1217, TorznabCatType.Audio, " | - In-house digitizing (Chanson, and Bards) lossles .."); + AddCategoryMapping(1227, TorznabCatType.Audio, " | - Video (Chanson, and Bards)"); + AddCategoryMapping(1228, TorznabCatType.Audio, " | - DVD Video (Chanson, and Bards)"); + AddCategoryMapping(413, TorznabCatType.Audio, "Music of other genres"); + AddCategoryMapping(974, TorznabCatType.Audio, " | - In-house digitizing (Music from other genres)"); + AddCategoryMapping(463, TorznabCatType.Audio, " | - Patriotic music of other genres (lossy)"); + AddCategoryMapping(464, TorznabCatType.Audio, " | - Patriotic music of other genres (lossless)"); + AddCategoryMapping(466, TorznabCatType.Audio, " | - International music of other genres (lossy)"); + AddCategoryMapping(465, TorznabCatType.Audio, " | - International music of other genres (lossless)"); + AddCategoryMapping(2018, TorznabCatType.Audio, " | - Music for ballroom dancing (lossy and lossless)"); + AddCategoryMapping(1396, TorznabCatType.Audio, " | - Orthodox chants (lossy)"); + AddCategoryMapping(1395, TorznabCatType.Audio, " | - Orthodox chants (lossless)"); + AddCategoryMapping(1351, TorznabCatType.Audio, " | - A collection of songs for children (lossy and lossless)"); + AddCategoryMapping(475, TorznabCatType.Audio, " | - Video (Music from other genres)"); + AddCategoryMapping(988, TorznabCatType.Audio, " | - DVD Video (Music from other genres)"); + AddCategoryMapping(880, TorznabCatType.Audio, " | - The Musical (lossy and lossless)"); + AddCategoryMapping(655, TorznabCatType.Audio, " | - The Musical (Video and DVD Video)"); + AddCategoryMapping(965, TorznabCatType.Audio, " | - Informal and vnezhanrovye collections (lossy)"); + AddCategoryMapping(919, TorznabCatType.Audio, "Sheet Music literature"); + AddCategoryMapping(944, TorznabCatType.Audio, " | - Academic Music (Notes and Media CD)"); + AddCategoryMapping(980, TorznabCatType.Audio, " | - Other destinations (notes, tablature)"); + AddCategoryMapping(946, TorznabCatType.Audio, " | - Tutorials and Schools"); + AddCategoryMapping(977, TorznabCatType.Audio, " | - Songbooks (Songbooks)"); + AddCategoryMapping(2074, TorznabCatType.Audio, " | - Music Literature and Theory"); + AddCategoryMapping(2349, TorznabCatType.Audio, " | - Music Magazines"); + + // Популярная музыка + AddCategoryMapping(2495, TorznabCatType.Audio, "Domestic Pop"); + AddCategoryMapping(424, TorznabCatType.Audio, " | - Patriotic Pop (lossy)"); + AddCategoryMapping(1361, TorznabCatType.Audio, " | - Patriotic Pop music (collections) (lossy)"); + AddCategoryMapping(425, TorznabCatType.Audio, " | - Patriotic Pop (lossless)"); + AddCategoryMapping(1635, TorznabCatType.Audio, " | - Soviet pop music, retro (lossy)"); + AddCategoryMapping(1634, TorznabCatType.Audio, " | - Soviet pop music, retro (lossless)"); + AddCategoryMapping(2497, TorznabCatType.Audio, "Foreign pop music"); + AddCategoryMapping(428, TorznabCatType.Audio, " | - Foreign pop music (lossy)"); + AddCategoryMapping(1362, TorznabCatType.Audio, " | - Foreign pop music (collections) (lossy)"); + AddCategoryMapping(429, TorznabCatType.Audio, " | - International Pop (lossless)"); + AddCategoryMapping(1219, TorznabCatType.Audio, " | - Foreign chanson (lossy)"); + AddCategoryMapping(1452, TorznabCatType.Audio, " | - Foreign chanson (lossless)"); + AddCategoryMapping(1331, TorznabCatType.Audio, " | - East Asian pop music (lossy)"); + AddCategoryMapping(1330, TorznabCatType.Audio, " | - East Asian Pop (lossless)"); + AddCategoryMapping(2499, TorznabCatType.Audio, "Eurodance, Disco, Hi-NRG"); + AddCategoryMapping(2503, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (lossy)"); + AddCategoryMapping(2504, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (сборники) (lossy)"); + AddCategoryMapping(2502, TorznabCatType.Audio, " |- Eurodance, Euro-House, Technopop (lossless)"); + AddCategoryMapping(2501, TorznabCatType.Audio, " |- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossy)"); + AddCategoryMapping(2505, TorznabCatType.Audio, " | - Disco, Italo-Disco, Euro-Disco, Hi-NRG (сборники) (lossy .."); + AddCategoryMapping(2500, TorznabCatType.Audio, " |- Disco, Italo-Disco, Euro-Disco, Hi-NRG (lossless)"); + AddCategoryMapping(2507, TorznabCatType.Audio, "Видео, DVD Video, HD Video (поп-музыка)"); + AddCategoryMapping(1121, TorznabCatType.Audio, " | - Patriotic Pop (Video)"); + AddCategoryMapping(1122, TorznabCatType.Audio, " | - Patriotic Pop (DVD Video)"); + AddCategoryMapping(2510, TorznabCatType.Audio, " | - Soviet pop music, retro (video)"); + AddCategoryMapping(2509, TorznabCatType.Audio, " | - Soviet pop music, retro (DVD Video)"); + AddCategoryMapping(431, TorznabCatType.Audio, " | - Foreign pop music (Video)"); + AddCategoryMapping(986, TorznabCatType.Audio, " | - Foreign pop music (DVD Video)"); + AddCategoryMapping(2532, TorznabCatType.Audio, " |- Eurodance, Disco (видео)"); + AddCategoryMapping(2531, TorznabCatType.Audio, " |- Eurodance, Disco (DVD Video)"); + AddCategoryMapping(2378, TorznabCatType.Audio, " | - East Asian pop music (Video)"); + AddCategoryMapping(2379, TorznabCatType.Audio, " | - East Asian pop music (DVD Video)"); + AddCategoryMapping(2383, TorznabCatType.Audio, " | - Foreign chanson (Video)"); + AddCategoryMapping(2384, TorznabCatType.Audio, " | - Foreign chanson (DVD Video)"); + AddCategoryMapping(2088, TorznabCatType.Audio, " | - Patriotic Pop (National concerts, video dock.) .."); + AddCategoryMapping(2089, TorznabCatType.Audio, " | - Foreign pop music (National concerts, video dock.) (Bu .."); + AddCategoryMapping(2426, TorznabCatType.Audio, " | - Patriotic Pop Music, Chanson, Eurodance, Disco (HD V .."); + AddCategoryMapping(2508, TorznabCatType.Audio, " | - International Pop Music, Chanson, Eurodance, Disco (HD Vide .."); + AddCategoryMapping(2512, TorznabCatType.Audio, "The multi-channel music and own digitization (pop music)"); + AddCategoryMapping(1444, TorznabCatType.Audio, " | - Foreign pop music (own digitization)"); + AddCategoryMapping(1785, TorznabCatType.Audio, " | - Eastern pop music (own digitization)"); + AddCategoryMapping(239, TorznabCatType.Audio, " | - Patriotic Pop (own digitization)"); + AddCategoryMapping(450, TorznabCatType.Audio, " | - Instrumental Pop (own digitization)"); + AddCategoryMapping(1163, TorznabCatType.Audio, " | - Multi-channel music (pop music)"); + AddCategoryMapping(1885, TorznabCatType.Audio, " |- Hi-Res stereo (Поп-музыка)"); + + // Джазовая и Блюзовая музыка + AddCategoryMapping(2267, TorznabCatType.Audio, "foreign jazz"); + AddCategoryMapping(2277, TorznabCatType.Audio, " |- Early Jazz, Swing, Gypsy (lossless)"); + AddCategoryMapping(2278, TorznabCatType.Audio, " |- Bop (lossless)"); + AddCategoryMapping(2279, TorznabCatType.Audio, " |- Mainstream Jazz, Cool (lossless)"); + AddCategoryMapping(2280, TorznabCatType.Audio, " |- Jazz Fusion (lossless)"); + AddCategoryMapping(2281, TorznabCatType.Audio, " |- World Fusion, Ethnic Jazz (lossless)"); + AddCategoryMapping(2282, TorznabCatType.Audio, " |- Avant-Garde Jazz, Free Improvisation (lossless)"); + AddCategoryMapping(2353, TorznabCatType.Audio, " |- Modern Creative, Third Stream (lossless)"); + AddCategoryMapping(2284, TorznabCatType.Audio, " |- Smooth, Jazz-Pop (lossless)"); + AddCategoryMapping(2285, TorznabCatType.Audio, " |- Vocal Jazz (lossless)"); + AddCategoryMapping(2283, TorznabCatType.Audio, " |- Funk, Soul, R&B (lossless)"); + AddCategoryMapping(2286, TorznabCatType.Audio, " | - Compilations foreign jazz (lossless)"); + AddCategoryMapping(2287, TorznabCatType.Audio, " | - Foreign jazz (lossy)"); + AddCategoryMapping(2268, TorznabCatType.Audio, "foreign blues"); + AddCategoryMapping(2293, TorznabCatType.Audio, " |- Blues (Texas, Chicago, Modern and Others) (lossless)"); + AddCategoryMapping(2292, TorznabCatType.Audio, " |- Blues-rock (lossless)"); + AddCategoryMapping(2290, TorznabCatType.Audio, " |- Roots, Pre-War Blues, Early R&B, Gospel (lossless)"); + AddCategoryMapping(2289, TorznabCatType.Audio, " | - Foreign blues (collections; Tribute VA) (lossless)"); + AddCategoryMapping(2288, TorznabCatType.Audio, " | - Foreign blues (lossy)"); + AddCategoryMapping(2269, TorznabCatType.Audio, "Domestic jazz and blues"); + AddCategoryMapping(2297, TorznabCatType.Audio, " | - Domestic Jazz (lossless)"); + AddCategoryMapping(2295, TorznabCatType.Audio, " | - Domestic jazz (lossy)"); + AddCategoryMapping(2296, TorznabCatType.Audio, " | - Domestic Blues (lossless)"); + AddCategoryMapping(2298, TorznabCatType.Audio, " | - Domestic Blues (lossy)"); + AddCategoryMapping(2270, TorznabCatType.Audio, "The multi-channel music and own digitization (Jazz and Blues)"); + AddCategoryMapping(2303, TorznabCatType.Audio, " | - Multi-channel music (Jazz and Blues)"); + AddCategoryMapping(2302, TorznabCatType.Audio, " | - Hi-Res stereo (Jazz and Blues)"); + AddCategoryMapping(2301, TorznabCatType.Audio, " | - In-house digitizing (Jazz and Blues)"); + AddCategoryMapping(2271, TorznabCatType.Audio, "Video, DVD Video, HD Video (Jazz and Blues)"); + AddCategoryMapping(2305, TorznabCatType.Audio, " | - Jazz and Blues (Video)"); + AddCategoryMapping(2304, TorznabCatType.Audio, " | - Jazz and Blues (DVD Video)"); + AddCategoryMapping(2306, TorznabCatType.Audio, " | - Jazz and Blues (HD Video)"); + + // Рок-музыка + AddCategoryMapping(1698, TorznabCatType.Audio, "foreign Rock"); + AddCategoryMapping(1702, TorznabCatType.Audio, " |- Classic Rock & Hard Rock (lossless)"); + AddCategoryMapping(1703, TorznabCatType.Audio, " |- Classic Rock & Hard Rock (lossy)"); + AddCategoryMapping(1704, TorznabCatType.Audio, " |- Progressive & Art-Rock (lossless)"); + AddCategoryMapping(1705, TorznabCatType.Audio, " |- Progressive & Art-Rock (lossy)"); + AddCategoryMapping(1706, TorznabCatType.Audio, " |- Folk-Rock (lossless)"); + AddCategoryMapping(1707, TorznabCatType.Audio, " |- Folk-Rock (lossy)"); + AddCategoryMapping(2329, TorznabCatType.Audio, " |- AOR (Melodic Hard Rock, Arena rock) (lossless)"); + AddCategoryMapping(2330, TorznabCatType.Audio, " |- AOR (Melodic Hard Rock, Arena rock) (lossy)"); + AddCategoryMapping(1708, TorznabCatType.Audio, " |- Pop-Rock & Soft Rock (lossless)"); + AddCategoryMapping(1709, TorznabCatType.Audio, " |- Pop-Rock & Soft Rock (lossy)"); + AddCategoryMapping(1710, TorznabCatType.Audio, " |- Instrumental Guitar Rock (lossless)"); + AddCategoryMapping(1711, TorznabCatType.Audio, " |- Instrumental Guitar Rock (lossy)"); + AddCategoryMapping(1712, TorznabCatType.Audio, " |- Rockabilly, Psychobilly, Rock'n'Roll (lossless)"); + AddCategoryMapping(1713, TorznabCatType.Audio, " |- Rockabilly, Psychobilly, Rock'n'Roll (lossy)"); + AddCategoryMapping(731, TorznabCatType.Audio, " | - Compilations foreign rock (lossless)"); + AddCategoryMapping(1799, TorznabCatType.Audio, " | - Compilations foreign rock (lossy)"); + AddCategoryMapping(1714, TorznabCatType.Audio, " | - East Asian Rock (lossless)"); + AddCategoryMapping(1715, TorznabCatType.Audio, " | - East Asian rock (lossy)"); + AddCategoryMapping(1716, TorznabCatType.Audio, "foreign Metal"); + AddCategoryMapping(1796, TorznabCatType.Audio, " |- Avant-garde, Experimental Metal (lossless)"); + AddCategoryMapping(1797, TorznabCatType.Audio, " |- Avant-garde, Experimental Metal (lossy)"); + AddCategoryMapping(1719, TorznabCatType.Audio, " |- Black (lossless)"); + AddCategoryMapping(1778, TorznabCatType.Audio, " |- Black (lossy)"); + AddCategoryMapping(1779, TorznabCatType.Audio, " |- Death, Doom (lossless)"); + AddCategoryMapping(1780, TorznabCatType.Audio, " |- Death, Doom (lossy)"); + AddCategoryMapping(1720, TorznabCatType.Audio, " |- Folk, Pagan, Viking (lossless)"); + AddCategoryMapping(798, TorznabCatType.Audio, " |- Folk, Pagan, Viking (lossy)"); + AddCategoryMapping(1724, TorznabCatType.Audio, " |- Gothic Metal (lossless)"); + AddCategoryMapping(1725, TorznabCatType.Audio, " |- Gothic Metal (lossy)"); + AddCategoryMapping(1730, TorznabCatType.Audio, " |- Grind, Brutal Death (lossless)"); + AddCategoryMapping(1731, TorznabCatType.Audio, " |- Grind, Brutal Death (lossy)"); + AddCategoryMapping(1726, TorznabCatType.Audio, " |- Heavy, Power, Progressive (lossless)"); + AddCategoryMapping(1727, TorznabCatType.Audio, " |- Heavy, Power, Progressive (lossy)"); + AddCategoryMapping(1815, TorznabCatType.Audio, " |- Sludge, Stoner, Post-Metal (lossless)"); + AddCategoryMapping(1816, TorznabCatType.Audio, " |- Sludge, Stoner, Post-Metal (lossy)"); + AddCategoryMapping(1728, TorznabCatType.Audio, " |- Thrash, Speed (lossless)"); + AddCategoryMapping(1729, TorznabCatType.Audio, " |- Thrash, Speed (lossy)"); + AddCategoryMapping(2230, TorznabCatType.Audio, " | - Compilations (lossless)"); + AddCategoryMapping(2231, TorznabCatType.Audio, " | - Compilations (lossy)"); + AddCategoryMapping(1732, TorznabCatType.Audio, "Foreign Alternative, Punk, Independent"); + AddCategoryMapping(1736, TorznabCatType.Audio, " |- Alternative & Nu-metal (lossless)"); + AddCategoryMapping(1737, TorznabCatType.Audio, " |- Alternative & Nu-metal (lossy)"); + AddCategoryMapping(1738, TorznabCatType.Audio, " |- Punk (lossless)"); + AddCategoryMapping(1739, TorznabCatType.Audio, " |- Punk (lossy)"); + AddCategoryMapping(1740, TorznabCatType.Audio, " |- Hardcore (lossless)"); + AddCategoryMapping(1741, TorznabCatType.Audio, " |- Hardcore (lossy)"); + AddCategoryMapping(1742, TorznabCatType.Audio, " |- Indie, Post-Rock & Post-Punk (lossless)"); + AddCategoryMapping(1743, TorznabCatType.Audio, " |- Indie, Post-Rock & Post-Punk (lossy)"); + AddCategoryMapping(1744, TorznabCatType.Audio, " |- Industrial & Post-industrial (lossless)"); + AddCategoryMapping(1745, TorznabCatType.Audio, " |- Industrial & Post-industrial (lossy)"); + AddCategoryMapping(1746, TorznabCatType.Audio, " |- Emocore, Post-hardcore, Metalcore (lossless)"); + AddCategoryMapping(1747, TorznabCatType.Audio, " |- Emocore, Post-hardcore, Metalcore (lossy)"); + AddCategoryMapping(1748, TorznabCatType.Audio, " |- Gothic Rock & Dark Folk (lossless)"); + AddCategoryMapping(1749, TorznabCatType.Audio, " |- Gothic Rock & Dark Folk (lossy)"); + AddCategoryMapping(2175, TorznabCatType.Audio, " |- Avant-garde, Experimental Rock (lossless)"); + AddCategoryMapping(2174, TorznabCatType.Audio, " |- Avant-garde, Experimental Rock (lossy)"); + AddCategoryMapping(722, TorznabCatType.Audio, "Domestic Rock"); + AddCategoryMapping(737, TorznabCatType.Audio, " | - Rock, Punk, Alternative (lossless)"); + AddCategoryMapping(738, TorznabCatType.Audio, " | - Rock, Punk, Alternative (lossy)"); + AddCategoryMapping(739, TorznabCatType.Audio, " |- Металл (lossless)"); + AddCategoryMapping(740, TorznabCatType.Audio, " |- Металл (lossy)"); + AddCategoryMapping(951, TorznabCatType.Audio, " | - Rock in the languages ​​of xUSSR (lossless)"); + AddCategoryMapping(952, TorznabCatType.Audio, " | - Rock in the languages ​​of xUSSR (lossy)"); + AddCategoryMapping(1752, TorznabCatType.Audio, "The multi-channel music and own digitization (Rock)"); + AddCategoryMapping(1756, TorznabCatType.Audio, " | - Foreign rock (own digitization)"); + AddCategoryMapping(1758, TorznabCatType.Audio, " | - Domestic Rock (own digitization)"); + AddCategoryMapping(1757, TorznabCatType.Audio, " | - Multi-channel music (rock)"); + AddCategoryMapping(1755, TorznabCatType.Audio, " |- Hi-Res stereo (рок)"); + AddCategoryMapping(453, TorznabCatType.Audio, " | - Conversions Quadraphonic (multichannel music)"); + AddCategoryMapping(1170, TorznabCatType.Audio, " | - Conversions SACD (multi-channel music)"); + AddCategoryMapping(1759, TorznabCatType.Audio, " | - Conversions from the Blu-Ray (multichannel music)"); + AddCategoryMapping(1852, TorznabCatType.Audio, " |- Апмиксы-Upmixes/Даунмиксы-Downmix (многоканальная и Hi-R.."); + AddCategoryMapping(1781, TorznabCatType.Audio, "Видео, DVD Video, HD Video (Рок-музыка)"); + AddCategoryMapping(1782, TorznabCatType.Audio, " |- Rock (Видео)"); + AddCategoryMapping(1783, TorznabCatType.Audio, " |- Rock (DVD Video)"); + AddCategoryMapping(2261, TorznabCatType.Audio, " | - Rock (Unofficial DVD Video)"); + AddCategoryMapping(1787, TorznabCatType.Audio, " |- Metal (Видео)"); + AddCategoryMapping(1788, TorznabCatType.Audio, " |- Metal (DVD Video)"); + AddCategoryMapping(2262, TorznabCatType.Audio, " | - Metal (Unofficial DVD Video)"); + AddCategoryMapping(1789, TorznabCatType.Audio, " |- Alternative, Punk, Independent (Видео)"); + AddCategoryMapping(1790, TorznabCatType.Audio, " |- Alternative, Punk, Independent (DVD Video)"); + AddCategoryMapping(2263, TorznabCatType.Audio, " |- Alternative, Punk, Independent (Неофициальные DVD Video)"); + AddCategoryMapping(1791, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative (Video)"); + AddCategoryMapping(1792, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative (DVD Video)"); + AddCategoryMapping(1793, TorznabCatType.Audio, " | - Domestic Metal (Video)"); + AddCategoryMapping(1794, TorznabCatType.Audio, " | - Domestic Metal (DVD Video)"); + AddCategoryMapping(2264, TorznabCatType.Audio, " | - Domestic Rock, Punk, Alternative, Metal (Neofitsial .."); + AddCategoryMapping(1795, TorznabCatType.Audio, " | - Rock (HD Video)"); + + // Электронная музыка + AddCategoryMapping(1821, TorznabCatType.Audio, "Trance, Goa Trance, Psy-Trance, PsyChill, Ambient, Dub"); + AddCategoryMapping(1844, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance (lossless)"); + AddCategoryMapping(1822, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance (lossy)"); + AddCategoryMapping(1894, TorznabCatType.Audio, " |- PsyChill, Ambient, Dub (lossless)"); + AddCategoryMapping(1895, TorznabCatType.Audio, " |- PsyChill, Ambient, Dub (lossy)"); + AddCategoryMapping(460, TorznabCatType.Audio, " |- Goa Trance, Psy-Trance, PsyChill, Ambient, Dub (Live Set.."); + AddCategoryMapping(1818, TorznabCatType.Audio, " |- Trance (lossless)"); + AddCategoryMapping(1819, TorznabCatType.Audio, " |- Trance (lossy)"); + AddCategoryMapping(1847, TorznabCatType.Audio, " |- Trance (Singles, EPs) (lossy)"); + AddCategoryMapping(1824, TorznabCatType.Audio, " |- Trance (Radioshows, Podcasts, Live Sets, Mixes) (lossy)"); + AddCategoryMapping(1807, TorznabCatType.Audio, "House, Techno, Hardcore, Hardstyle, Jumpstyle"); + AddCategoryMapping(1829, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (lossless)"); + AddCategoryMapping(1830, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (lossy)"); + AddCategoryMapping(1831, TorznabCatType.Audio, " |- Hardcore, Hardstyle, Jumpstyle (vinyl, web)"); + AddCategoryMapping(1857, TorznabCatType.Audio, " |- House (lossless)"); + AddCategoryMapping(1859, TorznabCatType.Audio, " |- House (Radioshow, Podcast, Liveset, Mixes)"); + AddCategoryMapping(1858, TorznabCatType.Audio, " |- House (lossy)"); + AddCategoryMapping(840, TorznabCatType.Audio, " | - House (Promorelyzы, collections of)"); + AddCategoryMapping(1860, TorznabCatType.Audio, " |- House (Singles, EPs) (lossy)"); + AddCategoryMapping(1825, TorznabCatType.Audio, " |- Techno (lossless)"); + AddCategoryMapping(1826, TorznabCatType.Audio, " |- Techno (lossy)"); + AddCategoryMapping(1827, TorznabCatType.Audio, " |- Techno (Radioshows, Podcasts, Livesets, Mixes)"); + AddCategoryMapping(1828, TorznabCatType.Audio, " |- Techno (Singles, EPs) (lossy)"); + AddCategoryMapping(1808, TorznabCatType.Audio, "Drum & Bass, Jungle, Breakbeat, Dubstep, IDM, Electro"); + AddCategoryMapping(797, TorznabCatType.Audio, " |- Electro, Electro-Freestyle, Nu Electro (lossless)"); + AddCategoryMapping(1805, TorznabCatType.Audio, " |- Electro, Electro-Freestyle, Nu Electro (lossy)"); + AddCategoryMapping(1832, TorznabCatType.Audio, " |- Drum & Bass, Jungle (lossless)"); + AddCategoryMapping(1833, TorznabCatType.Audio, " |- Drum & Bass, Jungle (lossy)"); + AddCategoryMapping(1834, TorznabCatType.Audio, " |- Drum & Bass, Jungle (Radioshows, Podcasts, Livesets, Mix.."); + AddCategoryMapping(1836, TorznabCatType.Audio, " |- Breakbeat (lossless)"); + AddCategoryMapping(1837, TorznabCatType.Audio, " |- Breakbeat (lossy)"); + AddCategoryMapping(1839, TorznabCatType.Audio, " |- Dubstep (lossless)"); + AddCategoryMapping(454, TorznabCatType.Audio, " |- Dubstep (lossy)"); + AddCategoryMapping(1838, TorznabCatType.Audio, " |- Breakbeat, Dubstep (Radioshows, Podcasts, Livesets, Mixe.."); + AddCategoryMapping(1840, TorznabCatType.Audio, " |- IDM (lossless)"); + AddCategoryMapping(1841, TorznabCatType.Audio, " |- IDM (lossy)"); + AddCategoryMapping(2229, TorznabCatType.Audio, " |- IDM Discography & Collections (lossy)"); + AddCategoryMapping(1809, TorznabCatType.Audio, "Chillout, Lounge, Downtempo, Trip-Hop"); + AddCategoryMapping(1861, TorznabCatType.Audio, " |- Chillout, Lounge, Downtempo (lossless)"); + AddCategoryMapping(1862, TorznabCatType.Audio, " |- Chillout, Lounge, Downtempo (lossy)"); + AddCategoryMapping(1947, TorznabCatType.Audio, " |- Nu Jazz, Acid Jazz, Future Jazz (lossless)"); + AddCategoryMapping(1946, TorznabCatType.Audio, " |- Nu Jazz, Acid Jazz, Future Jazz (lossy)"); + AddCategoryMapping(1945, TorznabCatType.Audio, " |- Trip Hop, Abstract Hip-Hop (lossless)"); + AddCategoryMapping(1944, TorznabCatType.Audio, " |- Trip Hop, Abstract Hip-Hop (lossy)"); + AddCategoryMapping(1810, TorznabCatType.Audio, "Traditional Electronic, Ambient, Modern Classical, Electroac.."); + AddCategoryMapping(1864, TorznabCatType.Audio, " |- Traditional Electronic, Ambient (lossless)"); + AddCategoryMapping(1865, TorznabCatType.Audio, " |- Traditional Electronic, Ambient (lossy)"); + AddCategoryMapping(1871, TorznabCatType.Audio, " |- Modern Classical, Electroacoustic (lossless)"); + AddCategoryMapping(1867, TorznabCatType.Audio, " |- Modern Classical, Electroacoustic (lossy)"); + AddCategoryMapping(1869, TorznabCatType.Audio, " |- Experimental (lossless)"); + AddCategoryMapping(1873, TorznabCatType.Audio, " |- Experimental (lossy)"); + AddCategoryMapping(1907, TorznabCatType.Audio, " |- 8-bit, Chiptune (lossy & lossless)"); + AddCategoryMapping(1811, TorznabCatType.Audio, "Industrial, Noise, EBM, Dark Electro, Aggrotech, Synthpop, N.."); + AddCategoryMapping(1868, TorznabCatType.Audio, " | - EBM, Dark Electro, Aggrotech (lossless)"); + AddCategoryMapping(1875, TorznabCatType.Audio, " | - EBM, Dark Electro, Aggrotech (lossy)"); + AddCategoryMapping(1877, TorznabCatType.Audio, " |- Industrial, Noise (lossless)"); + AddCategoryMapping(1878, TorznabCatType.Audio, " |- Industrial, Noise (lossy)"); + AddCategoryMapping(1880, TorznabCatType.Audio, " |- Synthpop, New Wave (lossless)"); + AddCategoryMapping(1881, TorznabCatType.Audio, " |- Synthpop, New Wave (lossy)"); + AddCategoryMapping(1866, TorznabCatType.Audio, " |- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossles.."); + AddCategoryMapping(406, TorznabCatType.Audio, " |- Darkwave, Neoclassical, Ethereal, Dungeon Synth (lossy)"); + AddCategoryMapping(1842, TorznabCatType.Audio, "Label Packs (lossless)"); + AddCategoryMapping(1648, TorznabCatType.Audio, "Label packs, Scene packs (lossy)"); + AddCategoryMapping(1812, TorznabCatType.Audio, "Электронная музыка (Видео, DVD Video/Audio, HD Video, DTS, S.."); + AddCategoryMapping(1886, TorznabCatType.Audio, " | - Electronic music (Official DVD Video)"); + AddCategoryMapping(1887, TorznabCatType.Audio, " | - Electronic music (Informal amateur DVD Vide .."); + AddCategoryMapping(1912, TorznabCatType.Audio, " | - Electronic music (Video)"); + AddCategoryMapping(1893, TorznabCatType.Audio, " | - Hi-Res stereo (electronic music)"); + AddCategoryMapping(1890, TorznabCatType.Audio, " | - Multi-channel music (electronic music)"); + AddCategoryMapping(1913, TorznabCatType.Audio, " | - Electronic music (HD Video)"); + AddCategoryMapping(1754, TorznabCatType.Audio, " | - Electronic music (own digitization)"); + + // Игры + AddCategoryMapping(5, TorznabCatType.PCGames, "Games for Windows (download)"); + AddCategoryMapping(635, TorznabCatType.PCGames, " | - Hot New Releases"); + AddCategoryMapping(127, TorznabCatType.PCGames, " | - Arcade"); + AddCategoryMapping(2204, TorznabCatType.PCGames, " | - Puzzle Games"); + AddCategoryMapping(53, TorznabCatType.PCGames, " | - Adventure and quests"); + AddCategoryMapping(1008, TorznabCatType.PCGames, " | - Quest-style \"search objects\""); + AddCategoryMapping(51, TorznabCatType.PCGames, " | - Strategy"); + AddCategoryMapping(961, TorznabCatType.PCGames, " | - Space and flight simulators"); + AddCategoryMapping(962, TorznabCatType.PCGames, " | - Autos and Racing"); + AddCategoryMapping(2187, TorznabCatType.PCGames, " | - Racing Simulators"); + AddCategoryMapping(54, TorznabCatType.PCGames, " | - Other simulators"); + AddCategoryMapping(55, TorznabCatType.PCGames, " |- Action"); + AddCategoryMapping(2203, TorznabCatType.PCGames, " | - Fighting"); + AddCategoryMapping(52, TorznabCatType.PCGames, " |- RPG"); + AddCategoryMapping(900, TorznabCatType.PCGames, " | - Anime games"); + AddCategoryMapping(246, TorznabCatType.PCGames, " | - Erotic Games"); + AddCategoryMapping(278, TorznabCatType.PCGames, " | - Chess"); + AddCategoryMapping(128, TorznabCatType.PCGames, " | - For the little ones"); + AddCategoryMapping(637, TorznabCatType.PCGames, "Old Games"); + AddCategoryMapping(642, TorznabCatType.PCGames, " | - Arcade (Old Games)"); + AddCategoryMapping(2385, TorznabCatType.PCGames, " | - Puzzle games (old games)"); + AddCategoryMapping(643, TorznabCatType.PCGames, " | - Adventure and quests (Old Games)"); + AddCategoryMapping(644, TorznabCatType.PCGames, " | - Strategies (Old Games)"); + AddCategoryMapping(2226, TorznabCatType.PCGames, " | - Space and flight simulators (Old Games)"); + AddCategoryMapping(2227, TorznabCatType.PCGames, " | - Autos and Racing (Old Games)"); + AddCategoryMapping(2225, TorznabCatType.PCGames, " | - Racing Simulators (Old Games)"); + AddCategoryMapping(645, TorznabCatType.PCGames, " | - Other simulators (Old Games)"); + AddCategoryMapping(646, TorznabCatType.PCGames, " | - Action (Old Games)"); + AddCategoryMapping(647, TorznabCatType.PCGames, " | - RPG (Old Games)"); + AddCategoryMapping(649, TorznabCatType.PCGames, " | - Erotic Games (Old Games)"); + AddCategoryMapping(650, TorznabCatType.PCGames, " | - For the little ones (Old Games)"); + AddCategoryMapping(1098, TorznabCatType.PCGames, " | - Game Collection (Old Games)"); + AddCategoryMapping(2228, TorznabCatType.PCGames, " | - IBM PC incompatible (Old Games)"); + AddCategoryMapping(2115, TorznabCatType.PCGames, "Online Games"); + AddCategoryMapping(2117, TorznabCatType.PCGames, " |- World of Warcraft"); + AddCategoryMapping(2155, TorznabCatType.PCGames, " |- Lineage II"); + AddCategoryMapping(2118, TorznabCatType.PCGames, " | - MMO (Official)"); + AddCategoryMapping(2119, TorznabCatType.PCGames, " | - MMO (Neoficialʹnye)"); + AddCategoryMapping(2489, TorznabCatType.PCGames, " | - Multiplayer games"); + AddCategoryMapping(2142, TorznabCatType.PCGames, "Microsoft Flight Simulator add-ons, and for him"); + AddCategoryMapping(2143, TorznabCatType.PCGames, " | - Scripts, meshes and airports [FS2004]"); + AddCategoryMapping(2060, TorznabCatType.PCGames, " |- Сценарии (FSX-P3D)"); + AddCategoryMapping(2145, TorznabCatType.PCGames, " | - Aircraft [FS2004]"); + AddCategoryMapping(2012, TorznabCatType.PCGames, " | - Planes, helicopters (FSX-P3D)"); + AddCategoryMapping(2146, TorznabCatType.PCGames, " | - Mission, traffic sounds, packs and tools"); + AddCategoryMapping(139, TorznabCatType.PCGames, "Others for Windows-based games"); + AddCategoryMapping(2478, TorznabCatType.PCGames, " | - Official patches"); + AddCategoryMapping(2479, TorznabCatType.PCGames, " | - Official Fashion, plug-ins, add-ons"); + AddCategoryMapping(2480, TorznabCatType.PCGames, " | - Informal fashion, plugins, add-ons"); + AddCategoryMapping(2481, TorznabCatType.PCGames, " | - Fun"); + AddCategoryMapping(761, TorznabCatType.PCGames, " | - Editors, emulators and other gaming utility"); + AddCategoryMapping(2482, TorznabCatType.PCGames, " |- NoCD / NoDVD"); + AddCategoryMapping(2533, TorznabCatType.PCGames, " | - Conservation games"); + AddCategoryMapping(2483, TorznabCatType.PCGames, " | - Cheat program and trainers"); + AddCategoryMapping(2484, TorznabCatType.PCGames, " | - Guides and passing"); + AddCategoryMapping(2485, TorznabCatType.PCGames, " | - The bonus discs for games"); + AddCategoryMapping(240, TorznabCatType.PCGames, "video Game"); + AddCategoryMapping(2415, TorznabCatType.PCGames, " | - Walkthroughs"); + AddCategoryMapping(2067, TorznabCatType.PCGames, " |- Lineage II Movies"); + AddCategoryMapping(2147, TorznabCatType.PCGames, " |- World of Warcraft Movies"); + AddCategoryMapping(960, TorznabCatType.PCGames, " |- Counter Strike Movies"); + AddCategoryMapping(548, TorznabCatType.Console, "Games for consoles"); + AddCategoryMapping(129, TorznabCatType.Console, " | - Portable and Console (Games)"); + AddCategoryMapping(908, TorznabCatType.ConsolePS3, " |- PS"); + AddCategoryMapping(357, TorznabCatType.ConsolePS3, " |- PS2"); + AddCategoryMapping(886, TorznabCatType.ConsolePS3, " |- PS3"); + AddCategoryMapping(1352, TorznabCatType.ConsolePSP, " |- PSP"); + AddCategoryMapping(1116, TorznabCatType.ConsolePSP, " | - PS1 games for PSP"); + AddCategoryMapping(973, TorznabCatType.ConsolePSVita, " |- PSVITA"); + AddCategoryMapping(887, TorznabCatType.ConsoleXbox, " | - Original Xbox"); + AddCategoryMapping(510, TorznabCatType.ConsoleXbox360, " |- Xbox 360"); + AddCategoryMapping(773, TorznabCatType.ConsoleWii, " |- Wii"); + AddCategoryMapping(774, TorznabCatType.ConsoleNDS, " |- NDS"); + AddCategoryMapping(968, TorznabCatType.ConsoleOther, " |- Dreamcast"); + AddCategoryMapping(546, TorznabCatType.ConsoleOther, " | - Games for the DVD player"); + AddCategoryMapping(2185, TorznabCatType.Console, "Video consoles"); + AddCategoryMapping(2487, TorznabCatType.ConsolePSVita, " | - Video for PSVita"); + AddCategoryMapping(2182, TorznabCatType.ConsolePSP, " | - Movies for PSP"); + AddCategoryMapping(2181, TorznabCatType.ConsolePSP, " | - For PSP TV Shows"); + AddCategoryMapping(2180, TorznabCatType.ConsolePSP, " | - Cartoons for PSP"); + AddCategoryMapping(2179, TorznabCatType.ConsolePSP, " | - Drama for PSP"); + AddCategoryMapping(2186, TorznabCatType.ConsolePSP, " | - Anime for PSP"); + AddCategoryMapping(700, TorznabCatType.ConsolePSP, " | - Video to PSP"); + AddCategoryMapping(1926, TorznabCatType.ConsolePS3, " | - Videos for the PS3 and other consoles"); + AddCategoryMapping(899, TorznabCatType.PCGames, "Games for Linux"); + AddCategoryMapping(1992, TorznabCatType.PCGames, " | - Native games for Linux"); + AddCategoryMapping(2059, TorznabCatType.PCGames, " | - Game Ported to Linux"); + + // Программы и Дизайн + AddCategoryMapping(1012, TorznabCatType.PC0day, "Operating systems from Microsoft"); + AddCategoryMapping(1019, TorznabCatType.PC0day, " | - Desktop operating system from Microsoft (released prior to Windows XP)"); + AddCategoryMapping(2153, TorznabCatType.PC0day, " | - Desktop operating system from Microsoft (since Windows XP)"); + AddCategoryMapping(1021, TorznabCatType.PC0day, " | - Server operating system from Microsoft"); + AddCategoryMapping(1025, TorznabCatType.PC0day, " | - Other (Operating Systems from Microsoft)"); + AddCategoryMapping(1376, TorznabCatType.PC0day, "Linux, Unix and other operating systems"); + AddCategoryMapping(1379, TorznabCatType.PC0day, " | - Operating Systems (Linux, Unix)"); + AddCategoryMapping(1381, TorznabCatType.PC0day, " | - Software (Linux, Unix)"); + AddCategoryMapping(1473, TorznabCatType.PC0day, " | - Other operating systems and software for them"); + AddCategoryMapping(1195, TorznabCatType.PC0day, "Test drives to adjust the audio / video equipment"); + AddCategoryMapping(1013, TorznabCatType.PC0day, "System programs"); + AddCategoryMapping(1028, TorznabCatType.PC0day, " | - Work with hard drive"); + AddCategoryMapping(1029, TorznabCatType.PC0day, " | - Backup"); + AddCategoryMapping(1030, TorznabCatType.PC0day, " | - Archivers and File Managers"); + AddCategoryMapping(1031, TorznabCatType.PC0day, " | - Software to configure and optimize the operating system"); + AddCategoryMapping(1032, TorznabCatType.PC0day, " | - Service computer service"); + AddCategoryMapping(1033, TorznabCatType.PC0day, " | - Work with data carriers"); + AddCategoryMapping(1034, TorznabCatType.PC0day, " | - Information and Diagnostics"); + AddCategoryMapping(1066, TorznabCatType.PC0day, " | - Software for Internet and networks"); + AddCategoryMapping(1035, TorznabCatType.PC0day, " | - Software to protect your computer (antivirus software, firewalls)"); + AddCategoryMapping(1038, TorznabCatType.PC0day, " | - Anti-spyware and anti-trojan"); + AddCategoryMapping(1039, TorznabCatType.PC0day, " | - Software to protect information"); + AddCategoryMapping(1536, TorznabCatType.PC0day, " | - Drivers and Firmware"); + AddCategoryMapping(1051, TorznabCatType.PC0day, " | - The original disks to computers and accessories"); + AddCategoryMapping(1040, TorznabCatType.PC0day, " | - Server software for Windows"); + AddCategoryMapping(1041, TorznabCatType.PC0day, " | - Change the Windows interface"); + AddCategoryMapping(1636, TorznabCatType.PC0day, " | - Screensavers"); + AddCategoryMapping(1042, TorznabCatType.PC0day, " | - Other (System programs on Windows)"); + AddCategoryMapping(1014, TorznabCatType.PC0day, "Systems for business, office, research and project work"); + AddCategoryMapping(1060, TorznabCatType.PC0day, " | - Everything for the home: dressmaking, sewing, cooking"); + AddCategoryMapping(1061, TorznabCatType.PC0day, " | - Office Systems"); + AddCategoryMapping(1062, TorznabCatType.PC0day, " | - Business Systems"); + AddCategoryMapping(1067, TorznabCatType.PC0day, " | - Recognition of text, sound and speech synthesis"); + AddCategoryMapping(1086, TorznabCatType.PC0day, " | - Work with PDF and DjVu"); + AddCategoryMapping(1068, TorznabCatType.PC0day, " | - Dictionaries, translators"); + AddCategoryMapping(1063, TorznabCatType.PC0day, " | - System for scientific work"); + AddCategoryMapping(1087, TorznabCatType.PC0day, " | - CAD (general and engineering)"); + AddCategoryMapping(1192, TorznabCatType.PC0day, " | - CAD (electronics, automation, GAP)"); + AddCategoryMapping(1088, TorznabCatType.PC0day, " | - Software for architects and builders"); + AddCategoryMapping(1193, TorznabCatType.PC0day, " | - Library and projects for architects and designers inter .."); + AddCategoryMapping(1071, TorznabCatType.PC0day, " | - Other reference systems"); + AddCategoryMapping(1073, TorznabCatType.PC0day, " | - Miscellaneous (business systems, office, research and design .."); + AddCategoryMapping(1052, TorznabCatType.PC0day, "Web Development and Programming"); + AddCategoryMapping(1053, TorznabCatType.PC0day, " | - WYSIWYG editors for web diz"); + AddCategoryMapping(1054, TorznabCatType.PC0day, " | - Text editors Illuminated"); + AddCategoryMapping(1055, TorznabCatType.PC0day, " | - Programming environments, compilers and support, etc. .."); + AddCategoryMapping(1056, TorznabCatType.PC0day, " | - Components for programming environments"); + AddCategoryMapping(2077, TorznabCatType.PC0day, " | - Database Management Systems"); + AddCategoryMapping(1057, TorznabCatType.PC0day, " | - Scripts and engines sites, CMS and extensions to it"); + AddCategoryMapping(1018, TorznabCatType.PC0day, " | - Templates for websites and CMS"); + AddCategoryMapping(1058, TorznabCatType.PC0day, " | - Miscellaneous (Web Development and Programming)"); + AddCategoryMapping(1016, TorznabCatType.PC0day, "Programs to work with multimedia and 3D"); + AddCategoryMapping(1079, TorznabCatType.PC0day, " | - Software Kits"); + AddCategoryMapping(1080, TorznabCatType.PC0day, " | - Plug-ins for Adobe's programs"); + AddCategoryMapping(1081, TorznabCatType.PC0day, " | - Graphic Editors"); + AddCategoryMapping(1082, TorznabCatType.PC0day, " | - Software for typesetting, printing, and working with fonts"); + AddCategoryMapping(1083, TorznabCatType.PC0day, " | - 3D modeling, rendering and plugins for them"); + AddCategoryMapping(1084, TorznabCatType.PC0day, " | - Animation"); + AddCategoryMapping(1085, TorznabCatType.PC0day, " | - Creating a BD / HD / DVD-Video"); + AddCategoryMapping(1089, TorznabCatType.PC0day, " | - Video Editors"); + AddCategoryMapping(1090, TorznabCatType.PC0day, " | - Video converters Audio"); + AddCategoryMapping(1065, TorznabCatType.PC0day, " | - Audio and video, CD- players and catalogers"); + AddCategoryMapping(1064, TorznabCatType.PC0day, " | - Cataloging and graphics viewers"); + AddCategoryMapping(1092, TorznabCatType.PC0day, " | - Miscellaneous (Programme for multimedia and 3D)"); + AddCategoryMapping(1204, TorznabCatType.PC0day, " | - Virtual Studios, sequencers and audio editor"); + AddCategoryMapping(1027, TorznabCatType.PC0day, " | - Virtual Instruments & Synthesizers"); + AddCategoryMapping(1199, TorznabCatType.PC0day, " | - Plug-ins for sound processing"); + AddCategoryMapping(1091, TorznabCatType.PC0day, " | - Miscellaneous (Programs for working with audio)"); + AddCategoryMapping(828, TorznabCatType.PC0day, "Materials for Multimedia and Design"); + AddCategoryMapping(1357, TorznabCatType.PC0day, " | - Authoring"); + AddCategoryMapping(890, TorznabCatType.PC0day, " | - Official compilations vector clipart"); + AddCategoryMapping(830, TorznabCatType.PC0day, " | - Other vector cliparts"); + AddCategoryMapping(1290, TorznabCatType.PC0day, " |- Photostoсks"); + AddCategoryMapping(1962, TorznabCatType.PC0day, " | - Photoshop Costumes"); + AddCategoryMapping(831, TorznabCatType.PC0day, " | - Frames and Vignettes for processing photos"); + AddCategoryMapping(829, TorznabCatType.PC0day, " | - Other raster clipart"); + AddCategoryMapping(633, TorznabCatType.PC0day, " | - 3D models, scenes and materials"); + AddCategoryMapping(1009, TorznabCatType.PC0day, " | - Footage"); + AddCategoryMapping(1963, TorznabCatType.PC0day, " | - Other collections footage"); + AddCategoryMapping(1954, TorznabCatType.PC0day, " | - Music Library"); + AddCategoryMapping(1010, TorznabCatType.PC0day, " | - Sound Effects"); + AddCategoryMapping(1674, TorznabCatType.PC0day, " | - Sample Libraries"); + AddCategoryMapping(2421, TorznabCatType.PC0day, " | - Library and saundbanki for samplers, presets for sy .."); + AddCategoryMapping(2492, TorznabCatType.PC0day, " |- Multitracks"); + AddCategoryMapping(839, TorznabCatType.PC0day, " | - Materials for creating menus and DVD covers"); + AddCategoryMapping(1679, TorznabCatType.PC0day, " | - Styles, brushes, shapes and patterns for Adobe Photoshop"); + AddCategoryMapping(1011, TorznabCatType.PC0day, " | - Fonts"); + AddCategoryMapping(835, TorznabCatType.PC0day, " | - Miscellaneous (Materials for Multimedia and Design)"); + AddCategoryMapping(1503, TorznabCatType.PC0day, "GIS, navigation systems and maps"); + AddCategoryMapping(1507, TorznabCatType.PC0day, " | - GIS (Geoinformatsionnыe sistemы)"); + AddCategoryMapping(1526, TorznabCatType.PC0day, " | - Maps provided with the program shell"); + AddCategoryMapping(1508, TorznabCatType.PC0day, " | - Atlases and maps modern (after 1950)"); + AddCategoryMapping(1509, TorznabCatType.PC0day, " | - Atlases and antique maps (up to 1950)"); + AddCategoryMapping(1510, TorznabCatType.PC0day, " | - Other Maps (astronomical, historical, topically .."); + AddCategoryMapping(1511, TorznabCatType.PC0day, " | - Built-in car navigation"); + AddCategoryMapping(1512, TorznabCatType.PC0day, " |- Garmin"); + AddCategoryMapping(1513, TorznabCatType.PC0day, " | -"); + AddCategoryMapping(1514, TorznabCatType.PC0day, " |- TomTom"); + AddCategoryMapping(1515, TorznabCatType.PC0day, " |- Navigon / Navitel"); + AddCategoryMapping(1516, TorznabCatType.PC0day, " |- Igo"); + AddCategoryMapping(1517, TorznabCatType.PC0day, " | - Miscellaneous - navigation and maps"); + + // Мобильные устройства + AddCategoryMapping(285, TorznabCatType.PCPhoneOther, "Games, applications and so on. Mobile"); + AddCategoryMapping(2149, TorznabCatType.PCPhoneAndroid, " | - Games for Android OS"); + AddCategoryMapping(2154, TorznabCatType.PCPhoneAndroid, " | - Applications for Android OS"); + AddCategoryMapping(2419, TorznabCatType.PCPhoneOther, " | - Applications for Windows Phone 7,8"); + AddCategoryMapping(2420, TorznabCatType.PCPhoneOther, " | - Games for Windows Phone 7,8"); + AddCategoryMapping(1004, TorznabCatType.PCPhoneOther, " | - Games for Symbian"); + AddCategoryMapping(289, TorznabCatType.PCPhoneOther, " | - Applications for Symbian"); + AddCategoryMapping(1001, TorznabCatType.PCPhoneOther, " | - Games for Java"); + AddCategoryMapping(1005, TorznabCatType.PCPhoneOther, " | - Applications for Java"); + AddCategoryMapping(1002, TorznabCatType.PCPhoneOther, " | - Games for Windows Mobile, Palm OS, BlackBerry and so on."); + AddCategoryMapping(290, TorznabCatType.PCPhoneOther, " | - Applications for Windows Mobile, Palm OS, BlackBerry and so on."); + AddCategoryMapping(288, TorznabCatType.PCPhoneOther, " | - Software for your phone"); + AddCategoryMapping(292, TorznabCatType.PCPhoneOther, " | - Firmware for phones"); + AddCategoryMapping(291, TorznabCatType.PCPhoneOther, " | - Wallpapers and Themes"); + AddCategoryMapping(957, TorznabCatType.PCPhoneOther, "Video for mobile devices"); + AddCategoryMapping(287, TorznabCatType.PCPhoneOther, " | - Video for Smartphones and PDAs"); + AddCategoryMapping(286, TorznabCatType.PCPhoneOther, " | - Mobile Video (3GP)"); + + // Apple + AddCategoryMapping(1366, TorznabCatType.PCMac, "Apple Macintosh"); + AddCategoryMapping(1368, TorznabCatType.PCMac, " |- Mac OS (для Macintosh)"); + AddCategoryMapping(1383, TorznabCatType.PCMac, " | - Mac OS (for RS-Hakintoš)"); + AddCategoryMapping(537, TorznabCatType.PCMac, " | - Game Mac OS"); + AddCategoryMapping(1394, TorznabCatType.PCMac, " | - Software for viewing and video processing"); + AddCategoryMapping(1370, TorznabCatType.PCMac, " | - Software to build and graphics processing"); + AddCategoryMapping(2237, TorznabCatType.PCMac, " | - Plug-ins for Adobe's programs"); + AddCategoryMapping(1372, TorznabCatType.PCMac, " | - Audio editor and converter"); + AddCategoryMapping(1373, TorznabCatType.PCMac, " | - System software"); + AddCategoryMapping(1375, TorznabCatType.PCMac, " | - Office software"); + AddCategoryMapping(1371, TorznabCatType.PCMac, " | - Software for the Internet and network"); + AddCategoryMapping(1374, TorznabCatType.PCMac, " | - Other software"); + AddCategoryMapping(1933, TorznabCatType.PCMac, "iOS"); + AddCategoryMapping(1935, TorznabCatType.PCMac, " | - Software for iOS"); + AddCategoryMapping(1003, TorznabCatType.PCMac, " | - Games for iOS"); + AddCategoryMapping(1937, TorznabCatType.PCMac, " | - Miscellaneous for iOS"); + AddCategoryMapping(2235, TorznabCatType.PCMac, "Video"); + AddCategoryMapping(1908, TorznabCatType.PCMac, " | - Movies for iPod, iPhone, iPad"); + AddCategoryMapping(864, TorznabCatType.PCMac, " | - TV Shows for iPod, iPhone, iPad"); + AddCategoryMapping(863, TorznabCatType.PCMac, " | - Cartoons for iPod, iPhone, iPad"); + AddCategoryMapping(2535, TorznabCatType.PCMac, " | - Anime for iPod, iPhone, iPad"); + AddCategoryMapping(2534, TorznabCatType.PCMac, " | - The music video to iPod, iPhone, iPad"); + AddCategoryMapping(2238, TorznabCatType.PCMac, "Видео HD"); + AddCategoryMapping(1936, TorznabCatType.PCMac, " | - HD Movies to Apple TV"); + AddCategoryMapping(315, TorznabCatType.PCMac, " | - HD TV Shows on Apple TV"); + AddCategoryMapping(1363, TorznabCatType.PCMac, " | - HD Animation for Apple TV"); + AddCategoryMapping(2082, TorznabCatType.PCMac, " | - Documentary HD video for Apple TV"); + AddCategoryMapping(2241, TorznabCatType.PCMac, " | - Musical HD video for Apple TV"); + AddCategoryMapping(2236, TorznabCatType.PCMac, "audio"); + AddCategoryMapping(1909, TorznabCatType.PCMac, " | - Audiobooks (AAC, ALAC)"); + AddCategoryMapping(1927, TorznabCatType.PCMac, " | - Music Lossless (ALAC)"); + AddCategoryMapping(2240, TorznabCatType.PCMac, " |- Музыка Lossy (AAC-iTunes)"); + AddCategoryMapping(2248, TorznabCatType.PCMac, " |- Музыка Lossy (AAC)"); + AddCategoryMapping(2244, TorznabCatType.PCMac, " |- Музыка Lossy (AAC) (Singles, EPs)"); + AddCategoryMapping(2243, TorznabCatType.PCMac, "F.A.Q."); + + // Медицина и здоровье + AddCategoryMapping(2125, TorznabCatType.Books, "Books, magazines and programs"); + AddCategoryMapping(2133, TorznabCatType.Books, " | - Clinical Medicine until 1980"); + AddCategoryMapping(2130, TorznabCatType.Books, " | - Clinical Medicine from 1980 to 2000"); + AddCategoryMapping(2313, TorznabCatType.Books, " | - Clinical Medicine since 2000"); + AddCategoryMapping(2314, TorznabCatType.Books, " | - Popular medical periodicals (newspapers and magazines)"); + AddCategoryMapping(2528, TorznabCatType.Books, " | - Scientific medical periodicals (newspapers and magazines)"); + AddCategoryMapping(2129, TorznabCatType.Books, " | - Life Sciences"); + AddCategoryMapping(2141, TorznabCatType.Books, " | - Pharmacy and Pharmacology"); + AddCategoryMapping(2132, TorznabCatType.Books, " | - Non-traditional, traditional medicine and popular books on the s .."); + AddCategoryMapping(2131, TorznabCatType.Books, " | - Veterinary Medicine, Miscellaneous"); + AddCategoryMapping(2315, TorznabCatType.Books, " | - Thematic collection of books"); + AddCategoryMapping(1350, TorznabCatType.Books, " | - Audio Books on medicine"); + AddCategoryMapping(2134, TorznabCatType.Books, " | - Medical software"); + AddCategoryMapping(2126, TorznabCatType.Books, "Tutorials, Doc. movies and TV shows on medicine"); + AddCategoryMapping(2135, TorznabCatType.Books, " | - Medicine and Dentistry"); + AddCategoryMapping(2140, TorznabCatType.Books, " | - Psychotherapy and clinical psychology"); + AddCategoryMapping(2136, TorznabCatType.Books, " | - Massage"); + AddCategoryMapping(2138, TorznabCatType.Books, " | - Health"); + AddCategoryMapping(2139, TorznabCatType.Books, " | - Documentary movies and TV shows on medicine"); + + // Разное + AddCategoryMapping(10, TorznabCatType.Other, "Miscellaneous"); + AddCategoryMapping(865, TorznabCatType.Other, " | - Psihoaktivnye audioprogrammy"); + AddCategoryMapping(1100, TorznabCatType.Other, " | - Avatars, Icons, Smileys"); + AddCategoryMapping(1643, TorznabCatType.Other, " | - Painting, Graphics, Sculpture, Digital Art"); + AddCategoryMapping(848, TorznabCatType.Other, " | - Pictures"); + AddCategoryMapping(808, TorznabCatType.Other, " | - Amateur Photos"); + AddCategoryMapping(630, TorznabCatType.Other, " | - Wallpapers"); + AddCategoryMapping(1664, TorznabCatType.Other, " | - Celebrity Photos"); + AddCategoryMapping(148, TorznabCatType.Other, " | - Audio"); + AddCategoryMapping(807, TorznabCatType.Other, " | - Video"); + AddCategoryMapping(147, TorznabCatType.Other, " | - Publications and educational materials (texts)"); + AddCategoryMapping(847, TorznabCatType.Other, " | - Trailers and additional materials for films"); AddCategoryMapping(1167, TorznabCatType.Other, " | - Amateur videos"); } public override async Task<ConfigurationData> GetConfigurationForSetup() { var response = await RequestStringWithCookies(LoginUrl); - var LoginResultParser = new HtmlParser(); - var LoginResultDocument = LoginResultParser.Parse(response.Content); + var LoginResultParser = new HtmlParser(); + var LoginResultDocument = LoginResultParser.Parse(response.Content); var captchaimg = LoginResultDocument.QuerySelector("img[src^=\"//static.t-ru.org/captcha/\"]"); - if (captchaimg != null) + if (captchaimg != null) { var captchaImage = await RequestBytesWithCookies("https:" + captchaimg.GetAttribute("src")); configData.CaptchaImage.Value = captchaImage.Content; var codefield = LoginResultDocument.QuerySelector("input[name^=\"cap_code_\"]"); - cap_code_field = codefield.GetAttribute("name"); - + cap_code_field = codefield.GetAttribute("name"); + var sidfield = LoginResultDocument.QuerySelector("input[name=\"cap_sid\"]"); - cap_sid = sidfield.GetAttribute("value"); + cap_sid = sidfield.GetAttribute("value"); } - else - { - configData.CaptchaImage.Value = null; + else + { + configData.CaptchaImage.Value = null; } return configData; } @@ -1469,26 +1469,26 @@ namespace Jackett.Indexers { "login", "entry" } }; - if (!string.IsNullOrWhiteSpace(cap_sid)) - { - pairs.Add("cap_sid", cap_sid); - pairs.Add(cap_code_field, configData.CaptchaText.Value); - - cap_sid = null; - cap_code_field = null; + if (!string.IsNullOrWhiteSpace(cap_sid)) + { + pairs.Add("cap_sid", cap_sid); + pairs.Add(cap_code_field, configData.CaptchaText.Value); + + cap_sid = null; + cap_code_field = null; } var result = await RequestLoginAndFollowRedirect(LoginUrl, pairs, CookieHeader, true, null, LoginUrl, true); - await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("class=\"logged-in-as-uname\""), () => - { - var errorMessage = result.Content; - var LoginResultParser = new HtmlParser(); - var LoginResultDocument = LoginResultParser.Parse(result.Content); - var errormsg = LoginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]"); - if (errormsg != null) - errorMessage = errormsg.TextContent; - - throw new ExceptionWithConfigData(errorMessage, configData); + await ConfigureIfOK(result.Cookies, result.Content != null && result.Content.Contains("class=\"logged-in-as-uname\""), () => + { + var errorMessage = result.Content; + var LoginResultParser = new HtmlParser(); + var LoginResultDocument = LoginResultParser.Parse(result.Content); + var errormsg = LoginResultDocument.QuerySelector("h4[class=\"warnColor1 tCenter mrg_16\"]"); + if (errormsg != null) + errorMessage = errormsg.TextContent; + + throw new ExceptionWithConfigData(errorMessage, configData); }); return IndexerConfigurationStatus.RequiresTesting; } @@ -1496,82 +1496,82 @@ namespace Jackett.Indexers public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) { var releases = new List<ReleaseInfo>(); - var searchString = query.GetQueryString(); - - var queryCollection = new NameValueCollection(); - - // if the search string is empty use the getnew view - if (string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("nm", searchString); + var searchString = query.GetQueryString(); + + var queryCollection = new NameValueCollection(); + + // if the search string is empty use the getnew view + if (string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("nm", searchString); } - else // use the normal search - { - searchString = searchString.Replace("-", " "); - queryCollection.Add("nm", searchString); + else // use the normal search + { + searchString = searchString.Replace("-", " "); + queryCollection.Add("nm", searchString); } var searchUrl = SearchUrl + "?" + queryCollection.GetQueryString(); - var results = await RequestStringWithCookies(searchUrl); - if (!results.Content.Contains("class=\"logged-in-as-uname\"")) - { - // re login - await ApplyConfiguration(null); - results = await RequestStringWithCookies(searchUrl); - } + var results = await RequestStringWithCookies(searchUrl); + if (!results.Content.Contains("class=\"logged-in-as-uname\"")) + { + // re login + await ApplyConfiguration(null); + results = await RequestStringWithCookies(searchUrl); + } try { string RowsSelector = "table#tor-tbl > tbody > tr"; - var SearchResultParser = new HtmlParser(); + var SearchResultParser = new HtmlParser(); var SearchResultDocument = SearchResultParser.Parse(results.Content); - var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); - foreach (var Row in Rows) + var Rows = SearchResultDocument.QuerySelectorAll(RowsSelector); + foreach (var Row in Rows) { - try + try { var release = new ReleaseInfo(); - release.MinimumRatio = 1; + release.MinimumRatio = 1; release.MinimumSeedTime = 0; - - var qDownloadLink = Row.QuerySelector("td.tor-size > a.tr-dl"); - if (qDownloadLink == null) // Expects moderation - continue; - - var qDetailsLink = Row.QuerySelector("td.t-title > div.t-title > a.tLink"); - var qSize = Row.QuerySelector("td.tor-size > u"); - - release.Title = qDetailsLink.TextContent; - release.Comments = new Uri(SiteLink + "forum/" + qDetailsLink.GetAttribute("href")); - release.Link = new Uri(SiteLink + "forum/" + qDownloadLink.GetAttribute("href")); - release.Guid = release.Comments; - release.Size = ReleaseInfo.GetBytes(qSize.TextContent); - - var seeders = Row.QuerySelector("td:nth-child(7) > u").TextContent; - if (string.IsNullOrWhiteSpace(seeders)) - seeders = "0"; - release.Seeders = ParseUtil.CoerceInt(seeders); - release.Peers = ParseUtil.CoerceInt(Row.QuerySelector("td:nth-child(8) > b").TextContent) + release.Seeders; - release.Grabs = ParseUtil.CoerceLong(Row.QuerySelector("td:nth-child(9)").TextContent); - - var timestr = Row.QuerySelector("td:nth-child(10) > u").TextContent; - release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr)); - - var forum = Row.QuerySelector("td.f-name > div.f-name > a"); - var forumid = forum.GetAttribute("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(forumid); - - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - releases.Add(release); - } - catch (Exception ex) - { - logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); + var qDownloadLink = Row.QuerySelector("td.tor-size > a.tr-dl"); + if (qDownloadLink == null) // Expects moderation + continue; + + var qDetailsLink = Row.QuerySelector("td.t-title > div.t-title > a.tLink"); + var qSize = Row.QuerySelector("td.tor-size > u"); + + release.Title = qDetailsLink.TextContent; + release.Comments = new Uri(SiteLink + "forum/" + qDetailsLink.GetAttribute("href")); + release.Link = new Uri(SiteLink + "forum/" + qDownloadLink.GetAttribute("href")); + release.Guid = release.Comments; + release.Size = ReleaseInfo.GetBytes(qSize.TextContent); + + var seeders = Row.QuerySelector("td:nth-child(7) > u").TextContent; + if (string.IsNullOrWhiteSpace(seeders)) + seeders = "0"; + release.Seeders = ParseUtil.CoerceInt(seeders); + release.Peers = ParseUtil.CoerceInt(Row.QuerySelector("td:nth-child(8) > b").TextContent) + release.Seeders; + release.Grabs = ParseUtil.CoerceLong(Row.QuerySelector("td:nth-child(9)").TextContent); + + var timestr = Row.QuerySelector("td:nth-child(10) > u").TextContent; + release.PublishDate = DateTimeUtil.UnixTimestampToDateTime(long.Parse(timestr)); + + var forum = Row.QuerySelector("td.f-name > div.f-name > a"); + var forumid = forum.GetAttribute("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(forumid); + + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + catch (Exception ex) + { + logger.Error(string.Format("{0}: Error while parsing row '{1}':\n\n{2}", ID, Row.OuterHtml, ex)); } - } + } } catch (Exception ex) { diff --git a/src/Jackett/Indexers/x264.cs b/src/Jackett/Indexers/x264.cs index 90239b7a..0bc73841 100644 --- a/src/Jackett/Indexers/x264.cs +++ b/src/Jackett/Indexers/x264.cs @@ -1,206 +1,206 @@ -using CsQuery; -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.Linq; -using System.Text; -using System.Threading.Tasks; -using Jackett.Models.IndexerConfig; -using System.Collections.Specialized; - -namespace Jackett.Indexers -{ - public class x264 : BaseIndexer, IIndexer - { - private string SearchUrl { get { return SiteLink + "browse.php"; } } - private string LoginUrl { get { return SiteLink + "login.php"; } } - private string SubmitLoginUrl { get { return SiteLink + "takelogin.php"; } } - - new ConfigurationDataRecaptchaLogin configData - { - get { return (ConfigurationDataRecaptchaLogin)base.configData; } - set { base.configData = value; } - } - - public x264(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) - : base(name: "x264", - description: "A movie/TV tracker", - link: "https://x264.me/", - caps: new TorznabCapabilities(), - manager: i, - client: w, - logger: l, - p: ps, - configData: new ConfigurationDataRecaptchaLogin()) - { - Encoding = Encoding.GetEncoding("iso-8859-1"); - Language = "en-us"; - Type = "private"; - - TorznabCaps.SupportsImdbSearch = true; - - AddCategoryMapping(20, TorznabCatType.Movies); // Movies&TV/Sources - AddCategoryMapping(53, TorznabCatType.MoviesHD); // Movies/1080p - AddCategoryMapping(30, TorznabCatType.MoviesHD); // Movies/576p - AddCategoryMapping(50, TorznabCatType.MoviesHD); // Movies/720p - AddCategoryMapping(33, TorznabCatType.MoviesSD); // Movies/SD - AddCategoryMapping(54, TorznabCatType.TVHD); // TV/1080p - AddCategoryMapping(31, TorznabCatType.TVHD); // TV/576p - AddCategoryMapping(51, TorznabCatType.TVHD); // TV/720p - AddCategoryMapping(25, TorznabCatType.TVSD); // TV/SD - } - - public override async Task<ConfigurationData> GetConfigurationForSetup() - { - var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); - CQ dom = loginPage.Content; - - var result = this.configData; - var captcha = dom.Find(".g-recaptcha"); - result.CookieHeader.Value = loginPage.Cookies; - result.Captcha.SiteKey = captcha.Attr("data-sitekey"); - result.Captcha.Version = "2"; - return result; - } - - public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) - { - LoadValuesFromJson(configJson); - var pairs = new Dictionary<string, string> { - { "username", configData.Username.Value }, - { "password", configData.Password.Value }, - { "g-recaptcha-response", configData.Captcha.Value } - }; - - if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) - { - // Cookie was manually supplied - CookieHeader = configData.Captcha.Cookie; - try - { - var results = await PerformQuery(new TorznabQuery()); - if (!results.Any()) - { - throw new Exception("Your cookie did not work"); - } - - SaveConfig(); - IsConfigured = true; - return IndexerConfigurationStatus.Completed; - } - catch (Exception e) - { - IsConfigured = false; - throw new Exception("Your cookie did not work: " + e.Message); - } - } - - var result = await RequestLoginAndFollowRedirect(SubmitLoginUrl, pairs, configData.CookieHeader.Value, true, null, LoginUrl); - await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => - { - var errorMessage = result.Content; - throw new ExceptionWithConfigData(errorMessage, configData); - }); - return IndexerConfigurationStatus.RequiresTesting; - } - - public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) - { - List<ReleaseInfo> releases = new List<ReleaseInfo>(); - - var searchString = query.GetQueryString(); - var searchUrl = SearchUrl; - var queryCollection = new NameValueCollection(); - queryCollection.Add("incldead", "1"); - queryCollection.Add("xtype", "0"); - queryCollection.Add("stype", "0"); - - if (query.ImdbID != null) - { - queryCollection.Add("search", query.ImdbID); - } - else if (!string.IsNullOrWhiteSpace(searchString)) - { - queryCollection.Add("search", searchString); - } - - foreach (var cat in MapTorznabCapsToTrackers(query)) - { - queryCollection.Add("c" + cat, "1"); - } - - searchUrl += "?" + queryCollection.GetQueryString(); - - var results = await RequestStringWithCookiesAndRetry(searchUrl); - try - { - CQ dom = results.Content; - - var sideWideFreeLeech = false; - if (dom.Find("td > b > font[color=\"white\"]:contains(Free Leech)").Length >= 1) - sideWideFreeLeech = true; - - var rows = dom["table > tbody > tr[height=36]"]; - foreach (var row in rows) - { - var release = new ReleaseInfo(); - release.MinimumRatio = 1; - release.MinimumSeedTime = 7 * 24 * 60 * 60; - - var qRow = row.Cq(); - var qCatLink = qRow.Find("a[href^=?cat]").First(); - var qDetailsLink = qRow.Find("a[href^=details.php]").First(); - var qSeeders = qRow.Find("td:eq(8)"); - var qLeechers = qRow.Find("td:eq(9)"); - var qDownloadLink = qRow.Find("a[href^=\"download.php\"]").First(); - var qImdbLink = qRow.Find("a[href^=/redir.php?url=http://www.imdb.com]"); - var qSize = qRow.Find("td:eq(6)"); - - var catStr = qCatLink.Attr("href").Split('=')[1]; - release.Category = MapTrackerCatToNewznab(catStr); - - release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); - release.Title = qDetailsLink.Text().Trim(); - release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); - release.Guid = release.Link; - - var sizeStr = qSize.Text(); - release.Size = ReleaseInfo.GetBytes(sizeStr); - - if(qImdbLink.Length == 1) { - var ImdbId = qImdbLink.Attr("href").Split('/').Last().Substring(2); - release.Imdb = ParseUtil.CoerceLong(ImdbId); - } - - release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); - release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; - +using CsQuery; +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.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models.IndexerConfig; +using System.Collections.Specialized; + +namespace Jackett.Indexers +{ + public class x264 : BaseIndexer, IIndexer + { + private string SearchUrl { get { return SiteLink + "browse.php"; } } + private string LoginUrl { get { return SiteLink + "login.php"; } } + private string SubmitLoginUrl { get { return SiteLink + "takelogin.php"; } } + + new ConfigurationDataRecaptchaLogin configData + { + get { return (ConfigurationDataRecaptchaLogin)base.configData; } + set { base.configData = value; } + } + + public x264(IIndexerManagerService i, Logger l, IWebClient w, IProtectionService ps) + : base(name: "x264", + description: "A movie/TV tracker", + link: "https://x264.me/", + caps: new TorznabCapabilities(), + manager: i, + client: w, + logger: l, + p: ps, + configData: new ConfigurationDataRecaptchaLogin()) + { + Encoding = Encoding.GetEncoding("iso-8859-1"); + Language = "en-us"; + Type = "private"; + + TorznabCaps.SupportsImdbSearch = true; + + AddCategoryMapping(20, TorznabCatType.Movies); // Movies&TV/Sources + AddCategoryMapping(53, TorznabCatType.MoviesHD); // Movies/1080p + AddCategoryMapping(30, TorznabCatType.MoviesHD); // Movies/576p + AddCategoryMapping(50, TorznabCatType.MoviesHD); // Movies/720p + AddCategoryMapping(33, TorznabCatType.MoviesSD); // Movies/SD + AddCategoryMapping(54, TorznabCatType.TVHD); // TV/1080p + AddCategoryMapping(31, TorznabCatType.TVHD); // TV/576p + AddCategoryMapping(51, TorznabCatType.TVHD); // TV/720p + AddCategoryMapping(25, TorznabCatType.TVSD); // TV/SD + } + + public override async Task<ConfigurationData> GetConfigurationForSetup() + { + var loginPage = await RequestStringWithCookies(LoginUrl, string.Empty); + CQ dom = loginPage.Content; + + var result = this.configData; + var captcha = dom.Find(".g-recaptcha"); + result.CookieHeader.Value = loginPage.Cookies; + result.Captcha.SiteKey = captcha.Attr("data-sitekey"); + result.Captcha.Version = "2"; + return result; + } + + public async Task<IndexerConfigurationStatus> ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + var pairs = new Dictionary<string, string> { + { "username", configData.Username.Value }, + { "password", configData.Password.Value }, + { "g-recaptcha-response", configData.Captcha.Value } + }; + + if (!string.IsNullOrWhiteSpace(configData.Captcha.Cookie)) + { + // Cookie was manually supplied + CookieHeader = configData.Captcha.Cookie; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (!results.Any()) + { + throw new Exception("Your cookie did not work"); + } + + SaveConfig(); + IsConfigured = true; + return IndexerConfigurationStatus.Completed; + } + catch (Exception e) + { + IsConfigured = false; + throw new Exception("Your cookie did not work: " + e.Message); + } + } + + var result = await RequestLoginAndFollowRedirect(SubmitLoginUrl, pairs, configData.CookieHeader.Value, true, null, LoginUrl); + await ConfigureIfOK(result.Cookies, result.Content.Contains("logout.php"), () => + { + var errorMessage = result.Content; + throw new ExceptionWithConfigData(errorMessage, configData); + }); + return IndexerConfigurationStatus.RequiresTesting; + } + + public async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) + { + List<ReleaseInfo> releases = new List<ReleaseInfo>(); + + var searchString = query.GetQueryString(); + var searchUrl = SearchUrl; + var queryCollection = new NameValueCollection(); + queryCollection.Add("incldead", "1"); + queryCollection.Add("xtype", "0"); + queryCollection.Add("stype", "0"); + + if (query.ImdbID != null) + { + queryCollection.Add("search", query.ImdbID); + } + else if (!string.IsNullOrWhiteSpace(searchString)) + { + queryCollection.Add("search", searchString); + } + + foreach (var cat in MapTorznabCapsToTrackers(query)) + { + queryCollection.Add("c" + cat, "1"); + } + + searchUrl += "?" + queryCollection.GetQueryString(); + + var results = await RequestStringWithCookiesAndRetry(searchUrl); + try + { + CQ dom = results.Content; + + var sideWideFreeLeech = false; + if (dom.Find("td > b > font[color=\"white\"]:contains(Free Leech)").Length >= 1) + sideWideFreeLeech = true; + + var rows = dom["table > tbody > tr[height=36]"]; + foreach (var row in rows) + { + var release = new ReleaseInfo(); + release.MinimumRatio = 1; + release.MinimumSeedTime = 7 * 24 * 60 * 60; + + var qRow = row.Cq(); + var qCatLink = qRow.Find("a[href^=?cat]").First(); + var qDetailsLink = qRow.Find("a[href^=details.php]").First(); + var qSeeders = qRow.Find("td:eq(8)"); + var qLeechers = qRow.Find("td:eq(9)"); + var qDownloadLink = qRow.Find("a[href^=\"download.php\"]").First(); + var qImdbLink = qRow.Find("a[href^=/redir.php?url=http://www.imdb.com]"); + var qSize = qRow.Find("td:eq(6)"); + + var catStr = qCatLink.Attr("href").Split('=')[1]; + release.Category = MapTrackerCatToNewznab(catStr); + + release.Link = new Uri(SiteLink + qDownloadLink.Attr("href")); + release.Title = qDetailsLink.Text().Trim(); + release.Comments = new Uri(SiteLink + qDetailsLink.Attr("href")); + release.Guid = release.Link; + + var sizeStr = qSize.Text(); + release.Size = ReleaseInfo.GetBytes(sizeStr); + + if(qImdbLink.Length == 1) { + var ImdbId = qImdbLink.Attr("href").Split('/').Last().Substring(2); + release.Imdb = ParseUtil.CoerceLong(ImdbId); + } + + release.Seeders = ParseUtil.CoerceInt(qSeeders.Text()); + release.Peers = ParseUtil.CoerceInt(qLeechers.Text()) + release.Seeders; + var files = qRow.Find("td:nth-child(3)").Text(); release.Files = ParseUtil.CoerceInt(files); var grabs = qRow.Find("td:nth-child(8)").Get(0).FirstChild.ToString(); release.Grabs = ParseUtil.CoerceInt(grabs); - if (sideWideFreeLeech || qRow.Find("font[color=\"red\"]:contains(FREE)").Length >= 1) - release.DownloadVolumeFactor = 0; + if (sideWideFreeLeech || qRow.Find("font[color=\"red\"]:contains(FREE)").Length >= 1) + release.DownloadVolumeFactor = 0; else - release.DownloadVolumeFactor = 1; - release.UploadVolumeFactor = 1; - - releases.Add(release); - } - } - catch (Exception ex) - { - OnParseError(results.Content, ex); - } - - return releases; - } - } -} + release.DownloadVolumeFactor = 1; + release.UploadVolumeFactor = 1; + + releases.Add(release); + } + } + catch (Exception ex) + { + OnParseError(results.Content, ex); + } + + return releases; + } + } +} diff --git a/src/Jackett/JackettModule.cs b/src/Jackett/JackettModule.cs index 484e726b..43501a72 100644 --- a/src/Jackett/JackettModule.cs +++ b/src/Jackett/JackettModule.cs @@ -1,139 +1,139 @@ -using Autofac; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Autofac.Integration.WebApi; -using Jackett.Indexers; -using Jackett.Utils; -using Jackett.Utils.Clients; -using AutoMapper; -using Jackett.Models; -using System.Reflection; - -namespace Jackett -{ - public class JackettModule : Autofac.Module - { - protected override void Load(ContainerBuilder builder) - { - // Just register everything! - var thisAssembly = typeof(JackettModule).Assembly; - builder.RegisterAssemblyTypes(thisAssembly).Except<IIndexer>().AsImplementedInterfaces().SingleInstance(); - builder.RegisterApiControllers(thisAssembly).InstancePerRequest(); - builder.RegisterType<HttpWebClient>(); - - // Register the best web client for the platform or the override - switch (Startup.ClientOverride) - { - case "httpclient": - builder.RegisterType<HttpWebClient>().As<IWebClient>(); - break; - case "httpclient2": - builder.RegisterType<HttpWebClient2>().As<IWebClient>(); - break; - case "safecurl": - builder.RegisterType<UnixSafeCurlWebClient>().As<IWebClient>(); - break; - case "libcurl": - builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>(); - break; - case "automatic": - default: - if (System.Environment.OSVersion.Platform == PlatformID.Unix) - { - var usehttpclient = false; - try { - Type monotype = Type.GetType("Mono.Runtime"); - if (monotype != null) - { - MethodInfo displayName = monotype.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); - if (displayName != null) - { - var monoVersion = displayName.Invoke(null, null).ToString(); - var monoVersionO = new Version(monoVersion.Split(' ')[0]); - if (monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) - { - // check if btls is supported - var monoSecurity = Assembly.Load("Mono.Security"); - Type monoTlsProviderFactory = monoSecurity.GetType("Mono.Security.Interface.MonoTlsProviderFactory"); - if (monoTlsProviderFactory != null) - { - MethodInfo isProviderSupported = monoTlsProviderFactory.GetMethod("IsProviderSupported"); - if(isProviderSupported != null) - { - var btlsSupported = (bool)isProviderSupported.Invoke(null, new string[] { "btls" }); - if (btlsSupported) - { - // initialize btls - MethodInfo initialize = monoTlsProviderFactory.GetMethod("Initialize", new[] { typeof(string) }); - if (initialize != null) - { - initialize.Invoke(null, new string[] { "btls" }); - usehttpclient = true; - } - } - } - } - } - } - } - } - catch (Exception e) - { - Console.Out.WriteLine("Error while deciding which HttpWebClient to use: " + e); - } - - if (usehttpclient) - builder.RegisterType<HttpWebClient>().As<IWebClient>(); - else - builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>(); - } - else - { - builder.RegisterType<HttpWebClient>().As<IWebClient>(); - } - break; - } - - // Register indexers - foreach (var indexer in thisAssembly.GetTypes() - .Where(p => typeof(IIndexer).IsAssignableFrom(p) && !p.IsInterface) - .ToArray()) - { - builder.RegisterType(indexer).Named<IIndexer>(BaseIndexer.GetIndexerID(indexer)); - } - - Mapper.CreateMap<WebClientByteResult, WebClientStringResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((be, str) => - { - str.Content = Encoding.UTF8.GetString(be.Content); - }); - - Mapper.CreateMap<WebClientStringResult, WebClientByteResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((str, be) => - { - if (!string.IsNullOrEmpty(str.Content)) - { - be.Content = Encoding.UTF8.GetBytes(str.Content); - } - }); - - Mapper.CreateMap<WebClientStringResult, WebClientStringResult>(); - Mapper.CreateMap<WebClientByteResult, WebClientByteResult>(); - Mapper.CreateMap<ReleaseInfo, ReleaseInfo>(); - - Mapper.CreateMap<ReleaseInfo, TrackerCacheResult>().AfterMap((r, t) => - { - if (r.Category != null) - { - var CategoryDesc = string.Join(", ", r.Category.Select(x => TorznabCatType.GetCatDesc(x)).Where(x => !string.IsNullOrEmpty(x))); - t.CategoryDesc = CategoryDesc; - } - else - { - t.CategoryDesc = ""; - } - }); - } - } -} +using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac.Integration.WebApi; +using Jackett.Indexers; +using Jackett.Utils; +using Jackett.Utils.Clients; +using AutoMapper; +using Jackett.Models; +using System.Reflection; + +namespace Jackett +{ + public class JackettModule : Autofac.Module + { + protected override void Load(ContainerBuilder builder) + { + // Just register everything! + var thisAssembly = typeof(JackettModule).Assembly; + builder.RegisterAssemblyTypes(thisAssembly).Except<IIndexer>().AsImplementedInterfaces().SingleInstance(); + builder.RegisterApiControllers(thisAssembly).InstancePerRequest(); + builder.RegisterType<HttpWebClient>(); + + // Register the best web client for the platform or the override + switch (Startup.ClientOverride) + { + case "httpclient": + builder.RegisterType<HttpWebClient>().As<IWebClient>(); + break; + case "httpclient2": + builder.RegisterType<HttpWebClient2>().As<IWebClient>(); + break; + case "safecurl": + builder.RegisterType<UnixSafeCurlWebClient>().As<IWebClient>(); + break; + case "libcurl": + builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>(); + break; + case "automatic": + default: + if (System.Environment.OSVersion.Platform == PlatformID.Unix) + { + var usehttpclient = false; + try { + Type monotype = Type.GetType("Mono.Runtime"); + if (monotype != null) + { + MethodInfo displayName = monotype.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + if (displayName != null) + { + var monoVersion = displayName.Invoke(null, null).ToString(); + var monoVersionO = new Version(monoVersion.Split(' ')[0]); + if (monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) + { + // check if btls is supported + var monoSecurity = Assembly.Load("Mono.Security"); + Type monoTlsProviderFactory = monoSecurity.GetType("Mono.Security.Interface.MonoTlsProviderFactory"); + if (monoTlsProviderFactory != null) + { + MethodInfo isProviderSupported = monoTlsProviderFactory.GetMethod("IsProviderSupported"); + if(isProviderSupported != null) + { + var btlsSupported = (bool)isProviderSupported.Invoke(null, new string[] { "btls" }); + if (btlsSupported) + { + // initialize btls + MethodInfo initialize = monoTlsProviderFactory.GetMethod("Initialize", new[] { typeof(string) }); + if (initialize != null) + { + initialize.Invoke(null, new string[] { "btls" }); + usehttpclient = true; + } + } + } + } + } + } + } + } + catch (Exception e) + { + Console.Out.WriteLine("Error while deciding which HttpWebClient to use: " + e); + } + + if (usehttpclient) + builder.RegisterType<HttpWebClient>().As<IWebClient>(); + else + builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>(); + } + else + { + builder.RegisterType<HttpWebClient>().As<IWebClient>(); + } + break; + } + + // Register indexers + foreach (var indexer in thisAssembly.GetTypes() + .Where(p => typeof(IIndexer).IsAssignableFrom(p) && !p.IsInterface) + .ToArray()) + { + builder.RegisterType(indexer).Named<IIndexer>(BaseIndexer.GetIndexerID(indexer)); + } + + Mapper.CreateMap<WebClientByteResult, WebClientStringResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((be, str) => + { + str.Content = Encoding.UTF8.GetString(be.Content); + }); + + Mapper.CreateMap<WebClientStringResult, WebClientByteResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((str, be) => + { + if (!string.IsNullOrEmpty(str.Content)) + { + be.Content = Encoding.UTF8.GetBytes(str.Content); + } + }); + + Mapper.CreateMap<WebClientStringResult, WebClientStringResult>(); + Mapper.CreateMap<WebClientByteResult, WebClientByteResult>(); + Mapper.CreateMap<ReleaseInfo, ReleaseInfo>(); + + Mapper.CreateMap<ReleaseInfo, TrackerCacheResult>().AfterMap((r, t) => + { + if (r.Category != null) + { + var CategoryDesc = string.Join(", ", r.Category.Select(x => TorznabCatType.GetCatDesc(x)).Where(x => !string.IsNullOrEmpty(x))); + t.CategoryDesc = CategoryDesc; + } + else + { + t.CategoryDesc = ""; + } + }); + } + } +} diff --git a/src/Jackett/Models/Config/ServerConfig.cs b/src/Jackett/Models/Config/ServerConfig.cs index 5b18ee2c..6f9b604f 100644 --- a/src/Jackett/Models/Config/ServerConfig.cs +++ b/src/Jackett/Models/Config/ServerConfig.cs @@ -1,47 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.Config -{ - public class ServerConfig - { - public ServerConfig() - { - Port = 9117; - AllowExternal = System.Environment.OSVersion.Platform == PlatformID.Unix; - } - - public int Port { get; set; } - public bool AllowExternal { get; set; } - public string APIKey { get; set; } - public string AdminPassword { get; set; } - public string InstanceId { get; set; } - public string BlackholeDir { get; set; } - public bool UpdateDisabled { get; set; } - public bool UpdatePrerelease { get; set; } - public string BasePathOverride { get; set; } - - public string[] GetListenAddresses(bool? external = null) - { - if (external == null) - { - external = AllowExternal; - } - if (external.Value) - { - return new string[] { "http://*:" + Port + "/" }; - } - else - { - return new string[] { - "http://127.0.0.1:" + Port + "/", - "http://localhost:" + Port + "/", - }; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.Config +{ + public class ServerConfig + { + public ServerConfig() + { + Port = 9117; + AllowExternal = System.Environment.OSVersion.Platform == PlatformID.Unix; + } + + public int Port { get; set; } + public bool AllowExternal { get; set; } + public string APIKey { get; set; } + public string AdminPassword { get; set; } + public string InstanceId { get; set; } + public string BlackholeDir { get; set; } + public bool UpdateDisabled { get; set; } + public bool UpdatePrerelease { get; set; } + public string BasePathOverride { get; set; } + + public string[] GetListenAddresses(bool? external = null) + { + if (external == null) + { + external = AllowExternal; + } + if (external.Value) + { + return new string[] { "http://*:" + Port + "/" }; + } + else + { + return new string[] { + "http://127.0.0.1:" + Port + "/", + "http://localhost:" + Port + "/", + }; + } + } + } +} diff --git a/src/Jackett/Models/GitHub/Asset.cs b/src/Jackett/Models/GitHub/Asset.cs index 8cc6305d..a89a10c3 100644 --- a/src/Jackett/Models/GitHub/Asset.cs +++ b/src/Jackett/Models/GitHub/Asset.cs @@ -1,14 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.GitHub -{ - public class Asset - { - public string Name { get; set; } - public string Browser_download_url { get; set; } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.GitHub +{ + public class Asset + { + public string Name { get; set; } + public string Browser_download_url { get; set; } + } +} diff --git a/src/Jackett/Models/GitHub/Release.cs b/src/Jackett/Models/GitHub/Release.cs index 4ab18761..886afc90 100644 --- a/src/Jackett/Models/GitHub/Release.cs +++ b/src/Jackett/Models/GitHub/Release.cs @@ -1,16 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.GitHub -{ - public class Release - { - public string Name { set; get; } - public DateTime Created_at { get; set; } - public bool Prerelease { get; set; } - public List<Asset> Assets { set; get; } = new List<Asset>(); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.GitHub +{ + public class Release + { + public string Name { set; get; } + public DateTime Created_at { get; set; } + public bool Prerelease { get; set; } + public List<Asset> Assets { set; get; } = new List<Asset>(); + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAbnormal.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAbnormal.cs index 13a9b7bd..412a4068 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAbnormal.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAbnormal.cs @@ -1,57 +1,57 @@ -namespace Jackett.Models.IndexerConfig.Bespoke -{ - class ConfigurationDataAbnormal : ConfigurationData - { - public HiddenItem AuthKey { get; set; } - public HiddenItem TorrentPass { get; set; } - public DisplayItem CredentialsWarning { get; private set; } - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public DisplayItem PagesWarning { get; private set; } - public StringItem Pages { get; private set; } - public DisplayItem SecurityWarning { get; private set; } - public BoolItem Latency { get; private set; } - public BoolItem Browser { get; private set; } - public DisplayItem LatencyWarning { get; private set; } - public StringItem LatencyStart { get; private set; } - public StringItem LatencyEnd { get; private set; } - public DisplayItem HeadersWarning { get; private set; } - public StringItem HeaderAccept { get; private set; } - public StringItem HeaderAcceptLang { get; private set; } - public BoolItem HeaderDNT { get; private set; } - public BoolItem HeaderUpgradeInsecure { get; private set; } - public StringItem HeaderUserAgent { 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 ConfigurationDataAbnormal() - : base() - { - AuthKey = new HiddenItem { Name = "AuthKey", Value = "" }; - TorrentPass = new HiddenItem { Name = "TorrentPass", Value = "" }; - CredentialsWarning = new DisplayItem("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>Username</b> is your account name on this tracker.</li><li><b>Password</b> is your password associated to your account name.</li></ul>") { Name = "Credentials" }; - Username = new StringItem { Name = "Username (Required)", Value = "" }; - Password = new StringItem { Name = "Password (Required)", Value = "" }; - PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Max Pages to Process</b> let you specify how many page (max) Jackett can process when doing a search. Setting a value <b>higher than 4 is dangerous</b> for you account ! (<b>Result of too many requests to tracker...that <u>will be suspect</u></b>).</li><li><b>With Dead Torrents</b> let you search <u>with</u> torrents which are marked Dead.</li><li><b>Freeleech Only</b> let you search <u>only</u> for torrents which are marked Freeleech.</li><li><b>With Nuked Releases</b> let you search <u>with</u> torrents which are marked Nuked.</li><li><b>3D Releases Only</b> let you search <u>only</u> for torrents which are marked 3D.</li><li><b>French Only</b> let you search <u>only</u> for torrents which are marked FRENCH or TRUEFRENCH (<i>MULTI not included !</i>).</li></ul>") { Name = "Preferences" }; - Pages = new StringItem { Name = "Max Pages to Process (Required)", Value = "4" }; - SecurityWarning = new DisplayItem("<b>Security Configuration</b> (<i>Read this area carefully !</i>),<br /><br /> <ul><li><b>Latency Simulation</b> will simulate human browsing with Jacket by pausing Jacket for an random time between each request, to fake a real content browsing.</li><li><b>Browser Simulation</b> will simulate a real human browser by injecting additionals headers when doing requests to tracker.</li></ul>") { Name = "Security" }; - Latency = new BoolItem() { Name = "Latency Simulation (Optional)", Value = false }; - Browser = new BoolItem() { Name = "Browser Simulation (Optional)", Value = true }; - LatencyWarning = new DisplayItem("<b>Latency Configuration</b> (<i>Required if latency simulation enabled</i>),<br /><br/> <ul><li>By filling this range, <b>Jackett will make a random timed pause</b> <u>between requests</u> to tracker <u>to simulate a real browser</u>.</li><li>MilliSeconds <b>only</b></li></ul>") { Name = "Simulate Latency" }; - LatencyStart = new StringItem { Name = "Minimum Latency (ms)", Value = "1589" }; - LatencyEnd = new StringItem { Name = "Maximum Latency (ms)", Value = "3674" }; - HeadersWarning = new DisplayItem("<b>Browser Headers Configuration</b> (<i>Required if browser simulation enabled</i>),<br /><br /> <ul><li>By filling these fields, <b>Jackett will inject headers</b> with your values <u>to simulate a real browser</u>.</li><li>You can get <b>your browser values</b> here: <a href='https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending' target='blank'>www.whatismybrowser.com</a></li></ul><br /><i><b>Note that</b> some headers are not necessary because they are injected automatically by this provider such as Accept_Encoding, Connection, Host or X-Requested-With</i>") { Name = "Injecting headers" }; - HeaderAccept = new StringItem { Name = "Accept", Value = "" }; - HeaderAcceptLang = new StringItem { Name = "Accept-Language", Value = "" }; - HeaderDNT = new BoolItem { Name = "DNT", Value = false }; - HeaderUpgradeInsecure = new BoolItem { Name = "Upgrade-Insecure-Requests", Value = false }; - HeaderUserAgent = new StringItem { Name = "User-Agent", Value = "" }; - DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; - } - } -} +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataAbnormal : ConfigurationData + { + public HiddenItem AuthKey { get; set; } + public HiddenItem TorrentPass { get; set; } + public DisplayItem CredentialsWarning { get; private set; } + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public DisplayItem PagesWarning { get; private set; } + public StringItem Pages { get; private set; } + public DisplayItem SecurityWarning { get; private set; } + public BoolItem Latency { get; private set; } + public BoolItem Browser { get; private set; } + public DisplayItem LatencyWarning { get; private set; } + public StringItem LatencyStart { get; private set; } + public StringItem LatencyEnd { get; private set; } + public DisplayItem HeadersWarning { get; private set; } + public StringItem HeaderAccept { get; private set; } + public StringItem HeaderAcceptLang { get; private set; } + public BoolItem HeaderDNT { get; private set; } + public BoolItem HeaderUpgradeInsecure { get; private set; } + public StringItem HeaderUserAgent { 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 ConfigurationDataAbnormal() + : base() + { + AuthKey = new HiddenItem { Name = "AuthKey", Value = "" }; + TorrentPass = new HiddenItem { Name = "TorrentPass", Value = "" }; + CredentialsWarning = new DisplayItem("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>Username</b> is your account name on this tracker.</li><li><b>Password</b> is your password associated to your account name.</li></ul>") { Name = "Credentials" }; + Username = new StringItem { Name = "Username (Required)", Value = "" }; + Password = new StringItem { Name = "Password (Required)", Value = "" }; + PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Max Pages to Process</b> let you specify how many page (max) Jackett can process when doing a search. Setting a value <b>higher than 4 is dangerous</b> for you account ! (<b>Result of too many requests to tracker...that <u>will be suspect</u></b>).</li><li><b>With Dead Torrents</b> let you search <u>with</u> torrents which are marked Dead.</li><li><b>Freeleech Only</b> let you search <u>only</u> for torrents which are marked Freeleech.</li><li><b>With Nuked Releases</b> let you search <u>with</u> torrents which are marked Nuked.</li><li><b>3D Releases Only</b> let you search <u>only</u> for torrents which are marked 3D.</li><li><b>French Only</b> let you search <u>only</u> for torrents which are marked FRENCH or TRUEFRENCH (<i>MULTI not included !</i>).</li></ul>") { Name = "Preferences" }; + Pages = new StringItem { Name = "Max Pages to Process (Required)", Value = "4" }; + SecurityWarning = new DisplayItem("<b>Security Configuration</b> (<i>Read this area carefully !</i>),<br /><br /> <ul><li><b>Latency Simulation</b> will simulate human browsing with Jacket by pausing Jacket for an random time between each request, to fake a real content browsing.</li><li><b>Browser Simulation</b> will simulate a real human browser by injecting additionals headers when doing requests to tracker.</li></ul>") { Name = "Security" }; + Latency = new BoolItem() { Name = "Latency Simulation (Optional)", Value = false }; + Browser = new BoolItem() { Name = "Browser Simulation (Optional)", Value = true }; + LatencyWarning = new DisplayItem("<b>Latency Configuration</b> (<i>Required if latency simulation enabled</i>),<br /><br/> <ul><li>By filling this range, <b>Jackett will make a random timed pause</b> <u>between requests</u> to tracker <u>to simulate a real browser</u>.</li><li>MilliSeconds <b>only</b></li></ul>") { Name = "Simulate Latency" }; + LatencyStart = new StringItem { Name = "Minimum Latency (ms)", Value = "1589" }; + LatencyEnd = new StringItem { Name = "Maximum Latency (ms)", Value = "3674" }; + HeadersWarning = new DisplayItem("<b>Browser Headers Configuration</b> (<i>Required if browser simulation enabled</i>),<br /><br /> <ul><li>By filling these fields, <b>Jackett will inject headers</b> with your values <u>to simulate a real browser</u>.</li><li>You can get <b>your browser values</b> here: <a href='https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending' target='blank'>www.whatismybrowser.com</a></li></ul><br /><i><b>Note that</b> some headers are not necessary because they are injected automatically by this provider such as Accept_Encoding, Connection, Host or X-Requested-With</i>") { Name = "Injecting headers" }; + HeaderAccept = new StringItem { Name = "Accept", Value = "" }; + HeaderAcceptLang = new StringItem { Name = "Accept-Language", Value = "" }; + HeaderDNT = new BoolItem { Name = "DNT", Value = false }; + HeaderUpgradeInsecure = new BoolItem { Name = "Upgrade-Insecure-Requests", Value = false }; + HeaderUserAgent = new StringItem { Name = "User-Agent", Value = "" }; + DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs index 1c009acc..601974f0 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataAnimeBytes.cs @@ -1,24 +1,24 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig.Bespoke -{ - class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin - { - public BoolItem IncludeRaw { get; private set; } - public DisplayItem DateWarning { get; private set; } - public BoolItem InsertSeason { get; private set; } - - public ConfigurationDataAnimeBytes() - : base() - { - IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false }; - DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" }; - InsertSeason = new BoolItem() { Name = "Prefix episode number with S01 for Sonarr Compatability", Value = false }; - } - } -} +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataAnimeBytes : ConfigurationDataBasicLogin + { + public BoolItem IncludeRaw { get; private set; } + public DisplayItem DateWarning { get; private set; } + public BoolItem InsertSeason { get; private set; } + + public ConfigurationDataAnimeBytes() + : base() + { + IncludeRaw = new BoolItem() { Name = "IncludeRaw", Value = false }; + DateWarning = new DisplayItem("This tracker does not supply upload dates so they are based off year of release.") { Name = "DateWarning" }; + InsertSeason = new BoolItem() { Name = "Prefix episode number with S01 for Sonarr Compatability", Value = false }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs index 54c475dd..c3d01bb9 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataFileList.cs @@ -1,22 +1,22 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig.Bespoke -{ - class ConfigurationDataFileList : ConfigurationDataBasicLogin - { - public BoolItem IncludeRomanianReleases { get; private set; } - public DisplayItem CatWarning { get; private set; } - - public ConfigurationDataFileList() - : base() - { - IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false }; - CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" }; - } - } -} +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataFileList : ConfigurationDataBasicLogin + { + public BoolItem IncludeRomanianReleases { get; private set; } + public DisplayItem CatWarning { get; private set; } + + public ConfigurationDataFileList() + : base() + { + IncludeRomanianReleases = new BoolItem() { Name = "IncludeRomanianReleases", Value = false }; + CatWarning = new DisplayItem("When mapping TV ensure you add category 5000 in addition to 5030,5040.") { Name = "CatWarning" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs index 067a312d..886ae4d0 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataNCore.cs @@ -1,62 +1,62 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig.Bespoke -{ - public class ConfigurationDataNCore : ConfigurationData - { - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public BoolItem Hungarian { get; set; } - public BoolItem English { get; set; } - - public ConfigurationDataNCore() - { - Username = new StringItem { Name = "Username", Value = "" }; - Password = new StringItem { Name = "Password", Value = "" }; - Hungarian = new BoolItem { Name = "Hungarian", Value = true }; - English = new BoolItem { Name = "English", Value = true }; - } - - public ConfigurationDataNCore(JToken json) - { - ConfigurationDataNCore configData = new ConfigurationDataNCore(); - - dynamic configArray = JsonConvert.DeserializeObject(json.ToString()); - foreach (var config in configArray) - { - string propertyName = UppercaseFirst((string)config.id); - switch (propertyName) - { - case "Username": - Username = new StringItem { Name = propertyName, Value = config.value }; - break; - case "Password": - Password = new StringItem { Name = propertyName, Value = config.value }; - break; - case "Hungarian": - Hungarian = new BoolItem { Name = propertyName, Value = config.value }; - break; - case "English": - English = new BoolItem { Name = propertyName, Value = config.value }; - break; - default: - break; - } - } - } - - static string UppercaseFirst(string s) - { - if (string.IsNullOrEmpty(s)) - return string.Empty; - return char.ToUpper(s[0]) + s.Substring(1); - } - } +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataNCore : ConfigurationData + { + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public BoolItem Hungarian { get; set; } + public BoolItem English { get; set; } + + public ConfigurationDataNCore() + { + Username = new StringItem { Name = "Username", Value = "" }; + Password = new StringItem { Name = "Password", Value = "" }; + Hungarian = new BoolItem { Name = "Hungarian", Value = true }; + English = new BoolItem { Name = "English", Value = true }; + } + + public ConfigurationDataNCore(JToken json) + { + ConfigurationDataNCore configData = new ConfigurationDataNCore(); + + dynamic configArray = JsonConvert.DeserializeObject(json.ToString()); + foreach (var config in configArray) + { + string propertyName = UppercaseFirst((string)config.id); + switch (propertyName) + { + case "Username": + Username = new StringItem { Name = propertyName, Value = config.value }; + break; + case "Password": + Password = new StringItem { Name = propertyName, Value = config.value }; + break; + case "Hungarian": + Hungarian = new BoolItem { Name = propertyName, Value = config.value }; + break; + case "English": + English = new BoolItem { Name = propertyName, Value = config.value }; + break; + default: + break; + } + } + } + + static string UppercaseFirst(string s) + { + if (string.IsNullOrEmpty(s)) + return string.Empty; + return char.ToUpper(s[0]) + s.Substring(1); + } + } } \ No newline at end of file diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataPhxBit.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataPhxBit.cs index 07b2c239..00cadb30 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataPhxBit.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataPhxBit.cs @@ -1,55 +1,55 @@ -namespace Jackett.Models.IndexerConfig.Bespoke -{ - class ConfigurationDataPhxBit : ConfigurationData - { - public HiddenItem PassKey { get; set; } - public DisplayItem CredentialsWarning { get; private set; } - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public DisplayItem PagesWarning { get; private set; } - public StringItem Pages { get; private set; } - public DisplayItem SecurityWarning { get; private set; } - public BoolItem Latency { get; private set; } - public BoolItem Browser { get; private set; } - public DisplayItem LatencyWarning { get; private set; } - public StringItem LatencyStart { get; private set; } - public StringItem LatencyEnd { get; private set; } - public DisplayItem HeadersWarning { get; private set; } - public StringItem HeaderAccept { get; private set; } - public StringItem HeaderAcceptLang { get; private set; } - public BoolItem HeaderDNT { get; private set; } - public BoolItem HeaderUpgradeInsecure { get; private set; } - public StringItem HeaderUserAgent { 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 ConfigurationDataPhxBit() - : base() - { - PassKey = new HiddenItem { Name = "PassKey", Value = "" }; - CredentialsWarning = new DisplayItem("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>Username</b> is your account name on this tracker.</li><li><b>Password</b> is your password associated to your account name.</li></ul>") { Name = "Credentials" }; - Username = new StringItem { Name = "Username (Required)", Value = "" }; - Password = new StringItem { Name = "Password (Required)", Value = "" }; - PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Max Pages to Process</b> let you specify how many page (max) Jackett can process when doing a search. Setting a value <b>higher than 4 is dangerous</b> for you account ! (<b>Result of too many requests to tracker...that <u>will be suspect</u></b>).</li></ul>") { Name = "Preferences" }; - Pages = new StringItem { Name = "Max Pages to Process (Required)", Value = "4" }; - SecurityWarning = new DisplayItem("<b>Security Configuration</b> (<i>Read this area carefully !</i>),<br /><br /> <ul><li><b>Latency Simulation</b> will simulate human browsing with Jacket by pausing Jacket for an random time between each request, to fake a real content browsing.</li><li><b>Browser Simulation</b> will simulate a real human browser by injecting additionals headers when doing requests to tracker.</li></ul>") { Name = "Security" }; - Latency = new BoolItem() { Name = "Latency Simulation (Optional)", Value = false }; - Browser = new BoolItem() { Name = "Browser Simulation (Optional)", Value = true }; - LatencyWarning = new DisplayItem("<b>Latency Configuration</b> (<i>Required if latency simulation enabled</i>),<br /><br/> <ul><li>By filling this range, <b>Jackett will make a random timed pause</b> <u>between requests</u> to tracker <u>to simulate a real browser</u>.</li><li>MilliSeconds <b>only</b></li></ul>") { Name = "Simulate Latency" }; - LatencyStart = new StringItem { Name = "Minimum Latency (ms)", Value = "1589" }; - LatencyEnd = new StringItem { Name = "Maximum Latency (ms)", Value = "3674" }; - HeadersWarning = new DisplayItem("<b>Browser Headers Configuration</b> (<i>Required if browser simulation enabled</i>),<br /><br /> <ul><li>By filling these fields, <b>Jackett will inject headers</b> with your values <u>to simulate a real browser</u>.</li><li>You can get <b>your browser values</b> here: <a href='https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending' target='blank'>www.whatismybrowser.com</a></li></ul><br /><i><b>Note that</b> some headers are not necessary because they are injected automatically by this provider such as Accept_Encoding, Connection, Host or X-Requested-With</i>") { Name = "Injecting headers" }; - HeaderAccept = new StringItem { Name = "Accept", Value = "" }; - HeaderAcceptLang = new StringItem { Name = "Accept-Language", Value = "" }; - HeaderDNT = new BoolItem { Name = "DNT", Value = false }; - HeaderUpgradeInsecure = new BoolItem { Name = "Upgrade-Insecure-Requests", Value = false }; - HeaderUserAgent = new StringItem { Name = "User-Agent", Value = "" }; - DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; - } - } -} +namespace Jackett.Models.IndexerConfig.Bespoke +{ + class ConfigurationDataPhxBit : ConfigurationData + { + public HiddenItem PassKey { get; set; } + public DisplayItem CredentialsWarning { get; private set; } + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public DisplayItem PagesWarning { get; private set; } + public StringItem Pages { get; private set; } + public DisplayItem SecurityWarning { get; private set; } + public BoolItem Latency { get; private set; } + public BoolItem Browser { get; private set; } + public DisplayItem LatencyWarning { get; private set; } + public StringItem LatencyStart { get; private set; } + public StringItem LatencyEnd { get; private set; } + public DisplayItem HeadersWarning { get; private set; } + public StringItem HeaderAccept { get; private set; } + public StringItem HeaderAcceptLang { get; private set; } + public BoolItem HeaderDNT { get; private set; } + public BoolItem HeaderUpgradeInsecure { get; private set; } + public StringItem HeaderUserAgent { 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 ConfigurationDataPhxBit() + : base() + { + PassKey = new HiddenItem { Name = "PassKey", Value = "" }; + CredentialsWarning = new DisplayItem("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>Username</b> is your account name on this tracker.</li><li><b>Password</b> is your password associated to your account name.</li></ul>") { Name = "Credentials" }; + Username = new StringItem { Name = "Username (Required)", Value = "" }; + Password = new StringItem { Name = "Password (Required)", Value = "" }; + PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Max Pages to Process</b> let you specify how many page (max) Jackett can process when doing a search. Setting a value <b>higher than 4 is dangerous</b> for you account ! (<b>Result of too many requests to tracker...that <u>will be suspect</u></b>).</li></ul>") { Name = "Preferences" }; + Pages = new StringItem { Name = "Max Pages to Process (Required)", Value = "4" }; + SecurityWarning = new DisplayItem("<b>Security Configuration</b> (<i>Read this area carefully !</i>),<br /><br /> <ul><li><b>Latency Simulation</b> will simulate human browsing with Jacket by pausing Jacket for an random time between each request, to fake a real content browsing.</li><li><b>Browser Simulation</b> will simulate a real human browser by injecting additionals headers when doing requests to tracker.</li></ul>") { Name = "Security" }; + Latency = new BoolItem() { Name = "Latency Simulation (Optional)", Value = false }; + Browser = new BoolItem() { Name = "Browser Simulation (Optional)", Value = true }; + LatencyWarning = new DisplayItem("<b>Latency Configuration</b> (<i>Required if latency simulation enabled</i>),<br /><br/> <ul><li>By filling this range, <b>Jackett will make a random timed pause</b> <u>between requests</u> to tracker <u>to simulate a real browser</u>.</li><li>MilliSeconds <b>only</b></li></ul>") { Name = "Simulate Latency" }; + LatencyStart = new StringItem { Name = "Minimum Latency (ms)", Value = "1589" }; + LatencyEnd = new StringItem { Name = "Maximum Latency (ms)", Value = "3674" }; + HeadersWarning = new DisplayItem("<b>Browser Headers Configuration</b> (<i>Required if browser simulation enabled</i>),<br /><br /> <ul><li>By filling these fields, <b>Jackett will inject headers</b> with your values <u>to simulate a real browser</u>.</li><li>You can get <b>your browser values</b> here: <a href='https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending' target='blank'>www.whatismybrowser.com</a></li></ul><br /><i><b>Note that</b> some headers are not necessary because they are injected automatically by this provider such as Accept_Encoding, Connection, Host or X-Requested-With</i>") { Name = "Injecting headers" }; + HeaderAccept = new StringItem { Name = "Accept", Value = "" }; + HeaderAcceptLang = new StringItem { Name = "Accept-Language", Value = "" }; + HeaderDNT = new BoolItem { Name = "DNT", Value = false }; + HeaderUpgradeInsecure = new BoolItem { Name = "Upgrade-Insecure-Requests", Value = false }; + HeaderUserAgent = new StringItem { Name = "User-Agent", Value = "" }; + DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs index aed0f139..83db0b16 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataRuTor.cs @@ -1,27 +1,27 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig.Bespoke -{ - public class ConfigurationDataRuTor : ConfigurationData - { - [JsonProperty] - public StringItem Url { get; private set; } - [JsonProperty] - public BoolItem StripRussian { get; private set; } - - public ConfigurationDataRuTor() - { - } - - public ConfigurationDataRuTor(string defaultUrl) - { - Url = new StringItem { Name = "Url", Value = defaultUrl }; - StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true }; - } - } -} +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataRuTor : ConfigurationData + { + [JsonProperty] + public StringItem Url { get; private set; } + [JsonProperty] + public BoolItem StripRussian { get; private set; } + + public ConfigurationDataRuTor() + { + } + + public ConfigurationDataRuTor(string defaultUrl) + { + Url = new StringItem { Name = "Url", Value = defaultUrl }; + StripRussian = new BoolItem() { Name = "StripRusNamePrefix", Value = true }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs index ba39425b..938ed4ce 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataStrike.cs @@ -1,18 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig.Bespoke -{ - public class ConfigurationDataStrike : ConfigurationDataUrl - { - public DisplayItem StrikeWarning { get; private set; } - - public ConfigurationDataStrike(string url) : base(url) - { - StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" }; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig.Bespoke +{ + public class ConfigurationDataStrike : ConfigurationDataUrl + { + public DisplayItem StrikeWarning { get; private set; } + + public ConfigurationDataStrike(string url) : base(url) + { + StrikeWarning = new DisplayItem("This indexer does not support RSS Sync, only Search") { Name = "Warning" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs index b0f8c9dc..d05c350a 100644 --- a/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs +++ b/src/Jackett/Models/IndexerConfig/Bespoke/ConfigurationDataXthor.cs @@ -1,27 +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("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>PassKey</b> is your private key on your account</li></ul>") { Name = "Credentials" }; - PassKey = new StringItem { Name = "PassKey", Value = "" }; - PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Freeleech Only</b> let you search <u>only</u> for torrents which are marked Freeleech.</li></ul>") { Name = "Preferences" }; - Freeleech = new BoolItem() { Name = "Freeleech Only (Optional)", Value = false }; - DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; - } - } -} +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("<b>Credentials Configuration</b> (<i>Private Tracker</i>),<br /><br /> <ul><li><b>PassKey</b> is your private key on your account</li></ul>") { Name = "Credentials" }; + PassKey = new StringItem { Name = "PassKey", Value = "" }; + PagesWarning = new DisplayItem("<b>Preferences Configuration</b> (<i>Tweak your search settings</i>),<br /><br /> <ul><li><b>Freeleech Only</b> let you search <u>only</u> for torrents which are marked Freeleech.</li></ul>") { Name = "Preferences" }; + Freeleech = new BoolItem() { Name = "Freeleech Only (Optional)", Value = false }; + DevWarning = new DisplayItem("<b>Development Facility</b> (<i>For Developers ONLY</i>),<br /><br /> <ul><li>By enabling development mode, <b>Jackett will bypass his cache</b> and will <u>output debug messages to console</u> instead of his log file.</li><li>By enabling Hard Drive Cache, <b>This provider</b> will <u>save each query answers from tracker</u> in temp directory, in fact this reduce drastically HTTP requests when building a provider at parsing step for example. So, <b> Jackett will search for a cached query answer on hard drive before executing query on tracker side !</b> <i>DEV MODE must be enabled to use it !</li></ul>") { 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" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationData.cs b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs index ba89535c..ee67297f 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationData.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationData.cs @@ -48,9 +48,9 @@ namespace Jackett.Models.IndexerConfig // transistion from alternatelink to sitelink var alternatelinkItem = arr.FirstOrDefault(f => f.Value<string>("id") == "alternatelink"); - if (alternatelinkItem != null && !string.IsNullOrEmpty(alternatelinkItem.Value<string>("value"))) - { - //SiteLink.Value = alternatelinkItem.Value<string>("value"); + if (alternatelinkItem != null && !string.IsNullOrEmpty(alternatelinkItem.Value<string>("value"))) + { + //SiteLink.Value = alternatelinkItem.Value<string>("value"); } foreach (var item in GetItems(forDisplay: false)) @@ -73,7 +73,7 @@ namespace Jackett.Models.IndexerConfig if (ps != null) sItem.Value = ps.UnProtect(newValue); } - } + } else { sItem.Value = newValue; @@ -145,9 +145,9 @@ namespace Jackett.Models.IndexerConfig .GetProperties() .Where(p => p.CanRead) .Where(p => p.PropertyType.IsSubclassOf(typeof(Item))) - .Select(p => (Item)p.GetValue(this)).ToList(); - - // remove/insert Site Link manualy to make sure it shows up first + .Select(p => (Item)p.GetValue(this)).ToList(); + + // remove/insert Site Link manualy to make sure it shows up first properties.Remove(SiteLink); properties.Insert(0, SiteLink); @@ -163,21 +163,21 @@ namespace Jackett.Models.IndexerConfig return properties.ToArray(); } - public void AddDynamic(string ID, Item item) - { - dynamics[ID] = item; + public void AddDynamic(string ID, Item item) + { + dynamics[ID] = item; } - public Item GetDynamic(string ID) - { - try - { - return dynamics[ID]; - } - catch(KeyNotFoundException) - { - return null; - } + public Item GetDynamic(string ID) + { + try + { + return dynamics[ID]; + } + catch(KeyNotFoundException) + { + return null; + } } public class Item diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs index 30fd25ee..ace73475 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataAPIKey.cs @@ -1,18 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Models.IndexerConfig -{ - public class ConfigurationDataAPIKey : ConfigurationData - { - public ConfigurationData.StringItem Key { get; private set; } - - public ConfigurationDataAPIKey() - { - Key = new ConfigurationData.StringItem { Name = "APIKey", Value = string.Empty }; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.IndexerConfig +{ + public class ConfigurationDataAPIKey : ConfigurationData + { + public ConfigurationData.StringItem Key { get; private set; } + + public ConfigurationDataAPIKey() + { + Key = new ConfigurationData.StringItem { Name = "APIKey", Value = string.Empty }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithRSSAndDisplay.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithRSSAndDisplay.cs index 981d6117..74275f41 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithRSSAndDisplay.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataBasicLoginWithRSSAndDisplay.cs @@ -1,25 +1,25 @@ -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 ConfigurationDataBasicLoginWithRSSAndDisplay : ConfigurationData - { - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public HiddenItem RSSKey { get; private set; } - public DisplayItem DisplayText { get; private set; } - - public ConfigurationDataBasicLoginWithRSSAndDisplay() - { - Username = new StringItem { Name = "Username" }; - Password = new StringItem { Name = "Password" }; - RSSKey = new HiddenItem { Name = "RSSKey" }; - DisplayText = new DisplayItem(""){ Name = "" }; - } - } -} +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 ConfigurationDataBasicLoginWithRSSAndDisplay : ConfigurationData + { + public StringItem Username { get; private set; } + public StringItem Password { get; private set; } + public HiddenItem RSSKey { get; private set; } + public DisplayItem DisplayText { get; private set; } + + public ConfigurationDataBasicLoginWithRSSAndDisplay() + { + Username = new StringItem { Name = "Username" }; + Password = new StringItem { Name = "Password" }; + RSSKey = new HiddenItem { Name = "RSSKey" }; + DisplayText = new DisplayItem(""){ Name = "" }; + } + } +} diff --git a/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginLink.cs b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginLink.cs index c3f2434d..030589f9 100644 --- a/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginLink.cs +++ b/src/Jackett/Models/IndexerConfig/ConfigurationDataLoginLink.cs @@ -1,23 +1,23 @@ -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 ConfigurationDataLoginLink : ConfigurationData - { - public StringItem LoginLink { get; private set; } - public HiddenItem RSSKey { get; private set; } - public DisplayItem DisplayText { get; private set; } - - public ConfigurationDataLoginLink() - { - LoginLink = new StringItem { Name = "Login Link" }; - RSSKey = new HiddenItem { Name = "RSSKey" }; - DisplayText = new DisplayItem(""){ Name = "" }; - } - } -} +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 ConfigurationDataLoginLink : ConfigurationData + { + public StringItem LoginLink { get; private set; } + public HiddenItem RSSKey { get; private set; } + public DisplayItem DisplayText { get; private set; } + + public ConfigurationDataLoginLink() + { + LoginLink = new StringItem { Name = "Login Link" }; + RSSKey = new HiddenItem { Name = "RSSKey" }; + DisplayText = new DisplayItem(""){ Name = "" }; + } + } +} diff --git a/src/Jackett/Models/ReleaseInfo.cs b/src/Jackett/Models/ReleaseInfo.cs index b6ca12cc..e93671b3 100644 --- a/src/Jackett/Models/ReleaseInfo.cs +++ b/src/Jackett/Models/ReleaseInfo.cs @@ -18,8 +18,8 @@ namespace Jackett.Models public Uri Comments { get; set; } public DateTime PublishDate { get; set; } public ICollection<int> Category { get; set; } - public long? Size { get; set; } - public long? Files { get; set; } + public long? Size { get; set; } + public long? Files { get; set; } public long? Grabs { get; set; } public string Description { get; set; } public long? RageID { get; set; } @@ -46,8 +46,8 @@ namespace Jackett.Models Comments = Comments, PublishDate = PublishDate, Category = Category, - Size = Size, - Files = Files, + Size = Size, + Files = Files, Grabs = Grabs, Description = Description, RageID = RageID, diff --git a/src/Jackett/Models/TorznabCatType.cs b/src/Jackett/Models/TorznabCatType.cs index 15427292..9f1a7f3a 100644 --- a/src/Jackett/Models/TorznabCatType.cs +++ b/src/Jackett/Models/TorznabCatType.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; namespace Jackett.Models @@ -14,7 +14,7 @@ namespace Jackett.Models if (cat != null && queryCats != null) { return cat.SubCategories.Any(c => queryCats.Contains(c.ID)); - } + } } return false; @@ -31,9 +31,9 @@ namespace Jackett.Models return string.Empty; } - public static string NormalizeCatName(string name) - { - return name.Replace(" ", "").ToLower(); + public static string NormalizeCatName(string name) + { + return name.Replace(" ", "").ToLower(); } public static TorznabCategory GetCatByName(string name) diff --git a/src/Jackett/Models/TorznabCategory.cs b/src/Jackett/Models/TorznabCategory.cs index 5a068f0b..adea3548 100644 --- a/src/Jackett/Models/TorznabCategory.cs +++ b/src/Jackett/Models/TorznabCategory.cs @@ -26,15 +26,15 @@ namespace Jackett.Models SubCategories = new List<TorznabCategory>(); } - public bool Contains(TorznabCategory cat) - { - if (this == cat) - return true; - - if (SubCategories.Contains(cat)) - return true; - - return false; + public bool Contains(TorznabCategory cat) + { + if (this == cat) + return true; + + if (SubCategories.Contains(cat)) + return true; + + return false; } public JToken ToJson() @@ -43,19 +43,19 @@ namespace Jackett.Models t["ID"] = ID; t["Name"] = Name; return t; - } - - public override bool Equals(Object obj) - { - if (obj == null || GetType() != obj.GetType()) - return false; - - return ID == ((TorznabCategory)obj).ID; - } - - public override int GetHashCode() - { - return ID; + } + + public override bool Equals(Object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + + return ID == ((TorznabCategory)obj).ID; + } + + public override int GetHashCode() + { + return ID; } } } diff --git a/src/Jackett/Models/TorznabQuery.cs b/src/Jackett/Models/TorznabQuery.cs index b335be23..7bbec859 100644 --- a/src/Jackett/Models/TorznabQuery.cs +++ b/src/Jackett/Models/TorznabQuery.cs @@ -5,7 +5,7 @@ using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Jackett.Models @@ -71,33 +71,33 @@ namespace Jackett.Models // Some trackers don't support AND logic for search terms resulting in unwanted results. // Using this method we can AND filter it within jackett. // With limit we can limit the amount of characters which should be compared (use it if a tracker doesn't return the full title). - public bool MatchQueryStringAND(string title, int? limit = null, string queryStringOverride = null) - { - // We cache the regex split results so we have to do it only once for each query. - if (QueryStringParts == null) - { - var queryString = GetQueryString(); - if (queryStringOverride != null) - queryString = queryStringOverride; - if (limit != null && limit > 0) - { - if (limit > queryString.Length) - limit = queryString.Length; - queryString = queryString.Substring(0, (int)limit); - } - Regex SplitRegex = new Regex("[^a-zA-Z0-9]+"); - QueryStringParts = SplitRegex.Split(queryString); - } - - // Check if each part of the query string is in the given title. - foreach (var QueryStringPart in QueryStringParts) - { - if (title.IndexOf(QueryStringPart, StringComparison.OrdinalIgnoreCase) < 0) - { - return false; - } - } - return true; + public bool MatchQueryStringAND(string title, int? limit = null, string queryStringOverride = null) + { + // We cache the regex split results so we have to do it only once for each query. + if (QueryStringParts == null) + { + var queryString = GetQueryString(); + if (queryStringOverride != null) + queryString = queryStringOverride; + if (limit != null && limit > 0) + { + if (limit > queryString.Length) + limit = queryString.Length; + queryString = queryString.Substring(0, (int)limit); + } + Regex SplitRegex = new Regex("[^a-zA-Z0-9]+"); + QueryStringParts = SplitRegex.Split(queryString); + } + + // Check if each part of the query string is in the given title. + foreach (var QueryStringPart in QueryStringParts) + { + if (title.IndexOf(QueryStringPart, StringComparison.OrdinalIgnoreCase) < 0) + { + return false; + } + } + return true; } public string GetEpisodeSearchString() diff --git a/src/Jackett/Properties/AssemblyInfo.cs b/src/Jackett/Properties/AssemblyInfo.cs index f84ef367..ba021bc7 100644 --- a/src/Jackett/Properties/AssemblyInfo.cs +++ b/src/Jackett/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Jackett")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Jackett")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5881fb69-3cb2-42b7-a744-2c1e537176bd")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.0.0.0")] -[assembly: AssemblyFileVersion("0.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jackett")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Jackett")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5881fb69-3cb2-42b7-a744-2c1e537176bd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/src/Jackett/Services/ConfigurationService.cs b/src/Jackett/Services/ConfigurationService.cs index b5ab6dcd..05ece220 100644 --- a/src/Jackett/Services/ConfigurationService.cs +++ b/src/Jackett/Services/ConfigurationService.cs @@ -196,8 +196,8 @@ namespace Jackett.Services } #endif return dir; - } - + } + public List<string> GetCardigannDefinitionsFolders() { List<string> dirs = new List<string>(); diff --git a/src/Jackett/Services/IndexerManagerService.cs b/src/Jackett/Services/IndexerManagerService.cs index ce4781ba..c3bebd15 100644 --- a/src/Jackett/Services/IndexerManagerService.cs +++ b/src/Jackett/Services/IndexerManagerService.cs @@ -44,42 +44,42 @@ namespace Jackett.Services cacheService = cache; } - protected void LoadIndexerConfig(IIndexer idx) - { - var configFilePath = GetIndexerConfigFilePath(idx); - if (File.Exists(configFilePath)) - { - try - { - var fileStr = File.ReadAllText(configFilePath); - var jsonString = JToken.Parse(fileStr); - idx.LoadFromSavedConfiguration(jsonString); - } - catch (Exception ex) - { - logger.Error(ex, "Failed loading configuration for {0}, trying backup", idx.DisplayName); - var configFilePathBak = configFilePath + ".bak"; - if (File.Exists(configFilePathBak)) - { - try - { - var fileStrBak = File.ReadAllText(configFilePathBak); - var jsonStringBak = JToken.Parse(fileStrBak); - idx.LoadFromSavedConfiguration(jsonStringBak); - logger.Info("Successfully loaded backup config for {0}", idx.DisplayName); - idx.SaveConfig(); - } - catch (Exception exbak) - { - logger.Error(exbak, "Failed loading backup configuration for {0}, you must reconfigure this indexer", idx.DisplayName); - } - } - else - { - logger.Error(ex, "Failed loading backup configuration for {0} (no backup available), you must reconfigure this indexer", idx.DisplayName); - } - } - } + protected void LoadIndexerConfig(IIndexer idx) + { + var configFilePath = GetIndexerConfigFilePath(idx); + if (File.Exists(configFilePath)) + { + try + { + var fileStr = File.ReadAllText(configFilePath); + var jsonString = JToken.Parse(fileStr); + idx.LoadFromSavedConfiguration(jsonString); + } + catch (Exception ex) + { + logger.Error(ex, "Failed loading configuration for {0}, trying backup", idx.DisplayName); + var configFilePathBak = configFilePath + ".bak"; + if (File.Exists(configFilePathBak)) + { + try + { + var fileStrBak = File.ReadAllText(configFilePathBak); + var jsonStringBak = JToken.Parse(fileStrBak); + idx.LoadFromSavedConfiguration(jsonStringBak); + logger.Info("Successfully loaded backup config for {0}", idx.DisplayName); + idx.SaveConfig(); + } + catch (Exception exbak) + { + logger.Error(exbak, "Failed loading backup configuration for {0}, you must reconfigure this indexer", idx.DisplayName); + } + } + else + { + logger.Error(ex, "Failed loading backup configuration for {0} (no backup available), you must reconfigure this indexer", idx.DisplayName); + } + } + } } public void InitIndexers() @@ -97,32 +97,32 @@ namespace Jackett.Services { logger.Info("Loading Cardigann definitions from: " + path); - try - { - if (!Directory.Exists(path)) - return; - - DirectoryInfo d = new DirectoryInfo(path); - - foreach (var file in d.GetFiles("*.yml")) - { - logger.Info("Loading Cardigann definition " + file.FullName); - string DefinitionString = File.ReadAllText(file.FullName); - CardigannIndexer idx = new CardigannIndexer(this, container.Resolve<IWebClient>(), logger, container.Resolve<IProtectionService>(), DefinitionString); - if (indexers.ContainsKey(idx.ID)) - { - logger.Debug(string.Format("Ignoring definition ID={0}, file={1}: Indexer already exists", idx.ID, file.FullName)); - } - else - { - indexers.Add(idx.ID, idx); - LoadIndexerConfig(idx); - } + try + { + if (!Directory.Exists(path)) + return; + + DirectoryInfo d = new DirectoryInfo(path); + + foreach (var file in d.GetFiles("*.yml")) + { + logger.Info("Loading Cardigann definition " + file.FullName); + string DefinitionString = File.ReadAllText(file.FullName); + CardigannIndexer idx = new CardigannIndexer(this, container.Resolve<IWebClient>(), logger, container.Resolve<IProtectionService>(), DefinitionString); + if (indexers.ContainsKey(idx.ID)) + { + logger.Debug(string.Format("Ignoring definition ID={0}, file={1}: Indexer already exists", idx.ID, file.FullName)); + } + else + { + indexers.Add(idx.ID, idx); + LoadIndexerConfig(idx); + } } - } - catch (Exception ex) - { - logger.Error(ex, "Error while loading Cardigann definitions: "+ ex.Message); + } + catch (Exception ex) + { + logger.Error(ex, "Error while loading Cardigann definitions: "+ ex.Message); } } @@ -162,13 +162,13 @@ namespace Jackett.Services var indexer = GetIndexer(name); var configPath = GetIndexerConfigFilePath(indexer); File.Delete(configPath); - if (indexer.GetType() == typeof(CardigannIndexer)) - { - indexers[name] = new CardigannIndexer(this, container.Resolve<IWebClient>(), logger, container.Resolve<IProtectionService>(), ((CardigannIndexer)indexer).DefinitionString); - } - else - { - indexers[name] = container.ResolveNamed<IIndexer>(indexer.ID); + if (indexer.GetType() == typeof(CardigannIndexer)) + { + indexers[name] = new CardigannIndexer(this, container.Resolve<IWebClient>(), logger, container.Resolve<IProtectionService>(), ((CardigannIndexer)indexer).DefinitionString); + } + else + { + indexers[name] = container.ResolveNamed<IIndexer>(indexer.ID); } } @@ -179,7 +179,7 @@ namespace Jackett.Services public void SaveConfig(IIndexer indexer, JToken obj) { - lock (configWriteLock) + lock (configWriteLock) { var uID = Guid.NewGuid().ToString("N"); var configFilePath = GetIndexerConfigFilePath(indexer); @@ -189,63 +189,63 @@ namespace Jackett.Services logger.Debug(string.Format("Saving new config file: {0}", configFilePathTmp)); - if (string.IsNullOrWhiteSpace(content)) - { - throw new Exception(string.Format("New config content for {0} is empty, please report this bug.", indexer.ID)); - } - - if (content.Contains("\x00")) - { - throw new Exception(string.Format("New config content for {0} contains 0x00, please report this bug. Content: {1}", indexer.ID, content)); - } - - // make sure the config directory exists + if (string.IsNullOrWhiteSpace(content)) + { + throw new Exception(string.Format("New config content for {0} is empty, please report this bug.", indexer.ID)); + } + + if (content.Contains("\x00")) + { + throw new Exception(string.Format("New config content for {0} contains 0x00, please report this bug. Content: {1}", indexer.ID, content)); + } + + // make sure the config directory exists if (!Directory.Exists(configService.GetIndexerConfigDir())) Directory.CreateDirectory(configService.GetIndexerConfigDir()); // create new temporary config file File.WriteAllText(configFilePathTmp, content); var fileInfo = new FileInfo(configFilePathTmp); - if (fileInfo.Length == 0) - { - throw new Exception(string.Format("New config file {0} is empty, please report this bug.", configFilePathTmp)); + if (fileInfo.Length == 0) + { + throw new Exception(string.Format("New config file {0} is empty, please report this bug.", configFilePathTmp)); } // create backup file File.Delete(configFilePathBak); - if (File.Exists(configFilePath)) - { - try - { - File.Move(configFilePath, configFilePathBak); - } + if (File.Exists(configFilePath)) + { + try + { + File.Move(configFilePath, configFilePathBak); + } catch (IOException ex) - { - logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePath, configFilePathBak, ex.ToString())); - } + { + logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePath, configFilePathBak, ex.ToString())); + } } // replace the actual config file File.Delete(configFilePath); - try - { - File.Move(configFilePathTmp, configFilePath); - } + try + { + File.Move(configFilePathTmp, configFilePath); + } catch (IOException ex) - { - logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePathTmp, configFilePath, ex.ToString())); - } - } - } - - public void SortIndexers() - { - // Apparently Dictionary are ordered but can't be sorted again - // This will recreate the indexers Dictionary to workaround this limitation - Dictionary<string, IIndexer> newIndexers = new Dictionary<string, IIndexer>(); - foreach (var indexer in indexers.OrderBy(_ => _.Value.DisplayName)) - newIndexers.Add(indexer.Key, indexer.Value); - indexers = newIndexers; - } + { + logger.Error(string.Format("Error while moving {0} to {1}: {2}", configFilePathTmp, configFilePath, ex.ToString())); + } + } + } + + public void SortIndexers() + { + // Apparently Dictionary are ordered but can't be sorted again + // This will recreate the indexers Dictionary to workaround this limitation + Dictionary<string, IIndexer> newIndexers = new Dictionary<string, IIndexer>(); + foreach (var indexer in indexers.OrderBy(_ => _.Value.DisplayName)) + newIndexers.Add(indexer.Key, indexer.Value); + indexers = newIndexers; + } } } diff --git a/src/Jackett/Services/ProtectionService.cs b/src/Jackett/Services/ProtectionService.cs index 58f0bfd7..a97e0848 100644 --- a/src/Jackett/Services/ProtectionService.cs +++ b/src/Jackett/Services/ProtectionService.cs @@ -19,7 +19,7 @@ namespace Jackett.Services public class ProtectionService : IProtectionService { DataProtectionScope PROTECTION_SCOPE = DataProtectionScope.LocalMachine; - private const string JACKETT_KEY = "JACKETT_KEY"; + private const string JACKETT_KEY = "JACKETT_KEY"; const string APPLICATION_KEY = "Dvz66r3n8vhTGip2/quiw5ISyM37f7L2iOdupzdKmzkvXGhAgQiWK+6F+4qpxjPVNks1qO7LdWuVqRlzgLzeW8mChC6JnBMUS1Fin4N2nS9lh4XPuCZ1che75xO92Nk2vyXUo9KSFG1hvEszAuLfG2Mcg1r0sVyVXd2gQDU/TbY="; IServerService serverService; @@ -54,8 +54,8 @@ namespace Jackett.Services var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY); if (jackettKey == null) - { - return UnProtectDefaultMethod(plainText); + { + return UnProtectDefaultMethod(plainText); } else { diff --git a/src/Jackett/Services/ServerService.cs b/src/Jackett/Services/ServerService.cs index b2cf707f..590555ce 100644 --- a/src/Jackett/Services/ServerService.cs +++ b/src/Jackett/Services/ServerService.cs @@ -17,13 +17,13 @@ using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; -using System.Text.RegularExpressions; -using System.Threading; +using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Web; @@ -37,9 +37,9 @@ namespace Jackett.Services void ReserveUrls(bool doInstall = true); ServerConfig Config { get; } void SaveConfig(); - Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent"); - string BasePath(); - List<string> notices { get; } + Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent"); + string BasePath(); + List<string> notices { get; } } public class ServerService : IServerService @@ -73,16 +73,16 @@ namespace Jackett.Services public ServerConfig Config { get { return config; } - } - - public List<string> notices - { - get - { - return _notices; - } - } - + } + + public List<string> notices + { + get + { + return _notices; + } + } + public Uri ConvertToProxyLink(Uri link, string serverUrl, string indexerId, string action = "dl", string file = "t.torrent") { if (link == null || (link.IsAbsoluteUri && link.Scheme == "magnet")) @@ -94,19 +94,19 @@ namespace Jackett.Services return new Uri(proxyLink); } - public string BasePath() - { - if (config.BasePathOverride == null || config.BasePathOverride == "") { - return "/"; + public string BasePath() + { + if (config.BasePathOverride == null || config.BasePathOverride == "") { + return "/"; } var path = config.BasePathOverride; - if (!path.EndsWith("/")) - { - path = path + "/"; + if (!path.EndsWith("/")) + { + path = path + "/"; } - if (!path.StartsWith("/")) - { - path = "/" + path; + if (!path.StartsWith("/")) + { + path = "/" + path; } return path; } @@ -161,131 +161,131 @@ namespace Jackett.Services public void Initalize() { logger.Info("Starting Jackett " + configService.GetVersion()); - try - { - var x = Environment.OSVersion; - var runtimedir = RuntimeEnvironment.GetRuntimeDirectory(); + try + { + var x = Environment.OSVersion; + var runtimedir = RuntimeEnvironment.GetRuntimeDirectory(); logger.Info("Environment version: " + Environment.Version.ToString() + " (" + runtimedir + ")"); - logger.Info("OS version: " + Environment.OSVersion.ToString() + (Environment.Is64BitOperatingSystem ? " (64bit OS)" : "") + (Environment.Is64BitProcess ? " (64bit process)" : "")); - - try - { - int workerThreads; - int completionPortThreads; - ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); - logger.Info("ThreadPool MaxThreads: " + workerThreads + " workerThreads, " + completionPortThreads + " completionPortThreads"); - } - catch (Exception e) - { - logger.Error("Error while getting MaxThreads details: " + e); - } - - try - { - var issuefile = "/etc/issue"; - if (File.Exists(issuefile)) - { - using (StreamReader reader = new StreamReader(issuefile)) - { - string firstLine; - firstLine = reader.ReadLine(); - if (firstLine != null) - logger.Info("issue: " + firstLine); - } - } - } - catch (Exception e) - { - logger.Error(e, "Error while reading the issue file"); + logger.Info("OS version: " + Environment.OSVersion.ToString() + (Environment.Is64BitOperatingSystem ? " (64bit OS)" : "") + (Environment.Is64BitProcess ? " (64bit process)" : "")); + + try + { + int workerThreads; + int completionPortThreads; + ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); + logger.Info("ThreadPool MaxThreads: " + workerThreads + " workerThreads, " + completionPortThreads + " completionPortThreads"); + } + catch (Exception e) + { + logger.Error("Error while getting MaxThreads details: " + e); } - Type monotype = Type.GetType("Mono.Runtime"); - if (monotype != null) - { - MethodInfo displayName = monotype.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); - var monoVersion = "unknown"; - if (displayName != null) - monoVersion = displayName.Invoke(null, null).ToString(); - logger.Info("mono version: " + monoVersion); - - var monoVersionO = new Version(monoVersion.Split(' ')[0]); - - if (monoVersionO.Major < 4) - { - logger.Error("Your mono version is to old (mono 3 is no longer supported). Please update to the latest version from http://www.mono-project.com/download/"); - Environment.Exit(2); - } - else if (monoVersionO.Major == 4 && monoVersionO.Minor == 2) - { - var notice = "mono version 4.2.* is known to cause problems with Jackett. If you experience any problems please try updating to the latest mono version from http://www.mono-project.com/download/ first."; - _notices.Add(notice); - logger.Error(notice); - } - - try - { - // Check for mono-devel - // Is there any better way which doesn't involve a hard cashes? - var mono_devel_file = Path.Combine(runtimedir, "mono-api-info.exe"); - if (!File.Exists(mono_devel_file)) - { - var notice = "It looks like the mono-devel package is not installed, please make sure it's installed to avoid crashes."; - _notices.Add(notice); - logger.Error(notice); - } - } - catch (Exception e) - { - logger.Error(e, "Error while checking for mono-devel"); - } - - try - { - // Check for ca-certificates-mono - var mono_cert_file = Path.Combine(runtimedir, "cert-sync.exe"); - if (!File.Exists(mono_cert_file)) - { - if (monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) - { - var notice = "The ca-certificates-mono package is not installed, HTTPS trackers won't work. Please install it."; - _notices.Add(notice); - logger.Error(notice); - } - else - { - logger.Info("The ca-certificates-mono package is not installed, it will become mandatory once mono >= 4.8 is used."); - } - - } - } - catch (Exception e) - { - logger.Error(e, "Error while checking for ca-certificates-mono"); - } - - try - { - Encoding.GetEncoding("windows-1255"); - } - catch (NotSupportedException e) - { - logger.Debug(e); - logger.Error(e.Message + " Most likely the mono-locale-extras package is not installed."); - Environment.Exit(2); - } - } + try + { + var issuefile = "/etc/issue"; + if (File.Exists(issuefile)) + { + using (StreamReader reader = new StreamReader(issuefile)) + { + string firstLine; + firstLine = reader.ReadLine(); + if (firstLine != null) + logger.Info("issue: " + firstLine); + } + } + } + catch (Exception e) + { + logger.Error(e, "Error while reading the issue file"); + } + + Type monotype = Type.GetType("Mono.Runtime"); + if (monotype != null) + { + MethodInfo displayName = monotype.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + var monoVersion = "unknown"; + if (displayName != null) + monoVersion = displayName.Invoke(null, null).ToString(); + logger.Info("mono version: " + monoVersion); + + var monoVersionO = new Version(monoVersion.Split(' ')[0]); + + if (monoVersionO.Major < 4) + { + logger.Error("Your mono version is to old (mono 3 is no longer supported). Please update to the latest version from http://www.mono-project.com/download/"); + Environment.Exit(2); + } + else if (monoVersionO.Major == 4 && monoVersionO.Minor == 2) + { + var notice = "mono version 4.2.* is known to cause problems with Jackett. If you experience any problems please try updating to the latest mono version from http://www.mono-project.com/download/ first."; + _notices.Add(notice); + logger.Error(notice); + } + + try + { + // Check for mono-devel + // Is there any better way which doesn't involve a hard cashes? + var mono_devel_file = Path.Combine(runtimedir, "mono-api-info.exe"); + if (!File.Exists(mono_devel_file)) + { + var notice = "It looks like the mono-devel package is not installed, please make sure it's installed to avoid crashes."; + _notices.Add(notice); + logger.Error(notice); + } + } + catch (Exception e) + { + logger.Error(e, "Error while checking for mono-devel"); + } + + try + { + // Check for ca-certificates-mono + var mono_cert_file = Path.Combine(runtimedir, "cert-sync.exe"); + if (!File.Exists(mono_cert_file)) + { + if (monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) + { + var notice = "The ca-certificates-mono package is not installed, HTTPS trackers won't work. Please install it."; + _notices.Add(notice); + logger.Error(notice); + } + else + { + logger.Info("The ca-certificates-mono package is not installed, it will become mandatory once mono >= 4.8 is used."); + } + + } + } + catch (Exception e) + { + logger.Error(e, "Error while checking for ca-certificates-mono"); + } + + try + { + Encoding.GetEncoding("windows-1255"); + } + catch (NotSupportedException e) + { + logger.Debug(e); + logger.Error(e.Message + " Most likely the mono-locale-extras package is not installed."); + Environment.Exit(2); + } + } } catch (Exception e) - { - logger.Error("Error while getting environment details: " + e); + { + logger.Error("Error while getting environment details: " + e); } CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); // Load indexers indexerService.InitIndexers(); - foreach(string dir in configService.GetCardigannDefinitionsFolders()) - { - indexerService.InitCardigannIndexers(dir); + foreach(string dir in configService.GetCardigannDefinitionsFolders()) + { + indexerService.InitCardigannIndexers(dir); } indexerService.SortIndexers(); client.Init(); @@ -299,24 +299,24 @@ namespace Jackett.Services var startOptions = new StartOptions(); config.GetListenAddresses().ToList().ForEach(u => startOptions.Urls.Add(u)); Startup.BasePath = BasePath(); - try - { - _server = WebApp.Start<Startup>(startOptions); + try + { + _server = WebApp.Start<Startup>(startOptions); } - catch (TargetInvocationException e) - { - var inner = e.InnerException; - if (inner is SocketException && ((SocketException)inner).SocketErrorCode == SocketError.AddressAlreadyInUse) // Linux (mono) - { - logger.Error("Address already in use: Most likely Jackett is already running."); - Environment.Exit(1); - } - else if (inner is HttpListenerException && ((HttpListenerException)inner).ErrorCode == 183) // Windows - { - logger.Error(inner.Message + " Most likely Jackett is already running."); - Environment.Exit(1); - } - throw e; + catch (TargetInvocationException e) + { + var inner = e.InnerException; + if (inner is SocketException && ((SocketException)inner).SocketErrorCode == SocketError.AddressAlreadyInUse) // Linux (mono) + { + logger.Error("Address already in use: Most likely Jackett is already running."); + Environment.Exit(1); + } + else if (inner is HttpListenerException && ((HttpListenerException)inner).ErrorCode == 183) // Windows + { + logger.Error(inner.Message + " Most likely Jackett is already running."); + Environment.Exit(1); + } + throw e; } logger.Debug("Web server started"); updater.StartUpdateChecker(); diff --git a/src/Jackett/Services/ServiceConfigService.cs b/src/Jackett/Services/ServiceConfigService.cs index e5426919..30497a69 100644 --- a/src/Jackett/Services/ServiceConfigService.cs +++ b/src/Jackett/Services/ServiceConfigService.cs @@ -119,10 +119,10 @@ namespace Jackett.Services public void RemoveService() { var service = GetService(NAME); - if(service == null) - { - logger.Warn("The service is already uninstalled"); - return; + if(service == null) + { + logger.Warn("The service is already uninstalled"); + return; } if (service.Status != ServiceControllerStatus.Stopped) { diff --git a/src/Jackett/Services/UpdateService.cs b/src/Jackett/Services/UpdateService.cs index ac05bbe6..2cde3f72 100644 --- a/src/Jackett/Services/UpdateService.cs +++ b/src/Jackett/Services/UpdateService.cs @@ -1,309 +1,309 @@ -using ICSharpCode.SharpZipLib.GZip; -using ICSharpCode.SharpZipLib.Tar; -using ICSharpCode.SharpZipLib.Zip; -using Jackett.Models.Config; -using Jackett.Models.GitHub; -using Jackett.Utils.Clients; -using Newtonsoft.Json; -using NLog; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net.Security; -using System.Reflection; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Jackett.Services -{ - public interface IUpdateService - { - void StartUpdateChecker(); - void CheckForUpdatesNow(); - void CleanupTempDir(); - } - - public class UpdateService: IUpdateService - { - Logger logger; - IWebClient client; - IConfigurationService configService; - ManualResetEvent locker = new ManualResetEvent(false); - ITrayLockService lockService; - bool forceupdatecheck = false; - - public UpdateService(Logger l, IWebClient c, IConfigurationService cfg, ITrayLockService ls) - { - logger = l; - client = c; - configService = cfg; - lockService = ls; - } - - private string ExePath() - { - var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); - return new FileInfo(location.AbsolutePath).FullName; - } - - public void StartUpdateChecker() - { - Task.Factory.StartNew(UpdateWorkerThread); - } - - public void CheckForUpdatesNow() - { - forceupdatecheck = true; - locker.Set(); - } - - private async void UpdateWorkerThread() - { - while (true) - { - locker.WaitOne((int)new TimeSpan(24, 0, 0).TotalMilliseconds); - locker.Reset(); - await CheckForUpdates(); - } - } - - private bool AcceptCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - return true; - } - - private async Task CheckForUpdates() - { - var config = configService.GetConfig<ServerConfig>(); - if (config.UpdateDisabled && !forceupdatecheck) - { - logger.Info($"Skipping update check as it is disabled."); - return; - } - - forceupdatecheck = true; - - var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix; - if (Debugger.IsAttached) - { - logger.Info($"Skipping checking for new releases as the debugger is attached."); - return; - } - - try - { - - var response = await client.GetString(new WebRequest() - { - Url = "https://api.github.com/repos/Jackett/Jackett/releases", - Encoding = Encoding.UTF8, - EmulateBrowser = false - }); - - if(response.Status != System.Net.HttpStatusCode.OK) - { - logger.Error("Failed to get the release list: " + response.Status); - } - - var releases = JsonConvert.DeserializeObject<List<Release>>(response.Content); - - if (!config.UpdatePrerelease) - { - releases = releases.Where(r => !r.Prerelease).ToList(); - } - - if (releases.Count > 0) - { - var latestRelease = releases.OrderByDescending(o => o.Created_at).First(); - var currentVersion = $"v{GetCurrentVersion()}"; - - if (latestRelease.Name != currentVersion && currentVersion != "v0.0.0.0") - { - logger.Info($"New release found. Current: {currentVersion} New: {latestRelease.Name}"); - try - { - var tempDir = await DownloadRelease(latestRelease.Assets, isWindows, latestRelease.Name); - // Copy updater - var installDir = Path.GetDirectoryName(ExePath()); - var updaterPath = Path.Combine(tempDir, "Jackett", "JackettUpdater.exe"); - if (updaterPath != null) - StartUpdate(updaterPath, installDir, isWindows, Startup.NoRestart); - } - catch (Exception e) - { - logger.Error(e, "Error performing update."); - } - } - else - { - logger.Info($"Checked for a updated release but none was found."); - } - } - } - catch (Exception e) - { - logger.Error(e, "Error checking for updates."); - } - finally - { - if (!isWindows) - { - System.Net.ServicePointManager.ServerCertificateValidationCallback -= AcceptCert; - } - } - } - - private string GetCurrentVersion() - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); - return fvi.FileVersion; - } - - private WebRequest SetDownloadHeaders(WebRequest req) - { - req.Headers = new Dictionary<string, string>() - { - { "Accept", "application/octet-stream" } - }; - - return req; - } - - public void CleanupTempDir() - { - var tempDir = Path.GetTempPath(); - - if (!Directory.Exists(tempDir)) - { - logger.Error("Temp dir doesn't exist: " + tempDir.ToString()); - return; - } - - try { - DirectoryInfo d = new DirectoryInfo(tempDir); - foreach (var dir in d.GetDirectories("JackettUpdate-*")) - { - try { - logger.Info("Deleting JackettUpdate temp files from " + dir.FullName); - dir.Delete(true); - } - catch (Exception e) - { - logger.Error("Error while deleting temp files from " + dir.FullName); - logger.Error(e); - } - } - } - catch (Exception e) - { - logger.Error("Unexpected error while deleting temp files from " + tempDir.ToString()); - logger.Error(e); - } - } - - private async Task<string> DownloadRelease(List<Asset> assets, bool isWindows, string version) - { - var targetAsset = assets.Where(a => isWindows ? a.Browser_download_url.ToLowerInvariant().EndsWith(".zip") : a.Browser_download_url.ToLowerInvariant().EndsWith(".gz")).FirstOrDefault(); - - if (targetAsset == null) - { - logger.Error("Failed to find asset to download!"); - return null; - } - - var url = targetAsset.Browser_download_url; - - var data = await client.GetBytes(SetDownloadHeaders(new WebRequest() { Url = url, EmulateBrowser = true, Type = RequestType.GET })); - - while (data.IsRedirect) - { - data = await client.GetBytes(new WebRequest() { Url = data.RedirectingTo, EmulateBrowser = true, Type = RequestType.GET }); - } - - var tempDir = Path.Combine(Path.GetTempPath(), "JackettUpdate-" + version + "-" + DateTime.Now.Ticks); - - if (Directory.Exists(tempDir)) - { - Directory.Delete(tempDir, true); - } - - Directory.CreateDirectory(tempDir); - - if (isWindows) - { - var zipPath = Path.Combine(tempDir, "Update.zip"); - File.WriteAllBytes(zipPath, data.Content); - var fastZip = new FastZip(); - fastZip.ExtractZip(zipPath, tempDir, null); - } - else - { - var gzPath = Path.Combine(tempDir, "Update.tar.gz"); - File.WriteAllBytes(gzPath, data.Content); - Stream inStream = File.OpenRead(gzPath); - Stream gzipStream = new GZipInputStream(inStream); - - TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream); - tarArchive.ExtractContents(tempDir); - tarArchive.Close(); - gzipStream.Close(); - inStream.Close(); - } - - return tempDir; - } - - private void StartUpdate(string updaterExePath, string installLocation, bool isWindows, bool NoRestart) - { - var exe = Path.GetFileName(ExePath()).ToLowerInvariant(); - var args = string.Join(" ", Environment.GetCommandLineArgs().Skip(1)); - - var startInfo = new ProcessStartInfo(); - - // Note: add a leading space to the --Args argument to avoid parsing as arguments - if (isWindows) - { - startInfo.Arguments = $"--Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; - startInfo.FileName = Path.Combine(updaterExePath); - } - else - { - // Wrap mono - args = exe + " " + args; - exe = "mono"; - - startInfo.Arguments = $"{Path.Combine(updaterExePath)} --Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; - startInfo.FileName = "mono"; - startInfo.UseShellExecute = false; - startInfo.CreateNoWindow = true; - } - - try { - var pid = Process.GetCurrentProcess().Id; - startInfo.Arguments += $" --KillPids \"{pid}\""; - } - catch (Exception e) - { - logger.Error("Unexpected error while retriving the PID"); - logger.Error(e); - } - - if (NoRestart) - startInfo.Arguments += " --NoRestart"; - - var procInfo = Process.Start(startInfo); - logger.Info($"Updater started process id: {procInfo.Id}"); - if (NoRestart == false) - { - logger.Info("Exiting Jackett.."); - lockService.Signal(); - Environment.Exit(0); - } - } - } -} +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; +using ICSharpCode.SharpZipLib.Zip; +using Jackett.Models.Config; +using Jackett.Models.GitHub; +using Jackett.Utils.Clients; +using Newtonsoft.Json; +using NLog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Security; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IUpdateService + { + void StartUpdateChecker(); + void CheckForUpdatesNow(); + void CleanupTempDir(); + } + + public class UpdateService: IUpdateService + { + Logger logger; + IWebClient client; + IConfigurationService configService; + ManualResetEvent locker = new ManualResetEvent(false); + ITrayLockService lockService; + bool forceupdatecheck = false; + + public UpdateService(Logger l, IWebClient c, IConfigurationService cfg, ITrayLockService ls) + { + logger = l; + client = c; + configService = cfg; + lockService = ls; + } + + private string ExePath() + { + var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); + return new FileInfo(location.AbsolutePath).FullName; + } + + public void StartUpdateChecker() + { + Task.Factory.StartNew(UpdateWorkerThread); + } + + public void CheckForUpdatesNow() + { + forceupdatecheck = true; + locker.Set(); + } + + private async void UpdateWorkerThread() + { + while (true) + { + locker.WaitOne((int)new TimeSpan(24, 0, 0).TotalMilliseconds); + locker.Reset(); + await CheckForUpdates(); + } + } + + private bool AcceptCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + + private async Task CheckForUpdates() + { + var config = configService.GetConfig<ServerConfig>(); + if (config.UpdateDisabled && !forceupdatecheck) + { + logger.Info($"Skipping update check as it is disabled."); + return; + } + + forceupdatecheck = true; + + var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix; + if (Debugger.IsAttached) + { + logger.Info($"Skipping checking for new releases as the debugger is attached."); + return; + } + + try + { + + var response = await client.GetString(new WebRequest() + { + Url = "https://api.github.com/repos/Jackett/Jackett/releases", + Encoding = Encoding.UTF8, + EmulateBrowser = false + }); + + if(response.Status != System.Net.HttpStatusCode.OK) + { + logger.Error("Failed to get the release list: " + response.Status); + } + + var releases = JsonConvert.DeserializeObject<List<Release>>(response.Content); + + if (!config.UpdatePrerelease) + { + releases = releases.Where(r => !r.Prerelease).ToList(); + } + + if (releases.Count > 0) + { + var latestRelease = releases.OrderByDescending(o => o.Created_at).First(); + var currentVersion = $"v{GetCurrentVersion()}"; + + if (latestRelease.Name != currentVersion && currentVersion != "v0.0.0.0") + { + logger.Info($"New release found. Current: {currentVersion} New: {latestRelease.Name}"); + try + { + var tempDir = await DownloadRelease(latestRelease.Assets, isWindows, latestRelease.Name); + // Copy updater + var installDir = Path.GetDirectoryName(ExePath()); + var updaterPath = Path.Combine(tempDir, "Jackett", "JackettUpdater.exe"); + if (updaterPath != null) + StartUpdate(updaterPath, installDir, isWindows, Startup.NoRestart); + } + catch (Exception e) + { + logger.Error(e, "Error performing update."); + } + } + else + { + logger.Info($"Checked for a updated release but none was found."); + } + } + } + catch (Exception e) + { + logger.Error(e, "Error checking for updates."); + } + finally + { + if (!isWindows) + { + System.Net.ServicePointManager.ServerCertificateValidationCallback -= AcceptCert; + } + } + } + + private string GetCurrentVersion() + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); + return fvi.FileVersion; + } + + private WebRequest SetDownloadHeaders(WebRequest req) + { + req.Headers = new Dictionary<string, string>() + { + { "Accept", "application/octet-stream" } + }; + + return req; + } + + public void CleanupTempDir() + { + var tempDir = Path.GetTempPath(); + + if (!Directory.Exists(tempDir)) + { + logger.Error("Temp dir doesn't exist: " + tempDir.ToString()); + return; + } + + try { + DirectoryInfo d = new DirectoryInfo(tempDir); + foreach (var dir in d.GetDirectories("JackettUpdate-*")) + { + try { + logger.Info("Deleting JackettUpdate temp files from " + dir.FullName); + dir.Delete(true); + } + catch (Exception e) + { + logger.Error("Error while deleting temp files from " + dir.FullName); + logger.Error(e); + } + } + } + catch (Exception e) + { + logger.Error("Unexpected error while deleting temp files from " + tempDir.ToString()); + logger.Error(e); + } + } + + private async Task<string> DownloadRelease(List<Asset> assets, bool isWindows, string version) + { + var targetAsset = assets.Where(a => isWindows ? a.Browser_download_url.ToLowerInvariant().EndsWith(".zip") : a.Browser_download_url.ToLowerInvariant().EndsWith(".gz")).FirstOrDefault(); + + if (targetAsset == null) + { + logger.Error("Failed to find asset to download!"); + return null; + } + + var url = targetAsset.Browser_download_url; + + var data = await client.GetBytes(SetDownloadHeaders(new WebRequest() { Url = url, EmulateBrowser = true, Type = RequestType.GET })); + + while (data.IsRedirect) + { + data = await client.GetBytes(new WebRequest() { Url = data.RedirectingTo, EmulateBrowser = true, Type = RequestType.GET }); + } + + var tempDir = Path.Combine(Path.GetTempPath(), "JackettUpdate-" + version + "-" + DateTime.Now.Ticks); + + if (Directory.Exists(tempDir)) + { + Directory.Delete(tempDir, true); + } + + Directory.CreateDirectory(tempDir); + + if (isWindows) + { + var zipPath = Path.Combine(tempDir, "Update.zip"); + File.WriteAllBytes(zipPath, data.Content); + var fastZip = new FastZip(); + fastZip.ExtractZip(zipPath, tempDir, null); + } + else + { + var gzPath = Path.Combine(tempDir, "Update.tar.gz"); + File.WriteAllBytes(gzPath, data.Content); + Stream inStream = File.OpenRead(gzPath); + Stream gzipStream = new GZipInputStream(inStream); + + TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream); + tarArchive.ExtractContents(tempDir); + tarArchive.Close(); + gzipStream.Close(); + inStream.Close(); + } + + return tempDir; + } + + private void StartUpdate(string updaterExePath, string installLocation, bool isWindows, bool NoRestart) + { + var exe = Path.GetFileName(ExePath()).ToLowerInvariant(); + var args = string.Join(" ", Environment.GetCommandLineArgs().Skip(1)); + + var startInfo = new ProcessStartInfo(); + + // Note: add a leading space to the --Args argument to avoid parsing as arguments + if (isWindows) + { + startInfo.Arguments = $"--Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; + startInfo.FileName = Path.Combine(updaterExePath); + } + else + { + // Wrap mono + args = exe + " " + args; + exe = "mono"; + + startInfo.Arguments = $"{Path.Combine(updaterExePath)} --Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; + startInfo.FileName = "mono"; + startInfo.UseShellExecute = false; + startInfo.CreateNoWindow = true; + } + + try { + var pid = Process.GetCurrentProcess().Id; + startInfo.Arguments += $" --KillPids \"{pid}\""; + } + catch (Exception e) + { + logger.Error("Unexpected error while retriving the PID"); + logger.Error(e); + } + + if (NoRestart) + startInfo.Arguments += " --NoRestart"; + + var procInfo = Process.Start(startInfo); + logger.Info($"Updater started process id: {procInfo.Id}"); + if (NoRestart == false) + { + logger.Info("Exiting Jackett.."); + lockService.Signal(); + Environment.Exit(0); + } + } + } +} diff --git a/src/Jackett/Startup.cs b/src/Jackett/Startup.cs index c8ba85a1..1a88eeaa 100644 --- a/src/Jackett/Startup.cs +++ b/src/Jackett/Startup.cs @@ -1,189 +1,189 @@ -using Owin; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http; -using Autofac.Integration.WebApi; -using Microsoft.Owin; -using Jackett; -using Microsoft.Owin.StaticFiles; -using Microsoft.Owin.FileSystems; -using Autofac; -using Jackett.Services; -using System.Web.Http.Tracing; -using Jackett.Utils; -using Microsoft.AspNet.Identity; -using System.Web.Http.ExceptionHandling; -using System.Net; - -[assembly: OwinStartup(typeof(Startup))] -namespace Jackett -{ - public class Startup - { - public static bool TracingEnabled - { - get; - set; - } - - public static bool LogRequests - { - get; - set; - } - - public static string ClientOverride - { - get; - set; - } - - public static string ProxyConnection - { - get; - set; - } - - public static bool? DoSSLFix - { - get; - set; - } - - public static bool? IgnoreSslErrors - { - get; - set; - } - - public static string CustomDataFolder - { - get; - set; - } - - public static string BasePath - { - get; - set; - } - - public static bool NoRestart - { - get; - set; - } - - public void Configuration(IAppBuilder appBuilder) - { - // Configure Web API for self-host. - var config = new HttpConfiguration(); - - // try to fix SocketException crashes - // based on http://stackoverflow.com/questions/23368885/signalr-owin-self-host-on-linux-mono-socketexception-when-clients-lose-connectio/30583109#30583109 - try - { - object httpListener; - if (appBuilder.Properties.TryGetValue(typeof(HttpListener).FullName, out httpListener) && httpListener is HttpListener) - { - // HttpListener should not return exceptions that occur when sending the response to the client - ((HttpListener)httpListener).IgnoreWriteExceptions = true; - //Engine.Logger.Info("set HttpListener.IgnoreWriteExceptions = true"); - } - } - catch (Exception e) - { - Engine.Logger.Error(e, "Error while setting HttpListener.IgnoreWriteExceptions = true"); - } - - appBuilder.Use<WebApiRootRedirectMiddleware>(); - - // register exception handler - config.Services.Replace(typeof(IExceptionHandler), new WebAPIExceptionHandler()); - - // Setup tracing if enabled - if (TracingEnabled) - { - config.EnableSystemDiagnosticsTracing(); - config.Services.Replace(typeof(ITraceWriter), new WebAPIToNLogTracer()); - } - // Add request logging if enabled - if (LogRequests) - { - config.MessageHandlers.Add(new WebAPIRequestLogger()); - } - config.DependencyResolver = new AutofacWebApiDependencyResolver(Engine.GetContainer()); - config.MapHttpAttributeRoutes(); - - config.Routes.MapHttpRoute( - name: "Admin", - routeTemplate: "admin/{action}", - defaults: new { controller = "Admin" } - ); - - config.Routes.MapHttpRoute( - name: "apiDefault", - routeTemplate: "api/{indexerID}", - defaults: new { controller = "Torznab", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "api", - routeTemplate: "api/{indexerID}/api", - defaults: new { controller = "Torznab", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "torznabDefault", - routeTemplate: "torznab/{indexerID}", - defaults: new { controller = "Torznab", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "torznab", - routeTemplate: "torznab/{indexerID}/api", - defaults: new { controller = "Torznab", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "potatoDefault", - routeTemplate: "potato/{indexerID}", - defaults: new { controller = "Potato", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "potato", - routeTemplate: "potato/{indexerID}/api", - defaults: new { controller = "Potato", action = "Call" } - ); - - config.Routes.MapHttpRoute( - name: "download", - routeTemplate: "dl/{indexerID}/{apiKey}", - defaults: new { controller = "Download", action = "Download" } - ); - - config.Routes.MapHttpRoute( - name: "blackhole", - routeTemplate: "bh/{indexerID}/{apikey}", - defaults: new { controller = "Blackhole", action = "Blackhole" } - ); - - appBuilder.UseWebApi(config); - - - appBuilder.UseFileServer(new FileServerOptions - { - RequestPath = new PathString(string.Empty), - FileSystem = new PhysicalFileSystem(Engine.ConfigService.GetContentFolder()), - EnableDirectoryBrowsing = false, - - }); - - } - } -} +using Owin; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using Autofac.Integration.WebApi; +using Microsoft.Owin; +using Jackett; +using Microsoft.Owin.StaticFiles; +using Microsoft.Owin.FileSystems; +using Autofac; +using Jackett.Services; +using System.Web.Http.Tracing; +using Jackett.Utils; +using Microsoft.AspNet.Identity; +using System.Web.Http.ExceptionHandling; +using System.Net; + +[assembly: OwinStartup(typeof(Startup))] +namespace Jackett +{ + public class Startup + { + public static bool TracingEnabled + { + get; + set; + } + + public static bool LogRequests + { + get; + set; + } + + public static string ClientOverride + { + get; + set; + } + + public static string ProxyConnection + { + get; + set; + } + + public static bool? DoSSLFix + { + get; + set; + } + + public static bool? IgnoreSslErrors + { + get; + set; + } + + public static string CustomDataFolder + { + get; + set; + } + + public static string BasePath + { + get; + set; + } + + public static bool NoRestart + { + get; + set; + } + + public void Configuration(IAppBuilder appBuilder) + { + // Configure Web API for self-host. + var config = new HttpConfiguration(); + + // try to fix SocketException crashes + // based on http://stackoverflow.com/questions/23368885/signalr-owin-self-host-on-linux-mono-socketexception-when-clients-lose-connectio/30583109#30583109 + try + { + object httpListener; + if (appBuilder.Properties.TryGetValue(typeof(HttpListener).FullName, out httpListener) && httpListener is HttpListener) + { + // HttpListener should not return exceptions that occur when sending the response to the client + ((HttpListener)httpListener).IgnoreWriteExceptions = true; + //Engine.Logger.Info("set HttpListener.IgnoreWriteExceptions = true"); + } + } + catch (Exception e) + { + Engine.Logger.Error(e, "Error while setting HttpListener.IgnoreWriteExceptions = true"); + } + + appBuilder.Use<WebApiRootRedirectMiddleware>(); + + // register exception handler + config.Services.Replace(typeof(IExceptionHandler), new WebAPIExceptionHandler()); + + // Setup tracing if enabled + if (TracingEnabled) + { + config.EnableSystemDiagnosticsTracing(); + config.Services.Replace(typeof(ITraceWriter), new WebAPIToNLogTracer()); + } + // Add request logging if enabled + if (LogRequests) + { + config.MessageHandlers.Add(new WebAPIRequestLogger()); + } + config.DependencyResolver = new AutofacWebApiDependencyResolver(Engine.GetContainer()); + config.MapHttpAttributeRoutes(); + + config.Routes.MapHttpRoute( + name: "Admin", + routeTemplate: "admin/{action}", + defaults: new { controller = "Admin" } + ); + + config.Routes.MapHttpRoute( + name: "apiDefault", + routeTemplate: "api/{indexerID}", + defaults: new { controller = "Torznab", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "api", + routeTemplate: "api/{indexerID}/api", + defaults: new { controller = "Torznab", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "torznabDefault", + routeTemplate: "torznab/{indexerID}", + defaults: new { controller = "Torznab", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "torznab", + routeTemplate: "torznab/{indexerID}/api", + defaults: new { controller = "Torznab", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "potatoDefault", + routeTemplate: "potato/{indexerID}", + defaults: new { controller = "Potato", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "potato", + routeTemplate: "potato/{indexerID}/api", + defaults: new { controller = "Potato", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "download", + routeTemplate: "dl/{indexerID}/{apiKey}", + defaults: new { controller = "Download", action = "Download" } + ); + + config.Routes.MapHttpRoute( + name: "blackhole", + routeTemplate: "bh/{indexerID}/{apikey}", + defaults: new { controller = "Blackhole", action = "Blackhole" } + ); + + appBuilder.UseWebApi(config); + + + appBuilder.UseFileServer(new FileServerOptions + { + RequestPath = new PathString(string.Empty), + FileSystem = new PhysicalFileSystem(Engine.ConfigService.GetContentFolder()), + EnableDirectoryBrowsing = false, + + }); + + } + } +} diff --git a/src/Jackett/Utils/BrowserUtil.cs b/src/Jackett/Utils/BrowserUtil.cs index 9d1fd1e6..8c888517 100644 --- a/src/Jackett/Utils/BrowserUtil.cs +++ b/src/Jackett/Utils/BrowserUtil.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Jackett.Utils @@ -23,36 +23,36 @@ namespace Jackett.Utils } } - // This can be used to decode e-mail addresses protected by cloudflare - public static string DecodeCloudFlareProtectedEmail(string input) - { - var key = Convert.ToInt32(input.Substring(0, 2), 16); - string result = ""; - for (var i = 2; i < input.Length - 1; i += 2) - { - var hexChar = input.Substring(i, 2); - var intChar = Convert.ToInt32(hexChar, 16) ^ key; - var strChar = Convert.ToChar(intChar); - result += strChar; - } - return result; - } - - // decode cloudflare protected emails in a HTML document - public static string DecodeCloudFlareProtectedEmailFromHTML(string html) - { - Regex CFEMailRegex = new Regex("<span class=\"__cf_email__\" data-cfemail=\"(\\w+)\">\\[email protected\\]<\\/span><script data-cfhash='[\\w]+' type=\"text\\/javascript\">.*?<\\/script>", RegexOptions.Compiled); - var CFEMailRegexMatches = CFEMailRegex.Match(html); - - while (CFEMailRegexMatches.Success) - { - string all = CFEMailRegexMatches.Groups[0].Value; - string cfemail = CFEMailRegexMatches.Groups[1].Value; - var decoded = DecodeCloudFlareProtectedEmail(cfemail); - html = html.Replace(all, decoded); - CFEMailRegexMatches = CFEMailRegexMatches.NextMatch(); - } - return html; + // This can be used to decode e-mail addresses protected by cloudflare + public static string DecodeCloudFlareProtectedEmail(string input) + { + var key = Convert.ToInt32(input.Substring(0, 2), 16); + string result = ""; + for (var i = 2; i < input.Length - 1; i += 2) + { + var hexChar = input.Substring(i, 2); + var intChar = Convert.ToInt32(hexChar, 16) ^ key; + var strChar = Convert.ToChar(intChar); + result += strChar; + } + return result; + } + + // decode cloudflare protected emails in a HTML document + public static string DecodeCloudFlareProtectedEmailFromHTML(string html) + { + Regex CFEMailRegex = new Regex("<span class=\"__cf_email__\" data-cfemail=\"(\\w+)\">\\[email protected\\]<\\/span><script data-cfhash='[\\w]+' type=\"text\\/javascript\">.*?<\\/script>", RegexOptions.Compiled); + var CFEMailRegexMatches = CFEMailRegex.Match(html); + + while (CFEMailRegexMatches.Success) + { + string all = CFEMailRegexMatches.Groups[0].Value; + string cfemail = CFEMailRegexMatches.Groups[1].Value; + var decoded = DecodeCloudFlareProtectedEmail(cfemail); + html = html.Replace(all, decoded); + CFEMailRegexMatches = CFEMailRegexMatches.NextMatch(); + } + return html; } } } diff --git a/src/Jackett/Utils/Clients/HttpWebClient.cs b/src/Jackett/Utils/Clients/HttpWebClient.cs index 6d9fa3a5..83a6c5a9 100644 --- a/src/Jackett/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett/Utils/Clients/HttpWebClient.cs @@ -1,247 +1,247 @@ -using AutoMapper; -using CloudFlareUtilities; -using Jackett.Models; -using Jackett.Services; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Jackett.Utils.Clients -{ - public class HttpWebClient : IWebClient - { - static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); - - public HttpWebClient(IProcessService p, Logger l, IConfigurationService c) - : base(p: p, - l: l, - c: c) - { - } - - override public void Init() - { - ServicePointManager.DefaultConnectionLimit = 1000; - - if (Startup.IgnoreSslErrors == true) - { - logger.Info(string.Format("HttpWebClient: Disabling certificate validation")); - ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; - } - - // custom handler for our own internal certificates - ServicePointManager.ServerCertificateValidationCallback += delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - if (sender.GetType() != typeof(HttpWebRequest)) - return sslPolicyErrors == SslPolicyErrors.None; - - var request = (HttpWebRequest)sender; - var hash = certificate.GetCertHashString(); - - ICollection<string> hosts; - - trustedCertificates.TryGetValue(hash, out hosts); - if (hosts != null) - { - if (hosts.Contains(request.Host)) - return true; - } - return sslPolicyErrors == SslPolicyErrors.None; - }; - } - - override protected async Task<WebClientByteResult> Run(WebRequest webRequest) - { - ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; - - var cookies = new CookieContainer(); - if (!string.IsNullOrEmpty(webRequest.Cookies)) - { - var uri = new Uri(webRequest.Url); - var cookieUrl = new Uri(uri.Scheme + "://" + uri.Host); // don't include the path, Scheme is needed for mono compatibility - foreach (var c in webRequest.Cookies.Split(';')) - { - try - { - cookies.SetCookies(cookieUrl, c.Trim()); - } - catch (CookieException ex) - { - logger.Info("(Non-critical) Problem loading cookie {0}, {1}, {2}", uri, c, ex.Message); - } - } - } - var useProxy = false; - WebProxy proxyServer = null; - if (Startup.ProxyConnection != null) - { - proxyServer = new WebProxy(Startup.ProxyConnection, false); - useProxy = true; - } - - using (ClearanceHandler clearanceHandlr = new ClearanceHandler()) - { - using (HttpClientHandler clientHandlr = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. - UseCookies = true, - Proxy = proxyServer, - UseProxy = useProxy, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }) - { - - clearanceHandlr.InnerHandler = clientHandlr; - using (var client = new HttpClient(clearanceHandlr)) - { - if (webRequest.EmulateBrowser) - client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); - else - client.DefaultRequestHeaders.Add("User-Agent", "Jackett/" + configService.GetVersion()); - - HttpResponseMessage response = null; - using (var request = new HttpRequestMessage()) - { - request.Headers.ExpectContinue = false; - request.RequestUri = new Uri(webRequest.Url); - - if (webRequest.Headers != null) - { - foreach (var header in webRequest.Headers) - { - if (header.Key != "Content-Type") - { - request.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - } - } - - if (!string.IsNullOrEmpty(webRequest.Referer)) - request.Headers.Referrer = new Uri(webRequest.Referer); - - if (!string.IsNullOrEmpty(webRequest.RawBody)) - { - var type = webRequest.Headers.Where(h => h.Key == "Content-Type").Cast<KeyValuePair<string, string>?>().FirstOrDefault(); - if (type.HasValue) - { - var str = new StringContent(webRequest.RawBody); - str.Headers.Remove("Content-Type"); - str.Headers.Add("Content-Type", type.Value.Value); - request.Content = str; - } - else - request.Content = new StringContent(webRequest.RawBody); - request.Method = HttpMethod.Post; - } - else if (webRequest.Type == RequestType.POST) - { - if (webRequest.PostData != null) - request.Content = new FormUrlEncodedContent(webRequest.PostData); - request.Method = HttpMethod.Post; - } - else - { - request.Method = HttpMethod.Get; - } - - using (response = await client.SendAsync(request)) - { - var result = new WebClientByteResult(); - result.Content = await response.Content.ReadAsByteArrayAsync(); - - foreach (var header in response.Headers) - { - IEnumerable<string> value = header.Value; - result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); - } - - // some cloudflare clients are using a refresh header - // Pull it out manually - if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable && response.Headers.Contains("Refresh")) - { - var refreshHeaders = response.Headers.GetValues("Refresh"); - var redirval = ""; - var redirtime = 0; - if (refreshHeaders != null) - { - foreach (var value in refreshHeaders) - { - var start = value.IndexOf("="); - var end = value.IndexOf(";"); - var len = value.Length; - if (start > -1) - { - redirval = value.Substring(start + 1); - result.RedirectingTo = redirval; - // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature - // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally - // it shoudln't include service unavailable..only if we have this redirect header. - response.StatusCode = System.Net.HttpStatusCode.Redirect; - redirtime = Int32.Parse(value.Substring(0, end)); - System.Threading.Thread.Sleep(redirtime * 1000); - } - } - } - } - if (response.Headers.Location != null) - { - result.RedirectingTo = response.Headers.Location.ToString(); - } - result.Status = response.StatusCode; - - // Compatiblity issue between the cookie format and httpclient - // Pull it out manually ignoring the expiry date then set it manually - // http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer - IEnumerable<string> cookieHeaders; - var responseCookies = new List<Tuple<string, string>>(); - - if (response.Headers.TryGetValues("set-cookie", out cookieHeaders)) - { - foreach (var value in cookieHeaders) - { - var nameSplit = value.IndexOf('='); - if (nameSplit > -1) - { - responseCookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') == -1 ? value.Length : (value.IndexOf(';'))) + ";")); - } - } - - var cookieBuilder = new StringBuilder(); - foreach (var cookieGroup in responseCookies.GroupBy(c => c.Item1)) - { - cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2); - } - result.Cookies = cookieBuilder.ToString().Trim(); - } - ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); - return result; - } - } - } - } - } - } - - override public void AddTrustedCertificate(string host, string hash) - { - hash = hash.ToUpper(); - ICollection<string> hosts; - trustedCertificates.TryGetValue(hash.ToUpper(), out hosts); - if (hosts == null) - { - hosts = new HashSet<string>(); - trustedCertificates[hash] = hosts; - } - hosts.Add(host); - } - } -} +using AutoMapper; +using CloudFlareUtilities; +using Jackett.Models; +using Jackett.Services; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Jackett.Utils.Clients +{ + public class HttpWebClient : IWebClient + { + static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); + + public HttpWebClient(IProcessService p, Logger l, IConfigurationService c) + : base(p: p, + l: l, + c: c) + { + } + + override public void Init() + { + ServicePointManager.DefaultConnectionLimit = 1000; + + if (Startup.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } + + // custom handler for our own internal certificates + ServicePointManager.ServerCertificateValidationCallback += delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + if (sender.GetType() != typeof(HttpWebRequest)) + return sslPolicyErrors == SslPolicyErrors.None; + + var request = (HttpWebRequest)sender; + var hash = certificate.GetCertHashString(); + + ICollection<string> hosts; + + trustedCertificates.TryGetValue(hash, out hosts); + if (hosts != null) + { + if (hosts.Contains(request.Host)) + return true; + } + return sslPolicyErrors == SslPolicyErrors.None; + }; + } + + override protected async Task<WebClientByteResult> Run(WebRequest webRequest) + { + ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; + + var cookies = new CookieContainer(); + if (!string.IsNullOrEmpty(webRequest.Cookies)) + { + var uri = new Uri(webRequest.Url); + var cookieUrl = new Uri(uri.Scheme + "://" + uri.Host); // don't include the path, Scheme is needed for mono compatibility + foreach (var c in webRequest.Cookies.Split(';')) + { + try + { + cookies.SetCookies(cookieUrl, c.Trim()); + } + catch (CookieException ex) + { + logger.Info("(Non-critical) Problem loading cookie {0}, {1}, {2}", uri, c, ex.Message); + } + } + } + var useProxy = false; + WebProxy proxyServer = null; + if (Startup.ProxyConnection != null) + { + proxyServer = new WebProxy(Startup.ProxyConnection, false); + useProxy = true; + } + + using (ClearanceHandler clearanceHandlr = new ClearanceHandler()) + { + using (HttpClientHandler clientHandlr = new HttpClientHandler + { + CookieContainer = cookies, + AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. + UseCookies = true, + Proxy = proxyServer, + UseProxy = useProxy, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }) + { + + clearanceHandlr.InnerHandler = clientHandlr; + using (var client = new HttpClient(clearanceHandlr)) + { + if (webRequest.EmulateBrowser) + client.DefaultRequestHeaders.Add("User-Agent", BrowserUtil.ChromeUserAgent); + else + client.DefaultRequestHeaders.Add("User-Agent", "Jackett/" + configService.GetVersion()); + + HttpResponseMessage response = null; + using (var request = new HttpRequestMessage()) + { + request.Headers.ExpectContinue = false; + request.RequestUri = new Uri(webRequest.Url); + + if (webRequest.Headers != null) + { + foreach (var header in webRequest.Headers) + { + if (header.Key != "Content-Type") + { + request.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + } + } + + if (!string.IsNullOrEmpty(webRequest.Referer)) + request.Headers.Referrer = new Uri(webRequest.Referer); + + if (!string.IsNullOrEmpty(webRequest.RawBody)) + { + var type = webRequest.Headers.Where(h => h.Key == "Content-Type").Cast<KeyValuePair<string, string>?>().FirstOrDefault(); + if (type.HasValue) + { + var str = new StringContent(webRequest.RawBody); + str.Headers.Remove("Content-Type"); + str.Headers.Add("Content-Type", type.Value.Value); + request.Content = str; + } + else + request.Content = new StringContent(webRequest.RawBody); + request.Method = HttpMethod.Post; + } + else if (webRequest.Type == RequestType.POST) + { + if (webRequest.PostData != null) + request.Content = new FormUrlEncodedContent(webRequest.PostData); + request.Method = HttpMethod.Post; + } + else + { + request.Method = HttpMethod.Get; + } + + using (response = await client.SendAsync(request)) + { + var result = new WebClientByteResult(); + result.Content = await response.Content.ReadAsByteArrayAsync(); + + foreach (var header in response.Headers) + { + IEnumerable<string> value = header.Value; + result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); + } + + // some cloudflare clients are using a refresh header + // Pull it out manually + if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable && response.Headers.Contains("Refresh")) + { + var refreshHeaders = response.Headers.GetValues("Refresh"); + var redirval = ""; + var redirtime = 0; + if (refreshHeaders != null) + { + foreach (var value in refreshHeaders) + { + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + response.StatusCode = System.Net.HttpStatusCode.Redirect; + redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); + } + } + } + } + if (response.Headers.Location != null) + { + result.RedirectingTo = response.Headers.Location.ToString(); + } + result.Status = response.StatusCode; + + // Compatiblity issue between the cookie format and httpclient + // Pull it out manually ignoring the expiry date then set it manually + // http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer + IEnumerable<string> cookieHeaders; + var responseCookies = new List<Tuple<string, string>>(); + + if (response.Headers.TryGetValues("set-cookie", out cookieHeaders)) + { + foreach (var value in cookieHeaders) + { + var nameSplit = value.IndexOf('='); + if (nameSplit > -1) + { + responseCookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') == -1 ? value.Length : (value.IndexOf(';'))) + ";")); + } + } + + var cookieBuilder = new StringBuilder(); + foreach (var cookieGroup in responseCookies.GroupBy(c => c.Item1)) + { + cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2); + } + result.Cookies = cookieBuilder.ToString().Trim(); + } + ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); + return result; + } + } + } + } + } + } + + override public void AddTrustedCertificate(string host, string hash) + { + hash = hash.ToUpper(); + ICollection<string> hosts; + trustedCertificates.TryGetValue(hash.ToUpper(), out hosts); + if (hosts == null) + { + hosts = new HashSet<string>(); + trustedCertificates[hash] = hosts; + } + hosts.Add(host); + } + } +} diff --git a/src/Jackett/Utils/Clients/HttpWebClient2.cs b/src/Jackett/Utils/Clients/HttpWebClient2.cs index 6102551d..1c978bd6 100644 --- a/src/Jackett/Utils/Clients/HttpWebClient2.cs +++ b/src/Jackett/Utils/Clients/HttpWebClient2.cs @@ -1,241 +1,241 @@ -using AutoMapper; -using CloudFlareUtilities; -using Jackett.Models; -using Jackett.Services; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Jackett.Utils.Clients -{ - // Compared to HttpWebClient this implementation will reuse the HttpClient instance (one per indexer). - // This should improve performance and avoid problems with too man open file handles. - public class HttpWebClient2 : IWebClient - { - CookieContainer cookies; - ClearanceHandler clearanceHandlr; - HttpClientHandler clientHandlr; - HttpClient client; - - static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); - - public HttpWebClient2(IProcessService p, Logger l, IConfigurationService c) - : base(p: p, - l: l, - c: c) - { - cookies = new CookieContainer(); - var useProxy = false; - WebProxy proxyServer = null; - if (Startup.ProxyConnection != null) - { - proxyServer = new WebProxy(Startup.ProxyConnection, false); - useProxy = true; - } - - clearanceHandlr = new ClearanceHandler(); - clientHandlr = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. - UseCookies = true, - Proxy = proxyServer, - UseProxy = useProxy, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }; - - clearanceHandlr.InnerHandler = clientHandlr; - client = new HttpClient(clearanceHandlr); - } - - override public void Init() - { - if (Startup.IgnoreSslErrors == true) - { - logger.Info(string.Format("HttpWebClient2: Disabling certificate validation")); - ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; - } - - ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; - - // custom handler for our own internal certificates - ServicePointManager.ServerCertificateValidationCallback += delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - if (sender.GetType() != typeof(HttpWebRequest)) - return sslPolicyErrors == SslPolicyErrors.None; - - var request = (HttpWebRequest)sender; - var hash = certificate.GetCertHashString(); - - ICollection<string> hosts; - - trustedCertificates.TryGetValue(hash, out hosts); - if (hosts != null) - { - if (hosts.Contains(request.Host)) - return true; - } - return sslPolicyErrors == SslPolicyErrors.None; - }; - } - - override protected async Task<WebClientByteResult> Run(WebRequest webRequest) - { - HttpResponseMessage response = null; - var request = new HttpRequestMessage(); - request.Headers.ExpectContinue = false; - request.RequestUri = new Uri(webRequest.Url); - - if (webRequest.EmulateBrowser) - request.Headers.UserAgent.ParseAdd(BrowserUtil.ChromeUserAgent); - else - request.Headers.UserAgent.ParseAdd("Jackett/" + configService.GetVersion()); - - // clear cookies from cookiecontainer - var oldCookies = cookies.GetCookies(request.RequestUri); - foreach (Cookie oldCookie in oldCookies) - { - oldCookie.Expired = true; - } - - if (!string.IsNullOrEmpty(webRequest.Cookies)) - { - // add cookies to cookiecontainer - var cookieUrl = new Uri(request.RequestUri.Scheme + "://" + request.RequestUri.Host); // don't include the path, Scheme is needed for mono compatibility - foreach (var ccookiestr in webRequest.Cookies.Split(';')) - { - var cookiestrparts = ccookiestr.Split('='); - var name = cookiestrparts[0].Trim(); - if (string.IsNullOrWhiteSpace(name)) - continue; - var value = ""; - if (cookiestrparts.Length >= 2) - value = cookiestrparts[1].Trim(); - var cookie = new Cookie(name, value); - cookies.Add(cookieUrl, cookie); - } - } - - if (webRequest.Headers != null) - { - foreach (var header in webRequest.Headers) - { - if (header.Key != "Content-Type") - { - request.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - } - } - - if (!string.IsNullOrEmpty(webRequest.Referer)) - request.Headers.Referrer = new Uri(webRequest.Referer); - - if (!string.IsNullOrEmpty(webRequest.RawBody)) - { - var type = webRequest.Headers.Where(h => h.Key == "Content-Type").Cast<KeyValuePair<string,string>?>().FirstOrDefault(); - if (type.HasValue) - { - var str = new StringContent(webRequest.RawBody); - str.Headers.Remove("Content-Type"); - str.Headers.Add("Content-Type", type.Value.Value); - request.Content = str; - } - else - request.Content = new StringContent(webRequest.RawBody); - request.Method = HttpMethod.Post; - } - else if (webRequest.Type == RequestType.POST) - { - if (webRequest.PostData != null) - request.Content = new FormUrlEncodedContent(webRequest.PostData); - request.Method = HttpMethod.Post; - } - else - { - request.Method = HttpMethod.Get; - } - - response = await client.SendAsync(request); - - var result = new WebClientByteResult(); - result.Content = await response.Content.ReadAsByteArrayAsync(); - - foreach (var header in response.Headers) - { - IEnumerable<string> value = header.Value; - result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); - } - - // some cloudflare clients are using a refresh header - // Pull it out manually - if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable && response.Headers.Contains("Refresh")) - { - var refreshHeaders = response.Headers.GetValues("Refresh"); - var redirval = ""; - var redirtime = 0; - if (refreshHeaders != null) - { - foreach (var value in refreshHeaders) - { - var start = value.IndexOf("="); - var end = value.IndexOf(";"); - var len = value.Length; - if (start > -1) - { - redirval = value.Substring(start + 1); - result.RedirectingTo = redirval; - // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature - // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally - // it shoudln't include service unavailable..only if we have this redirect header. - response.StatusCode = System.Net.HttpStatusCode.Redirect; - redirtime = Int32.Parse(value.Substring(0, end)); - System.Threading.Thread.Sleep(redirtime * 1000); - } - } - } - } - if (response.Headers.Location != null) - { - result.RedirectingTo = response.Headers.Location.ToString(); - } - result.Status = response.StatusCode; - - // Compatiblity issue between the cookie format and httpclient - // Pull it out manually ignoring the expiry date then set it manually - // http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer - IEnumerable<string> cookieHeaders; - var responseCookies = new List<Tuple<string, string>>(); - - if (response.Headers.TryGetValues("set-cookie", out cookieHeaders)) - { - foreach (var value in cookieHeaders) - { - logger.Debug(value); - var nameSplit = value.IndexOf('='); - if (nameSplit > -1) - { - responseCookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') == -1 ? value.Length : (value.IndexOf(';')))+";")); - } - } - - var cookieBuilder = new StringBuilder(); - foreach (var cookieGroup in responseCookies.GroupBy(c => c.Item1)) - { - cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2); - } - result.Cookies = cookieBuilder.ToString().Trim(); - } - ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); - return result; - } - } -} +using AutoMapper; +using CloudFlareUtilities; +using Jackett.Models; +using Jackett.Services; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Jackett.Utils.Clients +{ + // Compared to HttpWebClient this implementation will reuse the HttpClient instance (one per indexer). + // This should improve performance and avoid problems with too man open file handles. + public class HttpWebClient2 : IWebClient + { + CookieContainer cookies; + ClearanceHandler clearanceHandlr; + HttpClientHandler clientHandlr; + HttpClient client; + + static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); + + public HttpWebClient2(IProcessService p, Logger l, IConfigurationService c) + : base(p: p, + l: l, + c: c) + { + cookies = new CookieContainer(); + var useProxy = false; + WebProxy proxyServer = null; + if (Startup.ProxyConnection != null) + { + proxyServer = new WebProxy(Startup.ProxyConnection, false); + useProxy = true; + } + + clearanceHandlr = new ClearanceHandler(); + clientHandlr = new HttpClientHandler + { + CookieContainer = cookies, + AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. + UseCookies = true, + Proxy = proxyServer, + UseProxy = useProxy, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }; + + clearanceHandlr.InnerHandler = clientHandlr; + client = new HttpClient(clearanceHandlr); + } + + override public void Init() + { + if (Startup.IgnoreSslErrors == true) + { + logger.Info(string.Format("HttpWebClient2: Disabling certificate validation")); + ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; }; + } + + ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; + + // custom handler for our own internal certificates + ServicePointManager.ServerCertificateValidationCallback += delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + if (sender.GetType() != typeof(HttpWebRequest)) + return sslPolicyErrors == SslPolicyErrors.None; + + var request = (HttpWebRequest)sender; + var hash = certificate.GetCertHashString(); + + ICollection<string> hosts; + + trustedCertificates.TryGetValue(hash, out hosts); + if (hosts != null) + { + if (hosts.Contains(request.Host)) + return true; + } + return sslPolicyErrors == SslPolicyErrors.None; + }; + } + + override protected async Task<WebClientByteResult> Run(WebRequest webRequest) + { + HttpResponseMessage response = null; + var request = new HttpRequestMessage(); + request.Headers.ExpectContinue = false; + request.RequestUri = new Uri(webRequest.Url); + + if (webRequest.EmulateBrowser) + request.Headers.UserAgent.ParseAdd(BrowserUtil.ChromeUserAgent); + else + request.Headers.UserAgent.ParseAdd("Jackett/" + configService.GetVersion()); + + // clear cookies from cookiecontainer + var oldCookies = cookies.GetCookies(request.RequestUri); + foreach (Cookie oldCookie in oldCookies) + { + oldCookie.Expired = true; + } + + if (!string.IsNullOrEmpty(webRequest.Cookies)) + { + // add cookies to cookiecontainer + var cookieUrl = new Uri(request.RequestUri.Scheme + "://" + request.RequestUri.Host); // don't include the path, Scheme is needed for mono compatibility + foreach (var ccookiestr in webRequest.Cookies.Split(';')) + { + var cookiestrparts = ccookiestr.Split('='); + var name = cookiestrparts[0].Trim(); + if (string.IsNullOrWhiteSpace(name)) + continue; + var value = ""; + if (cookiestrparts.Length >= 2) + value = cookiestrparts[1].Trim(); + var cookie = new Cookie(name, value); + cookies.Add(cookieUrl, cookie); + } + } + + if (webRequest.Headers != null) + { + foreach (var header in webRequest.Headers) + { + if (header.Key != "Content-Type") + { + request.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + } + } + + if (!string.IsNullOrEmpty(webRequest.Referer)) + request.Headers.Referrer = new Uri(webRequest.Referer); + + if (!string.IsNullOrEmpty(webRequest.RawBody)) + { + var type = webRequest.Headers.Where(h => h.Key == "Content-Type").Cast<KeyValuePair<string,string>?>().FirstOrDefault(); + if (type.HasValue) + { + var str = new StringContent(webRequest.RawBody); + str.Headers.Remove("Content-Type"); + str.Headers.Add("Content-Type", type.Value.Value); + request.Content = str; + } + else + request.Content = new StringContent(webRequest.RawBody); + request.Method = HttpMethod.Post; + } + else if (webRequest.Type == RequestType.POST) + { + if (webRequest.PostData != null) + request.Content = new FormUrlEncodedContent(webRequest.PostData); + request.Method = HttpMethod.Post; + } + else + { + request.Method = HttpMethod.Get; + } + + response = await client.SendAsync(request); + + var result = new WebClientByteResult(); + result.Content = await response.Content.ReadAsByteArrayAsync(); + + foreach (var header in response.Headers) + { + IEnumerable<string> value = header.Value; + result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); + } + + // some cloudflare clients are using a refresh header + // Pull it out manually + if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable && response.Headers.Contains("Refresh")) + { + var refreshHeaders = response.Headers.GetValues("Refresh"); + var redirval = ""; + var redirtime = 0; + if (refreshHeaders != null) + { + foreach (var value in refreshHeaders) + { + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + response.StatusCode = System.Net.HttpStatusCode.Redirect; + redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); + } + } + } + } + if (response.Headers.Location != null) + { + result.RedirectingTo = response.Headers.Location.ToString(); + } + result.Status = response.StatusCode; + + // Compatiblity issue between the cookie format and httpclient + // Pull it out manually ignoring the expiry date then set it manually + // http://stackoverflow.com/questions/14681144/httpclient-not-storing-cookies-in-cookiecontainer + IEnumerable<string> cookieHeaders; + var responseCookies = new List<Tuple<string, string>>(); + + if (response.Headers.TryGetValues("set-cookie", out cookieHeaders)) + { + foreach (var value in cookieHeaders) + { + logger.Debug(value); + var nameSplit = value.IndexOf('='); + if (nameSplit > -1) + { + responseCookies.Add(new Tuple<string, string>(value.Substring(0, nameSplit), value.Substring(0, value.IndexOf(';') == -1 ? value.Length : (value.IndexOf(';')))+";")); + } + } + + var cookieBuilder = new StringBuilder(); + foreach (var cookieGroup in responseCookies.GroupBy(c => c.Item1)) + { + cookieBuilder.AppendFormat("{0} ", cookieGroup.Last().Item2); + } + result.Cookies = cookieBuilder.ToString().Trim(); + } + ServerUtil.ResureRedirectIsFullyQualified(webRequest, result); + return result; + } + } +} diff --git a/src/Jackett/Utils/Clients/IWebClient.cs b/src/Jackett/Utils/Clients/IWebClient.cs index c452bb4a..61b280de 100644 --- a/src/Jackett/Utils/Clients/IWebClient.cs +++ b/src/Jackett/Utils/Clients/IWebClient.cs @@ -1,150 +1,150 @@ -using AutoMapper; +using AutoMapper; using Jackett.Models; -using Jackett.Services; -using NLog; +using Jackett.Services; +using NLog; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Jackett.Utils.Clients { public abstract class IWebClient { - protected Logger logger; + protected Logger logger; protected IConfigurationService configService; protected IProcessService processService; protected DateTime lastRequest = DateTime.MinValue; protected TimeSpan requestDelayTimeSpan; - public double requestDelay - { - get { return requestDelayTimeSpan.TotalSeconds; } - set - { - requestDelayTimeSpan = TimeSpan.FromSeconds(value); - } + public double requestDelay + { + get { return requestDelayTimeSpan.TotalSeconds; } + set + { + requestDelayTimeSpan = TimeSpan.FromSeconds(value); + } } - virtual public void AddTrustedCertificate(string host, string hash) - { - // not implemented by default + virtual public void AddTrustedCertificate(string host, string hash) + { + // not implemented by default } - public IWebClient(IProcessService p, Logger l, IConfigurationService c) - { - processService = p; - logger = l; - configService = c; + public IWebClient(IProcessService p, Logger l, IConfigurationService c) + { + processService = p; + logger = l; + configService = c; } - async protected void DelayRequest(WebRequest request) - { - if (requestDelay != 0) - { - var timeElapsed = DateTime.Now - lastRequest; - if (timeElapsed < requestDelayTimeSpan) - { - var delay = requestDelayTimeSpan - timeElapsed; - logger.Debug(string.Format("IWebClient: delaying request for {0} by {1} seconds", request.Url, delay.TotalSeconds.ToString())); - await Task.Delay(delay); - } - lastRequest = DateTime.Now; - } + async protected void DelayRequest(WebRequest request) + { + if (requestDelay != 0) + { + var timeElapsed = DateTime.Now - lastRequest; + if (timeElapsed < requestDelayTimeSpan) + { + var delay = requestDelayTimeSpan - timeElapsed; + logger.Debug(string.Format("IWebClient: delaying request for {0} by {1} seconds", request.Url, delay.TotalSeconds.ToString())); + await Task.Delay(delay); + } + lastRequest = DateTime.Now; + } } - virtual protected void PrepareRequest(WebRequest request) - { - // add accept header if not set - if (request.Headers == null) - request.Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); - var hasAccept = false; - foreach (var header in request.Headers) - { - var key = header.Key.ToLower(); - if (key == "accept") - { - hasAccept = true; - } - } - if (!hasAccept) - request.Headers.Add("Accept", "*/*"); - return; + virtual protected void PrepareRequest(WebRequest request) + { + // add accept header if not set + if (request.Headers == null) + request.Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); + var hasAccept = false; + foreach (var header in request.Headers) + { + var key = header.Key.ToLower(); + if (key == "accept") + { + hasAccept = true; + } + } + if (!hasAccept) + request.Headers.Add("Accept", "*/*"); + return; } - virtual public async Task<WebClientByteResult> GetBytes(WebRequest request) - { - logger.Debug(string.Format("IWebClient.GetBytes(Url:{0})", request.Url)); - PrepareRequest(request); - DelayRequest(request); - var result = await Run(request); - result.Request = request; - logger.Debug(string.Format("IWebClient: Returning {0} => {1} bytes", result.Status, (result.IsRedirect ? result.RedirectingTo + " " : "") + (result.Content == null ? "<NULL>" : result.Content.Length.ToString()))); - return result; - } - - virtual public async Task<WebClientStringResult> GetString(WebRequest request) - { - logger.Debug(string.Format("IWebClient.GetString(Url:{0})", request.Url)); - PrepareRequest(request); - DelayRequest(request); - var result = await Run(request); - result.Request = request; - WebClientStringResult stringResult = Mapper.Map<WebClientStringResult>(result); - Encoding encoding = null; - if (request.Encoding != null) - { - encoding = request.Encoding; - } - else if (result.Headers.ContainsKey("content-type")) - { - Regex CharsetRegex = new Regex(@"charset=([\w-]+)", RegexOptions.Compiled); - var CharsetRegexMatch = CharsetRegex.Match(result.Headers["content-type"][0]); - if (CharsetRegexMatch.Success) - { - var charset = CharsetRegexMatch.Groups[1].Value; - try - { - encoding = Encoding.GetEncoding(charset); - } - catch (Exception ex) - { - logger.Error(string.Format("IWebClient.GetString(Url:{0}): Error loading encoding {0} based on header {1}: {2}", request.Url, charset, result.Headers["content-type"][0], ex)); - } - } - else - { - logger.Error(string.Format("IWebClient.GetString(Url:{0}): Got header without charset: {0}", request.Url, result.Headers["content-type"][0])); - } - } - - if (encoding == null) - { - logger.Error(string.Format("IWebClient.GetString(Url:{0}): No encoding detected, defaulting to UTF-8", request.Url)); - encoding = Encoding.UTF8; - } - - string decodedContent = null; - if (result.Content != null) - decodedContent = encoding.GetString(result.Content); - - stringResult.Content = decodedContent; - logger.Debug(string.Format("IWebClient: Returning {0} => {1}", result.Status, (result.IsRedirect ? result.RedirectingTo + " " : "") + (decodedContent == null ? "<NULL>" : decodedContent))); - - string[] server; - if (stringResult.Headers.TryGetValue("server", out server)) - { - if (server[0] == "cloudflare-nginx") - stringResult.Content = BrowserUtil.DecodeCloudFlareProtectedEmailFromHTML(stringResult.Content); - } - return stringResult; - } - -#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - virtual protected async Task<WebClientByteResult> Run(WebRequest webRequest) { throw new NotImplementedException(); } -#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - + virtual public async Task<WebClientByteResult> GetBytes(WebRequest request) + { + logger.Debug(string.Format("IWebClient.GetBytes(Url:{0})", request.Url)); + PrepareRequest(request); + DelayRequest(request); + var result = await Run(request); + result.Request = request; + logger.Debug(string.Format("IWebClient: Returning {0} => {1} bytes", result.Status, (result.IsRedirect ? result.RedirectingTo + " " : "") + (result.Content == null ? "<NULL>" : result.Content.Length.ToString()))); + return result; + } + + virtual public async Task<WebClientStringResult> GetString(WebRequest request) + { + logger.Debug(string.Format("IWebClient.GetString(Url:{0})", request.Url)); + PrepareRequest(request); + DelayRequest(request); + var result = await Run(request); + result.Request = request; + WebClientStringResult stringResult = Mapper.Map<WebClientStringResult>(result); + Encoding encoding = null; + if (request.Encoding != null) + { + encoding = request.Encoding; + } + else if (result.Headers.ContainsKey("content-type")) + { + Regex CharsetRegex = new Regex(@"charset=([\w-]+)", RegexOptions.Compiled); + var CharsetRegexMatch = CharsetRegex.Match(result.Headers["content-type"][0]); + if (CharsetRegexMatch.Success) + { + var charset = CharsetRegexMatch.Groups[1].Value; + try + { + encoding = Encoding.GetEncoding(charset); + } + catch (Exception ex) + { + logger.Error(string.Format("IWebClient.GetString(Url:{0}): Error loading encoding {0} based on header {1}: {2}", request.Url, charset, result.Headers["content-type"][0], ex)); + } + } + else + { + logger.Error(string.Format("IWebClient.GetString(Url:{0}): Got header without charset: {0}", request.Url, result.Headers["content-type"][0])); + } + } + + if (encoding == null) + { + logger.Error(string.Format("IWebClient.GetString(Url:{0}): No encoding detected, defaulting to UTF-8", request.Url)); + encoding = Encoding.UTF8; + } + + string decodedContent = null; + if (result.Content != null) + decodedContent = encoding.GetString(result.Content); + + stringResult.Content = decodedContent; + logger.Debug(string.Format("IWebClient: Returning {0} => {1}", result.Status, (result.IsRedirect ? result.RedirectingTo + " " : "") + (decodedContent == null ? "<NULL>" : decodedContent))); + + string[] server; + if (stringResult.Headers.TryGetValue("server", out server)) + { + if (server[0] == "cloudflare-nginx") + stringResult.Content = BrowserUtil.DecodeCloudFlareProtectedEmailFromHTML(stringResult.Content); + } + return stringResult; + } + +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + virtual protected async Task<WebClientByteResult> Run(WebRequest webRequest) { throw new NotImplementedException(); } +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously + abstract public void Init(); } } diff --git a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs index c86f5570..ceb20043 100644 --- a/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixLibCurlWebClient.cs @@ -11,34 +11,34 @@ using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using CloudFlareUtilities; - +using CloudFlareUtilities; + namespace Jackett.Utils.Clients { public class UnixLibCurlWebClient : IWebClient { - public UnixLibCurlWebClient(IProcessService p, Logger l, IConfigurationService c) + public UnixLibCurlWebClient(IProcessService p, Logger l, IConfigurationService c) : base(p: p, l: l, - c: c) + c: c) { } - private string CloudFlareChallengeSolverSolve(string challengePageContent, Uri uri) - { - var solution = ChallengeSolver.Solve(challengePageContent, uri.Host); - string clearanceUri = uri.Scheme + Uri.SchemeDelimiter + uri.Host + ":" + uri.Port + solution.ClearanceQuery; - return clearanceUri; - } - + private string CloudFlareChallengeSolverSolve(string challengePageContent, Uri uri) + { + var solution = ChallengeSolver.Solve(challengePageContent, uri.Host); + string clearanceUri = uri.Scheme + Uri.SchemeDelimiter + uri.Host + ":" + uri.Port + solution.ClearanceQuery; + return clearanceUri; + } + override public void Init() { try { Engine.Logger.Info("LibCurl init " + Curl.GlobalInit(CurlInitFlag.All).ToString()); - CurlHelper.OnErrorMessage += (msg) => - { - Engine.Logger.Error(msg); + CurlHelper.OnErrorMessage += (msg) => + { + Engine.Logger.Error(msg); }; } catch (Exception e) @@ -61,38 +61,38 @@ namespace Jackett.Utils.Clients // Wrapper for Run which takes care of CloudFlare challenges, calls RunCurl override protected async Task<WebClientByteResult> Run(WebRequest request) - { - WebClientByteResult result = await RunCurl(request); - - // check if we've received a CloudFlare challenge - string[] server; - if (result.Status == HttpStatusCode.ServiceUnavailable && result.Headers.TryGetValue("server", out server) && server[0] == "cloudflare-nginx") - { - logger.Info("UnixLibCurlWebClient: Received a new CloudFlare challenge"); - - // solve the challenge - string pageContent = Encoding.UTF8.GetString(result.Content); - Uri uri = new Uri(request.Url); - string clearanceUri = CloudFlareChallengeSolverSolve(pageContent, uri); - logger.Info(string.Format("UnixLibCurlWebClient: CloudFlare clearanceUri: {0}", clearanceUri)); - - // wait... - await Task.Delay(5000); - - // request clearanceUri to get cf_clearance cookie - var response = await CurlHelper.GetAsync(clearanceUri, request.Cookies, request.Referer); - logger.Info(string.Format("UnixLibCurlWebClient: received CloudFlare clearance cookie: {0}", response.Cookies)); - - // add new cf_clearance cookies to the original request - request.Cookies = response.Cookies + request.Cookies; - - // re-run the original request with updated cf_clearance cookie - result = await RunCurl(request); - - // add cf_clearance cookie to the final result so we update the config for the next request - result.Cookies = response.Cookies + " " + result.Cookies; - } - return result; + { + WebClientByteResult result = await RunCurl(request); + + // check if we've received a CloudFlare challenge + string[] server; + if (result.Status == HttpStatusCode.ServiceUnavailable && result.Headers.TryGetValue("server", out server) && server[0] == "cloudflare-nginx") + { + logger.Info("UnixLibCurlWebClient: Received a new CloudFlare challenge"); + + // solve the challenge + string pageContent = Encoding.UTF8.GetString(result.Content); + Uri uri = new Uri(request.Url); + string clearanceUri = CloudFlareChallengeSolverSolve(pageContent, uri); + logger.Info(string.Format("UnixLibCurlWebClient: CloudFlare clearanceUri: {0}", clearanceUri)); + + // wait... + await Task.Delay(5000); + + // request clearanceUri to get cf_clearance cookie + var response = await CurlHelper.GetAsync(clearanceUri, request.Cookies, request.Referer); + logger.Info(string.Format("UnixLibCurlWebClient: received CloudFlare clearance cookie: {0}", response.Cookies)); + + // add new cf_clearance cookies to the original request + request.Cookies = response.Cookies + request.Cookies; + + // re-run the original request with updated cf_clearance cookie + result = await RunCurl(request); + + // add cf_clearance cookie to the final result so we update the config for the next request + result.Cookies = response.Cookies + " " + result.Cookies; + } + return result; } protected async Task<WebClientByteResult> RunCurl(WebRequest request) @@ -113,7 +113,7 @@ namespace Jackett.Utils.Clients logger.Debug("UnixLibCurlWebClient: Posting " + StringUtil.PostDataFromDict(request.PostData)); } - response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer, request.Headers, request.RawBody); + response = await CurlHelper.PostAsync(request.Url, request.PostData, request.Cookies, request.Referer, request.Headers, request.RawBody); } var result = new WebClientByteResult() @@ -127,34 +127,34 @@ namespace Jackett.Utils.Clients { foreach (var header in response.HeaderList) { - var key = header[0].ToLowerInvariant(); - - result.Headers[key] = new string[] { header[1] }; // doesn't support multiple identical headers? - + var key = header[0].ToLowerInvariant(); + + result.Headers[key] = new string[] { header[1] }; // doesn't support multiple identical headers? + switch (key) { case "location": result.RedirectingTo = header[1]; break; case "refresh": - if (response.Status == System.Net.HttpStatusCode.ServiceUnavailable) + if (response.Status == System.Net.HttpStatusCode.ServiceUnavailable) { //"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R" var redirval = ""; var value = header[1]; - var start = value.IndexOf("="); - var end = value.IndexOf(";"); - var len = value.Length; - if (start > -1) - { - redirval = value.Substring(start + 1); - result.RedirectingTo = redirval; - // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature - // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally - // it shoudln't include service unavailable..only if we have this redirect header. - result.Status = System.Net.HttpStatusCode.Redirect; - var redirtime = Int32.Parse(value.Substring(0, end)); - System.Threading.Thread.Sleep(redirtime * 1000); + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + result.Status = System.Net.HttpStatusCode.Redirect; + var redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); } } break; diff --git a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs index 81192b3c..c4ef8855 100644 --- a/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs +++ b/src/Jackett/Utils/Clients/UnixSafeCurlWebClient.cs @@ -19,7 +19,7 @@ namespace Jackett.Utils.Clients public UnixSafeCurlWebClient(IProcessService p, Logger l, IConfigurationService c) : base(p: p, l: l, - c: c) + c: c) { } @@ -30,10 +30,10 @@ namespace Jackett.Utils.Clients override protected async Task<WebClientByteResult> Run(WebRequest request) { var args = new StringBuilder(); - if (Startup.ProxyConnection != null) - { - args.AppendFormat("-x " + Startup.ProxyConnection + " "); - } + if (Startup.ProxyConnection != null) + { + args.AppendFormat("-x " + Startup.ProxyConnection + " "); + } args.AppendFormat("--url \"{0}\" ", request.Url); @@ -71,9 +71,9 @@ namespace Jackett.Utils.Clients // https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html args.Append("--cipher " + SSLFix.CipherList); } - if (Startup.IgnoreSslErrors == true) - { - args.Append("-k "); + if (Startup.IgnoreSslErrors == true) + { + args.Append("-k "); } args.Append("-H \"Accept-Language: en-US,en\" "); args.Append("-H \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\" "); @@ -91,16 +91,16 @@ namespace Jackett.Utils.Clients if (headSplit < 0) throw new Exception("Invalid response"); var headers = stdout.Substring(0, headSplit); - if (Startup.ProxyConnection != null) - { - // the proxy provided headers too so we need to split headers again - var headSplit1 = stdout.IndexOf("\r\n\r\n",headSplit + 4); - if (headSplit1 > 0) - { - headers = stdout.Substring(headSplit + 4,headSplit1 - (headSplit + 4)); - headSplit = headSplit1; - } - } + if (Startup.ProxyConnection != null) + { + // the proxy provided headers too so we need to split headers again + var headSplit1 = stdout.IndexOf("\r\n\r\n",headSplit + 4); + if (headSplit1 > 0) + { + headers = stdout.Substring(headSplit + 4,headSplit1 - (headSplit + 4)); + headSplit = headSplit1; + } + } var headerCount = 0; var cookieBuilder = new StringBuilder(); var cookies = new List<Tuple<string, string>>(); @@ -134,19 +134,19 @@ namespace Jackett.Utils.Clients case "refresh": //"Refresh: 8;URL=/cdn-cgi/l/chk_jschl?pass=1451000679.092-1vJFUJLb9R" var redirval = ""; - var start = value.IndexOf("="); - var end = value.IndexOf(";"); - var len = value.Length; - if (start > -1) - { - redirval = value.Substring(start + 1); - result.RedirectingTo = redirval; - // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature - // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally - // it shoudln't include service unavailable..only if we have this redirect header. - result.Status = System.Net.HttpStatusCode.Redirect; - var redirtime = Int32.Parse(value.Substring(0, end)); - System.Threading.Thread.Sleep(redirtime * 1000); + var start = value.IndexOf("="); + var end = value.IndexOf(";"); + var len = value.Length; + if (start > -1) + { + redirval = value.Substring(start + 1); + result.RedirectingTo = redirval; + // normally we don't want a serviceunavailable (503) to be a redirect, but that's the nature + // of this cloudflare approach..don't want to alter BaseWebResult.IsRedirect because normally + // it shoudln't include service unavailable..only if we have this redirect header. + result.Status = System.Net.HttpStatusCode.Redirect; + var redirtime = Int32.Parse(value.Substring(0, end)); + System.Threading.Thread.Sleep(redirtime * 1000); } break; } diff --git a/src/Jackett/Utils/Clients/WebRequest.cs b/src/Jackett/Utils/Clients/WebRequest.cs index 5ef451e2..25257940 100644 --- a/src/Jackett/Utils/Clients/WebRequest.cs +++ b/src/Jackett/Utils/Clients/WebRequest.cs @@ -1,103 +1,103 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Utils.Clients -{ - public class WebRequest - { - public WebRequest() - { - PostData = new List<KeyValuePair<string, string>>(); - Type = RequestType.GET; - Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); - EmulateBrowser = true; - Encoding Encoding; - } - - public WebRequest(string url) - { - PostData = new List<KeyValuePair<string, string>>(); - Type = RequestType.GET; - Url = url; - Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); - EmulateBrowser = true; - Encoding Encoding; - } - - public string Url { get; set; } - public IEnumerable<KeyValuePair<string, string>> PostData { get; set; } - public string Cookies { get; set; } - public string Referer { get; set; } - public RequestType Type { get; set; } - public string RawBody { get; set; } - public bool EmulateBrowser { get; set; } - public Encoding Encoding { get; set; } - - /// <summary> - /// Warning this is only implemented on HTTPWebClient currently! - /// </summary> - public Dictionary<string, string> Headers { get; set; } - - public override bool Equals(System.Object obj) - { - if (obj is WebRequest) - { - var other = obj as WebRequest; - var postDataSame = PostData == null && other.PostData == null; - if (!postDataSame) - { - if (!(PostData == null || other.PostData == null)) - { - var ok = PostData.Count() == other.PostData.Count(); - foreach (var i in PostData) - { - if (!other.PostData.Any(item => item.Key == i.Key)) - { - ok = false; - break; - } - - if (PostData.FirstOrDefault(item => item.Key == i.Key).Value != other.PostData.FirstOrDefault(item => item.Key == i.Key).Value) - { - ok = false; - break; - } - } - - if (ok) - { - postDataSame = true; - } - } - } - - return other.Url == Url && - other.Referer == Referer && - other.Cookies == Cookies && - other.Type == Type && - other.Encoding == Encoding && - postDataSame; - - } - else - { - return false; - } - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - } - - public enum RequestType - { - GET, - POST - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Utils.Clients +{ + public class WebRequest + { + public WebRequest() + { + PostData = new List<KeyValuePair<string, string>>(); + Type = RequestType.GET; + Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); + EmulateBrowser = true; + Encoding Encoding; + } + + public WebRequest(string url) + { + PostData = new List<KeyValuePair<string, string>>(); + Type = RequestType.GET; + Url = url; + Headers = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); + EmulateBrowser = true; + Encoding Encoding; + } + + public string Url { get; set; } + public IEnumerable<KeyValuePair<string, string>> PostData { get; set; } + public string Cookies { get; set; } + public string Referer { get; set; } + public RequestType Type { get; set; } + public string RawBody { get; set; } + public bool EmulateBrowser { get; set; } + public Encoding Encoding { get; set; } + + /// <summary> + /// Warning this is only implemented on HTTPWebClient currently! + /// </summary> + public Dictionary<string, string> Headers { get; set; } + + public override bool Equals(System.Object obj) + { + if (obj is WebRequest) + { + var other = obj as WebRequest; + var postDataSame = PostData == null && other.PostData == null; + if (!postDataSame) + { + if (!(PostData == null || other.PostData == null)) + { + var ok = PostData.Count() == other.PostData.Count(); + foreach (var i in PostData) + { + if (!other.PostData.Any(item => item.Key == i.Key)) + { + ok = false; + break; + } + + if (PostData.FirstOrDefault(item => item.Key == i.Key).Value != other.PostData.FirstOrDefault(item => item.Key == i.Key).Value) + { + ok = false; + break; + } + } + + if (ok) + { + postDataSame = true; + } + } + } + + return other.Url == Url && + other.Referer == Referer && + other.Cookies == Cookies && + other.Type == Type && + other.Encoding == Encoding && + postDataSame; + + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + } + + public enum RequestType + { + GET, + POST + } +} diff --git a/src/Jackett/Utils/DateTimeUtil.cs b/src/Jackett/Utils/DateTimeUtil.cs index f0a0d6dd..46d629c2 100644 --- a/src/Jackett/Utils/DateTimeUtil.cs +++ b/src/Jackett/Utils/DateTimeUtil.cs @@ -1,10 +1,10 @@ -using Cliver; +using Cliver; using System; using System.Collections.Generic; -using System.Globalization; +using System.Globalization; using System.Linq; using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Jackett.Utils @@ -15,7 +15,7 @@ namespace Jackett.Utils public static DateTime UnixTimestampToDateTime(long unixTime) { - DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); dt = dt.AddSeconds(unixTime).ToLocalTime(); return dt; } @@ -49,17 +49,17 @@ namespace Jackett.Utils str = str.Replace("and", ""); TimeSpan timeAgo = TimeSpan.Zero; - Regex TimeagoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?"); - var TimeagoMatches = TimeagoRegex.Match(str); - - while (TimeagoMatches.Success) - { - string expanded = string.Empty; - - var val = ParseUtil.CoerceFloat(TimeagoMatches.Groups[1].Value); + Regex TimeagoRegex = new Regex(@"\s*?([\d\.]+)\s*?([^\d\s\.]+)\s*?"); + var TimeagoMatches = TimeagoRegex.Match(str); + + while (TimeagoMatches.Success) + { + string expanded = string.Empty; + + var val = ParseUtil.CoerceFloat(TimeagoMatches.Groups[1].Value); var unit = TimeagoMatches.Groups[2].Value; - TimeagoMatches = TimeagoMatches.NextMatch(); - + TimeagoMatches = TimeagoMatches.NextMatch(); + if (unit.Contains("sec") || unit == "s") timeAgo += TimeSpan.FromSeconds(val); else if (unit.Contains("min") || unit == "m") @@ -75,56 +75,56 @@ namespace Jackett.Utils else if (unit.Contains("year") || unit == "y") timeAgo += TimeSpan.FromDays(val * 365); else - { - throw new Exception("TimeAgo parsing failed, unknown unit: "+unit); + { + throw new Exception("TimeAgo parsing failed, unknown unit: "+unit); } } return DateTime.SpecifyKind(DateTime.Now - timeAgo, DateTimeKind.Local); } - public static TimeSpan ParseTimeSpan(string time) - { - if (string.IsNullOrWhiteSpace(time)) - return TimeSpan.Zero; - - TimeSpan offset = TimeSpan.Zero; - if (time.EndsWith("AM")) - { - time = time.Substring(0, time.Length - 2); - if(time.StartsWith("12")) // 12:15 AM becomes 00:15 - time = "00" + time.Substring(2); - } - else if (time.EndsWith("PM")) - { - time = time.Substring(0, time.Length - 2); - offset = TimeSpan.FromHours(12); - } - - var ts = TimeSpan.Parse(time); - ts += offset; - return ts; + public static TimeSpan ParseTimeSpan(string time) + { + if (string.IsNullOrWhiteSpace(time)) + return TimeSpan.Zero; + + TimeSpan offset = TimeSpan.Zero; + if (time.EndsWith("AM")) + { + time = time.Substring(0, time.Length - 2); + if(time.StartsWith("12")) // 12:15 AM becomes 00:15 + time = "00" + time.Substring(2); + } + else if (time.EndsWith("PM")) + { + time = time.Substring(0, time.Length - 2); + offset = TimeSpan.FromHours(12); + } + + var ts = TimeSpan.Parse(time); + ts += offset; + return ts; } // Uses the DateTimeRoutines library to parse the date // http://www.codeproject.com/Articles/33298/C-Date-Time-Parser public static DateTime FromFuzzyTime(string str, string format = null) - { - DateTimeRoutines.DateTimeFormat dt_format = DateTimeRoutines.DateTimeFormat.USA_DATE; - if (format == "UK") - { - dt_format = DateTimeRoutines.DateTimeFormat.UK_DATE; - } - - DateTimeRoutines.ParsedDateTime dt; - if (DateTimeRoutines.TryParseDateOrTime(str, dt_format, out dt)) - { - return dt.DateTime; - } - throw new Exception("FromFuzzyTime parsing failed"); - } - - public static Regex timeAgoRegexp = new Regex(@"(?i)\bago", RegexOptions.Compiled); + { + DateTimeRoutines.DateTimeFormat dt_format = DateTimeRoutines.DateTimeFormat.USA_DATE; + if (format == "UK") + { + dt_format = DateTimeRoutines.DateTimeFormat.UK_DATE; + } + + DateTimeRoutines.ParsedDateTime dt; + if (DateTimeRoutines.TryParseDateOrTime(str, dt_format, out dt)) + { + return dt.DateTime; + } + throw new Exception("FromFuzzyTime parsing failed"); + } + + public static Regex timeAgoRegexp = new Regex(@"(?i)\bago", RegexOptions.Compiled); public static Regex todayRegexp = new Regex(@"(?i)\btoday([\s,]*|$)", RegexOptions.Compiled); public static Regex tomorrowRegexp = new Regex(@"(?i)\btomorrow([\s,]*|$)", RegexOptions.Compiled); public static Regex yesterdayRegexp = new Regex(@"(?i)\byesterday([\s,]*|$)", RegexOptions.Compiled); @@ -132,168 +132,168 @@ namespace Jackett.Utils public static Regex missingYearRegexp2 = new Regex(@"^(\d{1,2}\s+\w{3})\s+(\d{1,2}\:\d{1,2}.*)$", RegexOptions.Compiled); // 1 Jan 10:30 public static DateTime FromUnknown(string str, string format = null) - { - try { - str = ParseUtil.NormalizeSpace(str); - Match match; - - if(str.ToLower().Contains("now")) - { - return DateTime.UtcNow; - } - - // ... ago - match = timeAgoRegexp.Match(str); - if (match.Success) - { - var timeago = str; - return FromTimeAgo(timeago); - } - - // Today ... - match = todayRegexp.Match(str); - if (match.Success) - { - var time = str.Replace(match.Groups[0].Value, ""); - DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); - dt += ParseTimeSpan(time); - return dt; - } - - // Yesterday ... - match = yesterdayRegexp.Match(str); - if (match.Success) - { - var time = str.Replace(match.Groups[0].Value, ""); - DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); - dt += ParseTimeSpan(time); - dt -= TimeSpan.FromDays(1); - return dt; - } - - // Tomorrow ... - match = tomorrowRegexp.Match(str); - if (match.Success) - { - var time = str.Replace(match.Groups[0].Value, ""); - DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); - dt += ParseTimeSpan(time); - dt += TimeSpan.FromDays(1); - return dt; - } - - try - { - // try parsing the str as an unix timestamp - var unixTimeStamp = long.Parse(str); - return UnixTimestampToDateTime(unixTimeStamp); - } - catch (FormatException) - { - // it wasn't a timestamp, continue.... - } - - // add missing year - match = missingYearRegexp.Match(str); - if (match.Success) - { - var date = match.Groups[1].Value; - string newDate = DateTime.Now.Year.ToString()+ "-"+date; - str = str.Replace(date, newDate); - } - - // add missing year 2 - match = missingYearRegexp2.Match(str); - if (match.Success) - { - var date = match.Groups[1].Value; - var time = match.Groups[2].Value; - str = date + " " + DateTime.Now.Year.ToString() + " " + time; - } - - return FromFuzzyTime(str, format); - } - catch (Exception ex) - { - throw new Exception(string.Format("DateTime parsing failed for \"{0}\": {1}", str, ex.ToString())); - } - } - + { + try { + str = ParseUtil.NormalizeSpace(str); + Match match; + + if(str.ToLower().Contains("now")) + { + return DateTime.UtcNow; + } + + // ... ago + match = timeAgoRegexp.Match(str); + if (match.Success) + { + var timeago = str; + return FromTimeAgo(timeago); + } + + // Today ... + match = todayRegexp.Match(str); + if (match.Success) + { + var time = str.Replace(match.Groups[0].Value, ""); + DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); + dt += ParseTimeSpan(time); + return dt; + } + + // Yesterday ... + match = yesterdayRegexp.Match(str); + if (match.Success) + { + var time = str.Replace(match.Groups[0].Value, ""); + DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); + dt += ParseTimeSpan(time); + dt -= TimeSpan.FromDays(1); + return dt; + } + + // Tomorrow ... + match = tomorrowRegexp.Match(str); + if (match.Success) + { + var time = str.Replace(match.Groups[0].Value, ""); + DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow.Date, DateTimeKind.Unspecified); + dt += ParseTimeSpan(time); + dt += TimeSpan.FromDays(1); + return dt; + } + + try + { + // try parsing the str as an unix timestamp + var unixTimeStamp = long.Parse(str); + return UnixTimestampToDateTime(unixTimeStamp); + } + catch (FormatException) + { + // it wasn't a timestamp, continue.... + } + + // add missing year + match = missingYearRegexp.Match(str); + if (match.Success) + { + var date = match.Groups[1].Value; + string newDate = DateTime.Now.Year.ToString()+ "-"+date; + str = str.Replace(date, newDate); + } + + // add missing year 2 + match = missingYearRegexp2.Match(str); + if (match.Success) + { + var date = match.Groups[1].Value; + var time = match.Groups[2].Value; + str = date + " " + DateTime.Now.Year.ToString() + " " + time; + } + + return FromFuzzyTime(str, format); + } + catch (Exception ex) + { + throw new Exception(string.Format("DateTime parsing failed for \"{0}\": {1}", str, ex.ToString())); + } + } + // converts a date/time string to a DateTime object using a GoLang layout - public static DateTime ParseDateTimeGoLang(string date, string layout) - { - date = ParseUtil.NormalizeSpace(date); - var pattern = layout; - - // year - pattern = pattern.Replace("2006", "yyyy"); - pattern = pattern.Replace("06", "yy"); - - // month - pattern = pattern.Replace("January", "MMMM"); - pattern = pattern.Replace("Jan", "MMM"); - pattern = pattern.Replace("01", "MM"); - - // day - pattern = pattern.Replace("Monday", "dddd"); - pattern = pattern.Replace("Mon", "ddd"); - pattern = pattern.Replace("02", "dd"); - //pattern = pattern.Replace("_2", ""); // space padding not supported nativly by C#? - pattern = pattern.Replace("2", "d"); - - // hours/minutes/seconds - pattern = pattern.Replace("05", "ss"); - - pattern = pattern.Replace("15", "HH"); - pattern = pattern.Replace("03", "hh"); - pattern = pattern.Replace("3", "h"); - - pattern = pattern.Replace("04", "mm"); - pattern = pattern.Replace("4", "m"); - - pattern = pattern.Replace("5", "s"); - - // month again - pattern = pattern.Replace("1", "M"); - - // fractional seconds - pattern = pattern.Replace(".0000", "ffff"); - pattern = pattern.Replace(".000", "fff"); - pattern = pattern.Replace(".00", "ff"); - pattern = pattern.Replace(".0", "f"); - - pattern = pattern.Replace(".9999", "FFFF"); - pattern = pattern.Replace(".999", "FFF"); - pattern = pattern.Replace(".99", "FF"); - pattern = pattern.Replace(".9", "F"); - - // AM/PM - pattern = pattern.Replace("PM", "tt"); - pattern = pattern.Replace("pm", "tt"); // not sure if this works - - // timezones - // these might need further tuning - //pattern = pattern.Replace("MST", ""); - //pattern = pattern.Replace("Z07:00:00", ""); - pattern = pattern.Replace("Z07:00", "'Z'zzz"); - pattern = pattern.Replace("Z07", "'Z'zz"); - //pattern = pattern.Replace("Z070000", ""); - //pattern = pattern.Replace("Z0700", ""); - pattern = pattern.Replace("Z07:00", "'Z'zzz"); - pattern = pattern.Replace("Z07", "'Z'zz"); - //pattern = pattern.Replace("-07:00:00", ""); - pattern = pattern.Replace("-07:00", "zzz"); - //pattern = pattern.Replace("-0700", "zz"); - pattern = pattern.Replace("-07", "zz"); - - try - { - return DateTime.ParseExact(date, pattern, CultureInfo.InvariantCulture); - } - catch (FormatException ex) - { - throw new FormatException(string.Format("Error while parsing DateTime \"{0}\", using layout \"{1}\" ({2}): {3}", date, layout, pattern, ex.Message)); - } - } + public static DateTime ParseDateTimeGoLang(string date, string layout) + { + date = ParseUtil.NormalizeSpace(date); + var pattern = layout; + + // year + pattern = pattern.Replace("2006", "yyyy"); + pattern = pattern.Replace("06", "yy"); + + // month + pattern = pattern.Replace("January", "MMMM"); + pattern = pattern.Replace("Jan", "MMM"); + pattern = pattern.Replace("01", "MM"); + + // day + pattern = pattern.Replace("Monday", "dddd"); + pattern = pattern.Replace("Mon", "ddd"); + pattern = pattern.Replace("02", "dd"); + //pattern = pattern.Replace("_2", ""); // space padding not supported nativly by C#? + pattern = pattern.Replace("2", "d"); + + // hours/minutes/seconds + pattern = pattern.Replace("05", "ss"); + + pattern = pattern.Replace("15", "HH"); + pattern = pattern.Replace("03", "hh"); + pattern = pattern.Replace("3", "h"); + + pattern = pattern.Replace("04", "mm"); + pattern = pattern.Replace("4", "m"); + + pattern = pattern.Replace("5", "s"); + + // month again + pattern = pattern.Replace("1", "M"); + + // fractional seconds + pattern = pattern.Replace(".0000", "ffff"); + pattern = pattern.Replace(".000", "fff"); + pattern = pattern.Replace(".00", "ff"); + pattern = pattern.Replace(".0", "f"); + + pattern = pattern.Replace(".9999", "FFFF"); + pattern = pattern.Replace(".999", "FFF"); + pattern = pattern.Replace(".99", "FF"); + pattern = pattern.Replace(".9", "F"); + + // AM/PM + pattern = pattern.Replace("PM", "tt"); + pattern = pattern.Replace("pm", "tt"); // not sure if this works + + // timezones + // these might need further tuning + //pattern = pattern.Replace("MST", ""); + //pattern = pattern.Replace("Z07:00:00", ""); + pattern = pattern.Replace("Z07:00", "'Z'zzz"); + pattern = pattern.Replace("Z07", "'Z'zz"); + //pattern = pattern.Replace("Z070000", ""); + //pattern = pattern.Replace("Z0700", ""); + pattern = pattern.Replace("Z07:00", "'Z'zzz"); + pattern = pattern.Replace("Z07", "'Z'zz"); + //pattern = pattern.Replace("-07:00:00", ""); + pattern = pattern.Replace("-07:00", "zzz"); + //pattern = pattern.Replace("-0700", "zz"); + pattern = pattern.Replace("-07", "zz"); + + try + { + return DateTime.ParseExact(date, pattern, CultureInfo.InvariantCulture); + } + catch (FormatException ex) + { + throw new FormatException(string.Format("Error while parsing DateTime \"{0}\", using layout \"{1}\" ({2}): {3}", date, layout, pattern, ex.Message)); + } + } } } diff --git a/src/Jackett/Utils/JsonContent.cs b/src/Jackett/Utils/JsonContent.cs index b49245b4..83bfe187 100644 --- a/src/Jackett/Utils/JsonContent.cs +++ b/src/Jackett/Utils/JsonContent.cs @@ -12,17 +12,17 @@ using System.Threading.Tasks; namespace Jackett.Utils { - public class JsonContent : StringContent - { - public JsonContent(object value) - : this(value, Encoding.UTF8) - { - Headers.ContentType.CharSet = "utf-8"; - } - - public JsonContent(object value, Encoding encoding) - : base(JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), encoding, "application/json") - { - } + public class JsonContent : StringContent + { + public JsonContent(object value) + : this(value, Encoding.UTF8) + { + Headers.ContentType.CharSet = "utf-8"; + } + + public JsonContent(object value, Encoding encoding) + : base(JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), encoding, "application/json") + { + } } } diff --git a/src/Jackett/Utils/ParseUtil.cs b/src/Jackett/Utils/ParseUtil.cs index 24f68d99..af2774df 100644 --- a/src/Jackett/Utils/ParseUtil.cs +++ b/src/Jackett/Utils/ParseUtil.cs @@ -1,120 +1,120 @@ -using System.Globalization; -using System.Text.RegularExpressions; -using System.Web; - -namespace Jackett.Utils -{ - public static class ParseUtil - { - private static readonly Regex InvalidXmlChars = - new Regex( - @"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]", - RegexOptions.Compiled); - private static readonly Regex ImdbId = new Regex(@"^(?:tt)?(\d{1,7})$", RegexOptions.Compiled); - - public static string NormalizeSpace(string s) - { - return s.Trim(); - } - - public static string NormalizeMultiSpaces(string s) - { - return new Regex(@"\s+").Replace(NormalizeSpace(s), " "); ; - } - - public static string NormalizeNumber(string s) - { - var normalized = NormalizeSpace(s); - normalized = normalized.Replace("-", "0"); - normalized = normalized.Replace(",", ""); - return normalized; - } - - public static string RemoveInvalidXmlChars(string text) - { - return string.IsNullOrEmpty(text) ? "" : InvalidXmlChars.Replace(text, ""); - } - - public static double CoerceDouble(string str) - { - return double.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); - } - - public static float CoerceFloat(string str) - { - return float.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); - } - - public static int CoerceInt(string str) - { - return int.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); - } - - public static long CoerceLong(string str) - { - return long.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); - } - - public static bool TryCoerceDouble(string str, out double result) - { - return double.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - } - - public static bool TryCoerceFloat(string str, out float result) - { - return float.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - } - - public static bool TryCoerceInt(string str, out int result) - { - return int.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - } - - public static bool TryCoerceLong(string str, out long result) - { - return long.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); - } - - public static string GetArgumentFromQueryString(string url, string argument) - { - if (url == null || argument == null) - return null; - var qsStr = url.Split(new char[] { '?' }, 2)[1]; - qsStr = qsStr.Split(new char[] { '#' }, 2)[0]; - var qs = HttpUtility.ParseQueryString(qsStr); - return qs.Get(argument); - } - - public static long? GetLongFromString(string str) - { - if (str == null) - return null; - Regex IdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); - var IdMatch = IdRegEx.Match(str); - if (!IdMatch.Success) - return null; - var Id = IdMatch.Groups[1].Value; - return CoerceLong(Id); - } - - public static int? GetImdbID(string imdbstr) - { - if (imdbstr == null) - return null; - var match = ImdbId.Match(imdbstr); - if (!match.Success) - return null; - - return int.Parse(match.Groups[1].Value, NumberStyles.Any, CultureInfo.InvariantCulture); - } - - public static string GetFullImdbID(string imdbstr) - { - var imdbid = GetImdbID(imdbstr); - if (imdbid == null) - return null; - - return "tt" + ((int)imdbid).ToString("D7"); - } - } +using System.Globalization; +using System.Text.RegularExpressions; +using System.Web; + +namespace Jackett.Utils +{ + public static class ParseUtil + { + private static readonly Regex InvalidXmlChars = + new Regex( + @"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]", + RegexOptions.Compiled); + private static readonly Regex ImdbId = new Regex(@"^(?:tt)?(\d{1,7})$", RegexOptions.Compiled); + + public static string NormalizeSpace(string s) + { + return s.Trim(); + } + + public static string NormalizeMultiSpaces(string s) + { + return new Regex(@"\s+").Replace(NormalizeSpace(s), " "); ; + } + + public static string NormalizeNumber(string s) + { + var normalized = NormalizeSpace(s); + normalized = normalized.Replace("-", "0"); + normalized = normalized.Replace(",", ""); + return normalized; + } + + public static string RemoveInvalidXmlChars(string text) + { + return string.IsNullOrEmpty(text) ? "" : InvalidXmlChars.Replace(text, ""); + } + + public static double CoerceDouble(string str) + { + return double.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static float CoerceFloat(string str) + { + return float.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static int CoerceInt(string str) + { + return int.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static long CoerceLong(string str) + { + return long.Parse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static bool TryCoerceDouble(string str, out double result) + { + return double.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + } + + public static bool TryCoerceFloat(string str, out float result) + { + return float.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + } + + public static bool TryCoerceInt(string str, out int result) + { + return int.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + } + + public static bool TryCoerceLong(string str, out long result) + { + return long.TryParse(NormalizeNumber(str), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + } + + public static string GetArgumentFromQueryString(string url, string argument) + { + if (url == null || argument == null) + return null; + var qsStr = url.Split(new char[] { '?' }, 2)[1]; + qsStr = qsStr.Split(new char[] { '#' }, 2)[0]; + var qs = HttpUtility.ParseQueryString(qsStr); + return qs.Get(argument); + } + + public static long? GetLongFromString(string str) + { + if (str == null) + return null; + Regex IdRegEx = new Regex(@"(\d+)", RegexOptions.Compiled); + var IdMatch = IdRegEx.Match(str); + if (!IdMatch.Success) + return null; + var Id = IdMatch.Groups[1].Value; + return CoerceLong(Id); + } + + public static int? GetImdbID(string imdbstr) + { + if (imdbstr == null) + return null; + var match = ImdbId.Match(imdbstr); + if (!match.Success) + return null; + + return int.Parse(match.Groups[1].Value, NumberStyles.Any, CultureInfo.InvariantCulture); + } + + public static string GetFullImdbID(string imdbstr) + { + var imdbid = GetImdbID(imdbstr); + if (imdbid == null) + return null; + + return "tt" + ((int)imdbid).ToString("D7"); + } + } } \ No newline at end of file diff --git a/src/Jackett/Utils/StringCipher.cs b/src/Jackett/Utils/StringCipher.cs index 17124f66..ea4acd33 100644 --- a/src/Jackett/Utils/StringCipher.cs +++ b/src/Jackett/Utils/StringCipher.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Utils -{ - public static class StringCipher - { - // This constant is used to determine the keysize of the encryption algorithm in bits. - // We divide this by 8 within the code below to get the equivalent number of bytes. - private const int Keysize = 256; - - // This constant determines the number of iterations for the password bytes generation function. - private const int DerivationIterations = 1000; - - public static string Encrypt(string plainText, string passPhrase) - { - // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text - // so that the same Salt and IV values can be used when decrypting. - var saltStringBytes = Generate256BitsOfRandomEntropy(); - var ivStringBytes = Generate256BitsOfRandomEntropy(); - var plainTextBytes = Encoding.UTF8.GetBytes(plainText); - using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) - { - var keyBytes = password.GetBytes(Keysize / 8); - using (var symmetricKey = new RijndaelManaged()) - { - symmetricKey.BlockSize = 256; - symmetricKey.Mode = CipherMode.CBC; - symmetricKey.Padding = PaddingMode.PKCS7; - using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)) - { - using (var memoryStream = new MemoryStream()) - { - using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) - { - cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); - cryptoStream.FlushFinalBlock(); - // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. - var cipherTextBytes = saltStringBytes; - cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray(); - cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray(); - memoryStream.Close(); - cryptoStream.Close(); - return Convert.ToBase64String(cipherTextBytes); - } - } - } - } - } - } - - public static string Decrypt(string cipherText, string passPhrase) - { - // Get the complete stream of bytes that represent: - // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] - var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); - // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. - var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); - // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. - var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); - // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. - var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray(); - - using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) - { - var keyBytes = password.GetBytes(Keysize / 8); - using (var symmetricKey = new RijndaelManaged()) - { - symmetricKey.BlockSize = 256; - symmetricKey.Mode = CipherMode.CBC; - symmetricKey.Padding = PaddingMode.PKCS7; - using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)) - { - using (var memoryStream = new MemoryStream(cipherTextBytes)) - { - using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) - { - var plainTextBytes = new byte[cipherTextBytes.Length]; - var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); - memoryStream.Close(); - cryptoStream.Close(); - return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); - } - } - } - } - } - } - - private static byte[] Generate256BitsOfRandomEntropy() - { - var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits. - using (var rngCsp = new RNGCryptoServiceProvider()) - { - // Fill the array with cryptographically secure random bytes. - rngCsp.GetBytes(randomBytes); - } - return randomBytes; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Utils +{ + public static class StringCipher + { + // This constant is used to determine the keysize of the encryption algorithm in bits. + // We divide this by 8 within the code below to get the equivalent number of bytes. + private const int Keysize = 256; + + // This constant determines the number of iterations for the password bytes generation function. + private const int DerivationIterations = 1000; + + public static string Encrypt(string plainText, string passPhrase) + { + // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text + // so that the same Salt and IV values can be used when decrypting. + var saltStringBytes = Generate256BitsOfRandomEntropy(); + var ivStringBytes = Generate256BitsOfRandomEntropy(); + var plainTextBytes = Encoding.UTF8.GetBytes(plainText); + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream()) + { + using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) + { + cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); + cryptoStream.FlushFinalBlock(); + // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. + var cipherTextBytes = saltStringBytes; + cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray(); + cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray(); + memoryStream.Close(); + cryptoStream.Close(); + return Convert.ToBase64String(cipherTextBytes); + } + } + } + } + } + } + + public static string Decrypt(string cipherText, string passPhrase) + { + // Get the complete stream of bytes that represent: + // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] + var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); + // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. + var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); + // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. + var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); + // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. + var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray(); + + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream(cipherTextBytes)) + { + using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) + { + var plainTextBytes = new byte[cipherTextBytes.Length]; + var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); + memoryStream.Close(); + cryptoStream.Close(); + return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); + } + } + } + } + } + } + + private static byte[] Generate256BitsOfRandomEntropy() + { + var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits. + using (var rngCsp = new RNGCryptoServiceProvider()) + { + // Fill the array with cryptographically secure random bytes. + rngCsp.GetBytes(randomBytes); + } + return randomBytes; + } + } +} diff --git a/src/Jackett/Utils/StringUtil.cs b/src/Jackett/Utils/StringUtil.cs index bd51f24b..ff9d6e95 100644 --- a/src/Jackett/Utils/StringUtil.cs +++ b/src/Jackett/Utils/StringUtil.cs @@ -1,10 +1,10 @@ -using AngleSharp.Dom; -using AngleSharp.Html; +using AngleSharp.Dom; +using AngleSharp.Html; using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.Globalization; -using System.IO; +using System.Globalization; +using System.IO; using System.Linq; using System.Net.Http; using System.Security.Cryptography; @@ -30,19 +30,19 @@ namespace Jackett.Utils } // replaces culture specific characters with the corresponding base characters (e.g. è becomes e). - public static String RemoveDiacritics(String s) - { - String normalizedString = s.Normalize(NormalizationForm.FormD); - StringBuilder stringBuilder = new StringBuilder(); - - for (int i = 0; i < normalizedString.Length; i++) - { - Char c = normalizedString[i]; - if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) - stringBuilder.Append(c); - } - - return stringBuilder.ToString(); + public static String RemoveDiacritics(String s) + { + String normalizedString = s.Normalize(NormalizationForm.FormD); + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < normalizedString.Length; i++) + { + Char c = normalizedString[i]; + if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) + stringBuilder.Append(c); + } + + return stringBuilder.ToString(); } public static string FromBase64(string str) @@ -104,7 +104,7 @@ namespace Jackett.Utils } public static void Add(this ICollection<KeyValuePair<string, string>> collection, string key, string value) - { + { collection.Add(new KeyValuePair<string, string>(key, value)); } @@ -113,11 +113,11 @@ namespace Jackett.Utils if (element == null) return "<NULL>"; - StringBuilder sb = new StringBuilder(); - StringWriter sw = new StringWriter(sb); - var formatter = new PrettyMarkupFormatter(); + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + var formatter = new PrettyMarkupFormatter(); element.ToHtml(sw, formatter); - return sb.ToString(); + return sb.ToString(); } diff --git a/src/Jackett/Utils/TorznabCapsUtil.cs b/src/Jackett/Utils/TorznabCapsUtil.cs index a96dff3d..8cae39fc 100644 --- a/src/Jackett/Utils/TorznabCapsUtil.cs +++ b/src/Jackett/Utils/TorznabCapsUtil.cs @@ -1,94 +1,94 @@ -using Jackett.Models; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Jackett.Utils -{ - public class TorznabUtil - { - static Regex reduceSpacesRegex = new Regex("\\s{2,}", RegexOptions.Compiled); - - static Regex findYearRegex = new Regex(@"(?<=\[|\(|\s)(\d{4})(?=\]|\)|\s)", RegexOptions.Compiled); - - public static TorznabCapabilities CreateDefaultTorznabTVCaps() - { - var caps = new TorznabCapabilities(); - caps.Categories.AddRange(new[] { - TorznabCatType.TV, - TorznabCatType.TVSD, - TorznabCatType.TVHD - }); - return caps; - } - - private static int GetYearFromTitle(string title) - { - var match = findYearRegex.Match(title); - if (match.Success) - { - var year = ParseUtil.CoerceInt(match.Value); - if(year>1850 && year < 2100) - { - return year; - } - } - - return 0; - } - - public static IEnumerable<ReleaseInfo> FilterResultsToTitle(IEnumerable<ReleaseInfo> results, string name, int imdbYear) - { - if (string.IsNullOrWhiteSpace(name)) - return results; - - name = CleanTitle(name); - var filteredResults = new List<ReleaseInfo>(); - foreach (var result in results) - { - // don't filter results with IMDBID (will be filtered seperately) - if (result.Imdb != null) - { - filteredResults.Add(result); - continue; - } - - if (result.Title == null) - continue; - - // Match on title - if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(CleanTitle(result.Title), name, CompareOptions.IgnoreNonSpace) >= 0) - { - // Match on year - var titleYear = GetYearFromTitle(result.Title); - if (imdbYear == 0 || titleYear == 0 || titleYear == imdbYear) - { - filteredResults.Add(result); - } - } - } - - return filteredResults; - } - - public static IEnumerable<ReleaseInfo> FilterResultsToImdb(IEnumerable<ReleaseInfo> results, string imdb) - { - if (string.IsNullOrWhiteSpace(imdb)) - return results; - // Filter out releases that do have a valid imdb ID, that is not equal to the one we're searching for. - return - results.Where( - result => !result.Imdb.HasValue || result.Imdb.Value == 0 || ("tt" + result.Imdb.Value.ToString("D7")).Equals(imdb)); - } - - private static string CleanTitle(string title) - { - title = title.Replace(':', ' ').Replace('.', ' ').Replace('-', ' ').Replace('_', ' ').Replace('+', ' ').Replace("'", "").Replace("[", "").Replace("]", "").Replace("(", "").Replace(")", ""); - return reduceSpacesRegex.Replace(title, " ").ToLowerInvariant(); - } - } -} +using Jackett.Models; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Jackett.Utils +{ + public class TorznabUtil + { + static Regex reduceSpacesRegex = new Regex("\\s{2,}", RegexOptions.Compiled); + + static Regex findYearRegex = new Regex(@"(?<=\[|\(|\s)(\d{4})(?=\]|\)|\s)", RegexOptions.Compiled); + + public static TorznabCapabilities CreateDefaultTorznabTVCaps() + { + var caps = new TorznabCapabilities(); + caps.Categories.AddRange(new[] { + TorznabCatType.TV, + TorznabCatType.TVSD, + TorznabCatType.TVHD + }); + return caps; + } + + private static int GetYearFromTitle(string title) + { + var match = findYearRegex.Match(title); + if (match.Success) + { + var year = ParseUtil.CoerceInt(match.Value); + if(year>1850 && year < 2100) + { + return year; + } + } + + return 0; + } + + public static IEnumerable<ReleaseInfo> FilterResultsToTitle(IEnumerable<ReleaseInfo> results, string name, int imdbYear) + { + if (string.IsNullOrWhiteSpace(name)) + return results; + + name = CleanTitle(name); + var filteredResults = new List<ReleaseInfo>(); + foreach (var result in results) + { + // don't filter results with IMDBID (will be filtered seperately) + if (result.Imdb != null) + { + filteredResults.Add(result); + continue; + } + + if (result.Title == null) + continue; + + // Match on title + if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(CleanTitle(result.Title), name, CompareOptions.IgnoreNonSpace) >= 0) + { + // Match on year + var titleYear = GetYearFromTitle(result.Title); + if (imdbYear == 0 || titleYear == 0 || titleYear == imdbYear) + { + filteredResults.Add(result); + } + } + } + + return filteredResults; + } + + public static IEnumerable<ReleaseInfo> FilterResultsToImdb(IEnumerable<ReleaseInfo> results, string imdb) + { + if (string.IsNullOrWhiteSpace(imdb)) + return results; + // Filter out releases that do have a valid imdb ID, that is not equal to the one we're searching for. + return + results.Where( + result => !result.Imdb.HasValue || result.Imdb.Value == 0 || ("tt" + result.Imdb.Value.ToString("D7")).Equals(imdb)); + } + + private static string CleanTitle(string title) + { + title = title.Replace(':', ' ').Replace('.', ' ').Replace('-', ' ').Replace('_', ' ').Replace('+', ' ').Replace("'", "").Replace("[", "").Replace("]", "").Replace("(", "").Replace(")", ""); + return reduceSpacesRegex.Replace(title, " ").ToLowerInvariant(); + } + } +} diff --git a/src/Jackett/Utils/WebApiRootRedirectMiddleware.cs b/src/Jackett/Utils/WebApiRootRedirectMiddleware.cs index 5360a099..60fb557c 100644 --- a/src/Jackett/Utils/WebApiRootRedirectMiddleware.cs +++ b/src/Jackett/Utils/WebApiRootRedirectMiddleware.cs @@ -1,42 +1,42 @@ -using Jackett.Services; -using Microsoft.Owin; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett.Utils -{ - public class WebApiRootRedirectMiddleware : OwinMiddleware - { - public WebApiRootRedirectMiddleware(OwinMiddleware next) - : base(next) - { - } - - public async override Task Invoke(IOwinContext context) - { - var url = context.Request.Uri; - if(context.Request.Path != null && context.Request.Path.HasValue && context.Request.Path.Value.StartsWith(Startup.BasePath)) - { - context.Request.Path = new PathString(context.Request.Path.Value.Substring(Startup.BasePath.Length-1)); - } - - if (context.Request.Path == null || string.IsNullOrWhiteSpace(context.Request.Path.ToString()) || context.Request.Path.ToString() == "/") - { - // 301 is the status code of permanent redirect - context.Response.StatusCode = 302; - var redir = Startup.BasePath + "Admin/Dashboard"; - Engine.Logger.Info("redirecting to " + redir); - context.Response.Headers.Set("Location", redir); - } - else - { - - - await Next.Invoke(context); - } - } - } +using Jackett.Services; +using Microsoft.Owin; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Utils +{ + public class WebApiRootRedirectMiddleware : OwinMiddleware + { + public WebApiRootRedirectMiddleware(OwinMiddleware next) + : base(next) + { + } + + public async override Task Invoke(IOwinContext context) + { + var url = context.Request.Uri; + if(context.Request.Path != null && context.Request.Path.HasValue && context.Request.Path.Value.StartsWith(Startup.BasePath)) + { + context.Request.Path = new PathString(context.Request.Path.Value.Substring(Startup.BasePath.Length-1)); + } + + if (context.Request.Path == null || string.IsNullOrWhiteSpace(context.Request.Path.ToString()) || context.Request.Path.ToString() == "/") + { + // 301 is the status code of permanent redirect + context.Response.StatusCode = 302; + var redir = Startup.BasePath + "Admin/Dashboard"; + Engine.Logger.Info("redirecting to " + redir); + context.Response.Headers.Set("Location", redir); + } + else + { + + + await Next.Invoke(context); + } + } + } } \ No newline at end of file diff --git a/src/Jackett/WebAPIExceptionHandler.cs b/src/Jackett/WebAPIExceptionHandler.cs index 74c7d085..9ad6dc6f 100644 --- a/src/Jackett/WebAPIExceptionHandler.cs +++ b/src/Jackett/WebAPIExceptionHandler.cs @@ -6,55 +6,55 @@ using System.Threading; using System.Threading.Tasks; using System.Web.Http.ExceptionHandling; using Jackett.Utils; -using System.Net.Http; -using System.Net; -using System.Web.Http; -using System.Net.Sockets; - +using System.Net.Http; +using System.Net; +using System.Web.Http; +using System.Net.Sockets; + namespace Jackett { - class WebAPIExceptionHandler : IExceptionHandler - { - public virtual Task HandleAsync(ExceptionHandlerContext context, - CancellationToken cancellationToken) - { - if (!ShouldHandle(context)) - { - return Task.FromResult(0); - } - - return HandleAsyncCore(context, cancellationToken); - } - - public virtual Task HandleAsyncCore(ExceptionHandlerContext context, - CancellationToken cancellationToken) - { - HandleCore(context); - return Task.FromResult(0); - } - - public virtual void HandleCore(ExceptionHandlerContext context) - { - // attempt to fix #930 - if (context.Exception is SocketException) - { - Engine.Logger.Error("Ignoring unhandled SocketException: " + context.Exception.GetExceptionDetails()); - return; - } - - Engine.Logger.Error("HandleCore(): unhandled exception: " + context.Exception.GetExceptionDetails()); - - var resp = new HttpResponseMessage(HttpStatusCode.InternalServerError) - { - Content = new StringContent(context.Exception.Message), - ReasonPhrase = "Jackett_InternalServerError" - }; - throw new HttpResponseException(resp); - } - - public virtual bool ShouldHandle(ExceptionHandlerContext context) - { - return context.ExceptionContext.CatchBlock.IsTopLevel; - } + class WebAPIExceptionHandler : IExceptionHandler + { + public virtual Task HandleAsync(ExceptionHandlerContext context, + CancellationToken cancellationToken) + { + if (!ShouldHandle(context)) + { + return Task.FromResult(0); + } + + return HandleAsyncCore(context, cancellationToken); + } + + public virtual Task HandleAsyncCore(ExceptionHandlerContext context, + CancellationToken cancellationToken) + { + HandleCore(context); + return Task.FromResult(0); + } + + public virtual void HandleCore(ExceptionHandlerContext context) + { + // attempt to fix #930 + if (context.Exception is SocketException) + { + Engine.Logger.Error("Ignoring unhandled SocketException: " + context.Exception.GetExceptionDetails()); + return; + } + + Engine.Logger.Error("HandleCore(): unhandled exception: " + context.Exception.GetExceptionDetails()); + + var resp = new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent(context.Exception.Message), + ReasonPhrase = "Jackett_InternalServerError" + }; + throw new HttpResponseException(resp); + } + + public virtual bool ShouldHandle(ExceptionHandlerContext context) + { + return context.ExceptionContext.CatchBlock.IsTopLevel; + } } } -- GitLab