/// <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));
        }
示例#2
0
        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);
 }
示例#4
0
        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);
        }
示例#6
0
        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);
        }