From 4f5bbcaac9f28e7112c2f781973c7507d9373234 Mon Sep 17 00:00:00 2001 From: da3dsoul Date: Fri, 29 Dec 2023 18:16:47 -0500 Subject: [PATCH] Fix Endpoints for File/id, File Search, ReleaseManagement Series, and Add Filter Name and Group --- .../API/v3/Controllers/FileController.cs | 27 ++++++------- .../API/v3/Controllers/FilterController.cs | 9 ++++- .../ReleaseManagementController.cs | 8 ++-- Shoko.Server/API/v3/Helpers/FilterFactory.cs | 13 ++++--- Shoko.Server/API/v3/Models/Shoko/Filter.cs | 19 +++++++++ Shoko.Server/Extensions/StringExtensions.cs | 39 +++++++++++++++++++ Shoko.Server/Filters/FilterExpression.cs | 4 ++ Shoko.Server/Filters/FilterExpressionGroup.cs | 12 ++++++ .../Filters/Functions/DateAddFunction.cs | 1 + .../Filters/Functions/DateDiffFunction.cs | 1 + .../Filters/Functions/TodayFunction.cs | 1 + .../Filters/Info/HasTMDbLinkExpression.cs | 1 + .../Filters/Info/HasTvDBLinkExpression.cs | 1 + .../Filters/Info/MissingTMDbLinkExpression.cs | 1 + .../Filters/Info/MissingTvDBLinkExpression.cs | 1 + .../Logic/DateTimes/DateEqualsExpression.cs | 1 + .../DateGreaterThanEqualsExpression.cs | 1 + .../DateTimes/DateGreaterThanExpression.cs | 1 + .../DateTimes/DateLessThanEqualsExpression.cs | 1 + .../Logic/DateTimes/DateLessThanExpression.cs | 1 + .../DateTimes/DateNotEqualsExpression.cs | 1 + .../Logic/Expressions/AndExpression.cs | 1 + .../Logic/Expressions/NotExpression.cs | 1 + .../Filters/Logic/Expressions/OrExpression.cs | 1 + .../Logic/Expressions/XorExpression.cs | 1 + .../Logic/Numbers/NumberEqualsExpression.cs | 1 + .../NumberGreaterThanEqualsExpression.cs | 1 + .../Numbers/NumberGreaterThanExpression.cs | 1 + .../Numbers/NumberLessThanEqualsExpression.cs | 1 + .../Logic/Numbers/NumberLessThanExpression.cs | 1 + .../Numbers/NumberNotEqualsExpression.cs | 1 + .../Logic/Strings/StringContainsExpression.cs | 1 + .../Logic/Strings/StringEndsWithExpression.cs | 1 + .../Logic/Strings/StringEqualsExpression.cs | 1 + .../Strings/StringFuzzyMatchesExpression.cs | 1 + .../Strings/StringNotEqualsExpression.cs | 1 + .../Strings/StringRegexMatchesExpression.cs | 1 + .../Strings/StringStartsWithExpression.cs | 1 + .../DateSelectors/AddedDateSelector.cs | 1 + .../DateSelectors/AirDateSelector.cs | 1 + .../DateSelectors/LastAddedDateSelector.cs | 1 + .../DateSelectors/LastAirDateSelector.cs | 1 + .../DateSelectors/LastWatchedDateSelector.cs | 1 + .../DateSelectors/WatchedDateSelector.cs | 1 + .../AudioLanguageCountSelector.cs | 1 + .../AverageAniDBRatingSelector.cs | 1 + .../NumberSelectors/EpisodeCountSelector.cs | 1 + .../HighestAniDBRatingSelector.cs | 1 + .../HighestUserRatingSelector.cs | 1 + .../LowestAniDBRatingSelector.cs | 1 + .../LowestUserRatingSelector.cs | 1 + .../MissingEpisodeCollectingCountSelector.cs | 1 + .../MissingEpisodeCountSelector.cs | 1 + .../NumberSelectors/SeriesCountSelector.cs | 1 + .../SubtitleLanguageCountSelector.cs | 1 + .../TotalEpisodeCountSelector.cs | 1 + .../UnwatchedEpisodeCountSelector.cs | 1 + .../WatchedEpisodeCountSelector.cs | 1 + .../StringSelectors/FilePathSelector.cs | 1 + .../Selectors/StringSelectors/NameSelector.cs | 1 + .../Cached/AnimeSeriesRepository.cs | 4 +- 61 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 Shoko.Server/Filters/FilterExpressionGroup.cs diff --git a/Shoko.Server/API/v3/Controllers/FileController.cs b/Shoko.Server/API/v3/Controllers/FileController.cs index 864da2ecd..d370819e7 100644 --- a/Shoko.Server/API/v3/Controllers/FileController.cs +++ b/Shoko.Server/API/v3/Controllers/FileController.cs @@ -103,16 +103,12 @@ public ActionResult> Search([FromRoute] string query, [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet includeDataFrom = null, [FromQuery] bool fuzzy = true) { - var enumerable = ModelHelper.FilterFiles(RepoFactory.VideoLocal.GetAll(), User, pageSize, page, include, exclude, include_only, sortOrder, - includeDataFrom).List; - // Search. - var searched = enumerable - .Search(query, tuple => tuple.Locations.Select(place => place.AbsolutePath).Where(path => path != null), fuzzy) - .Select(result => result.Result); - - // Skip and limit. - return searched.ToListResult(page, pageSize); + var searched = RepoFactory.VideoLocal.GetAll() + .Search(query, tuple => tuple.Places.Select(place => place?.FilePath).Where(path => path != null), fuzzy) + .Select(result => result.Result).Skip((page-1)*pageSize).Take(pageSize).ToList(); + return ModelHelper.FilterFiles(searched, User, pageSize, page, include, exclude, include_only, sortOrder, + includeDataFrom); } /// @@ -161,21 +157,20 @@ public ActionResult DeleteFiles([FromBody] File.Input.BatchDeleteBody body = nul /// Get File Details /// /// Shoko VideoLocalID - /// Set to true to include series and episode cross-references. + /// Include items that are not included by default /// Include data from selected s. - /// Include media info data. - /// Include absolute paths for the file locations. /// [HttpGet("{fileID}")] - public ActionResult GetFile([FromRoute] int fileID, [FromQuery] bool includeXRefs = false, - [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet includeDataFrom = null, - [FromQuery] bool includeMediaInfo = false, [FromQuery] bool includeAbsolutePaths = false) + public ActionResult GetFile([FromRoute] int fileID, [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] FileNonDefaultIncludeType[] include = default, + [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet includeDataFrom = null) { var file = RepoFactory.VideoLocal.GetByID(fileID); if (file == null) return NotFound(FileNotFoundWithFileID); - return new File(HttpContext, file, includeXRefs, includeDataFrom, includeMediaInfo, includeAbsolutePaths); + include ??= Array.Empty(); + return new File(HttpContext, file, include.Contains(FileNonDefaultIncludeType.XRefs), includeDataFrom, + include.Contains(FileNonDefaultIncludeType.MediaInfo), include.Contains(FileNonDefaultIncludeType.AbsolutePaths)); } /// diff --git a/Shoko.Server/API/v3/Controllers/FilterController.cs b/Shoko.Server/API/v3/Controllers/FilterController.cs index b300541be..e41148c7a 100644 --- a/Shoko.Server/API/v3/Controllers/FilterController.cs +++ b/Shoko.Server/API/v3/Controllers/FilterController.cs @@ -10,6 +10,7 @@ using Shoko.Server.API.v3.Helpers; using Shoko.Server.API.v3.Models.Common; using Shoko.Server.API.v3.Models.Shoko; +using Shoko.Server.Extensions; using Shoko.Server.Filters; using Shoko.Server.Filters.Interfaces; using Shoko.Server.Models; @@ -150,7 +151,9 @@ public ActionResult AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b }; return new Filter.FilterExpressionHelp { - Expression = a.Name.Replace("Expression", "").Replace("Function", ""), + Expression = a.Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim(), + Name = expression.Name, + Group = expression.Group, Description = expression.HelpDescription, PossibleParameters = expression.HelpPossibleParameters, PossibleSecondParameters = expression.HelpPossibleSecondParameters, @@ -186,7 +189,9 @@ public ActionResult AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b if (criteria == null) return null; return new Filter.SortingCriteriaHelp { - Type = a.Name.Replace("SortingSelector", ""), Description = criteria.HelpDescription + Type = a.Name.TrimEnd("SortingSelector").Trim(), + Name = criteria.Name, + Description = criteria.HelpDescription }; }).Where(a => a != null).ToArray(); return _sortingTypes; diff --git a/Shoko.Server/API/v3/Controllers/ReleaseManagementController.cs b/Shoko.Server/API/v3/Controllers/ReleaseManagementController.cs index 36d49076f..2c2fd447c 100644 --- a/Shoko.Server/API/v3/Controllers/ReleaseManagementController.cs +++ b/Shoko.Server/API/v3/Controllers/ReleaseManagementController.cs @@ -63,7 +63,7 @@ public ActionResult> GetSeriesWithM /// [HttpGet("Series/{seriesID}")] public ActionResult> GetEpisodesForSeries( - int seriesID, + [FromRoute] int seriesID, [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet includeDataFrom = null, [FromQuery] bool includeFiles = true, [FromQuery] bool includeMediaInfo = true, @@ -79,7 +79,7 @@ public ActionResult> GetEpisodesForSeries( if (!User.AllowedSeries(series)) return new ListResult(); - IEnumerable enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations); + IEnumerable enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID); return enumerable .ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths), page, pageSize); @@ -121,7 +121,7 @@ public ActionResult> GetEpisodes( /// [HttpGet("Series/{seriesID}/Episode/FilesToDelete")] public ActionResult> GetFileIdsWithPreference( - int seriesID, + [FromRoute] int seriesID, [FromQuery] bool ignoreVariations = true ) { @@ -132,7 +132,7 @@ public ActionResult> GetFileIdsWithPreference( if (!User.AllowedSeries(series)) return new List(); - IEnumerable enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations); + IEnumerable enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID); return enumerable .SelectMany(episode => diff --git a/Shoko.Server/API/v3/Helpers/FilterFactory.cs b/Shoko.Server/API/v3/Helpers/FilterFactory.cs index d43809b52..656f0e6e8 100644 --- a/Shoko.Server/API/v3/Helpers/FilterFactory.cs +++ b/Shoko.Server/API/v3/Helpers/FilterFactory.cs @@ -7,6 +7,7 @@ using Shoko.Commons.Extensions; using Shoko.Models.Enums; using Shoko.Server.API.v3.Models.Shoko; +using Shoko.Server.Extensions; using Shoko.Server.Filters; using Shoko.Server.Filters.Interfaces; using Shoko.Server.Models; @@ -28,11 +29,11 @@ public FilterFactory(IHttpContextAccessor context, FilterEvaluator evaluator) _expressionTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) .Where(a => a != typeof(FilterExpression) && !a.IsGenericType && typeof(FilterExpression).IsAssignableFrom(a) && - !typeof(SortingExpression).IsAssignableFrom(a)).ToDictionary(a => a.Name.Replace("Expression", "").Replace("Function", "").Replace("Selector", "")); + !typeof(SortingExpression).IsAssignableFrom(a)).ToDictionary(a => a.Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector")); _sortingTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) .Where(a => a != typeof(FilterExpression) && !a.IsAbstract && !a.IsGenericType && typeof(SortingExpression).IsAssignableFrom(a)) - .ToDictionary(a => a.Name.Replace("SortingSelector", "")); + .ToDictionary(a => a.Name.TrimEnd("SortingSelector")); } public Filter GetFilter(FilterPreset groupFilter, bool fullModel = false) @@ -101,7 +102,7 @@ public Filter.FilterCondition GetExpressionTree(FilterExpression expression) if (expression is null) return null; var result = new Filter.FilterCondition { - Type = expression.GetType().Name.Replace("Expression", "").Replace("Function", "").Replace("Selector", "") + Type = expression.GetType().Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim() }; // Left/First @@ -164,7 +165,7 @@ public Filter.FilterCondition GetExpressionTree(FilterExpression expression) public FilterExpression GetExpressionTree(Filter.FilterCondition condition) { if (condition is null) return null; - if (!_expressionTypes.TryGetValue(condition.Type.Replace("Expression", "").Replace("Function", "").Replace("Selector", ""), out var type)) + if (!_expressionTypes.TryGetValue(condition.Type.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim(), out var type)) throw new ArgumentException($"FilterCondition type {condition.Type} was not found"); var result = (FilterExpression)Activator.CreateInstance(type); @@ -235,7 +236,7 @@ public Filter.SortingCriteria GetSortingCriteria(SortingExpression expression) var result = new Filter.SortingCriteria { - Type = expression.GetType().Name.Replace("SortingSelector", ""), + Type = expression.GetType().Name.TrimEnd("SortingSelector"), IsInverted = expression.Descending }; @@ -245,7 +246,7 @@ public Filter.SortingCriteria GetSortingCriteria(SortingExpression expression) { currentCriteria.Next = new Filter.SortingCriteria { - Type = currentExpression.GetType().Name.Replace("SortingSelector", ""), + Type = currentExpression.GetType().Name.TrimEnd("SortingSelector"), IsInverted = currentExpression.Descending }; currentCriteria = currentCriteria.Next; diff --git a/Shoko.Server/API/v3/Models/Shoko/Filter.cs b/Shoko.Server/API/v3/Models/Shoko/Filter.cs index 6a246ec9a..b8ebdbc5a 100644 --- a/Shoko.Server/API/v3/Models/Shoko/Filter.cs +++ b/Shoko.Server/API/v3/Models/Shoko/Filter.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Shoko.Server.API.v3.Models.Common; +using Shoko.Server.Filters; // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -116,6 +117,18 @@ public class FilterExpressionHelp /// [Required] public string Expression { get; init; } + + /// + /// The human readable name of the Expression + /// + [Required] + public string Name { get; init; } + + /// + /// The group that this filter expression belongs to. This can help with filtering the expression types + /// + [Required] + public FilterExpressionGroup Group { get; init; } /// /// A description of what the expression is doing, comparing, etc @@ -214,6 +227,12 @@ public class SortingCriteriaHelp [Required] public string Type { get; init; } + /// + /// Human readable name + /// + [Required] + public string Name { get; set; } + /// /// A description of what the expression is doing, comparing, etc /// diff --git a/Shoko.Server/Extensions/StringExtensions.cs b/Shoko.Server/Extensions/StringExtensions.cs index 88b6227a8..7dab5ba79 100644 --- a/Shoko.Server/Extensions/StringExtensions.cs +++ b/Shoko.Server/Extensions/StringExtensions.cs @@ -75,4 +75,43 @@ public static bool EqualsInvariantIgnoreCase(this string value1, string value2) { return value1.Equals(value2, StringComparison.InvariantCultureIgnoreCase); } + + public static string CamelCaseToNatural(this string text, bool preserveAcronyms=true) + { + if (string.IsNullOrWhiteSpace(text)) + return string.Empty; + StringBuilder newText = new StringBuilder(text.Length * 2); + newText.Append(text[0]); + for (int i = 1; i < text.Length; i++) + { + if (char.IsUpper(text[i])) + if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) || + (preserveAcronyms && char.IsUpper(text[i - 1]) && + i < text.Length - 1 && !char.IsUpper(text[i + 1]))) + newText.Append(' '); + newText.Append(text[i]); + } + return newText.ToString(); + } + + public static string TrimStart(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase) + { + if (string.IsNullOrEmpty(value)) return inputText; + while (!string.IsNullOrEmpty(inputText) && inputText.StartsWith(value, comparisonType)) inputText = inputText[(value.Length - 1)..]; + + return inputText; + } + + public static string TrimEnd(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase) + { + if (string.IsNullOrEmpty(value)) return inputText; + while (!string.IsNullOrEmpty(inputText) && inputText.EndsWith(value, comparisonType)) inputText = inputText[..^value.Length]; + + return inputText; + } + + public static string Trim(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase) + { + return TrimStart(TrimEnd(inputText, value, comparisonType), value, comparisonType); + } } diff --git a/Shoko.Server/Filters/FilterExpression.cs b/Shoko.Server/Filters/FilterExpression.cs index 5b34636e3..cc76e4488 100644 --- a/Shoko.Server/Filters/FilterExpression.cs +++ b/Shoko.Server/Filters/FilterExpression.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.Serialization; using Newtonsoft.Json; +using Shoko.Server.Extensions; using Shoko.Server.Filters.Interfaces; namespace Shoko.Server.Filters; @@ -9,6 +10,9 @@ public class FilterExpression : IFilterExpression { [IgnoreDataMember] [JsonIgnore] public virtual bool TimeDependent => false; [IgnoreDataMember] [JsonIgnore] public virtual bool UserDependent => false; + [IgnoreDataMember] [JsonIgnore] public virtual string Name => + GetType().Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("SortingSelector").TrimEnd("Selector").CamelCaseToNatural(); + [IgnoreDataMember] [JsonIgnore] public virtual FilterExpressionGroup Group => FilterExpressionGroup.Info; [IgnoreDataMember] [JsonIgnore] public virtual string HelpDescription => string.Empty; [IgnoreDataMember] [JsonIgnore] public virtual string[] HelpPossibleParameters => Array.Empty(); [IgnoreDataMember] [JsonIgnore] public virtual string[] HelpPossibleSecondParameters => Array.Empty(); diff --git a/Shoko.Server/Filters/FilterExpressionGroup.cs b/Shoko.Server/Filters/FilterExpressionGroup.cs new file mode 100644 index 000000000..ead58fe42 --- /dev/null +++ b/Shoko.Server/Filters/FilterExpressionGroup.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +namespace Shoko.Server.Filters; + +[JsonConverter(typeof(StringEnumConverter))] +public enum FilterExpressionGroup +{ + Info, + Logic, + Function, + Selector +} diff --git a/Shoko.Server/Filters/Functions/DateAddFunction.cs b/Shoko.Server/Filters/Functions/DateAddFunction.cs index 9e18c919b..cd3dd645b 100644 --- a/Shoko.Server/Filters/Functions/DateAddFunction.cs +++ b/Shoko.Server/Filters/Functions/DateAddFunction.cs @@ -21,6 +21,7 @@ public DateAddFunction(FilterExpression selector, TimeSpan parameter) public override bool TimeDependent => Selector.TimeDependent; public override bool UserDependent => Selector.UserDependent; public override string HelpDescription => "This adds a timespan to a date selector"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Function; public FilterExpression Left { diff --git a/Shoko.Server/Filters/Functions/DateDiffFunction.cs b/Shoko.Server/Filters/Functions/DateDiffFunction.cs index 21fdfac0d..14a84e450 100644 --- a/Shoko.Server/Filters/Functions/DateDiffFunction.cs +++ b/Shoko.Server/Filters/Functions/DateDiffFunction.cs @@ -18,6 +18,7 @@ public DateDiffFunction() { } public override bool TimeDependent => Selector.TimeDependent; public override bool UserDependent => Selector.UserDependent; public override string HelpDescription => "This subtracts a timespan from a date selector."; + public override FilterExpressionGroup Group => FilterExpressionGroup.Function; public FilterExpression Left { diff --git a/Shoko.Server/Filters/Functions/TodayFunction.cs b/Shoko.Server/Filters/Functions/TodayFunction.cs index 99913de5f..9450990ea 100644 --- a/Shoko.Server/Filters/Functions/TodayFunction.cs +++ b/Shoko.Server/Filters/Functions/TodayFunction.cs @@ -8,6 +8,7 @@ public class TodayFunction : FilterExpression public override bool TimeDependent => true; public override bool UserDependent => false; public override string HelpDescription => "This returns the current date, at midnight (00:00:00.0000)"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Function; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Info/HasTMDbLinkExpression.cs b/Shoko.Server/Filters/Info/HasTMDbLinkExpression.cs index 112966d92..c20dce8e1 100644 --- a/Shoko.Server/Filters/Info/HasTMDbLinkExpression.cs +++ b/Shoko.Server/Filters/Info/HasTMDbLinkExpression.cs @@ -6,6 +6,7 @@ public class HasTMDbLinkExpression : FilterExpression { public override bool TimeDependent => false; public override bool UserDependent => false; + public override string Name => "Has TMDb Link"; public override string HelpDescription => "This passes if any of the anime have a TMDb link"; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) diff --git a/Shoko.Server/Filters/Info/HasTvDBLinkExpression.cs b/Shoko.Server/Filters/Info/HasTvDBLinkExpression.cs index e6c8233eb..fee9e112a 100644 --- a/Shoko.Server/Filters/Info/HasTvDBLinkExpression.cs +++ b/Shoko.Server/Filters/Info/HasTvDBLinkExpression.cs @@ -6,6 +6,7 @@ public class HasTvDBLinkExpression : FilterExpression { public override bool TimeDependent => false; public override bool UserDependent => false; + public override string Name => "Has TvDB Link"; public override string HelpDescription => "This passes if any of the anime have a TvDB link"; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) diff --git a/Shoko.Server/Filters/Info/MissingTMDbLinkExpression.cs b/Shoko.Server/Filters/Info/MissingTMDbLinkExpression.cs index 403a0d806..03ac82967 100644 --- a/Shoko.Server/Filters/Info/MissingTMDbLinkExpression.cs +++ b/Shoko.Server/Filters/Info/MissingTMDbLinkExpression.cs @@ -9,6 +9,7 @@ public class MissingTMDbLinkExpression : FilterExpression { public override bool TimeDependent => false; public override bool UserDependent => false; + public override string Name => "Missing TMDb Link"; public override string HelpDescription => "This passes if any of the anime should have a TMDb link but does not have one"; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) diff --git a/Shoko.Server/Filters/Info/MissingTvDBLinkExpression.cs b/Shoko.Server/Filters/Info/MissingTvDBLinkExpression.cs index fc1a8d6f4..8ed39582e 100644 --- a/Shoko.Server/Filters/Info/MissingTvDBLinkExpression.cs +++ b/Shoko.Server/Filters/Info/MissingTvDBLinkExpression.cs @@ -9,6 +9,7 @@ public class MissingTvDBLinkExpression : FilterExpression { public override bool TimeDependent => false; public override bool UserDependent => false; + public override string Name => "Missing TvDB Link"; public override string HelpDescription => "This passes if any of the anime should have a TvDB link but does not have one"; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateEqualsExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateEqualsExpression.cs index 8dc7c2832..aeb847d11 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateEqualsExpression.cs @@ -23,6 +23,7 @@ public DateEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector equals either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanEqualsExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanEqualsExpression.cs index 4cffdb7a0..15d876df7 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanEqualsExpression.cs @@ -23,6 +23,7 @@ public DateGreaterThanEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is greater than or equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanExpression.cs index 2cea49924..404dfe544 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateGreaterThanExpression.cs @@ -23,6 +23,7 @@ public DateGreaterThanExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is greater than either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateLessThanEqualsExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateLessThanEqualsExpression.cs index 0c658c310..16a3c28be 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateLessThanEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateLessThanEqualsExpression.cs @@ -23,6 +23,7 @@ public DateLessThanEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is less than or equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateLessThanExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateLessThanExpression.cs index be2ec39f2..ade34b4be 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateLessThanExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateLessThanExpression.cs @@ -23,6 +23,7 @@ public DateLessThanExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is less than either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/DateTimes/DateNotEqualsExpression.cs b/Shoko.Server/Filters/Logic/DateTimes/DateNotEqualsExpression.cs index 8de1bea2c..ed90a8ffb 100644 --- a/Shoko.Server/Filters/Logic/DateTimes/DateNotEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/DateTimes/DateNotEqualsExpression.cs @@ -23,6 +23,7 @@ public DateNotEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is not equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Expressions/AndExpression.cs b/Shoko.Server/Filters/Logic/Expressions/AndExpression.cs index ce6fd6644..db944db5e 100644 --- a/Shoko.Server/Filters/Logic/Expressions/AndExpression.cs +++ b/Shoko.Server/Filters/Logic/Expressions/AndExpression.cs @@ -16,6 +16,7 @@ public AndExpression() { } public override bool TimeDependent => Left.TimeDependent || Right.TimeDependent; public override bool UserDependent => Left.UserDependent || Right.UserDependent; public override string HelpDescription => "This passes if both the left expression and the right expression pass"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public FilterExpression Left { get; set; } public FilterExpression Right { get; set; } diff --git a/Shoko.Server/Filters/Logic/Expressions/NotExpression.cs b/Shoko.Server/Filters/Logic/Expressions/NotExpression.cs index bb8f8669d..4db19eb01 100644 --- a/Shoko.Server/Filters/Logic/Expressions/NotExpression.cs +++ b/Shoko.Server/Filters/Logic/Expressions/NotExpression.cs @@ -14,6 +14,7 @@ public NotExpression() { } public override bool TimeDependent => Left.TimeDependent; public override bool UserDependent => Left.UserDependent; public override string HelpDescription => "This passes if the left expression does not pass, e.g. an inverse"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public FilterExpression Left { get; set; } diff --git a/Shoko.Server/Filters/Logic/Expressions/OrExpression.cs b/Shoko.Server/Filters/Logic/Expressions/OrExpression.cs index 143f41c2f..1cbe978ca 100644 --- a/Shoko.Server/Filters/Logic/Expressions/OrExpression.cs +++ b/Shoko.Server/Filters/Logic/Expressions/OrExpression.cs @@ -16,6 +16,7 @@ public OrExpression() { } public override bool TimeDependent => Left.TimeDependent || Right.TimeDependent; public override bool UserDependent => Left.UserDependent || Right.UserDependent; public override string HelpDescription => "This passes if either the left expression or the right expression pass"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public FilterExpression Left { get; set; } public FilterExpression Right { get; set; } diff --git a/Shoko.Server/Filters/Logic/Expressions/XorExpression.cs b/Shoko.Server/Filters/Logic/Expressions/XorExpression.cs index b9c7ec2b6..4637de604 100644 --- a/Shoko.Server/Filters/Logic/Expressions/XorExpression.cs +++ b/Shoko.Server/Filters/Logic/Expressions/XorExpression.cs @@ -16,6 +16,7 @@ public XorExpression() { } public override bool TimeDependent => Left.TimeDependent || Right.TimeDependent; public override bool UserDependent => Left.UserDependent || Right.UserDependent; public override string HelpDescription => "This passes if either the left expression or the right expression pass, but not both"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public FilterExpression Left { get; set; } public FilterExpression Right { get; set; } diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberEqualsExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberEqualsExpression.cs index beed27834..ebd72f79d 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberEqualsExpression.cs @@ -23,6 +23,7 @@ public NumberEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector equals either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanEqualsExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanEqualsExpression.cs index c28cdc34a..23240de83 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanEqualsExpression.cs @@ -23,6 +23,7 @@ public NumberGreaterThanEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is greater than or equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanExpression.cs index 9b9ab6a46..5fc31eac6 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberGreaterThanExpression.cs @@ -23,6 +23,7 @@ public NumberGreaterThanExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is greater than either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberLessThanEqualsExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberLessThanEqualsExpression.cs index 94e5f12e5..c117bf5a6 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberLessThanEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberLessThanEqualsExpression.cs @@ -23,6 +23,7 @@ public NumberLessThanEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is less than or equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberLessThanExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberLessThanExpression.cs index 8c240f552..fcfac65cc 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberLessThanExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberLessThanExpression.cs @@ -23,6 +23,7 @@ public NumberLessThanExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is less than either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Numbers/NumberNotEqualsExpression.cs b/Shoko.Server/Filters/Logic/Numbers/NumberNotEqualsExpression.cs index 68c7c36a4..b2dd788bd 100644 --- a/Shoko.Server/Filters/Logic/Numbers/NumberNotEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Numbers/NumberNotEqualsExpression.cs @@ -23,6 +23,7 @@ public NumberNotEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is not equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringContainsExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringContainsExpression.cs index 746da9593..c367d0690 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringContainsExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringContainsExpression.cs @@ -25,6 +25,7 @@ public StringContainsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector contains either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringEndsWithExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringEndsWithExpression.cs index 6d3df779a..edefad8f4 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringEndsWithExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringEndsWithExpression.cs @@ -25,6 +25,7 @@ public StringEndsWithExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector ends with either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringEqualsExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringEqualsExpression.cs index e8f47fb80..06a49e4e6 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringEqualsExpression.cs @@ -23,6 +23,7 @@ public StringEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector equals either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringFuzzyMatchesExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringFuzzyMatchesExpression.cs index b501f35e0..02cd1330d 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringFuzzyMatchesExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringFuzzyMatchesExpression.cs @@ -26,6 +26,7 @@ public StringFuzzyMatchesExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector fuzzy matches either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringNotEqualsExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringNotEqualsExpression.cs index 60dbd5f43..c1245b241 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringNotEqualsExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringNotEqualsExpression.cs @@ -23,6 +23,7 @@ public StringNotEqualsExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector is not equal to either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringRegexMatchesExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringRegexMatchesExpression.cs index 59cb8cddf..6cc6242f6 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringRegexMatchesExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringRegexMatchesExpression.cs @@ -25,6 +25,7 @@ public StringRegexMatchesExpression() { } public override bool TimeDependent => Left.TimeDependent; public override bool UserDependent => Left.UserDependent; public override string HelpDescription => "This passes if the left selector matches the regular expression given in the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Logic/Strings/StringStartsWithExpression.cs b/Shoko.Server/Filters/Logic/Strings/StringStartsWithExpression.cs index e63ef5633..8db5cfec5 100644 --- a/Shoko.Server/Filters/Logic/Strings/StringStartsWithExpression.cs +++ b/Shoko.Server/Filters/Logic/Strings/StringStartsWithExpression.cs @@ -25,6 +25,7 @@ public StringStartsWithExpression() { } public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false); public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false); public override string HelpDescription => "This passes if the left selector starts with either the right selector or the parameter"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Logic; public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/AddedDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/AddedDateSelector.cs index a80926ff7..0f926e1bf 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/AddedDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/AddedDateSelector.cs @@ -8,6 +8,7 @@ public class AddedDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the date that a filterable was created"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/AirDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/AirDateSelector.cs index 4ce434ac8..fd2f5ecd2 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/AirDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/AirDateSelector.cs @@ -8,6 +8,7 @@ public class AirDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the first date that a filterable aired"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/LastAddedDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/LastAddedDateSelector.cs index 5134c9dd9..5572869da 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/LastAddedDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/LastAddedDateSelector.cs @@ -8,6 +8,7 @@ public class LastAddedDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the last date that any episode was added in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/LastAirDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/LastAirDateSelector.cs index 5b5951528..a1bfb6f06 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/LastAirDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/LastAirDateSelector.cs @@ -8,6 +8,7 @@ public class LastAirDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the last date that a filterable aired"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/LastWatchedDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/LastWatchedDateSelector.cs index 7b59f19db..081cbab7d 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/LastWatchedDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/LastWatchedDateSelector.cs @@ -8,6 +8,7 @@ public class LastWatchedDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the last date that a filterable was watched by the current user"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/DateSelectors/WatchedDateSelector.cs b/Shoko.Server/Filters/Selectors/DateSelectors/WatchedDateSelector.cs index 4e712ec69..3fa05072d 100644 --- a/Shoko.Server/Filters/Selectors/DateSelectors/WatchedDateSelector.cs +++ b/Shoko.Server/Filters/Selectors/DateSelectors/WatchedDateSelector.cs @@ -8,6 +8,7 @@ public class WatchedDateSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the first date that a filterable was watched by the current user"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/AudioLanguageCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/AudioLanguageCountSelector.cs index 44455615b..91473bfe4 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/AudioLanguageCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/AudioLanguageCountSelector.cs @@ -7,6 +7,7 @@ public class AudioLanguageCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns how many distinct audio languages are present in all of the files in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/AverageAniDBRatingSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/AverageAniDBRatingSelector.cs index dbf4d9a00..1a7364ee4 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/AverageAniDBRatingSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/AverageAniDBRatingSelector.cs @@ -8,6 +8,7 @@ public class AverageAniDBRatingSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the average AniDB rating in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/EpisodeCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/EpisodeCountSelector.cs index 18d2334a8..64bd387d4 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/EpisodeCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/EpisodeCountSelector.cs @@ -7,6 +7,7 @@ public class EpisodeCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the total number of episodes in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/HighestAniDBRatingSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/HighestAniDBRatingSelector.cs index fb288da73..bdc13c459 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/HighestAniDBRatingSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/HighestAniDBRatingSelector.cs @@ -8,6 +8,7 @@ public class HighestAniDBRatingSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the highest AniDB rating in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/HighestUserRatingSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/HighestUserRatingSelector.cs index ac016a733..0372de366 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/HighestUserRatingSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/HighestUserRatingSelector.cs @@ -8,6 +8,7 @@ public class HighestUserRatingSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the highest user rating in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/LowestAniDBRatingSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/LowestAniDBRatingSelector.cs index 637cef7f5..8d6d6e705 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/LowestAniDBRatingSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/LowestAniDBRatingSelector.cs @@ -8,6 +8,7 @@ public class LowestAniDBRatingSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the lowest AniDB rating in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/LowestUserRatingSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/LowestUserRatingSelector.cs index e12718c4c..06ba99011 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/LowestUserRatingSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/LowestUserRatingSelector.cs @@ -8,6 +8,7 @@ public class LowestUserRatingSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the lowest user rating in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCollectingCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCollectingCountSelector.cs index 020090126..c27280fb3 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCollectingCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCollectingCountSelector.cs @@ -7,6 +7,7 @@ public class MissingEpisodeCollectingCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the number of missing episodes in a filterable that are from a release group that is already in the filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCountSelector.cs index 1c90e4476..ef0f88593 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/MissingEpisodeCountSelector.cs @@ -7,6 +7,7 @@ public class MissingEpisodeCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the number of missing episodes from any release group in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/SeriesCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/SeriesCountSelector.cs index d2a29a603..ebfb37778 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/SeriesCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/SeriesCountSelector.cs @@ -7,6 +7,7 @@ public class SeriesCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the number of series in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/SubtitleLanguageCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/SubtitleLanguageCountSelector.cs index d54b7c92e..1ec2d667c 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/SubtitleLanguageCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/SubtitleLanguageCountSelector.cs @@ -7,6 +7,7 @@ public class SubtitleLanguageCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns how many distinct subtitle languages are present in all of the files in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/TotalEpisodeCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/TotalEpisodeCountSelector.cs index ab051b5f4..fd3088035 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/TotalEpisodeCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/TotalEpisodeCountSelector.cs @@ -7,6 +7,7 @@ public class TotalEpisodeCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the total number of episodes in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/UnwatchedEpisodeCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/UnwatchedEpisodeCountSelector.cs index 406e52b69..c3cb1859d 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/UnwatchedEpisodeCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/UnwatchedEpisodeCountSelector.cs @@ -8,6 +8,7 @@ public class UnwatchedEpisodeCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the number of episodes in a filterable that have not been watched by the current user"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/NumberSelectors/WatchedEpisodeCountSelector.cs b/Shoko.Server/Filters/Selectors/NumberSelectors/WatchedEpisodeCountSelector.cs index f8c4f7374..87f4772eb 100644 --- a/Shoko.Server/Filters/Selectors/NumberSelectors/WatchedEpisodeCountSelector.cs +++ b/Shoko.Server/Filters/Selectors/NumberSelectors/WatchedEpisodeCountSelector.cs @@ -8,6 +8,7 @@ public class WatchedEpisodeCountSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => true; public override string HelpDescription => "This returns the number of episodes in a filterable that have been watched by the current user"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override double Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/StringSelectors/FilePathSelector.cs b/Shoko.Server/Filters/Selectors/StringSelectors/FilePathSelector.cs index d74805e8d..ddc69e234 100644 --- a/Shoko.Server/Filters/Selectors/StringSelectors/FilePathSelector.cs +++ b/Shoko.Server/Filters/Selectors/StringSelectors/FilePathSelector.cs @@ -7,6 +7,7 @@ public class FilePathSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns a comma separated list of the file paths in a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override string Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Filters/Selectors/StringSelectors/NameSelector.cs b/Shoko.Server/Filters/Selectors/StringSelectors/NameSelector.cs index ba14193a3..209fa40ab 100644 --- a/Shoko.Server/Filters/Selectors/StringSelectors/NameSelector.cs +++ b/Shoko.Server/Filters/Selectors/StringSelectors/NameSelector.cs @@ -7,6 +7,7 @@ public class NameSelector : FilterExpression public override bool TimeDependent => false; public override bool UserDependent => false; public override string HelpDescription => "This returns the name of a filterable"; + public override FilterExpressionGroup Group => FilterExpressionGroup.Selector; public override string Evaluate(IFilterable filterable, IFilterableUserInfo userInfo) { diff --git a/Shoko.Server/Repositories/Cached/AnimeSeriesRepository.cs b/Shoko.Server/Repositories/Cached/AnimeSeriesRepository.cs index 89f5fd9da..63796df1e 100644 --- a/Shoko.Server/Repositories/Cached/AnimeSeriesRepository.cs +++ b/Shoko.Server/Repositories/Cached/AnimeSeriesRepository.cs @@ -327,9 +327,9 @@ public List GetMostRecentlyAdded(int maxResults, int userID) } private const string IgnoreVariationsQuery = - @"SELECT ani.AnimeID FROM VideoLocal AS vl JOIN CrossRef_File_Episode ani ON vl.Hash = ani.Hash WHERE vl.IsVariation = 0 AND vl.Hash != '' GROUP BY ani.EpisodeID HAVING COUNT(ani.EpisodeID) > 1"; + @"SELECT DISTINCT ani.AnimeID FROM VideoLocal AS vl JOIN CrossRef_File_Episode ani ON vl.Hash = ani.Hash WHERE vl.IsVariation = 0 AND vl.Hash != '' GROUP BY ani.AnimeID, ani.EpisodeID HAVING COUNT(ani.EpisodeID) > 1"; private const string CountVariationsQuery = - @"SELECT ani.AnimeID FROM VideoLocal AS vl JOIN CrossRef_File_Episode ani ON vl.Hash = ani.Hash WHERE vl.Hash != '' GROUP BY ani.EpisodeID HAVING COUNT(ani.EpisodeID) > 1"; + @"SELECT DISTINCT ani.AnimeID FROM VideoLocal AS vl JOIN CrossRef_File_Episode ani ON vl.Hash = ani.Hash WHERE vl.Hash != '' GROUP BY ani.AnimeID, ani.EpisodeID HAVING COUNT(ani.EpisodeID) > 1"; public List GetWithMultipleReleases(bool ignoreVariations) {