From 529102ebcf509700119207713bd7cec17aaac9c6 Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 16 Nov 2020 14:24:56 -0500 Subject: [PATCH] Cardigann Categories --- src/NzbDrone.Core/Indexers/CategoryMapping.cs | 22 ++ .../IndexerDefinitionUpdateCommand.cs | 9 - .../Indexers/Definitions/Newznab/Newznab.cs | 12 +- .../Newznab/NewznabCapabilitiesProvider.cs | 2 +- .../Indexers/Definitions/Torznab/Torznab.cs | 12 +- .../Indexers/IndexerCapabilities.cs | 40 ++- .../Indexers/IndexerCapabilitiesCategories.cs | 211 ++++++++++++++ src/NzbDrone.Core/Indexers/IndexerCatType.cs | 273 ++++++++++++++++++ src/NzbDrone.Core/Indexers/IndexerCategory.cs | 1 + src/NzbDrone.Core/Indexers/IndexerFactory.cs | 44 +++ 10 files changed, 575 insertions(+), 51 deletions(-) create mode 100644 src/NzbDrone.Core/Indexers/CategoryMapping.cs delete mode 100644 src/NzbDrone.Core/Indexers/Definitions/Cardigann/IndexerDefinitionUpdateCommand.cs create mode 100644 src/NzbDrone.Core/Indexers/IndexerCapabilitiesCategories.cs create mode 100644 src/NzbDrone.Core/Indexers/IndexerCatType.cs diff --git a/src/NzbDrone.Core/Indexers/CategoryMapping.cs b/src/NzbDrone.Core/Indexers/CategoryMapping.cs new file mode 100644 index 000000000..961c91e07 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/CategoryMapping.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NzbDrone.Core.Indexers +{ + public class CategoryMapping + { + public CategoryMapping(string trackerCat, string trackerCatDesc, int newzCat) + { + TrackerCategory = trackerCat; + TrackerCategoryDesc = trackerCatDesc; + NewzNabCategory = newzCat; + } + + public string TrackerCategory { get; private set; } + public string TrackerCategoryDesc { get; private set; } + public int NewzNabCategory { get; private set; } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/IndexerDefinitionUpdateCommand.cs b/src/NzbDrone.Core/Indexers/Definitions/Cardigann/IndexerDefinitionUpdateCommand.cs deleted file mode 100644 index 0e547d9cc..000000000 --- a/src/NzbDrone.Core/Indexers/Definitions/Cardigann/IndexerDefinitionUpdateCommand.cs +++ /dev/null @@ -1,9 +0,0 @@ -using NzbDrone.Core.Messaging.Commands; - -namespace NzbDrone.Core.Indexers.Definitions.Cardigann -{ - public class IndexerDefinitionUpdateCommand : Command - { - public override bool SendUpdatesToClient => true; - } -} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs index 461d69285..13af91cc6 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/Newznab.cs @@ -110,17 +110,9 @@ namespace NzbDrone.Core.Indexers.Newznab failures.AddIfNotNull(TestCapabilities()); } - protected static List CategoryIds(List categories) + protected static List CategoryIds(IndexerCapabilitiesCategories categories) { - var l = categories.Select(c => c.Id).ToList(); - - foreach (var category in categories) - { - if (category.SubCategories != null) - { - l.AddRange(CategoryIds(category.SubCategories)); - } - } + var l = categories.GetTorznabCategoryTree().Select(c => c.Id).ToList(); return l; } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs index 6042ecb65..524fa9be9 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabCapabilitiesProvider.cs @@ -214,7 +214,7 @@ namespace NzbDrone.Core.Indexers.Newznab }); } - capabilities.Categories.Add(cat); + capabilities.Categories.AddCategoryMapping(cat.Name, cat); } } diff --git a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs index 764c08a67..0dc2d14e0 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Torznab/Torznab.cs @@ -97,17 +97,9 @@ namespace NzbDrone.Core.Indexers.Torznab failures.AddIfNotNull(TestCapabilities()); } - protected static List CategoryIds(List categories) + protected static List CategoryIds(IndexerCapabilitiesCategories categories) { - var l = categories.Select(c => c.Id).ToList(); - - foreach (var category in categories) - { - if (category.SubCategories != null) - { - l.AddRange(CategoryIds(category.SubCategories)); - } - } + var l = categories.GetTorznabCategoryTree().Select(c => c.Id).ToList(); return l; } diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs index 854cbb3e0..c8ed18784 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilities.cs @@ -41,7 +41,9 @@ namespace NzbDrone.Core.Indexers public enum BookSearchParam { - Q + Q, + Title, + Author } public class IndexerCapabilities @@ -75,8 +77,10 @@ namespace NzbDrone.Core.Indexers public List BookSearchParams; public bool BookSearchAvailable => BookSearchParams.Count > 0; + public bool BookSearchTitleAvailable => BookSearchParams.Contains(BookSearchParam.Title); + public bool BookSearchAuthorAvailable => BookSearchParams.Contains(BookSearchParam.Author); - public List Categories { get; private set; } + public readonly IndexerCapabilitiesCategories Categories; public IndexerCapabilities() { @@ -85,7 +89,7 @@ namespace NzbDrone.Core.Indexers MovieSearchParams = new List(); MusicSearchParams = new List(); BookSearchParams = new List(); - Categories = new List(); + Categories = new IndexerCapabilitiesCategories(); } public void ParseCardigannSearchModes(Dictionary> modes) @@ -315,26 +319,20 @@ namespace NzbDrone.Core.Indexers return string.Join(",", parameters); } - private string SupportedBookSearchParams + private string SupportedBookSearchParams() { - get + var parameters = new List { "q" }; // q is always enabled + if (BookSearchTitleAvailable) { - var parameters = new List() { "q" }; - if (BookSearchAvailable) - { - parameters.Add("author,title"); - } + parameters.Add("title"); + } - return string.Join(",", parameters); + if (BookSearchAuthorAvailable) + { + parameters.Add("author"); } - } - public bool SupportsCategories(int[] categories) - { - var subCategories = Categories.SelectMany(c => c.SubCategories); - var allCategories = Categories.Concat(subCategories); - var supportsCategory = allCategories.Any(i => categories.Any(c => c == i.Id)); - return supportsCategory; + return string.Join(",", parameters); } public XDocument GetXDocument() @@ -367,9 +365,9 @@ namespace NzbDrone.Core.Indexers new XAttribute("supportedParams", SupportedMusicSearchParams())), new XElement("book-search", new XAttribute("available", BookSearchAvailable ? "yes" : "no"), - new XAttribute("supportedParams", SupportedBookSearchParams))), + new XAttribute("supportedParams", SupportedBookSearchParams()))), new XElement("categories", - from c in Categories.OrderBy(x => x.Id < 100000 ? "z" + x.Id.ToString() : x.Name) + from c in Categories.GetTorznabCategoryTree(true) select new XElement("category", new XAttribute("id", c.Id), new XAttribute("name", c.Name), @@ -390,7 +388,7 @@ namespace NzbDrone.Core.Indexers left.MovieSearchParams = left.MovieSearchParams.Union(right.MovieSearchParams).ToList(); left.MusicSearchParams = left.MusicSearchParams.Union(right.MusicSearchParams).ToList(); left.BookSearchParams = left.BookSearchParams.Union(right.BookSearchParams).ToList(); - left.Categories.AddRange(right.Categories.Where(x => x.Id < 100000).Except(left.Categories)); // exclude indexer specific categories (>= 100000) + left.Categories.Concat(right.Categories); return left; } } diff --git a/src/NzbDrone.Core/Indexers/IndexerCapabilitiesCategories.cs b/src/NzbDrone.Core/Indexers/IndexerCapabilitiesCategories.cs new file mode 100644 index 000000000..bb3cf079b --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerCapabilitiesCategories.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace NzbDrone.Core.Indexers +{ + public class IndexerCapabilitiesCategories + { + private readonly List _categoryMapping = new List(); + private readonly List _torznabCategoryTree = new List(); + + public List GetTrackerCategories() => _categoryMapping + .Where(m => m.NewzNabCategory < 100000) + .Select(m => m.TrackerCategory).Distinct().ToList(); + + public List GetTorznabCategoryTree(bool sorted = false) + { + if (!sorted) + { + return _torznabCategoryTree; + } + + // we build a new tree, original is unsorted + // first torznab categories ordered by id and then custom cats ordered by name + var sortedTree = _torznabCategoryTree + .Select(c => + { + var sortedSubCats = c.SubCategories.OrderBy(x => x.Id); + var newCat = new IndexerCategory(c.Id, c.Name); + newCat.SubCategories.AddRange(sortedSubCats); + return newCat; + }).OrderBy(x => x.Id >= 100000 ? "zzz" + x.Name : x.Id.ToString()).ToList(); + + return sortedTree; + } + + public List GetTorznabCategoryList(bool sorted = false) + { + var tree = GetTorznabCategoryTree(sorted); + + // create a flat list (without subcategories) + var newFlatList = new List(); + foreach (var cat in tree) + { + newFlatList.Add(cat.CopyWithoutSubCategories()); + newFlatList.AddRange(cat.SubCategories); + } + + return newFlatList; + } + + public void AddCategoryMapping(string trackerCategory, IndexerCategory torznabCategory, string trackerCategoryDesc = null) + { + _categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, torznabCategory.Id)); + AddTorznabCategoryTree(torznabCategory); + + if (trackerCategoryDesc == null) + { + return; + } + + // create custom cats (1:1 categories) if trackerCategoryDesc is defined + // - if trackerCategory is "integer" we use that number to generate custom category id + // - if trackerCategory is "string" we compute a hash to generate fixed integer id for the custom category + // the hash is not perfect but it should work in most cases. we can't use sequential numbers because + // categories are updated frequently and the id must be fixed to work in 3rd party apps + if (!int.TryParse(trackerCategory, out var trackerCategoryInt)) + { + var hashed = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(trackerCategory)); + trackerCategoryInt = BitConverter.ToUInt16(hashed, 0); // id between 0 and 65535 < 100000 + } + + var customCat = new IndexerCategory(trackerCategoryInt + 100000, trackerCategoryDesc); + _categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, customCat.Id)); + AddTorznabCategoryTree(customCat); + } + + //public List MapTorznabCapsToTrackers(TorznabQuery query, bool mapChildrenCatsToParent = false) + //{ + // var expandedQueryCats = ExpandTorznabQueryCategories(query, mapChildrenCatsToParent); + // var result = _categoryMapping + // .Where(c => expandedQueryCats.Contains(c.NewzNabCategory)) + // .Select(mapping => mapping.TrackerCategory).Distinct().ToList(); + // return result; + //} + public ICollection MapTrackerCatToNewznab(string trackerCategory) + { + if (string.IsNullOrWhiteSpace(trackerCategory)) + { + return new List(); + } + + var cats = _categoryMapping + .Where(m => + !string.IsNullOrWhiteSpace(m.TrackerCategory) && + string.Equals(m.TrackerCategory, trackerCategory, StringComparison.InvariantCultureIgnoreCase)) + .Select(c => c.NewzNabCategory).ToList(); + return cats; + } + + public ICollection MapTrackerCatDescToNewznab(string trackerCategoryDesc) + { + if (string.IsNullOrWhiteSpace(trackerCategoryDesc)) + { + return new List(); + } + + var cats = _categoryMapping + .Where(m => + !string.IsNullOrWhiteSpace(m.TrackerCategoryDesc) && + string.Equals(m.TrackerCategoryDesc, trackerCategoryDesc, StringComparison.InvariantCultureIgnoreCase)) + .Select(c => c.NewzNabCategory).ToList(); + return cats; + } + + public int[] SupportedCategories(int[] categories) + { + if (categories == null || categories.Length == 0) + { + return Array.Empty(); + } + + var subCategories = _torznabCategoryTree.SelectMany(c => c.SubCategories); + var allCategories = _torznabCategoryTree.Concat(subCategories); + return allCategories.Where(c => categories.Contains(c.Id)).Select(c => c.Id).ToArray(); + } + + public void Concat(IndexerCapabilitiesCategories rhs) + { + // exclude indexer specific categories (>= 100000) + // we don't concat _categoryMapping because it makes no sense for the aggregate indexer + rhs.GetTorznabCategoryList().Where(x => x.Id < 100000).ToList().ForEach(AddTorznabCategoryTree); + } + + //public List ExpandTorznabQueryCategories(TorznabQuery query, bool mapChildrenCatsToParent = false) + //{ + // var expandedQueryCats = new List(); + // foreach (var queryCategory in query.Categories) + // { + // expandedQueryCats.Add(queryCategory); + // if (queryCategory >= 100000) + // { + // continue; + // } + + // var parentCat = _torznabCategoryTree.FirstOrDefault(c => c.Id == queryCategory); + // if (parentCat != null) + // { + // // if it's parent cat we add all the children + // expandedQueryCats.AddRange(parentCat.SubCategories.Select(c => c.Id)); + // } + // else if (mapChildrenCatsToParent) + // { + // // if it's child cat and mapChildrenCatsToParent is enabled we add the parent + // var queryCategoryTorznab = new IndexerCategory(queryCategory, ""); + // parentCat = _torznabCategoryTree.FirstOrDefault(c => c.Contains(queryCategoryTorznab)); + // if (parentCat != null) + // { + // expandedQueryCats.Add(parentCat.Id); + // } + // } + // } + + // return expandedQueryCats.Distinct().ToList(); + //} + private void AddTorznabCategoryTree(IndexerCategory torznabCategory) + { + // build the category tree + if (TorznabCatType.ParentCats.Contains(torznabCategory)) + { + // parent cat + if (!_torznabCategoryTree.Contains(torznabCategory)) + { + _torznabCategoryTree.Add(torznabCategory.CopyWithoutSubCategories()); + } + } + else + { + // child or custom cat + var parentCat = TorznabCatType.ParentCats.FirstOrDefault(c => c.Contains(torznabCategory)); + if (parentCat != null) + { + // child cat + var nodeCat = _torznabCategoryTree.FirstOrDefault(c => c.Equals(parentCat)); + if (nodeCat != null) + { + // parent cat already exists + if (!nodeCat.Contains(torznabCategory)) + { + nodeCat.SubCategories.Add(torznabCategory); + } + } + else + { + // create parent cat and add child + nodeCat = parentCat.CopyWithoutSubCategories(); + nodeCat.SubCategories.Add(torznabCategory); + _torznabCategoryTree.Add(nodeCat); + } + } + else + { + // custom cat + _torznabCategoryTree.Add(torznabCategory); + } + } + } + } +} diff --git a/src/NzbDrone.Core/Indexers/IndexerCatType.cs b/src/NzbDrone.Core/Indexers/IndexerCatType.cs new file mode 100644 index 000000000..c8c7e81cd --- /dev/null +++ b/src/NzbDrone.Core/Indexers/IndexerCatType.cs @@ -0,0 +1,273 @@ +using System.Collections.Generic; +using System.Linq; + +namespace NzbDrone.Core.Indexers +{ + public static class TorznabCatType + { + public static readonly IndexerCategory Console = new IndexerCategory(1000, "Console"); + public static readonly IndexerCategory ConsoleNDS = new IndexerCategory(1010, "Console/NDS"); + public static readonly IndexerCategory ConsolePSP = new IndexerCategory(1020, "Console/PSP"); + public static readonly IndexerCategory ConsoleWii = new IndexerCategory(1030, "Console/Wii"); + public static readonly IndexerCategory ConsoleXBox = new IndexerCategory(1040, "Console/XBox"); + public static readonly IndexerCategory ConsoleXBox360 = new IndexerCategory(1050, "Console/XBox 360"); + public static readonly IndexerCategory ConsoleWiiware = new IndexerCategory(1060, "Console/Wiiware"); + public static readonly IndexerCategory ConsoleXBox360DLC = new IndexerCategory(1070, "Console/XBox 360 DLC"); + public static readonly IndexerCategory ConsolePS3 = new IndexerCategory(1080, "Console/PS3"); + public static readonly IndexerCategory ConsoleOther = new IndexerCategory(1090, "Console/Other"); + public static readonly IndexerCategory Console3DS = new IndexerCategory(1110, "Console/3DS"); + public static readonly IndexerCategory ConsolePSVita = new IndexerCategory(1120, "Console/PS Vita"); + public static readonly IndexerCategory ConsoleWiiU = new IndexerCategory(1130, "Console/WiiU"); + public static readonly IndexerCategory ConsoleXBoxOne = new IndexerCategory(1140, "Console/XBox One"); + public static readonly IndexerCategory ConsolePS4 = new IndexerCategory(1180, "Console/PS4"); + + public static readonly IndexerCategory Movies = new IndexerCategory(2000, "Movies"); + public static readonly IndexerCategory MoviesForeign = new IndexerCategory(2010, "Movies/Foreign"); + public static readonly IndexerCategory MoviesOther = new IndexerCategory(2020, "Movies/Other"); + public static readonly IndexerCategory MoviesSD = new IndexerCategory(2030, "Movies/SD"); + public static readonly IndexerCategory MoviesHD = new IndexerCategory(2040, "Movies/HD"); + public static readonly IndexerCategory MoviesUHD = new IndexerCategory(2045, "Movies/UHD"); + public static readonly IndexerCategory MoviesBluRay = new IndexerCategory(2050, "Movies/BluRay"); + public static readonly IndexerCategory Movies3D = new IndexerCategory(2060, "Movies/3D"); + public static readonly IndexerCategory MoviesDVD = new IndexerCategory(2070, "Movies/DVD"); + public static readonly IndexerCategory MoviesWEBDL = new IndexerCategory(2080, "Movies/WEB-DL"); + + public static readonly IndexerCategory Audio = new IndexerCategory(3000, "Audio"); + public static readonly IndexerCategory AudioMP3 = new IndexerCategory(3010, "Audio/MP3"); + public static readonly IndexerCategory AudioVideo = new IndexerCategory(3020, "Audio/Video"); + public static readonly IndexerCategory AudioAudiobook = new IndexerCategory(3030, "Audio/Audiobook"); + public static readonly IndexerCategory AudioLossless = new IndexerCategory(3040, "Audio/Lossless"); + public static readonly IndexerCategory AudioOther = new IndexerCategory(3050, "Audio/Other"); + public static readonly IndexerCategory AudioForeign = new IndexerCategory(3060, "Audio/Foreign"); + + public static readonly IndexerCategory PC = new IndexerCategory(4000, "PC"); + public static readonly IndexerCategory PC0day = new IndexerCategory(4010, "PC/0day"); + public static readonly IndexerCategory PCISO = new IndexerCategory(4020, "PC/ISO"); + public static readonly IndexerCategory PCMac = new IndexerCategory(4030, "PC/Mac"); + public static readonly IndexerCategory PCMobileOther = new IndexerCategory(4040, "PC/Mobile-Other"); + public static readonly IndexerCategory PCGames = new IndexerCategory(4050, "PC/Games"); + public static readonly IndexerCategory PCMobileiOS = new IndexerCategory(4060, "PC/Mobile-iOS"); + public static readonly IndexerCategory PCMobileAndroid = new IndexerCategory(4070, "PC/Mobile-Android"); + + public static readonly IndexerCategory TV = new IndexerCategory(5000, "TV"); + public static readonly IndexerCategory TVWEBDL = new IndexerCategory(5010, "TV/WEB-DL"); + public static readonly IndexerCategory TVForeign = new IndexerCategory(5020, "TV/Foreign"); + public static readonly IndexerCategory TVSD = new IndexerCategory(5030, "TV/SD"); + public static readonly IndexerCategory TVHD = new IndexerCategory(5040, "TV/HD"); + public static readonly IndexerCategory TVUHD = new IndexerCategory(5045, "TV/UHD"); + public static readonly IndexerCategory TVOther = new IndexerCategory(5050, "TV/Other"); + public static readonly IndexerCategory TVSport = new IndexerCategory(5060, "TV/Sport"); + public static readonly IndexerCategory TVAnime = new IndexerCategory(5070, "TV/Anime"); + public static readonly IndexerCategory TVDocumentary = new IndexerCategory(5080, "TV/Documentary"); + + public static readonly IndexerCategory XXX = new IndexerCategory(6000, "XXX"); + public static readonly IndexerCategory XXXDVD = new IndexerCategory(6010, "XXX/DVD"); + public static readonly IndexerCategory XXXWMV = new IndexerCategory(6020, "XXX/WMV"); + public static readonly IndexerCategory XXXXviD = new IndexerCategory(6030, "XXX/XviD"); + public static readonly IndexerCategory XXXx264 = new IndexerCategory(6040, "XXX/x264"); + public static readonly IndexerCategory XXXUHD = new IndexerCategory(6045, "XXX/UHD"); + public static readonly IndexerCategory XXXPack = new IndexerCategory(6050, "XXX/Pack"); + public static readonly IndexerCategory XXXImageSet = new IndexerCategory(6060, "XXX/ImageSet"); + public static readonly IndexerCategory XXXOther = new IndexerCategory(6070, "XXX/Other"); + public static readonly IndexerCategory XXXSD = new IndexerCategory(6080, "XXX/SD"); + public static readonly IndexerCategory XXXWEBDL = new IndexerCategory(6090, "XXX/WEB-DL"); + + public static readonly IndexerCategory Books = new IndexerCategory(7000, "Books"); + public static readonly IndexerCategory BooksMags = new IndexerCategory(7010, "Books/Mags"); + public static readonly IndexerCategory BooksEBook = new IndexerCategory(7020, "Books/EBook"); + public static readonly IndexerCategory BooksComics = new IndexerCategory(7030, "Books/Comics"); + public static readonly IndexerCategory BooksTechnical = new IndexerCategory(7040, "Books/Technical"); + public static readonly IndexerCategory BooksOther = new IndexerCategory(7050, "Books/Other"); + public static readonly IndexerCategory BooksForeign = new IndexerCategory(7060, "Books/Foreign"); + + public static readonly IndexerCategory Other = new IndexerCategory(8000, "Other"); + public static readonly IndexerCategory OtherMisc = new IndexerCategory(8010, "Other/Misc"); + public static readonly IndexerCategory OtherHashed = new IndexerCategory(8020, "Other/Hashed"); + + public static readonly IndexerCategory[] ParentCats = + { + Console, + Movies, + Audio, + PC, + TV, + XXX, + Books, + Other + }; + + public static readonly IndexerCategory[] AllCats = + { + Console, + ConsoleNDS, + ConsolePSP, + ConsoleWii, + ConsoleXBox, + ConsoleXBox360, + ConsoleWiiware, + ConsoleXBox360DLC, + ConsolePS3, + ConsoleOther, + Console3DS, + ConsolePSVita, + ConsoleWiiU, + ConsoleXBoxOne, + ConsolePS4, + Movies, + MoviesForeign, + MoviesOther, + MoviesSD, + MoviesHD, + MoviesUHD, + MoviesBluRay, + Movies3D, + MoviesDVD, + MoviesWEBDL, + Audio, + AudioMP3, + AudioVideo, + AudioAudiobook, + AudioLossless, + AudioOther, + AudioForeign, + PC, + PC0day, + PCISO, + PCMac, + PCMobileOther, + PCGames, + PCMobileiOS, + PCMobileAndroid, + TV, + TVWEBDL, + TVForeign, + TVSD, + TVHD, + TVUHD, + TVOther, + TVSport, + TVAnime, + TVDocumentary, + XXX, + XXXDVD, + XXXWMV, + XXXXviD, + XXXx264, + XXXUHD, + XXXPack, + XXXImageSet, + XXXOther, + XXXSD, + XXXWEBDL, + Books, + BooksMags, + BooksEBook, + BooksComics, + BooksTechnical, + BooksOther, + BooksForeign, + Other, + OtherMisc, + OtherHashed + }; + + static TorznabCatType() + { + Console.SubCategories.AddRange( + new List + { + ConsoleNDS, + ConsolePSP, + ConsoleWii, + ConsoleXBox, + ConsoleXBox360, + ConsoleWiiware, + ConsoleXBox360DLC, + ConsolePS3, + ConsoleOther, + Console3DS, + ConsolePSVita, + ConsoleWiiU, + ConsoleXBoxOne, + ConsolePS4 + }); + Movies.SubCategories.AddRange( + new List + { + MoviesForeign, + MoviesOther, + MoviesSD, + MoviesHD, + MoviesUHD, + MoviesBluRay, + Movies3D, + MoviesDVD, + MoviesWEBDL + }); + Audio.SubCategories.AddRange( + new List + { + AudioMP3, + AudioVideo, + AudioAudiobook, + AudioLossless, + AudioOther, + AudioForeign + }); + PC.SubCategories.AddRange( + new List + { + PC0day, + PCISO, + PCMac, + PCMobileOther, + PCGames, + PCMobileiOS, + PCMobileAndroid + }); + TV.SubCategories.AddRange( + new List + { + TVWEBDL, + TVForeign, + TVSD, + TVHD, + TVUHD, + TVOther, + TVSport, + TVAnime, + TVDocumentary + }); + XXX.SubCategories.AddRange( + new List + { + XXXDVD, + XXXWMV, + XXXXviD, + XXXx264, + XXXUHD, + XXXPack, + XXXImageSet, + XXXOther, + XXXSD, + XXXWEBDL + }); + Books.SubCategories.AddRange( + new List + { + BooksMags, + BooksEBook, + BooksComics, + BooksTechnical, + BooksOther, + BooksForeign + }); + Other.SubCategories.AddRange(new List { OtherMisc, OtherHashed }); + } + + public static string GetCatDesc(int torznabCatId) => + AllCats.FirstOrDefault(c => c.Id == torznabCatId)?.Name ?? string.Empty; + + public static IndexerCategory GetCatByName(string name) => AllCats.FirstOrDefault(c => c.Name == name); + } +} diff --git a/src/NzbDrone.Core/Indexers/IndexerCategory.cs b/src/NzbDrone.Core/Indexers/IndexerCategory.cs index 3ac8d29eb..d526a101c 100644 --- a/src/NzbDrone.Core/Indexers/IndexerCategory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerCategory.cs @@ -35,5 +35,6 @@ namespace NzbDrone.Core.Indexers // Get Hash code should be calculated off read only properties. // ID is not readonly public override int GetHashCode() => Id; + public IndexerCategory CopyWithoutSubCategories() => new IndexerCategory(Id, Name); } } diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index f3cf51a95..65056caf4 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -53,6 +53,7 @@ namespace NzbDrone.Core.Indexers definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); + MapCardigannCategories(definition, defFile); } } @@ -71,6 +72,7 @@ namespace NzbDrone.Core.Indexers definition.Privacy = defFile.Type == "private" ? IndexerPrivacy.Private : IndexerPrivacy.Public; definition.Capabilities = new IndexerCapabilities(); definition.Capabilities.ParseCardigannSearchModes(defFile.Caps.Modes); + MapCardigannCategories(definition, defFile); } return definition; @@ -81,6 +83,48 @@ namespace NzbDrone.Core.Indexers return base.Active().Where(c => c.Enable).ToList(); } + private void MapCardigannCategories(IndexerDefinition def, CardigannDefinition defFile) + { + if (defFile.Caps.Categories != null) + { + foreach (var category in defFile.Caps.Categories) + { + var cat = TorznabCatType.GetCatByName(category.Value); + + if (cat == null) + { + continue; + } + + def.Capabilities.Categories.AddCategoryMapping(category.Key, cat); + } + } + + if (defFile.Caps.Categorymappings != null) + { + foreach (var categorymapping in defFile.Caps.Categorymappings) + { + IndexerCategory torznabCat = null; + + if (categorymapping.cat != null) + { + torznabCat = TorznabCatType.GetCatByName(categorymapping.cat); + if (torznabCat == null) + { + continue; + } + } + + def.Capabilities.Categories.AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc); + + //if (categorymapping.Default) + //{ + // DefaultCategories.Add(categorymapping.id); + //} + } + } + } + public override IEnumerable GetDefaultDefinitions() { foreach (var provider in _providers)