public static void StoreSeries(IDictionary <Guid, IList <MediaItemAspect> > aspects, SeriesStub series)
        {
            SingleMediaItemAspect seriesAspect = MediaItemAspect.GetOrCreateAspect(aspects, TempSeriesAspect.Metadata);

            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_TVDBID, series.Id.HasValue ? series.Id.Value : 0);
            string title = !string.IsNullOrEmpty(series.Title) ? series.Title : series.ShowTitle;

            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_NAME, title);
            if (!string.IsNullOrEmpty(series.SortTitle))
            {
                seriesAspect.SetAttribute(TempSeriesAspect.ATTR_SORT_NAME, series.SortTitle);
            }
            else
            {
                seriesAspect.SetAttribute(TempSeriesAspect.ATTR_SORT_NAME, BaseInfo.GetSortTitle(title));
            }
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_CERTIFICATION, series.Mpaa != null && series.Mpaa.Count > 0 ? series.Mpaa.First() : null);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_ENDED, !string.IsNullOrEmpty(series.Status) ? series.Status.Contains("End") : false);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_PLOT, !string.IsNullOrEmpty(series.Plot) ? series.Plot : series.Outline);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_PREMIERED, series.Premiered.HasValue ? series.Premiered.Value : series.Year.HasValue ? series.Year.Value : default(DateTime?));
            seriesAspect.SetCollectionAttribute(TempSeriesAspect.ATTR_GENRES, series.Genres);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_RATING, series.Rating.HasValue ? Convert.ToDouble(series.Rating.Value) : 0.0);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_VOTES, series.Votes.HasValue ? series.Votes.Value : series.Rating.HasValue ? 1 : 0);
            seriesAspect.SetAttribute(TempSeriesAspect.ATTR_STATION, series.Studio);
        }
        private async Task <bool> TryExtractStubItemsAsync(IResourceAccessor mediaItemAccessor, ICollection <IDictionary <Guid, IList <MediaItemAspect> > > extractedStubAspectData)
        {
            // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
            // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
            // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
            var miNumber = Interlocked.Increment(ref _lastMediaItemNumber);

            try
            {
                _debugLogger.Info("[#{0}]: Start extracting stubs for resource '{1}'", miNumber, mediaItemAccessor);

                if (!IsStubResource(mediaItemAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; file does not have a supported extension", miNumber);
                    return(false);
                }

                // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
                // Otherwise it is not possible to find a stub-file in the MediaItem's directory.
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
                    return(false);
                }

                var fsra            = mediaItemAccessor as IFileSystemResourceAccessor;
                var albumStubReader = new StubAlbumReader(_debugLogger, miNumber, true, _settings);
                if (fsra != null && await albumStubReader.TryReadMetadataAsync(fsra).ConfigureAwait(false))
                {
                    AlbumStub album = albumStubReader.GetAlbumStubs().FirstOrDefault();
                    if (album != null && album.Tracks != null && album.Tracks > 0)
                    {
                        for (int trackNo = 1; trackNo <= album.Tracks.Value; trackNo++)
                        {
                            Dictionary <Guid, IList <MediaItemAspect> > extractedAspectData = new Dictionary <Guid, IList <MediaItemAspect> >();
                            string title = string.Format("{0}: {1}", album.Title, "Track " + trackNo);

                            MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_TYPE, ProviderResourceAspect.TYPE_STUB);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, fsra.CanonicalLocalResourcePath.Serialize());
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "audio/L16");

                            SingleMediaItemAspect audioAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, AudioAspect.Metadata);
                            audioAspect.SetAttribute(AudioAspect.ATTR_ISCD, true);
                            audioAspect.SetAttribute(AudioAspect.ATTR_TRACK, trackNo);
                            audioAspect.SetAttribute(AudioAspect.ATTR_TRACKNAME, title);
                            audioAspect.SetAttribute(AudioAspect.ATTR_ENCODING, "PCM");
                            if (album.Cd.HasValue)
                            {
                                audioAspect.SetAttribute(AudioAspect.ATTR_DISCID, album.Cd.Value);
                            }
                            audioAspect.SetAttribute(AudioAspect.ATTR_BITRATE, 1411); // 44.1 kHz * 16 bit * 2 channel
                            audioAspect.SetAttribute(AudioAspect.ATTR_CHANNELS, 2);
                            audioAspect.SetAttribute(AudioAspect.ATTR_NUMTRACKS, album.Tracks.Value);
                            audioAspect.SetAttribute(AudioAspect.ATTR_ALBUM, album.Title);
                            if (album.Artists.Count > 0)
                            {
                                audioAspect.SetCollectionAttribute(AudioAspect.ATTR_ALBUMARTISTS, album.Artists);
                            }

                            SingleMediaItemAspect stubAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, StubAspect.Metadata);
                            stubAspect.SetAttribute(StubAspect.ATTR_DISC_NAME, album.DiscName);
                            stubAspect.SetAttribute(StubAspect.ATTR_MESSAGE, album.Message);

                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, BaseInfo.GetSortTitle(title));
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, false);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISSTUB, true);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, fsra.LastChanged);

                            extractedStubAspectData.Add(extractedAspectData);
                        }
                    }
                }
                else
                {
                    _debugLogger.Warn("[#{0}]: No valid metadata found in album stub file", miNumber);
                }


                _debugLogger.Info("[#{0}]: Successfully finished extracting stubs", miNumber);
                return(true);
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Warn("StubAudioMetadataExtractor: Exception while extracting stubs for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
                _debugLogger.Error("[#{0}]: Exception while extracting stubs", e, miNumber);
                return(false);
            }
        }
Example #3
0
        private async Task <bool> TryExtractStubItemsAsync(IResourceAccessor mediaItemAccessor, ICollection <IDictionary <Guid, IList <MediaItemAspect> > > extractedStubAspectData)
        {
            // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
            // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
            // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
            var miNumber = Interlocked.Increment(ref _lastMediaItemNumber);

            try
            {
                _debugLogger.Info("[#{0}]: Start extracting stubs for resource '{1}'", miNumber, mediaItemAccessor);

                if (!IsStubResource(mediaItemAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; file does not have a supported extension", miNumber);
                    return(false);
                }

                // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
                // Otherwise it is not possible to find a stub-file in the MediaItem's directory.
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
                    return(false);
                }

                var fsra             = mediaItemAccessor as IFileSystemResourceAccessor;
                var seriesStubReader = new StubSeriesReader(_debugLogger, miNumber, true, _settings);
                if (fsra != null && await seriesStubReader.TryReadMetadataAsync(fsra).ConfigureAwait(false))
                {
                    SeriesStub series = seriesStubReader.GetSeriesStubs().FirstOrDefault();
                    if (series != null && series.Episodes != null && series.Episodes.Count > 0)
                    {
                        Dictionary <Guid, IList <MediaItemAspect> > extractedAspectData = new Dictionary <Guid, IList <MediaItemAspect> >();
                        string title = string.Format("{0} S{1:00}{2}", series.Title, series.Season.Value, string.Join("", series.Episodes.Select(e => "E" + e.ToString("00"))));

                        MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_TYPE, ProviderResourceAspect.TYPE_STUB);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, fsra.CanonicalLocalResourcePath.Serialize());
                        if (IsVhs(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/unknown");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_SD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(4.0 / 3.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 720);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 576);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 2);
                        }
                        else if (IsTv(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/unknown");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 2);
                        }
                        else if (IsDvd(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/mp2t");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_SD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 720);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 576);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "MPEG-2 Video");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }
                        else if (IsBluray(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/mp4");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 24F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "AVC");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }
                        else if (IsHdDvd(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/wvc1");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 24F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "VC1");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }

                        SingleMediaItemAspect videoAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
                        videoAspect.SetAttribute(VideoAspect.ATTR_ISDVD, true);

                        SingleMediaItemAspect movieAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, EpisodeAspect.Metadata);
                        movieAspect.SetCollectionAttribute(EpisodeAspect.ATTR_EPISODE, series.Episodes);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SEASON, series.Season.Value);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_EPISODE_NAME, string.Format("{0} {1}", "Episode", string.Join(", ", series.Episodes)));
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SERIES_NAME, series.Title);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SERIES_SEASON, string.Format("{0} S{1:00}", series.Title, series.Season.Value));

                        SingleMediaItemAspect stubAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, StubAspect.Metadata);
                        stubAspect.SetAttribute(StubAspect.ATTR_DISC_NAME, series.DiscName);
                        stubAspect.SetAttribute(StubAspect.ATTR_MESSAGE, series.Message);

                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, series.Title);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, BaseInfo.GetSortTitle(series.Title));
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, false);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISSTUB, true);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, fsra.LastChanged);

                        extractedStubAspectData.Add(extractedAspectData);
                    }
                }
                else
                {
                    _debugLogger.Warn("[#{0}]: No valid metadata found in movie stub file", miNumber);
                }


                _debugLogger.Info("[#{0}]: Successfully finished extracting stubs", miNumber);
                return(true);
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Warn("StubMovieMetadataExtractor: Exception while extracting stubs for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
                _debugLogger.Error("[#{0}]: Exception while extracting stubs", e, miNumber);
                return(false);
            }
        }
Example #4
0
        public IList <MediaItem> Query(ISQLDatabase database, ITransaction transaction, bool singleMode)
        {
            ILogger logger = ServiceRegistration.Get <ILogger>();

            try
            {
                IList <MediaItemAspectMetadata> selectedMIAs = new List <MediaItemAspectMetadata>(_necessaryRequestedMIAs.Union(_optionalRequestedMIAs));

                IList <Guid> mediaItemIds;
                IDictionary <Guid, IList <Guid> > complexMediaItemIds;
                IList <MediaItem> mediaItems = GetMediaItems(database, transaction, singleMode, selectedMIAs, out mediaItemIds, out complexMediaItemIds);

                //logger.Debug("CompiledMediaItemQuery::Query got media items IDs [{0}]", string.Join(",", mediaItemIds));

                // TODO: Why bother looking for complex attributes on MIAs we don't have?
                IDictionary <Guid, IDictionary <MediaItemAspectMetadata.AttributeSpecification, IList> > complexAttributeValues =
                    new Dictionary <Guid, IDictionary <MediaItemAspectMetadata.AttributeSpecification, IList> >();

                ICollection <IList <Guid> > mediaItemIdsClusters = CollectionUtils.Cluster(mediaItemIds, CompiledFilter.MAX_IN_VALUES_SIZE);

                foreach (IList <Guid> mediaItemIdsCluster in mediaItemIdsClusters.Where(x => x.Count > 0))
                {
                    AddComplexAttributes(database, transaction, mediaItemIdsCluster, complexAttributeValues, complexMediaItemIds);
                }

                foreach (MediaItem mediaItem in mediaItems)
                {
                    foreach (SingleMediaItemAspectMetadata miam in selectedMIAs.Where(x => x is SingleMediaItemAspectMetadata))
                    {
                        // Skip complex attributes for this MIA if it's not already in the media item
                        if (!mediaItem.Aspects.ContainsKey(miam.AspectId))
                        {
                            continue;
                        }
                        IDictionary <MediaItemAspectMetadata.AttributeSpecification, IList> attributeValues;
                        if (!complexAttributeValues.TryGetValue(mediaItem.MediaItemId, out attributeValues))
                        {
                            continue;
                        }
                        SingleMediaItemAspect mia = MediaItemAspect.GetOrCreateAspect(mediaItem.Aspects, miam);
                        foreach (MediaItemAspectMetadata.AttributeSpecification attr in miam.AttributeSpecifications.Values)
                        {
                            if (attr.Cardinality != Cardinality.Inline)
                            {
                                IList attrValues;
                                if (attributeValues != null && attributeValues.TryGetValue(attr, out attrValues))
                                {
                                    mia.SetCollectionAttribute(attr, attrValues);
                                }
                            }
                        }
                    }
                }

                IDictionary <Guid, ICollection <MultipleMediaItemAspect> > multipleMiaValues =
                    new Dictionary <Guid, ICollection <MultipleMediaItemAspect> >();
                foreach (IList <Guid> mediaItemIdsCluster in mediaItemIdsClusters.Where(x => x.Count > 0))
                {
                    AddMultipleMIAs(database, transaction, _explicitRequestedMIAs, mediaItemIdsCluster, multipleMiaValues);
                }

                if (multipleMiaValues.Count > 0)
                {
                    //logger.Debug("Got multiple MIAs [{0}]", string.Join(",", multipleMiaValues.Keys));
                    foreach (MediaItem mediaItem in mediaItems)
                    {
                        ICollection <MultipleMediaItemAspect> values;
                        if (!multipleMiaValues.TryGetValue(mediaItem.MediaItemId, out values))
                        {
                            continue;
                        }
                        foreach (MultipleMediaItemAspect value in values)
                        {
                            //logger.Debug("Adding MIA {0} #{1}", value.Metadata.Name, value.Index);
                            MediaItemAspect.AddOrUpdateAspect(mediaItem.Aspects, value);
                        }
                    }
                }

                return(mediaItems);
            }
            catch (Exception e)
            {
                logger.Error("Unable to query", e);
                throw e;
            }
        }