/// <summary> /// Combines the <paramref name="currentFilter"/> with a <see cref="RelationshipFilter"/> for each media item id /// in <paramref name="linkedIds"/> with the apecified <paramref name="role"/> and <paramref name="linkedRole"/>. /// </summary> /// <param name="currentFilter">The filter to combine.</param> /// <param name="role">The role to use for the <see cref="RelationshipFilter"/>.</param> /// <param name="linkedRole">The linked role to use for the <see cref="RelationshipFilter"/>.</param> /// <param name="linkedIds">The linked ids to use for the <see cref="RelationshipFilter"/>.</param> /// <returns></returns> protected static IFilter CombineWithRelationship(IFilter currentFilter, Guid role, Guid linkedRole, IEnumerable <Guid> linkedIds) { IFilter relationships = BooleanCombinationFilter.CombineFilters(BooleanOperator.Or, linkedIds.Select(id => new RelationshipFilter(role, linkedRole, id))); return(BooleanCombinationFilter.CombineFilters(BooleanOperator.And, currentFilter, relationships)); }
protected void CompileStatementParts(MIA_Management miaManagement, IFilter filter, Namespace ns, BindVarNamespace bvNamespace, ICollection <MediaItemAspectMetadata> requiredMIATypes, string outerMIIDJoinVariable, ICollection <TableJoin> tableJoins, IList <object> resultParts, IList <BindVar> resultBindVars) { if (filter == null) { return; } MediaItemIdFilter mediaItemIdFilter = filter as MediaItemIdFilter; if (mediaItemIdFilter != null) { ICollection <Guid> mediaItemIds = mediaItemIdFilter.MediaItemIds; if (mediaItemIds.Count == 0) { resultParts.Add("1 = 2"); } else { if (mediaItemIds.Count == 1) { resultParts.Add(outerMIIDJoinVariable); BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), mediaItemIds.First(), typeof(Guid)); resultParts.Add(" = @" + bindVar.Name); resultBindVars.Add(bindVar); } else { bool first = true; ICollection <string> clusterExpressions = new List <string>(); foreach (IList <Guid> mediaItemIdsCluster in CollectionUtils.Cluster(mediaItemIds, MAX_IN_VALUES_SIZE)) { IList <string> bindVarRefs = new List <string>(MAX_IN_VALUES_SIZE); foreach (Guid mediaItemId in mediaItemIdsCluster) { BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), mediaItemId, typeof(Guid)); bindVarRefs.Add("@" + bindVar.Name); resultBindVars.Add(bindVar); } if (!first) { resultParts.Add(" OR "); } first = false; resultParts.Add(outerMIIDJoinVariable); resultParts.Add(" IN (" + StringUtils.Join(", ", bindVarRefs) + ")"); } resultParts.Add(StringUtils.Join(" OR ", clusterExpressions)); } } return; } BooleanCombinationFilter boolFilter = filter as BooleanCombinationFilter; if (boolFilter != null) { int numOperands = boolFilter.Operands.Count; IEnumerator enumOperands = boolFilter.Operands.GetEnumerator(); if (!enumOperands.MoveNext()) { return; } if (numOperands > 1) { resultParts.Add("("); } CompileStatementParts(miaManagement, (IFilter)enumOperands.Current, ns, bvNamespace, requiredMIATypes, outerMIIDJoinVariable, tableJoins, resultParts, resultBindVars); while (enumOperands.MoveNext()) { switch (boolFilter.Operator) { case BooleanOperator.And: resultParts.Add(" AND "); break; case BooleanOperator.Or: resultParts.Add(" OR "); break; default: throw new NotImplementedException(string.Format( "Boolean filter operator '{0}' isn't supported by the media library", boolFilter.Operator)); } CompileStatementParts(miaManagement, (IFilter)enumOperands.Current, ns, bvNamespace, requiredMIATypes, outerMIIDJoinVariable, tableJoins, resultParts, resultBindVars); } if (numOperands > 1) { resultParts.Add(")"); } return; } NotFilter notFilter = filter as NotFilter; if (notFilter != null) { resultParts.Add("NOT ("); CompileStatementParts(miaManagement, notFilter.InnerFilter, ns, bvNamespace, requiredMIATypes, outerMIIDJoinVariable, tableJoins, resultParts, resultBindVars); resultParts.Add(")"); return; } FalseFilter falseFilter = filter as FalseFilter; if (falseFilter != null) { resultParts.Add("1 = 2"); return; } // Must be done before checking IAttributeFilter - EmptyFilter is also an IAttributeFilter but must be // compiled in a different way EmptyFilter emptyFilter = filter as EmptyFilter; if (emptyFilter != null) { MediaItemAspectMetadata.AttributeSpecification attributeType = emptyFilter.AttributeType; requiredMIATypes.Add(attributeType.ParentMIAM); Cardinality cardinality = attributeType.Cardinality; if (cardinality == Cardinality.Inline || cardinality == Cardinality.ManyToOne) { resultParts.Add(new QueryAttribute(attributeType)); resultParts.Add(" IS NULL"); // MTO attributes are joined with left outer joins and thus can also be checked for NULL } else if (cardinality == Cardinality.OneToMany) { resultParts.Add("NOT EXISTS("); resultParts.Add("SELECT V."); resultParts.Add(MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME); resultParts.Add(" FROM "); resultParts.Add(miaManagement.GetMIACollectionAttributeTableName(attributeType)); resultParts.Add(" V WHERE V."); resultParts.Add(MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME); resultParts.Add("="); resultParts.Add(outerMIIDJoinVariable); resultParts.Add(")"); } else if (cardinality == Cardinality.ManyToMany) { resultParts.Add("NOT EXISTS("); resultParts.Add("SELECT NM."); resultParts.Add(MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME); resultParts.Add(" FROM "); resultParts.Add(miaManagement.GetMIACollectionAttributeNMTableName(attributeType)); resultParts.Add(" NM INNER JOIN "); resultParts.Add(miaManagement.GetMIACollectionAttributeTableName(attributeType)); resultParts.Add(" V ON NM."); resultParts.Add(MIA_Management.FOREIGN_COLL_ATTR_ID_COL_NAME); resultParts.Add(" = V."); resultParts.Add(MIA_Management.FOREIGN_COLL_ATTR_ID_COL_NAME); resultParts.Add(" WHERE NM."); resultParts.Add(MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME); resultParts.Add("="); resultParts.Add(outerMIIDJoinVariable); resultParts.Add(")"); } return; } IAttributeFilter attributeFilter = filter as IAttributeFilter; if (attributeFilter != null) { // For attribute filters, we have to create different kinds of expressions, depending on the // cardinality of the attribute to be filtered. // For Inline and MTO attributes, we simply create // // QA [Operator] [Comparison-Value] // // for OTM attributes, we create // // INNER JOIN [OTM-Value-Table] V ON V.MEDIA_ITEM_ID=[Outer-Join-Variable-Placeholder] // WHERE [...] and V.VALUE [Operator] [Comparison-Value]) // // for MTM attributes, we create // // INNER JOIN [MTM-NM-Table] NM ON NM.MEDIA_ITEM_ID=[Outer-Join-Variable-Placeholder] // INNER JOIN [MTM-Value-Table] V ON NM.ID = V.ID // WHERE [...] AND V.VALUE [Operator] [Comparison-Value]) MediaItemAspectMetadata.AttributeSpecification attributeType = attributeFilter.AttributeType; requiredMIATypes.Add(attributeType.ParentMIAM); Cardinality cardinality = attributeType.Cardinality; if (cardinality == Cardinality.Inline || cardinality == Cardinality.ManyToOne) { BuildAttributeFilterExpression(attributeFilter, new QueryAttribute(attributeType), bvNamespace, resultParts, resultBindVars); } else if (cardinality == Cardinality.OneToMany) { string joinTable = miaManagement.GetMIACollectionAttributeTableName(attributeType); string attrName; if (!_innerJoinedTables.TryGetValue(joinTable, out attrName)) { TableQueryData tqd = new TableQueryData(joinTable); tableJoins.Add(new TableJoin("LEFT OUTER JOIN", tqd, new RequestedAttribute(tqd, MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME), outerMIIDJoinVariable)); attrName = new RequestedAttribute(tqd, MIA_Management.COLL_ATTR_VALUE_COL_NAME).GetQualifiedName(ns); _innerJoinedTables.Add(joinTable, attrName); } BuildAttributeFilterExpression(attributeFilter, attrName, bvNamespace, resultParts, resultBindVars); } else if (cardinality == Cardinality.ManyToMany) { string miaCollectionAttributeNMTableName = miaManagement.GetMIACollectionAttributeNMTableName(attributeType); string attrName; if (!_innerJoinedTables.TryGetValue(miaCollectionAttributeNMTableName, out attrName)) { TableQueryData tqdMiaCollectionAttributeNMTable = new TableQueryData(miaCollectionAttributeNMTableName); tableJoins.Add(new TableJoin("LEFT OUTER JOIN", tqdMiaCollectionAttributeNMTable, new RequestedAttribute(tqdMiaCollectionAttributeNMTable, MIA_Management.MIA_MEDIA_ITEM_ID_COL_NAME), outerMIIDJoinVariable)); TableQueryData tqdMiaCollectionAttributeTable = new TableQueryData(miaManagement.GetMIACollectionAttributeTableName(attributeType)); tableJoins.Add(new TableJoin("LEFT OUTER JOIN", tqdMiaCollectionAttributeTable, new RequestedAttribute(tqdMiaCollectionAttributeNMTable, MIA_Management.FOREIGN_COLL_ATTR_ID_COL_NAME), new RequestedAttribute(tqdMiaCollectionAttributeTable, MIA_Management.FOREIGN_COLL_ATTR_ID_COL_NAME))); attrName = tqdMiaCollectionAttributeTable.GetAlias(ns) + "." + MIA_Management.COLL_ATTR_VALUE_COL_NAME; _innerJoinedTables.Add(miaCollectionAttributeNMTableName, attrName); } BuildAttributeFilterExpression(attributeFilter, attrName, bvNamespace, resultParts, resultBindVars); } return; } throw new InvalidDataException("Filter type '{0}' isn't supported by the media library", filter.GetType().Name); }
/// <summary> /// Combines the <paramref name="filter"/> with any existing filters. /// </summary> /// <param name="filter">The filter to combine.</param> protected void CombineFilter(IFilter filter) { _filter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, _filter, filter); }
public override async Task <ICollection <FilterValue> > GetAvailableValuesAsync(IEnumerable <Guid> necessaryMIATypeIds, IFilter selectAttributeFilter, IFilter filter) { IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; if (cd == null) { throw new NotConnectedException("The MediaLibrary is not connected"); } bool showVirtual = VirtualMediaHelper.ShowVirtualMedia(necessaryMIATypeIds); if (string.IsNullOrEmpty(CertificationHelper.DisplayMovieCertificationCountry)) { HomogenousMap valueGroups = await cd.GetValueGroupsAsync(MovieAspect.ATTR_CERTIFICATION, null, ProjectionFunction.None, necessaryMIATypeIds, filter, true, showVirtual); IList <FilterValue> result = new List <FilterValue>(valueGroups.Count); int numEmptyEntries = 0; foreach (KeyValuePair <object, object> group in valueGroups) { string certification = (string)group.Key; if (!string.IsNullOrEmpty(certification)) { CertificationMapping cert; if (CertificationMapper.TryFindMovieCertification(certification, out cert)) { result.Add(new FilterValue(cert.CertificationId, cert.Name, new RelationalFilter(MovieAspect.ATTR_CERTIFICATION, RelationalOperator.EQ, certification), null, (int)group.Value, this)); } } else { numEmptyEntries += (int)group.Value; } } if (numEmptyEntries > 0) { result.Insert(0, new FilterValue("UR", Consts.RES_VALUE_UNRATED_TITLE, new EmptyFilter(MovieAspect.ATTR_CERTIFICATION), null, numEmptyEntries, this)); } return(result); } else { IList <FilterValue> result = new List <FilterValue>(); IFilter emptyFilter = new EmptyFilter(MovieAspect.ATTR_CERTIFICATION); int numEmptyItems = await cd.CountMediaItemsAsync(necessaryMIATypeIds, BooleanCombinationFilter.CombineFilters(BooleanOperator.And, filter, emptyFilter), true, showVirtual); if (numEmptyItems > 0) { result.Add(new FilterValue("UR", Consts.RES_VALUE_UNRATED_TITLE, emptyFilter, null, numEmptyItems, this)); } List <string> usedFilters = new List <string>(); foreach (var cert in CertificationMapper.GetMovieCertificationsForCountry(CertificationHelper.DisplayMovieCertificationCountry)) { IEnumerable <CertificationMapping> certs = CertificationMapper.FindAllAllowedMovieCertifications(cert.CertificationId); if (certs.Count() > 0) { List <string> certList = new List <string>(certs.Select(c => c.CertificationId).Except(usedFilters)); usedFilters.AddRange(certList); IFilter certFilter = new InFilter(MovieAspect.ATTR_CERTIFICATION, certList); int numItems = await cd.CountMediaItemsAsync(necessaryMIATypeIds, BooleanCombinationFilter.CombineFilters(BooleanOperator.And, filter, certFilter), true, showVirtual); result.Add(new FilterValue(cert.CertificationId, cert.Name, certFilter, null, numItems, this)); } } return(result); } }
internal static WebTVShowBasic TVShowBasic(IOwinContext context, MediaItem item) { ISet <Guid> necessaryMIATypespisodes = new HashSet <Guid>(); necessaryMIATypespisodes.Add(MediaAspect.ASPECT_ID); necessaryMIATypespisodes.Add(EpisodeAspect.ASPECT_ID); IFilter unwatchedEpisodeFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, new RelationshipFilter(EpisodeAspect.ROLE_EPISODE, SeriesAspect.ROLE_SERIES, item.MediaItemId), new RelationalUserDataFilter(Guid.Empty, UserDataKeysKnown.KEY_PLAY_PERCENTAGE, RelationalOperator.LT, UserDataKeysKnown.GetSortablePlayPercentageString(100), true)); int unwatchedCount = MediaLibraryAccess.CountMediaItems(context, necessaryMIATypespisodes, unwatchedEpisodeFilter); var mediaAspect = item.GetAspect(MediaAspect.Metadata); var seriesAspect = item.GetAspect(SeriesAspect.Metadata); var importerAspect = item.GetAspect(ImporterAspect.Metadata); DateTime? firstAired = mediaAspect.GetAttributeValue <DateTime?>(MediaAspect.ATTR_RECORDINGTIME); IList <WebActor> actors = seriesAspect.GetCollectionAttribute <string>(SeriesAspect.ATTR_ACTORS)?.Distinct().Select(a => new WebActor(a)).ToList() ?? new List <WebActor>(); WebArtwork aw = new WebArtwork(); var show = new WebTVShowBasic() { Id = item.MediaItemId.ToString(), Title = seriesAspect.GetAttributeValue <string>(SeriesAspect.ATTR_SERIES_NAME), DateAdded = importerAspect.GetAttributeValue <DateTime>(ImporterAspect.ATTR_DATEADDED), EpisodeCount = seriesAspect.GetAttributeValue <int>(SeriesAspect.ATTR_AVAILABLE_EPISODES), SeasonCount = seriesAspect.GetAttributeValue <int>(SeriesAspect.ATTR_AVAILABLE_SEASONS), Rating = Convert.ToSingle(seriesAspect.GetAttributeValue <double>(SeriesAspect.ATTR_TOTAL_RATING)), ContentRating = seriesAspect.GetAttributeValue <string>(SeriesAspect.ATTR_CERTIFICATION), Actors = actors, UnwatchedEpisodeCount = unwatchedCount, Year = firstAired.HasValue ? firstAired.Value.Year : 0, }; IList <MediaItemAspect> genres; if (item.Aspects.TryGetValue(GenreAspect.ASPECT_ID, out genres)) { show.Genres = genres.Select(g => g.GetAttributeValue <string>(GenreAspect.ATTR_GENRE)).ToList(); } string tvDbId; MediaItemAspect.TryGetExternalAttribute(item.Aspects, ExternalIdentifierAspect.SOURCE_TVDB, ExternalIdentifierAspect.TYPE_SERIES, out tvDbId); if (tvDbId != null) { show.ExternalId.Add(new WebExternalId { Site = "TVDB", Id = tvDbId }); } string imdbId; MediaItemAspect.TryGetExternalAttribute(item.Aspects, ExternalIdentifierAspect.SOURCE_IMDB, ExternalIdentifierAspect.TYPE_SERIES, out imdbId); if (imdbId != null) { show.ExternalId.Add(new WebExternalId { Site = "IMDB", Id = imdbId }); } return(show); }
public void TestMediaItemsLoader_SingleAndMultipleMIAs_BooleanLikeFilter() { MockDBUtils.Reset(); SingleTestMIA mia1 = TestBackendUtils.CreateSingleMIA("SINGLE1", Cardinality.Inline, true, true); MultipleTestMIA mia2 = TestBackendUtils.CreateMultipleMIA("MULTIPLE2", Cardinality.Inline, true, false); MultipleTestMIA mia3 = TestBackendUtils.CreateMultipleMIA("MULTIPLE3", Cardinality.Inline, false, true); Guid itemId0 = new Guid("aaaaaaaa-1111-1111-1111-aaaaaaaaaaaa"); Guid itemId1 = new Guid("bbbbbbbb-2222-2222-2222-bbbbbbbbbbbb"); IFilter filter = new BooleanCombinationFilter(BooleanOperator.And, new List <IFilter> { new LikeFilter(mia1.ATTR_STRING, "%", null), new LikeFilter(mia2.ATTR_STRING, "%", null) }); MockReader reader = MockDBUtils.AddReader(1, "SELECT T0.MEDIA_ITEM_ID A2, T0.MEDIA_ITEM_ID A3, T1.MEDIA_ITEM_ID A4, T0.ATTR_STRING A0, T0.ATTR_INTEGER A1 " + "FROM M_SINGLE1 T0 INNER JOIN M_MULTIPLE2 T1 ON T1.MEDIA_ITEM_ID = T0.MEDIA_ITEM_ID " + " WHERE T0.MEDIA_ITEM_ID IN(SELECT MEDIA_ITEM_ID FROM M_MULTIPLE2 WHERE ATTR_STRING LIKE @V0) AND T0.ATTR_STRING LIKE @V1", "A2", "A3", "A4", "A0", "A1"); reader.AddResult(itemId0, itemId0, itemId0, "zero", 0, "0_0"); reader.AddResult(itemId1, itemId1, itemId1, "one", 1, "1_1"); MockReader multipleReader2 = MockDBUtils.AddReader(2, "SELECT T0.MEDIA_ITEM_ID A2, T0.MEDIA_ITEM_ID A3, T0.ATTR_ID A0, T0.ATTR_STRING A1 FROM M_MULTIPLE2 T0 WHERE T0.MEDIA_ITEM_ID IN (@V0, @V1)", "A2", "A3", "A0", "A1"); multipleReader2.AddResult(itemId0, itemId0, "0_0", "zerozero"); multipleReader2.AddResult(itemId0, itemId0, "0_1", "zeroone"); multipleReader2.AddResult(itemId1, itemId1, "1_0", "onezero"); MockReader multipleReader3 = MockDBUtils.AddReader(3, "SELECT T0.MEDIA_ITEM_ID A2, T0.MEDIA_ITEM_ID A3, T0.ATTR_ID A0, T0.ATTR_INTEGER A1 FROM M_MULTIPLE3 T0 WHERE T0.MEDIA_ITEM_ID IN (@V0, @V1)", "A2", "A3", "A0", "A1"); multipleReader3.AddResult(itemId0, itemId0, "1_0", 10); multipleReader3.AddResult(itemId0, itemId0, "1_1", 11); multipleReader3.AddResult(itemId0, itemId0, "1_2", 12); multipleReader3.AddResult(itemId0, itemId0, "1_3", 13); multipleReader3.AddResult(itemId0, itemId0, "1_4", 14); multipleReader3.AddResult(itemId1, itemId1, "1_0", 20); Guid[] requiredAspects = { mia1.ASPECT_ID, mia2.ASPECT_ID }; Guid[] optionalAspects = { mia3.ASPECT_ID }; MediaItemQuery query = new MediaItemQuery(requiredAspects, optionalAspects, filter); CompiledMediaItemQuery compiledQuery = CompiledMediaItemQuery.Compile(MockCore.Management, query); IList <MediaItem> results = compiledQuery.QueryList(); /* * foreach (MediaItem result in results) * //Console.WriteLine("Query result " + result.MediaItemId + ": " + string.Join(",", result.Aspects.Values) + ": " + result); */ SingleMediaItemAspect value; IList <MultipleMediaItemAspect> values; Assert.AreEqual(2, results.Count, "Results count"); Assert.AreEqual(itemId0, results[0].MediaItemId, "MediaItem ID #0"); Assert.IsTrue(MediaItemAspect.TryGetAspect(results[0].Aspects, mia1.Metadata, out value), "MIA1 #0"); Assert.AreEqual("zero", value.GetAttributeValue(mia1.ATTR_STRING), "MIA1 string attibute #0"); Assert.AreEqual(0, value.GetAttributeValue(mia1.ATTR_INTEGER), "MIA1 integer attibute #0"); Assert.IsTrue(MediaItemAspect.TryGetAspects(results[0].Aspects, mia2.Metadata, out values), "MIA2 #0"); Assert.AreEqual(2, values.Count, "MIA2 count #0"); Assert.AreEqual("zerozero", values[0].GetAttributeValue(mia2.ATTR_STRING), "MIA2 string attibute 0 #0"); Assert.AreEqual("zeroone", values[1].GetAttributeValue(mia2.ATTR_STRING), "MIA2 string attibute 1 #0"); Assert.IsTrue(MediaItemAspect.TryGetAspects(results[0].Aspects, mia3.Metadata, out values), "MIA3 #0"); Assert.AreEqual(5, values.Count, "MIA3 count #0"); Assert.AreEqual(10, values[0].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 0 #0"); Assert.AreEqual(11, values[1].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 1 #0"); Assert.AreEqual(12, values[2].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 2 #0"); Assert.AreEqual(13, values[3].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 3 #0"); Assert.AreEqual(14, values[4].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 4 #0"); Assert.AreEqual(itemId1, results[1].MediaItemId, "MediaItem ID #1"); Assert.IsTrue(MediaItemAspect.TryGetAspect(results[1].Aspects, mia1.Metadata, out value), "MIA1 #0"); Assert.AreEqual("one", value.GetAttributeValue(mia1.ATTR_STRING), "MIA1 string attibute #1"); Assert.AreEqual(1, value.GetAttributeValue(mia1.ATTR_INTEGER), "MIA1 integer attibute #1"); Assert.IsTrue(MediaItemAspect.TryGetAspects(results[1].Aspects, mia2.Metadata, out values), "MIA2 #1"); Assert.AreEqual(1, values.Count, "MIA2 count #1"); Assert.AreEqual("onezero", values[0].GetAttributeValue(mia2.ATTR_STRING), "MIA2 string attibute 0 #1"); Assert.IsTrue(MediaItemAspect.TryGetAspects(results[1].Aspects, mia3.Metadata, out values), "MIA3 #0"); Assert.AreEqual(1, values.Count, "MIA3 count #1"); Assert.AreEqual(20, values[0].GetAttributeValue(mia3.ATTR_INTEGER), "MIA3 integer attibute 0 #1"); }
public override async Task <ICollection <FilterValue> > GetAvailableValuesAsync(IEnumerable <Guid> necessaryMIATypeIds, IFilter selectAttributeFilter, IFilter filter) { IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; if (cd == null) { throw new NotConnectedException("The MediaLibrary is not connected"); } bool showVirtual = VirtualMediaHelper.ShowVirtualMedia(necessaryMIATypeIds); ViewSettings settings = ServiceRegistration.Get <ISettingsManager>().Load <ViewSettings>(); IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>(); Dictionary <int, FilterValue> genredFilters = new Dictionary <int, FilterValue>(); List <FilterValue> ungenredFilters = new List <FilterValue>(); if (_necessaryMIATypeIds != null) { necessaryMIATypeIds = _necessaryMIATypeIds; } HomogenousMap valueGroups = null; HomogenousMap valueKeys = null; if (_keyAttributeType != null) { Tuple <HomogenousMap, HomogenousMap> values = await cd.GetKeyValueGroupsAsync(_keyAttributeType, _valueAttributeType, selectAttributeFilter, ProjectionFunction.None, necessaryMIATypeIds, filter, true, showVirtual); valueGroups = values.Item1; valueKeys = values.Item2; } else { valueGroups = await cd.GetValueGroupsAsync(_valueAttributeType, selectAttributeFilter, ProjectionFunction.None, necessaryMIATypeIds, filter, true, showVirtual); } IList <FilterValue> result = new List <FilterValue>(valueGroups.Count); int numEmptyEntries = 0; foreach (KeyValuePair <object, object> group in valueGroups) { string name = GetDisplayName(group.Key); if (name == string.Empty) { numEmptyEntries += (int)group.Value; } else if (!string.IsNullOrEmpty(_genreCategory) && settings.UseLocalizedGenres) { int?genreId = valueKeys[group.Key] as int?; if (!genreId.HasValue) { ungenredFilters.Add(new FilterValue(valueKeys[group.Key], name, new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key), null, (int)group.Value, this)); } else if (!genredFilters.ContainsKey(genreId.Value)) { if (converter.GetGenreName(genreId.Value, _genreCategory, null, out string genreName)) { name = genreName; } genredFilters.Add(genreId.Value, new FilterValue(genreId.Value, name, new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key), null, (int)group.Value, this)); } else { genredFilters[genreId.Value] = new FilterValue(genreId.Value, genredFilters[genreId.Value].Title, BooleanCombinationFilter.CombineFilters(BooleanOperator.Or, genredFilters[genreId.Value].Filter, new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key)), null, genredFilters[genreId.Value].NumItems.Value + (int)group.Value, this); } } else { result.Add(new FilterValue(valueKeys[group.Key], name, new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key), null, (int)group.Value, this)); } } foreach (var gf in genredFilters.Values) { result.Add(gf); } foreach (var ugf in ungenredFilters) { result.Add(ugf); } if (numEmptyEntries > 0) { result.Insert(0, new FilterValue(Consts.RES_VALUE_EMPTY_TITLE, new EmptyFilter(_valueAttributeType), null, numEmptyEntries, this)); } return(result); }