Esempio n. 1
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

            if (fsra == null || !fsra.IsFile)
            {
                return(false);
            }
            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                return(false);
            }

            try
            {
                var extension = DosPathHelper.GetExtension(fsra.ResourceName).ToLowerInvariant();
                if (extension != ".ts")
                {
                    return(false);
                }

                using (MediaInfoWrapper mediaInfo = ReadMediaInfo(fsra))
                {
                    // Before we start evaluating the file, check if it is not a video file (
                    if (mediaInfo.IsValid && (mediaInfo.GetVideoCount() != 0 || mediaInfo.GetAudioCount() == 0))
                    {
                        return(false);
                    }
                    string fileName = ProviderPathHelper.GetFileNameWithoutExtension(fsra.Path) ?? string.Empty;
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, fileName);
                    MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "slimtv/radio");

                    var audioBitrate = mediaInfo.GetAudioBitrate(0);
                    if (audioBitrate.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, (int)(audioBitrate.Value / 1000)); // We store kbit/s;
                    }
                    var audioChannels = mediaInfo.GetAudioChannels(0);
                    if (audioChannels.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_CHANNELS, audioChannels.Value);
                    }
                    var audioSampleRate = mediaInfo.GetAudioSampleRate(0);
                    if (audioSampleRate.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_SAMPLERATE, audioSampleRate.Value);
                    }

                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_ENCODING, mediaInfo.GetAudioCodec(0));
                    // MediaInfo returns milliseconds, we need seconds
                    long?time = mediaInfo.GetPlaytime(0);
                    if (time.HasValue && time > 1000)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, time.Value / 1000);
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                ServiceRegistration.Get <ILogger>().Info("RadioRecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
                return(false);
            }
        }
Esempio n. 2
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            string fileName = mediaItemAccessor.ResourceName;

            if (!HasImageExtension(fileName))
            {
                return(false);
            }

            MediaItemAspect mediaAspect          = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
            MediaItemAspect imageAspect          = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata);
            MediaItemAspect thumbnailSmallAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailSmallAspect.Metadata);
            MediaItemAspect thumbnailLargeAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailLargeAspect.Metadata);

            try
            {
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                // Open a stream for media item to detect mimeType.
                using (Stream mediaStream = fsra.OpenRead())
                {
                    string mimeType = MimeTypeDetector.GetMimeType(mediaStream);
                    if (mimeType != null)
                    {
                        mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, mimeType);
                    }
                }
                // Extract EXIF information from media item.
                using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra))
                {
                    mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName));
                    mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : fsra.LastChanged);
                    mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription));

                    if (exif.PixXDim.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int)exif.PixXDim);
                    }
                    if (exif.PixYDim.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_HEIGHT, (int)exif.PixYDim);
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_MAKE, StringUtils.TrimToNull(exif.EquipMake));
                    imageAspect.SetAttribute(ImageAspect.ATTR_MODEL, StringUtils.TrimToNull(exif.EquipModel));
                    if (exif.ExposureBias.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double)exif.ExposureBias).ToString());
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime);
                    imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode));
                    if (exif.FNumber.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_FNUMBER, string.Format("F {0}", (double)exif.FNumber));
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_ISO_SPEED, StringUtils.TrimToNull(exif.ISOSpeed));
                    imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, (Int32)(exif.OrientationType ?? 0));
                    imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString());

                    if (exif.Latitude.HasValue && exif.Longitude.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_LATITUDE, exif.Latitude);
                        imageAspect.SetAttribute(ImageAspect.ATTR_LONGITUDE, exif.Longitude);

                        LocationInfo locationInfo;
                        if (!forceQuickMode && GeoLocationMatcher.Instance.TryLookup(exif.Latitude.Value, exif.Longitude.Value, out locationInfo))
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City);
                            imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.State);
                            imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.Country);
                        }
                    }

                    using (ILocalFsResourceAccessor lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor((IFileSystemResourceAccessor)fsra.Clone()))
                    {
                        string localFsResourcePath = lfsra.LocalFileSystemPath;
                        if (localFsResourcePath != null)
                        {
                            // In quick mode only allow thumbs taken from cache.
                            bool cachedOnly = forceQuickMode;

                            // Thumbnail extraction
                            IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                            byte[]    thumbData;
                            ImageType imageType;
                            if (generator.GetThumbnail(localFsResourcePath, 96, 96, cachedOnly, out thumbData, out imageType))
                            {
                                thumbnailSmallAspect.SetAttribute(ThumbnailSmallAspect.ATTR_THUMBNAIL, thumbData);
                            }
                            if (generator.GetThumbnail(localFsResourcePath, 256, 256, cachedOnly, out thumbData, out imageType))
                            {
                                thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                            }
                        }
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("ImageMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
Esempio n. 3
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

            if (fsra == null)
            {
                return(false);
            }
            if (!fsra.IsFile)
            {
                return(false);
            }
            string fileName = fsra.ResourceName;

            if (!HasAudioExtension(fileName))
            {
                return(false);
            }

            try
            {
                File tag;
                try
                {
                    ByteVector.UseBrokenLatin1Behavior = true; // Otherwise we have problems retrieving non-latin1 chars
                    tag = File.Create(new ResourceProviderFileAbstraction(fsra));
                }
                catch (CorruptFileException)
                {
                    // Only log at the info level here - And simply return false. This makes the importer know that we
                    // couldn't perform our task here.
                    ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Audio file '{0}' seems to be broken", fsra.CanonicalLocalResourcePath);
                    return(false);
                }

                // Some file extensions like .mp4 can contain audio and video. Do not handle files with video content here.
                if (tag.Properties.VideoHeight > 0 && tag.Properties.VideoWidth > 0)
                {
                    return(false);
                }

                fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                string title;
                string artist;
                uint?  trackNo;
                GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                if (!string.IsNullOrEmpty(tag.Tag.Title))
                {
                    title = tag.Tag.Title;
                }
                IEnumerable <string> artists;
                if (tag.Tag.Performers.Length > 0)
                {
                    artists = tag.Tag.Performers;
                    if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                    {
                        artists = PatchID3v23Enumeration(artists);
                    }
                }
                else
                {
                    artists = artist == null ? null : new string[] { artist }
                };
                if (tag.Tag.Track != 0)
                {
                    trackNo = tag.Tag.Track;
                }
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, fsra.Size);
                // FIXME Albert: tag.MimeType returns taglib/mp3 for an MP3 file. This is not what we want and collides with the
                // mimetype handling in the BASS player, which expects audio/xxx.
                if (!string.IsNullOrWhiteSpace(tag.MimeType))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_MIME_TYPE, tag.MimeType.Replace("taglib/", "audio/"));
                }

                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ARTISTS, ApplyAdditionalSeparator(artists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_ALBUM, StringUtils.TrimToNull(tag.Tag.Album));
                IEnumerable <string> albumArtists = tag.Tag.AlbumArtists;
                if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                {
                    albumArtists = PatchID3v23Enumeration(albumArtists);
                }
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ALBUMARTISTS, ApplyAdditionalSeparator(albumArtists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, tag.Properties.AudioBitrate);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tag.Tag.Comment));
                IEnumerable <string> composers = tag.Tag.Composers;
                if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                {
                    composers = PatchID3v23Enumeration(composers);
                }
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_COMPOSERS, ApplyAdditionalSeparator(composers));

                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, (long)tag.Properties.Duration.TotalSeconds);
                if (tag.Tag.Genres.Length > 0)
                {
                    IEnumerable <string> genres = tag.Tag.Genres;
                    if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                    {
                        genres = PatchID3v23Enumeration(genres);
                    }
                    MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_GENRES, ApplyAdditionalSeparator(genres));
                }
                if (trackNo.HasValue)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_TRACK, (int)trackNo.Value);
                }
                if (tag.Tag.TrackCount != 0)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_NUMTRACKS, (int)tag.Tag.TrackCount);
                }
                int year = (int)tag.Tag.Year;
                if (year >= 30 && year <= 99)
                {
                    year += 1900;
                }
                if (year >= 1930 && year <= 2030)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));
                }


                // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                IPicture[] pics = tag.Tag.Pictures;
                if (pics.Length > 0)
                {
                    try
                    {
                        using (MemoryStream stream = new MemoryStream(pics[0].Data.Data))
                            using (MemoryStream resized = (MemoryStream)ImageUtilities.ResizeImage(stream, ImageFormat.Jpeg, MAX_COVER_WIDTH, MAX_COVER_HEIGHT))
                            {
                                MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, resized.ToArray());
                            }
                    }
                    // Decoding of invalid image data can fail, but main MediaItem is correct.
                    catch { }
                }
                else
                {
                    // In quick mode only allow thumbs taken from cache.
                    bool cachedOnly = forceQuickMode;

                    // Thumbnail extraction
                    fileName = mediaItemAccessor.ResourcePathName;
                    IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                    byte[]    thumbData;
                    ImageType imageType;
                    if (generator.GetThumbnail(fileName, 256, 256, cachedOnly, out thumbData, out imageType))
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                    }
                }
                return(true);
            }
            catch (UnsupportedFormatException)
            {
                ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Unsupported audio file '{0}'", fsra.CanonicalLocalResourcePath);
                return(false);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
Esempio n. 4
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            string fileName = mediaItemAccessor.ResourceName;

            if (!HasImageExtension(fileName))
            {
                return(false);
            }

            bool refresh = false;

            if (extractedAspectData.ContainsKey(ImageAspect.ASPECT_ID))
            {
                refresh = true;
            }

            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (!refresh)
                {
                    MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, true);

                    if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                    {
                        return(false);
                    }

                    // Open a stream for media item to detect mimeType.
                    using (Stream mediaStream = fsra.OpenRead())
                    {
                        string mimeType = MimeTypeDetector.GetMimeType(mediaStream) ?? DEFAULT_MIMETYPE;
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mimeType);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                    }
                }

                MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
                mediaAspect.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);
                MediaItemAspect imageAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata);

                if (!refresh)
                {
                    // Extract EXIF information from media item.
                    using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra))
                    {
                        mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName));
                        mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : fsra.LastChanged);
                        mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription));

                        if (exif.PixXDim.HasValue)
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int)exif.PixXDim);
                        }
                        if (exif.PixYDim.HasValue)
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_HEIGHT, (int)exif.PixYDim);
                        }
                        imageAspect.SetAttribute(ImageAspect.ATTR_MAKE, StringUtils.TrimToNull(exif.EquipMake));
                        imageAspect.SetAttribute(ImageAspect.ATTR_MODEL, StringUtils.TrimToNull(exif.EquipModel));
                        if (exif.ExposureBias.HasValue)
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double)exif.ExposureBias).ToString());
                        }
                        imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime);
                        imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode));
                        if (exif.FNumber.HasValue)
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_FNUMBER, string.Format("F {0}", (double)exif.FNumber));
                        }
                        imageAspect.SetAttribute(ImageAspect.ATTR_ISO_SPEED, StringUtils.TrimToNull(exif.ISOSpeed));
                        imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, (Int32)(exif.OrientationType ?? 0));
                        imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString());

                        if (exif.Latitude.HasValue && exif.Longitude.HasValue)
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_LATITUDE, exif.Latitude);
                            imageAspect.SetAttribute(ImageAspect.ATTR_LONGITUDE, exif.Longitude);
                        }
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(true);
                    }

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                            if (localFsResourcePath != null)
                            {
                                // Thumbnail extraction
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, true, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                }
                            }
                        }
                    return(true);
                }
                else
                {
                    bool   updated   = false;
                    double?latitude  = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LATITUDE);
                    double?longitude = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LONGITUDE);
                    if (IncludeGeoLocationDetails && !importOnly && latitude.HasValue && longitude.HasValue &&
                        string.IsNullOrEmpty(imageAspect.GetAttributeValue <string>(ImageAspect.ATTR_COUNTRY)))
                    {
                        CivicAddress locationInfo;
                        if (!forceQuickMode && GeoLocationService.Instance.TryLookup(new GeoCoordinate(latitude.Value, longitude.Value), out locationInfo))
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City);
                            imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.StateProvince);
                            imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.CountryRegion);
                            updated = true;
                        }
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(updated);
                    }

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                            if (localFsResourcePath != null)
                            {
                                // In quick mode only allow thumbs taken from cache.
                                bool cachedOnly = forceQuickMode;
                                // Thumbnail extraction
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, cachedOnly, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                    updated = true;
                                }
                            }
                        }
                    return(updated);
                }
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("ImageMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
Esempio n. 5
0
        public override bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            // If the base AudioMDE already extracted metadata, don't try here again to avoid conflicts.
            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                return(false);
            }

            ILocalFsResourceAccessor fsra = mediaItemAccessor as ILocalFsResourceAccessor;

            if (fsra == null)
            {
                return(false);
            }
            if (!fsra.IsFile)
            {
                return(false);
            }
            string fileName = fsra.ResourceName;

            if (!HasAudioExtension(fileName))
            {
                return(false);
            }

            try
            {
                TAG_INFO tags;
                using (fsra.EnsureLocalFileSystemAccess())
                    tags = BassTags.BASS_TAG_GetFromFile(fsra.LocalFileSystemPath);
                if (tags == null)
                {
                    return(false);
                }

                fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                string title;
                string artist;
                uint?  trackNo;
                GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                if (!string.IsNullOrWhiteSpace(tags.title))
                {
                    title = tags.title;
                }
                IEnumerable <string> artists;
                if (!string.IsNullOrWhiteSpace(tags.artist))
                {
                    artists = SplitTagEnum(tags.artist);
                    artists = PatchID3v23Enumeration(artists);
                }
                else
                {
                    artists = artist == null ? null : new string[] { artist }
                };
                if (!string.IsNullOrWhiteSpace(tags.track) && tags.track != "0")
                {
                    int iTrackNo;
                    if (int.TryParse(tags.track, out iTrackNo))
                    {
                        trackNo = (uint?)iTrackNo;
                    }
                    else
                    {
                        trackNo = null;
                    }
                }

                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, fsra.Size);
                // Calling EnsureLocalFileSystemAccess not necessary; only string operation
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_MIME_TYPE, "audio/" + Path.GetExtension(fsra.LocalFileSystemPath).Substring(1));
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ARTISTS, ApplyAdditionalSeparator(artists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_ALBUM, StringUtils.TrimToNull(tags.album));
                IEnumerable <string> albumArtists = SplitTagEnum(tags.albumartist);
                albumArtists = PatchID3v23Enumeration(albumArtists);

                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ALBUMARTISTS, ApplyAdditionalSeparator(albumArtists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, tags.bitrate);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tags.comment));
                IEnumerable <string> composers = SplitTagEnum(tags.composer);
                composers = PatchID3v23Enumeration(composers);
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_COMPOSERS, ApplyAdditionalSeparator(composers));

                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, (long)tags.duration);

                IEnumerable <string> genres = SplitTagEnum(tags.genre);
                genres = PatchID3v23Enumeration(genres);
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_GENRES, ApplyAdditionalSeparator(genres));

                if (trackNo.HasValue)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_TRACK, (int)trackNo.Value);
                }

                int year;
                if (int.TryParse(tags.year, out year))
                {
                    if (year >= 30 && year <= 99)
                    {
                        year += 1900;
                    }
                    if (year >= 1930 && year <= 2030)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));
                    }
                }

                // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                if (tags.PictureCount > 0)
                {
                    try
                    {
                        using (Image cover = tags.PictureGetImage(0))
                            using (Image resized = ImageUtilities.ResizeImage(cover, MAX_COVER_WIDTH, MAX_COVER_HEIGHT))
                                using (MemoryStream result = new MemoryStream())
                                {
                                    resized.Save(result, ImageFormat.Jpeg);
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, result.ToArray());
                                }
                    }
                    // Decoding of invalid image data can fail, but main MediaItem is correct.
                    catch { }
                }
                else
                {
                    // In quick mode only allow thumbs taken from cache.
                    bool cachedOnly = forceQuickMode;

                    // Thumbnail extraction
                    fileName = mediaItemAccessor.ResourcePathName;
                    IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                    byte[]    thumbData;
                    ImageType imageType;
                    if (generator.GetThumbnail(fileName, cachedOnly, out thumbData, out imageType))
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                ServiceRegistration.Get <ILogger>().Info("BassAudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
        public virtual bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

            if (fsra == null)
            {
                return(false);
            }
            if (!fsra.IsFile)
            {
                return(false);
            }
            string fileName = fsra.ResourceName;

            if (!HasAudioExtension(fileName))
            {
                return(false);
            }

            bool refresh = false;

            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                refresh = true;
            }

            try
            {
                TrackInfo trackInfo = new TrackInfo();
                if (refresh)
                {
                    trackInfo.FromMetadata(extractedAspectData);
                }
                if (!trackInfo.IsBaseInfoPresent)
                {
                    File tag = null;
                    try
                    {
                        ByteVector.UseBrokenLatin1Behavior = true; // Otherwise we have problems retrieving non-latin1 chars
                        tag = File.Create(new ResourceProviderFileAbstraction(fsra));
                    }
                    catch (CorruptFileException)
                    {
                        // Only log at the info level here - And simply return false. This makes the importer know that we
                        // couldn't perform our task here.
                        ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Audio file '{0}' seems to be broken", fsra.CanonicalLocalResourcePath);
                        return(false);
                    }

                    using (tag)
                    {
                        // Some file extensions like .mp4 can contain audio and video. Do not handle files with video content here.
                        if (tag.Properties.VideoHeight > 0 && tag.Properties.VideoWidth > 0)
                        {
                            return(false);
                        }

                        fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                        string title;
                        string sortTitle;
                        string artist;
                        uint?  trackNo;
                        GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                        if (!string.IsNullOrEmpty(title))
                        {
                            title = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(title.ToLowerInvariant());
                        }
                        if (!string.IsNullOrEmpty(artist))
                        {
                            artist = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(artist.ToLowerInvariant());
                        }

                        if (!string.IsNullOrEmpty(tag.Tag.Title))
                        {
                            title = tag.Tag.Title.Trim();
                        }

                        sortTitle = BaseInfo.GetSortTitle(title);
                        if (!string.IsNullOrEmpty(tag.Tag.TitleSort))
                        {
                            sortTitle = tag.Tag.TitleSort.Trim();
                        }

                        IEnumerable <string> artists;
                        if (tag.Tag.Performers.Length > 0)
                        {
                            artists = tag.Tag.Performers;
                            if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                            {
                                artists = PatchID3v23Enumeration(artists);
                            }
                        }
                        else
                        {
                            artists = artist == null ? null : new string[] { artist.Trim() }
                        };
                        if (tag.Tag.Track != 0)
                        {
                            trackNo = tag.Tag.Track;
                        }

                        if (importOnly)
                        {
                            MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, true);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, fsra.CanonicalLocalResourcePath.Serialize());
                            // FIXME Albert: tag.MimeType returns taglib/mp3 for an MP3 file. This is not what we want and collides with the
                            // mimetype handling in the BASS player, which expects audio/xxx.
                            if (!string.IsNullOrWhiteSpace(tag.MimeType))
                            {
                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, tag.MimeType.Replace("taglib/", "audio/"));
                            }

                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, sortTitle);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, false);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tag.Tag.Comment));
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, fsra.LastChanged);
                        }

                        trackInfo.TrackName     = title;
                        trackInfo.TrackNameSort = sortTitle;
                        if (tag.Properties.Codecs.Count() > 0)
                        {
                            trackInfo.Encoding = tag.Properties.Codecs.First().Description;
                        }
                        if (tag.Properties.Duration.TotalSeconds != 0)
                        {
                            trackInfo.Duration = (long)tag.Properties.Duration.TotalSeconds;
                        }
                        if (tag.Properties.AudioBitrate != 0)
                        {
                            trackInfo.BitRate = (int)tag.Properties.AudioBitrate;
                        }
                        if (tag.Properties.AudioChannels != 0)
                        {
                            trackInfo.Channels = (int)tag.Properties.AudioChannels;
                        }
                        if (tag.Properties.AudioSampleRate != 0)
                        {
                            trackInfo.SampleRate = (int)tag.Properties.AudioSampleRate;
                        }

                        TagLib.Id3v2.Tag id3Tag = (TagLib.Id3v2.Tag)tag.GetTag(TagTypes.Id3v2, false);
                        if (id3Tag != null && !id3Tag.IsEmpty)
                        {
                            trackInfo.Compilation = id3Tag.IsCompilation;
                        }

                        trackInfo.Album = !string.IsNullOrEmpty(tag.Tag.Album) ? tag.Tag.Album.Trim() : null;
                        if (!string.IsNullOrEmpty(tag.Tag.AlbumSort))
                        {
                            IAudioRelationshipExtractor.StoreAlbum(extractedAspectData, tag.Tag.Album, tag.Tag.AlbumSort.Trim());
                        }

                        if (trackNo.HasValue)
                        {
                            trackInfo.TrackNum = (int)trackNo.Value;
                        }
                        if (tag.Tag.TrackCount != 0)
                        {
                            trackInfo.TotalTracks = (int)tag.Tag.TrackCount;
                        }
                        if (tag.Tag.Disc != 0)
                        {
                            trackInfo.DiscNum = (int)tag.Tag.Disc;
                        }
                        if (tag.Tag.DiscCount != 0)
                        {
                            trackInfo.TotalDiscs = (int)tag.Tag.DiscCount;
                        }
                        if (!string.IsNullOrEmpty(tag.Tag.Lyrics))
                        {
                            trackInfo.TrackLyrics = tag.Tag.Lyrics;
                        }

                        if (tag.Tag.TrackCount != 0)
                        {
                            trackInfo.TotalTracks = (int)tag.Tag.TrackCount;
                        }

                        if (!string.IsNullOrEmpty(tag.Tag.MusicBrainzTrackId))
                        {
                            trackInfo.MusicBrainzId = tag.Tag.MusicBrainzTrackId;
                        }
                        if (!string.IsNullOrEmpty(tag.Tag.MusicBrainzReleaseId))
                        {
                            trackInfo.AlbumMusicBrainzId = tag.Tag.MusicBrainzReleaseId;
                        }
                        if (!string.IsNullOrEmpty(tag.Tag.MusicBrainzDiscId))
                        {
                            trackInfo.AlbumMusicBrainzDiscId = tag.Tag.MusicBrainzDiscId;
                        }
                        if (!string.IsNullOrEmpty(tag.Tag.AmazonId))
                        {
                            trackInfo.AlbumAmazonId = tag.Tag.AmazonId;
                        }
                        if (!string.IsNullOrEmpty(tag.Tag.MusicIpId))
                        {
                            trackInfo.MusicIpId = tag.Tag.MusicIpId;
                        }

                        trackInfo.Artists = new List <PersonInfo>();
                        if (artists != null)
                        {
                            foreach (string artistName in ApplyAdditionalSeparator(artists))
                            {
                                trackInfo.Artists.Add(new PersonInfo()
                                {
                                    Name            = artistName.Trim(),
                                    Occupation      = PersonAspect.OCCUPATION_ARTIST,
                                    ParentMediaName = trackInfo.Album,
                                    MediaName       = trackInfo.TrackName
                                });
                            }
                        }

                        //Save id if possible
                        if (trackInfo.Artists.Count == 1 && !string.IsNullOrEmpty(tag.Tag.MusicBrainzArtistId))
                        {
                            trackInfo.Artists[0].MusicBrainzId = tag.Tag.MusicBrainzArtistId;
                        }

                        IEnumerable <string> albumArtists = tag.Tag.AlbumArtists;
                        if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                        {
                            albumArtists = PatchID3v23Enumeration(albumArtists);
                        }
                        trackInfo.AlbumArtists = new List <PersonInfo>();
                        if (albumArtists != null)
                        {
                            foreach (string artistName in ApplyAdditionalSeparator(albumArtists))
                            {
                                trackInfo.AlbumArtists.Add(new PersonInfo()
                                {
                                    Name            = artistName.Trim(),
                                    Occupation      = PersonAspect.OCCUPATION_ARTIST,
                                    ParentMediaName = trackInfo.Album,
                                    MediaName       = trackInfo.TrackName
                                });
                            }
                        }

                        //Save id if possible
                        if (trackInfo.AlbumArtists.Count == 1 && !string.IsNullOrEmpty(tag.Tag.MusicBrainzReleaseArtistId))
                        {
                            trackInfo.AlbumArtists[0].MusicBrainzId = tag.Tag.MusicBrainzReleaseArtistId;
                        }

                        IEnumerable <string> composers = tag.Tag.Composers;
                        if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                        {
                            composers = PatchID3v23Enumeration(composers);
                        }
                        trackInfo.Composers = new List <PersonInfo>();
                        if (composers != null)
                        {
                            foreach (string composerName in ApplyAdditionalSeparator(composers))
                            {
                                trackInfo.Composers.Add(new PersonInfo()
                                {
                                    Name            = composerName.Trim(),
                                    Occupation      = PersonAspect.OCCUPATION_COMPOSER,
                                    ParentMediaName = trackInfo.Album,
                                    MediaName       = trackInfo.TrackName
                                });
                            }
                        }

                        if (tag.Tag.Genres.Length > 0)
                        {
                            IEnumerable <string> genres = tag.Tag.Genres;
                            if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                            {
                                genres = PatchID3v23Enumeration(genres);
                            }
                            trackInfo.Genres = ApplyAdditionalSeparator(genres).Select(s => new GenreInfo {
                                Name = s.Trim()
                            }).ToList();
                            OnlineMatcherService.Instance.AssignMissingMusicGenreIds(trackInfo.Genres);
                        }

                        int year = (int)tag.Tag.Year;
                        if (year >= 30 && year <= 99)
                        {
                            year += 1900;
                        }
                        if (year >= 1930 && year <= 2030)
                        {
                            trackInfo.ReleaseDate = new DateTime(year, 1, 1);
                        }

                        if (!trackInfo.HasThumbnail)
                        {
                            // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                            IPicture[] pics = tag.Tag.Pictures;
                            if (pics.Length > 0)
                            {
                                try
                                {
                                    using (MemoryStream stream = new MemoryStream(pics[0].Data.Data))
                                    {
                                        trackInfo.Thumbnail  = stream.ToArray();
                                        trackInfo.HasChanged = true;
                                    }
                                }
                                // Decoding of invalid image data can fail, but main MediaItem is correct.
                                catch { }
                            }
                            else
                            {
                                // In quick mode only allow thumbs taken from cache.
                                bool cachedOnly = importOnly || forceQuickMode;

                                // Thumbnail extraction
                                fileName = mediaItemAccessor.ResourcePathName;
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                byte[]    thumbData;
                                ImageType imageType;
                                if (generator.GetThumbnail(fileName, cachedOnly, out thumbData, out imageType))
                                {
                                    trackInfo.Thumbnail  = thumbData;
                                    trackInfo.HasChanged = true;
                                }
                            }
                        }
                    }

                    if (string.IsNullOrEmpty(trackInfo.Album) || trackInfo.Artists.Count == 0)
                    {
                        MusicNameMatcher.MatchTrack(fileName, trackInfo);
                    }
                }

                //Determine compilation
                if (importOnly && !trackInfo.Compilation)
                {
                    if (trackInfo.AlbumArtists.Count > 0 &&
                        (trackInfo.AlbumArtists[0].Name.IndexOf("Various", StringComparison.InvariantCultureIgnoreCase) >= 0 ||
                         trackInfo.AlbumArtists[0].Name.Equals("VA", StringComparison.InvariantCultureIgnoreCase)))
                    {
                        trackInfo.Compilation = true;
                    }
                    else
                    {
                        //Look for itunes compilation folder
                        var mediaItemPath = mediaItemAccessor.CanonicalLocalResourcePath;
                        var albumMediaItemDirectoryPath  = ResourcePathHelper.Combine(mediaItemPath, "../");
                        var artistMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../../");

                        if (IsDiscFolder(trackInfo.Album, albumMediaItemDirectoryPath.FileName))
                        {
                            //Probably a CD folder so try next parent
                            artistMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../../../");
                        }
                        if (artistMediaItemDirectoryPath.FileName.IndexOf("Compilation", StringComparison.InvariantCultureIgnoreCase) >= 0)
                        {
                            trackInfo.Compilation = true;
                        }
                    }
                }

                if (!refresh)
                {
                    //Check artists
                    trackInfo.Artists      = GetCorrectedArtistsList(trackInfo, trackInfo.Artists);
                    trackInfo.AlbumArtists = GetCorrectedArtistsList(trackInfo, trackInfo.AlbumArtists);
                }

                trackInfo.AssignNameId();

                if (!forceQuickMode)
                {
                    AudioCDMatcher.GetDiscMatchAndUpdate(mediaItemAccessor.ResourcePathName, trackInfo);

                    if (SkipOnlineSearches && !SkipFanArtDownload)
                    {
                        TrackInfo tempInfo = trackInfo.Clone();
                        OnlineMatcherService.Instance.FindAndUpdateTrack(tempInfo, importOnly);
                        trackInfo.CopyIdsFrom(tempInfo);
                        trackInfo.HasChanged = tempInfo.HasChanged;
                    }
                    else if (!SkipOnlineSearches)
                    {
                        OnlineMatcherService.Instance.FindAndUpdateTrack(trackInfo, importOnly);
                    }
                }

                if (refresh)
                {
                    if ((IncludeArtistDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_ARTIST) && trackInfo.Artists.Count > 0) ||
                        (IncludeArtistDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_ALBUMARTIST) && trackInfo.AlbumArtists.Count > 0) ||
                        (IncludeComposerDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_COMPOSER) && trackInfo.Composers.Count > 0))
                    {
                        trackInfo.HasChanged = true;
                    }
                }

                if (!trackInfo.HasChanged && !importOnly)
                {
                    return(false);
                }

                trackInfo.SetMetadata(extractedAspectData);

                if (importOnly)
                {
                    //Store metadata for the Relationship Extractors
                    if (IncludeArtistDetails)
                    {
                        IAudioRelationshipExtractor.StorePersons(extractedAspectData, trackInfo.Artists, false);
                        IAudioRelationshipExtractor.StorePersons(extractedAspectData, trackInfo.AlbumArtists, true);
                    }
                    if (IncludeComposerDetails)
                    {
                        IAudioRelationshipExtractor.StorePersons(extractedAspectData, trackInfo.Composers, false);
                    }
                }

                return(trackInfo.IsBaseInfoPresent);
            }
            catch (UnsupportedFormatException)
            {
                ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Unsupported audio file '{0}'", fsra.CanonicalLocalResourcePath);
                return(false);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
        public override async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            // If the base AudioMDE already extracted metadata, don't try here again to avoid conflicts.
            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                return(false);
            }

            ILocalFsResourceAccessor fsra = mediaItemAccessor as ILocalFsResourceAccessor;

            if (fsra == null)
            {
                return(false);
            }
            if (!fsra.IsFile)
            {
                return(false);
            }
            string fileName = fsra.ResourceName;

            if (!HasAudioExtension(fileName))
            {
                return(false);
            }
            if (extractedAspectData.ContainsKey(ReimportAspect.ASPECT_ID)) //Ignore for reimports because the tags might be the cause of the wrong match
            {
                return(false);
            }

            try
            {
                TAG_INFO tags;
                using (fsra.EnsureLocalFileSystemAccess())
                    tags = BassTags.BASS_TAG_GetFromFile(fsra.LocalFileSystemPath);
                if (tags == null)
                {
                    return(false);
                }

                fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                string title;
                string artist;
                uint?  trackNo;
                GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                if (!string.IsNullOrWhiteSpace(tags.title))
                {
                    title = tags.title;
                }
                IEnumerable <string> artists;
                if (!string.IsNullOrWhiteSpace(tags.artist))
                {
                    artists = SplitTagEnum(tags.artist);
                    artists = PatchID3v23Enumeration(artists);
                }
                else
                {
                    artists = artist == null ? null : new string[] { artist }
                };
                if (!string.IsNullOrWhiteSpace(tags.track) && tags.track != "0")
                {
                    int iTrackNo;
                    if (int.TryParse(tags.track, out iTrackNo))
                    {
                        trackNo = (uint?)iTrackNo;
                    }
                    else
                    {
                        trackNo = null;
                    }
                }

                TrackInfo trackInfo = new TrackInfo();
                if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
                {
                    trackInfo.FromMetadata(extractedAspectData);
                }
                else
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                    IList <MultipleMediaItemAspect> providerResourceAspect;
                    if (MediaItemAspect.TryGetAspects(extractedAspectData, ProviderResourceAspect.Metadata, out providerResourceAspect))
                    {
                        providerResourceAspect[0].SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                        // Calling EnsureLocalFileSystemAccess not necessary; only string operation
                        providerResourceAspect[0].SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "audio/" + Path.GetExtension(fsra.LocalFileSystemPath).Substring(1));
                    }
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, tags.bitrate);
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tags.comment));
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, (long)tags.duration);
                }

                if (!trackInfo.IsBaseInfoPresent)
                {
                    trackInfo.TrackName = title;
                    trackInfo.Album     = StringUtils.TrimToNull(tags.album);
                    if (trackNo.HasValue)
                    {
                        trackInfo.TrackNum = (int)trackNo.Value;
                    }

                    trackInfo.Artists = new List <PersonInfo>();
                    foreach (string artistName in ApplyAdditionalSeparator(artists))
                    {
                        trackInfo.Artists.Add(new PersonInfo()
                        {
                            Name            = artistName,
                            Occupation      = PersonAspect.OCCUPATION_ARTIST,
                            ParentMediaName = trackInfo.Album,
                            MediaName       = trackInfo.TrackName
                        });
                    }

                    IEnumerable <string> albumArtists = SplitTagEnum(tags.albumartist);
                    albumArtists           = PatchID3v23Enumeration(albumArtists);
                    trackInfo.AlbumArtists = new List <PersonInfo>();
                    foreach (string artistName in ApplyAdditionalSeparator(albumArtists))
                    {
                        trackInfo.AlbumArtists.Add(new PersonInfo()
                        {
                            Name            = artistName,
                            Occupation      = PersonAspect.OCCUPATION_ARTIST,
                            ParentMediaName = trackInfo.Album,
                            MediaName       = trackInfo.TrackName
                        });
                    }

                    IEnumerable <string> composers = SplitTagEnum(tags.composer);
                    composers           = PatchID3v23Enumeration(composers);
                    trackInfo.Composers = new List <PersonInfo>();
                    foreach (string composerName in ApplyAdditionalSeparator(composers))
                    {
                        trackInfo.Composers.Add(new PersonInfo()
                        {
                            Name            = composerName,
                            Occupation      = PersonAspect.OCCUPATION_COMPOSER,
                            ParentMediaName = trackInfo.Album,
                            MediaName       = trackInfo.TrackName
                        });
                    }

                    IEnumerable <string> genres = SplitTagEnum(tags.genre);
                    genres           = PatchID3v23Enumeration(genres);
                    trackInfo.Genres = ApplyAdditionalSeparator(genres).Where(s => !string.IsNullOrEmpty(s?.Trim())).Select(s => new GenreInfo {
                        Name = s.Trim()
                    }).ToList();
                    IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>();
                    foreach (var genre in trackInfo.Genres)
                    {
                        if (!genre.Id.HasValue && converter.GetGenreId(genre.Name, GenreCategory.Music, null, out int genreId))
                        {
                            genre.Id = genreId;
                        }
                    }

                    int year;
                    if (int.TryParse(tags.year, out year))
                    {
                        if (year >= 30 && year <= 99)
                        {
                            year += 1900;
                        }
                        if (year >= 1930 && year <= 2030)
                        {
                            trackInfo.ReleaseDate = new DateTime(year, 1, 1);
                        }
                    }

                    if (!trackInfo.HasThumbnail)
                    {
                        // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                        if (tags.PictureCount > 0)
                        {
                            try
                            {
                                using (Image cover = tags.PictureGetImage(0))
                                    using (MemoryStream result = new MemoryStream())
                                    {
                                        cover.Save(result, ImageFormat.Jpeg);
                                        trackInfo.Thumbnail  = result.ToArray();
                                        trackInfo.HasChanged = true;
                                    }
                            }
                            // Decoding of invalid image data can fail, but main MediaItem is correct.
                            catch { }
                        }
                    }
                }

                if (!SkipOnlineSearches && !forceQuickMode)
                {
                    await OnlineMatcherService.Instance.FindAndUpdateTrackAsync(trackInfo).ConfigureAwait(false);
                }

                if (!trackInfo.HasChanged)
                {
                    return(false);
                }

                trackInfo.SetMetadata(extractedAspectData);

                return(trackInfo.IsBaseInfoPresent);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here
                ServiceRegistration.Get <ILogger>().Info("BassAudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }